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.
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:
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 POST
s à cette vuedelete
à la place, vérifiez les autorisations après l'appel get_object
et renvoyez une réponse personnalisée.success_url
(éventuellement personnalisable) afin que l'utilisateur puisse confirmer que l'objet a été supprimé.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:
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)
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'),
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.
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)
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)
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