Overriding delete method in generic delete view not working and getting warning

I have a model for presets

class Preset(models.Model):
     id = models.UUIDField(default=uuid.uuid4, unique=True, editable=False, primary_key=True)
     user = models.ForeignKey('accounts.CustomUser', on_delete=models.PROTECT)
     user_provided_name = models.CharField(max_length=100, null=False, blank=False) 
     archived = models.BooleanField(default=False)

The presets are referenced as a FK in the Session model:

class Session(models.Model):
     id = models.UUIDField(default=uuid.uuid4, unique=True, editable=False, primary_key=True)
     user = models.ForeignKey('accounts.CustomUser', on_delete=models.PROTECT)
     user_provided_name = models.CharField(max_length=150, null=False, blank=False)
     preset = models.ForeignKey(CropPreset, on_delete=models.PROTECT)

I am using the generic DeleteView. When a user tries to delete a preset but it has been used in the Session model, I want it to not delete, but just mark it as archived.

Here is my current DeleteView:

class PresetDeleteView(LoginRequiredMixin, DeleteView):
    def get_success_url(self):
        messages.success(self.request, "Your preset has been deleted")
        return reverse('presets_list')
    
    def get_queryset(self):
        return Preset.objects.filter(user=self.request.user)

    def delete(self, *args, **kwargs):
        try:
            return super(PresetDeleteView, self).delete(*args, **kwargs)
        except models.ProtectedError as e:
            self.object = self.get_object()
            self.object.archived=True
            self.object.save()
            return HttpResponseRedirect(self.get_success_url)

When I try this view with a preset with no attached session, it deletes the record just fine but I get this warning in the command line:

DeleteViewCustomDeleteWarning: DeleteView uses FormMixin to handle POST requests. As a consequence, any custom deletion logic in PresetDeleteView.delete() handler should be moved to form_valid().
  self = cls(**initkwargs)

When I try to run the view with a preset that has records attached and mark it as archived, it just gives me this on the Django debug screen

ProtectedError at /presets/delete/<whatever the uuid is here>/

2 questions:
What does the DeleteViewCustomDeleteWarning mean?
How do I get it to actually execute the except statement in the delete method I am overriding?

See DeleteView -- Classy CBV and DeleteView to get a detailed view of what a DeleteView is doing.

Briefly, DeleteView receives a POST request, not a DELETE request.

The post method in BaseDeleteView does not call self.delete, it calls self.form_valid. Then, self.form_valid calls self.object.delete before returning the redirect to success_url.

So, in a “normal” POST-based form submission, self.delete in the view does not get called. An HTML form may only submit a get or post command.
(It would get called if it was a rest-style submission using AJAX with a delete.)

The warning message is telling you what you need to do. The logic that you’re putting in the delete method needs to be in form_valid if you want it to run.

1 Like