【问题标题】:Deleting objects in Django在 Django 中删除对象
【发布时间】:2011-03-08 16:02:44
【问题描述】:

在一个迷你博客应用程序中,我想创建一个删除功能,以便博客所有者可以删除他的条目(并且只删除他的条目)。 我想这样做的唯一方法是使用表格。 虽然我的删除代码看起来清晰正确,但它不起作用。 我的代码:

def delete_new(request,id):
   u = New.objects.get(pk=id).delete()
   if request.method == 'POST':
       form = DeleteNewForm(request.POST)    
       form.u.delete()             
       form.save()   
   return render_to_response('news/deleteNew.html', {
           'form': form,
           }, 
        context_instance=RequestContext(request)) 

在模板中:

<a href='/news/delete_new/{{object.id}}/'> Delete</a> <br /> 

这是正确的方法吗?我的意思是,为此创建一个表格? 此外,获取与删除链接关联的博客文章的唯一方法是将 id 作为参数。这样对吗?我的意思是,也许任何用户都可以在 url 中输入另一个 id,然后删除另一个条目(最终不是他的一个)

【问题讨论】:

    标签: django forms object django-views


    【解决方案1】:

    您需要使用表单,否则您很容易受到CSRF attacks 的攻击。在检查请求是 GET 还是 POST 之前,您还要删除模型。

    创建一个简单的ModelForm

    from django import forms
    
    from .models import New
    
    class DeleteNewForm(forms.ModelForm):
        class Meta:
            model = New
            fields = []
    

    在同一个 Django 应用中的 views.py 中:

    from django.shortcuts import render, get_object_or_404
    
    from .forms import DeleteNewForm
    from .models import New
    
    def delete_new(request, new_id):
        new_to_delete = get_object_or_404(New, id=new_id)
        #+some code to check if this object belongs to the logged in user
    
        if request.method == 'POST':
            form = DeleteNewForm(request.POST, instance=new_to_delete)
    
            if form.is_valid(): # checks CSRF
                new_to_delete.delete()
                return HttpResponseRedirect("/") # wherever to go after deleting
    
        else:
            form = DeleteNewForm(instance=new_to_delete)
    
        template_vars = {'form': form}
        return render(request, 'news/deleteNew.html', template_vars)
    

    【讨论】:

    • 解释为什么这是最好的:在任何情况下,提交、更新和删除都必须使用 POST(或 PUT)请求。 GET 请求可以在看起来无害的链接中被屏蔽。比如说,如果一个主要网站在 example.com/account/delete/ 上有一个简单的“删除我的所有东西”,我可以在博客文章或类似 TinyURL 的服务中隐藏这样的链接。访问时,您会看到一个很好的“您的个人资料已删除”。页。 Wilfred Hughes 等混合方法在 GET 上显示确认页面,其中包含带有 CSRF 令牌的表单。 POST 请求验证 CSRF,然后最终删除请求的资源。
    【解决方案2】:

    一般来说,要删除对象,您应该使用 POST(或 DELETE)HTTP methods

    如果您真的想在示例中使用 HTTP GET,则需要解决以下问题:

    如果您的 url 指向像您这样的 url:&lt;a href='/news/delete_new/{{object.id}}/'&gt; Delete&lt;/a&gt;,那么您可以简单地编写视图来检查对象是否属于登录用户,如果是,则删除此条目,就像您已经编写的代码一样:

    def delete_new(request,id):
       #+some code to check if New belongs to logged in user
       u = New.objects.get(pk=id).delete()
    

    要检查新对象是否属于某个用户,您需要在 UserNew 之间创建关联(如 New 模型中的 created_by = models.ForeignKey(User))。

    您可以通过这种方式获得登录用户:request.user

    我希望我能正确理解你的观点,并且我的回答对你有所帮助。

    PS:你也可以考虑使用{% url %}标签,而不是直接在模板中写url。

    【讨论】:

    • 它运行顺利,并且只有一行:u = New.objects.filter(created_by = request.user).get(pk=id).delete() 谢谢! :)
    • 确切地说,如果给定用户没有这样的 New 对象,您可以添加一些错误处理并显示漂亮的错误消息(使用您的一个班轮它会大声失败并出现 500 错误)。但基本上这就是您在这里需要做的所有事情:)很高兴我的回答对您有所帮助。
    • 我强烈建议使用表单并检查 POST,因为对页面的 GET 不应该改变服务器上的状态。 (尽管实际上这里发生的事情相对“安全”)
    • 这样做会将您的网站打开到 CSRF,因为没有令牌被传输/需要。
    • 这是安全的,并且允许用户删除属于其他用户的内容的 CSRF 攻击。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-02-14
    • 2018-10-17
    • 1970-01-01
    • 1970-01-01
    • 2012-02-26
    • 1970-01-01
    • 2018-11-05
    相关资源
    最近更新 更多