Кто-нибудь знает или может кому-нибудь создать простой пример универсального DeleteView на основе Django? Я хочу подклассифицировать DeleteView и убедиться, что пользователь, который в настоящий момент вошел в систему, имеет право собственности на объект перед его удалением. Любая помощь будет очень высоко ценится. Заранее благодарю вас.
Пример демонстрации на основе класса Django
Ответ 1
Здесь простой:
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
Предостережения:
-
DeleteView
не будет удалять запросыGET
; это ваша возможность предоставить шаблон подтверждения (вы можете указать имя в атрибуте классаtemplate_name
) кнопкой "Да, я уверен", котораяPOST
для этого представления - Вы можете предпочесть сообщение об ошибке 404? В этом случае переопределите метод
delete
, проверьте разрешения после вызоваget_object
и верните настроенный ответ. - Не забудьте указать шаблон, соответствующий (необязательно настраиваемому) атрибуту класса
success_url
, чтобы пользователь мог подтвердить, что объект был удален.
Ответ 2
Я в основном подклассифицировал некоторые из Generic Class-Based-Views, чтобы сделать именно это. Основное различие заключается в том, что я просто отфильтровал запросы. Я не могу ручаться за то, является ли этот метод лучше или хуже, но для меня это имело больше смысла.
Не забудьте проигнорировать "MessageMixin" - просто там, чтобы легко отправлять сообщения с помощью Django Messaging Framework с переменной, указанной для каждого представления. Вот код, который я написал для нашего сайта:
представления
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 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 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 data.
"""
success_message = "Deleted Successfully"
def get_queryset(self):
qs = super(RequestDeleteView, self).get_queryset()
return qs.filter(owner=self.request.user)
Использование
Затем вы можете легко создавать свои собственные представления для использования этого типа функций. Например, я просто создаю их в своем 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'),
Формы
Важно отметить: Я перегрузил эти методы get_form_kwargs(), чтобы предоставить моим Forms экземпляр "запроса". Если вы не хотите, чтобы объект Request был передан в форму, просто удалите эти перегруженные методы. Если вы хотите их использовать, выполните следующий пример:
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
Это немного больше, чем вы просили - но это помогает узнать, как сделать то же самое для Create and Update views. Эта же общая методология также может быть применена к ListView и DetailView.
MessageMixin
На всякий случай кто-то хочет использовать MessageMixin.
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)
Ответ 3
Я бы предложил, чтобы лучший (и самый простой) способ сделать это состоял бы в использовании UserPassesTestMixin
, который дает вам более чистый разделение проблем.
Пример:
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
Ответ 4
Самый простой способ сделать это - предварительный набор запросов:
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)