Example of Django Class-Based DeleteView Example of Django Class-Based DeleteView django django

Example of Django Class-Based DeleteView


Here's a simple one:

from django.views.generic import DeleteViewfrom django.http import Http404class MyDeleteView(DeleteView):    def get_object(self, queryset=None):        """ Hook to ensure object is owned by request.user. """        obj = super(MyDeleteView, self).get_object()        if not obj.owner == self.request.user:            raise Http404        return obj

Caveats:

  • The DeleteView won't delete on GET requests; this is your opportunity to provide a confirmation template (you can provide the name in the template_name class attribute) with a "Yes I'm sure" button which POSTs to this view
  • You may prefer an error message to a 404? In this case, override the delete method instead, check permissions after the get_object call and return a customised response.
  • Don't forget to provide a template which matches the (optionally customisable) success_url class attribute so that the user can confirm that the object has been deleted.


I've basically sub-classed some of the Generic Class-Based-Views to do exactly that. The main difference is I just filtered out the querysets. I can't vouch for whether this method is any better or worse but it made more sense to me.

Feel free to ignore the "MessageMixin" -- that's just there to easily present Messages using the Django Messaging Framework w/ a variable specified for each view. Here's the code I've written for our site:

Views

from django.views.generic import CreateView, UpdateView, \        DeleteView, ListView, DetailViewfrom myproject.core.views import MessageMixinclass RequestCreateView(MessageMixin, CreateView):    """     Sub-class of the CreateView to automatically pass the Request to the Form.     """    success_message = "Created Successfully"    def get_form_kwargs(self):        """ Add the Request object to the Form's Keyword Arguments. """        kwargs = super(RequestCreateView, self).get_form_kwargs()        kwargs.update({'request': self.request})        return kwargsclass RequestUpdateView(MessageMixin, UpdateView):    """    Sub-class the UpdateView to pass the request to the form and limit the    queryset to the requesting user.            """    success_message = "Updated Successfully"    def get_form_kwargs(self):        """ Add the Request object to the form's keyword arguments. """        kwargs = super(RequestUpdateView, self).get_form_kwargs()        kwargs.update({'request': self.request})        return kwargs    def get_queryset(self):        """ Limit a User to only modifying their own data. """        qs = super(RequestUpdateView, self).get_queryset()        return qs.filter(owner=self.request.user)class RequestDeleteView(MessageMixin, DeleteView):    """    Sub-class the DeleteView to restrict a User from deleting other     user's data.    """    success_message = "Deleted Successfully"    def get_queryset(self):        qs = super(RequestDeleteView, self).get_queryset()        return qs.filter(owner=self.request.user)

Usage

Then, you can easily create your own views to use this type of functionality. For example, I am just creating them in my urls.py:

from myproject.utils.views import RequestDeleteView#...url(r'^delete-photo/(?P<pk>[\w]+)/$', RequestDeleteView.as_view(                   model=Photo,                   success_url='/site/media/photos',                   template_name='site/media-photos-delete.html',                   success_message='Your Photo has been deleted successfully.'                   ), name='fireflie-delete-photo-form'),

Forms

Important to note: I have overloaded those get_form_kwargs() methods to provide my Forms with an instance of 'request'. If you don't want the Request object passed to the Form, simply remove those overloaded methods. If you want to use them, follow this example:

from django.forms import ModelFormclass RequestModelForm(ModelForm):    """    Sub-class the ModelForm to provide an instance of 'request'.    It also saves the object with the appropriate user.    """    def __init__(self, request, *args, **kwargs):        """ Override init to grab the request object. """        self.request = request        super(RequestModelForm, self).__init__(*args, **kwargs)    def save(self, commit=True):        m = super(RequestModelForm, self).save(commit=False)        m.owner = self.request.user        if commit:            m.save()        return m

This is a bit more than you asked -- but it helps to know how to do the same for Create and Update views as well. This same general methodology could also be applied to ListView & DetailView.

MessageMixin

Just in case anyone wants that MessageMixin I use.

class MessageMixin(object):    """    Make it easy to display notification messages when using Class Based Views.    """    def delete(self, request, *args, **kwargs):        messages.success(self.request, self.success_message)        return super(MessageMixin, self).delete(request, *args, **kwargs)    def form_valid(self, form):        messages.success(self.request, self.success_message)        return super(MessageMixin, self).form_valid(form)


The simplest way to do that is to prefilter the queryset:

from django.views.generic import DeleteViewclass PostDeleteView(DeleteView):    model = Post    success_url = reverse_lazy('blog:list_post')    def get_queryset(self):        owner = self.request.user        return self.model.objects.filter(owner=owner)