Correct way to use get_success_url for a DeleteView when the URL needs kwargs from the object being deleted

I have two models, Schemes and Buildings, where each Building instance belongs to a particular Scheme instance. And the URLs are set up like this:

urlpatterns += [
    path('scheme/<uuid:pk>/buildings/', BuildingListView.as_view(), name='building-list'),
    path('scheme/<uuid:pk2>/building/<uuid:pk>/', BuildingDetailView.as_view(), name='building-detail'),
    path('scheme/<uuid:pk>/buildings/add/', BuildingCreateView.as_view(), name='create-building'),
    path('scheme/<uuid:pk2>/building/<uuid:pk>/edit/', BuildingUpdateView.as_view(), name='update-building'),
    path('scheme/<uuid:pk2>/building/<uuid:pk>/delete/', BuildingDeleteView.as_view(), name='delete-building'),
]

I created my delete view so that it will redirect to the first URL in the above list (‘building-list’). However, this need the pk of the Building instance, which is tied to the object being deleted.

I’ve come across multiple options while searching for a solution, and those included:

  • Overriding a method called ‘delete( )’ of the DeleteView
  • Using the init() to save the required pk before the item gets deleted
  • Workarounds inside the get_success_url method itself, using kwargs or object
  • And a few other that I didn’t understand at all…

None worked, and the issue appeared to be still tied to get_success_url getting executed after the object was deleted. (although, I don’t think I did the delete( ) method workaround correctly).

However, after some fiddling around, I thought of calling the get_success_url inside the form_valid before the object is deleted, and save it there. And then the view worked. This is my DeleteView right now:

class BuildingDeleteView(PermissionRequiredMixin, DeleteView):
    model = Building
    permission_required = 'components.delete_building'

    def form_valid(self, form):
        try:
            success_url = self.get_success_url()
            self.object.delete()
            return HttpResponseRedirect(success_url)
        except Exception as e:
            return HttpResponseRedirect(
                reverse_lazy('schemes:delete-building', kwargs={'pk2': self.object.scheme.pk, 'pk': self.object.pk})
            )

    def get_success_url(self, **kwargs) -> str:
        scheme = self.get_object().scheme
        return reverse_lazy('schemes:building-list', kwargs={'pk': scheme.id})

What I would like to know is, if I’m doing something incorrect here, or if there’s something that might result in some other bug in a scenario which I’m unware of.

Any help or recommendations on the correctness of the above, or if not, the best convention to handle a similar situation is much appreciated.

If you look at the source code for the BaseDeleteView, you’ll see that its definition for form_valid is:

def form_valid(self, form):
    success_url = self.get_success_url()
    self.object.delete()
    return HttpResponseRedirect(success_url)

Look familiar? It’s basically what you’ve got, except that you are catching any exceptions that might be thrown.

What that boils down to is that yes, this would be correct.

As always, thank you very much for the answer and the clarification Ken. I’m going to take a closer looks some of those Base Views as classy cbvs, as you’ve pointed out in many posts.
Thanks again!