web-dev-qa-db-fra.com

Exemple de DeleteView basé sur les classes de Django

Est-ce que quelqu'un connaît ou peut-il s'il vous plaît produire un exemple simple du programme générique DeleteView basé sur les classes de Django? Je veux sous-classer DeleteView et m'assurer que l'utilisateur actuellement connecté a la propriété de l'objet avant qu'il ne soit supprimé. Toute aide serait très appréciée. Merci d'avance.

50
Lockjaw

Voici un simple:

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

Mises en garde:

  • La DeleteView ne supprimera pas les demandes GET; C'est l'occasion de fournir un modèle de confirmation (vous pouvez indiquer le nom dans l'attribut de classe template_name) avec un bouton "Oui, je suis sûr" qui POSTs à cette vue
  • Vous préférez peut-être un message d'erreur à un 404? Dans ce cas, remplacez la méthode delete à la place, vérifiez les autorisations après l'appel get_object et renvoyez une réponse personnalisée.
  • N'oubliez pas de fournir un modèle correspondant à l'attribut de classe success_url (éventuellement personnalisable) afin que l'utilisateur puisse confirmer que l'objet a été supprimé.
56
DrMeers

J'ai essentiellement sous-classé certaines des vues génériques basées sur la classe pour faire exactement cela. La principale différence est que je viens de filtrer les querysets. Je ne peux pas garantir que cette méthode soit meilleure ou pire, mais cela me semblait plus logique.

Sentez-vous libre d'ignorer le "MessageMixin" - il s'agit simplement de présenter facilement des messages à l'aide de la structure de messagerie Django avec une variable spécifiée pour chaque vue. Voici le code que j'ai écrit pour notre site:

Des vues

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)

Usage

Ensuite, vous pouvez facilement créer vos propres vues pour utiliser ce type de fonctionnalité. Par exemple, je ne fais que les créer dans mon 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'),

Formes

Important à noter: J'ai surchargé ces méthodes get_form_kwargs () pour fournir à mes formulaires une instance de 'demande'. Si vous ne voulez pas que l'objet Request soit passé au formulaire, supprimez simplement ces méthodes surchargées. Si vous voulez les utiliser, suivez cet exemple:

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

C’est un peu plus que ce que vous avez demandé - mais il est utile de savoir comment faire de même pour les vues Créer et Mettre à jour. Cette même méthodologie générale pourrait également être appliquée à ListView & DetailView.

MessageMixin

Juste au cas où quelqu'un voudrait que MessageMixin soit utilisé.

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

Le moyen le plus simple de le faire est de pré-filtrer le queryset:

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

Je suggérerais que le meilleur moyen (et le plus simple) de procéder consiste à utiliser la variable UserPassesTestMixin , qui vous permet de mieux distinguer les préoccupations.

Exemple:

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