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.

1 Like

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!