【问题标题】:Example of Django Class-Based DeleteViewDjango 基于类的 DeleteView 示例
【发布时间】:2011-07-28 17:23:44
【问题描述】:

有谁知道或者可以请任何人制作一个简单的 Django 基于类的通用 DeleteView 示例吗?我想继承 DeleteView 并确保当前登录的用户在删除之前拥有该对象的所有权。任何帮助将不胜感激。提前谢谢你。

【问题讨论】:

    标签: django django-views django-class-based-views


    【解决方案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 类属性中提供名称)和“是的,我确定”按钮,POSTs 到此视图
    • 您可能更喜欢错误消息而不是 404?在这种情况下,请改写 delete 方法,在 get_object 调用后检查权限并返回自定义响应。
    • 不要忘记提供与(可选自定义)success_url 类属性相匹配的模板,以便用户确认对象已被删除。

    【讨论】:

    • 啊——这太有帮助了!感谢您抽出宝贵时间。文档中没有问题,但盯着文档看几天会很费劲。
    • 用用户检查覆盖调度方法不是更好吗?在 get_object 方法中做检查有什么好处?
    • @Erik @DrMeers 我会覆盖get_queryset 方法。这样做要简单得多:return self.request.user.foo_set.all()。然后默认的get_object 方法将过滤掉查询集,该查询集只有self.request.user 拥有的项目。如果没有找到,它会 404。
    • 只是出于好奇,如果用户直接发帖到 MyDeleteView 的 url 怎么办?上述解决方案中给出的视图不会被调用,因此任何用户都可以删除任何对象,无论其权限如何。
    • @cphyc 在代码到达self.object.delete() 之前,总是在DeletionMixin.delete 中调用get_object 方法。直接发到MyDeleteView的url 正常的删除方式
    【解决方案2】:

    我基本上已经对一些基于类的通用视图进行了子类化来做到这一点。主要区别是我只是过滤掉了查询集。我不能保证这种方法是好是坏,但它对我来说更有意义。

    请随意忽略“MessageMixin”——它只是为了使用 Django 消息框架(带有为每个视图指定的变量)轻松呈现消息。这是我为我们的网站编写的代码:

    观看次数

    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)
    

    用法

    然后,您可以轻松创建自己的视图来使用此类功能。例如,我只是在我的 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() 方法来为我的表单提供一个“请求”实例。如果您不希望将 Request 对象传递给 Form,只需删除那些重载的方法。如果您想使用它们,请按照以下示例进行操作:

    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 和 Update 视图执行相同的操作。同样的通用方法也可以应用于 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)
    

    【讨论】:

    • 现在有 django.contrib.messages.views.SuccessMessageMixin。 code.djangoproject.com/ticket/16319
    • 一般来说,要将请求实例添加到您的上下文中,请使用django.template.context_processors.request 上下文处理器。
    【解决方案3】:

    最简单的方法是预过滤查询集:

    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)
    

    【讨论】:

    • 我喜欢这个答案,您只查询一次对象(此页面上的某些解决方案需要双重查找),如果对象被过滤出用户范围,它会固有地引发 Http404 错误,不需要额外的用户身份验证逻辑。
    【解决方案4】:

    我建议最好(也是最简单)的方法是使用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
    

    【讨论】:

    • 我相信这会使对象从数据库中获取两次,第一次是在调用 test_func 时,第二次是在视图实际呈现时?
    猜你喜欢
    • 2017-08-27
    • 2023-03-24
    • 2014-07-04
    • 2012-03-21
    • 2013-08-03
    • 1970-01-01
    • 1970-01-01
    • 2011-01-18
    • 1970-01-01
    相关资源
    最近更新 更多