Django:更干燥的方法来防止编辑/删除对象?

4 投票
2 回答
788 浏览
提问于 2025-04-17 20:49

我看完Django的权限文档后,还是有点困惑。
我想要防止用户编辑或删除他们不拥有的对象。
我这样做了,效果不错:

在views.py文件中:

def deleteReward(request, reward_id):
    reward = get_object_or_404(Reward, pk=reward_id)
    if reward.owner.user != request.user: # if the user linked to the reward is not the current one
        raise Exception("This reward is not yours, you can't delete it !")
    #...

但是我觉得这样不太干净,也不符合DRY原则,原因有两个:

  1. 在每个editStuff和deleteStuff的视图中,我都得写同样的代码。

  2. 我现在正在用Tastypie写一个API,如果权限逻辑放在视图里,我就不能重用它。看起来最好的解决办法是把API的权限和Django的权限对应起来(但我在视图中写的代码和权限没有关系)。

你能帮我找到正确的方法吗?非常感谢。

2 个回答

1

get_object_or_404 函数传递一个额外的参数:

reward = get_object_or_404(Reward, pk=reward_id, owner=request.user)
2

这是我的一个工作示例。

1) 查询集

class PermissionQuerySet(models.query.QuerySet):
    def editable_by(self, user):
        return self.filter(user=user)

    def viewable_by(self, user):
        return self.filter(user=user)

2) 管理器

class PermissionManager(models.Manager):
    def get_query_set(self):
        return PermissionQuerySet(self.model)

    def editable_by(self, user, *args):
        return self.get_query_set().editable_by(user, *args)

    def viewable_by(self, user, *args):
        return self.get_query_set().viewable_by(user, *args)

3) 模型

class MyModel(models.Model):
    ...
    objects = PermissionManager()

这种方法在基于类的视图中效果很好。我看到你在使用TastyPie。我之前没用过它,但看起来它也使用基于类的视图。

这是一个工作示例:

class MyUpdateView(UpdateView):
    def post(self, request, *args, **kwargs):
        self.request = request
        super(MyUpdateView, self).post(request, *args, **kwargs)

    def get_query_set(self):
        queryset = super(MyUpdateView, self).get_query_set()
        queryset = queryset.editable_by(self.request.user)
        if not queryset.exists():
            raise Exception("This reward is not yours, you can't delete it !")
        return queryset

我想你可以想象如何在CreateView和DeleteView中使用这种方法。我觉得在TastyPie中实现这个也很简单。

撰写回答