createview - crud django
Ejemplo de DeleteView basado en clases de Django (4)
Aquí hay una 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
Advertencias:
- El
DeleteView
no borrará en las solicitudesGET
; esta es su oportunidad de proporcionar una plantilla de confirmación (puede proporcionar el nombre en el atributo de clasetemplate_name
) con un botón "Sí, estoy seguro", quePOST
está en esta vista - Usted puede preferir un mensaje de error a un 404? En este caso, anule el método de
delete
, verifique los permisos después de la llamada aget_object
y devuelva una respuesta personalizada. - No olvide proporcionar una plantilla que coincida con el atributo de clase
success_url
(opcionalmente personalizable) para que el usuario pueda confirmar que el objeto se ha eliminado.
¿Alguien sabe o puede alguien por favor producir un ejemplo simple de DeleteView genérico basado en clase de Django? Quiero crear una subclase de DeleteView y asegurarme de que el usuario que ha iniciado sesión actualmente sea propietario del objeto antes de eliminarlo. Cualquier ayuda sería muy apreciada. Gracias de antemano.
Básicamente, he subclasificado algunas de las Vistas genéricas basadas en clase para hacer exactamente eso. La principal diferencia es que acabo de filtrar los querysets. No puedo responder si este método es mejor o peor, pero tenía más sentido para mí.
Siéntase libre de ignorar el "MessageMixin", que está ahí para presentar fácilmente los Mensajes utilizando el Marco de Mensajería de Django con una variable especificada para cada vista. Aquí está el código que he escrito para nuestro sitio:
Puntos de vista
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)
Uso
Luego, puede crear fácilmente sus propias vistas para utilizar este tipo de funcionalidad. Por ejemplo, solo los estoy creando en mi 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''),
Formas
Importante tener en cuenta: he sobrecargado los métodos get_form_kwargs () para proporcionar a mis Formularios una instancia de "solicitud". Si no desea que el objeto de solicitud se pase al formulario, simplemente elimine los métodos sobrecargados. Si quieres usarlos, sigue este ejemplo:
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
Esto es un poco más de lo que pidió, pero es útil saber cómo hacer lo mismo para las vistas Crear y Actualizar. Esta misma metodología general también podría aplicarse a ListView y DetailView.
MessageMixin
Por si alguien quiere ese MessageMixin que uso.
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)
La forma más sencilla de hacerlo es prefiltrar el 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)
Propongo que la mejor (y más simple) forma de hacerlo sería utilizar UserPassesTestMixin
que le proporciona una separación de preocupaciones más UserPassesTestMixin
.
Ejemplo:
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