web-dev-qa-db-de.com

Beispiel für eine Django-Klassen-basierte DeleteView

Kennt jemand etwas oder kann jemand ein einfaches Beispiel für Djangos generisches DeleteView generieren? Ich möchte DeleteView subclass und sicherstellen, dass der aktuell angemeldete Benutzer das Eigentum des Objekts besitzt, bevor es gelöscht wird. Jede Hilfe wäre sehr dankbar. Danke im Voraus.

50
Lockjaw

Hier ist eine einfache:

from Django.views.generic import DeleteView
from Django.http import Http404

class 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

Vorsichtsmaßnahmen:

  • Die Variable DeleteView wird bei GET-Anforderungen nicht gelöscht. Dies ist Ihre Gelegenheit, eine Bestätigungsvorlage (Sie können den Namen im Klassenattribut template_name angeben) mit einer Schaltfläche "Ja, ich bin sicher" anzugeben, die POSTs für diese Ansicht enthält
  • Sie können eine Fehlermeldung einer 404 vorziehen? In diesem Fall überschreiben Sie stattdessen die delete-Methode, überprüfen Sie die Berechtigungen nach dem get_object-Aufruf und geben Sie eine angepasste Antwort zurück.
  • Vergessen Sie nicht, eine Vorlage bereitzustellen, die dem (optional anpassbaren) success_url-Klassenattribut entspricht, damit der Benutzer bestätigen kann, dass das Objekt gelöscht wurde.
56
DrMeers

Ich habe im Grunde einige der generischen klassenbasierten Ansichten dahingehend klassifiziert, dass sie genau das tun. Der Hauptunterschied besteht darin, dass ich nur die Querysets herausgefiltert habe. Ich kann nicht dafür bürgen, ob diese Methode besser oder schlechter ist, aber für mich war es sinnvoller.

Sie können das "MessageMixin" einfach ignorieren. Hier können Sie Nachrichten einfach mit dem Django Messaging Framework mit einer für jede Ansicht angegebenen Variablen präsentieren. Hier ist der Code, den ich für unsere Site geschrieben habe:

Ansichten

from Django.views.generic import CreateView, UpdateView, \
        DeleteView, ListView, DetailView

from myproject.core.views import MessageMixin

class 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 kwargs

class 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)

Verwendungszweck

Sie können dann leicht eigene Ansichten erstellen, um diese Art von Funktionalität zu verwenden. Zum Beispiel erstelle ich sie in meiner 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'),

Formen

Wichtig zu beachten: Ich habe diese get_form_kwargs () - Methoden überladen, um meine Formulare mit einer Instanz von 'request' zu versehen. Wenn das Request-Objekt nicht an das Formular übergeben werden soll, entfernen Sie einfach diese überladenen Methoden. Wenn Sie sie verwenden möchten, folgen Sie diesem Beispiel:

from Django.forms import ModelForm

class 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

Dies ist etwas mehr als Sie gefragt haben - aber es ist hilfreich zu wissen, wie Sie dies auch für die Erstellungs- und Aktualisierungsansicht tun. Dieselbe allgemeine Methodik könnte auch auf ListView & DetailView angewendet werden.

MessageMixin

Nur für den Fall, dass jemand das MessageMixin möchte, das ich verwende.

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)
42
Kurtis

Am einfachsten ist es, das Abfrageset vorzufiltern:

from Django.views.generic import DeleteView


class 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)
3
Israel Teixeira

Ich würde vorschlagen, dass der beste (und einfachste) Weg, dies zu tun, die Verwendung der UserPassesTestMixin wäre, die eine sauberere Trennung der Bedenken ermöglicht.

Beispiel:

from Django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from Django.views.generic import DeleteView


class MyDeleteView(LoginRequiredMixin, UserPassesTestMixin, DeleteView):
    def test_func(self):
        """ Only let the user access this page if they own the object being deleted"""
        return self.get_object().owner == self.request.user
0
Inti