Django - 对象级别权限和基于类的通用视图

时间:2011-10-21 04:25:21

标签: python django permissions

这是模型:

class Car(models.Model):
    user = models.ForeignKey(User, related_name='cars')
    name = models.CharField(max_length=64)

Url模式是这样的:

url(r'^car/(?P<pk>\d+)/$', login_required(CarDetails.as_view()), name='car_details)

并查看:

class CarDetail(DetailView):
    context_object_name = 'car'
    template_name = 'my_app/car_details.html'
    model = models.Car

    def get_object(self, *args, **kwargs):
        car = super(CarDetail, self).get_object(*args, **kwargs)
        if car.user != self.request.user:
            raise PermissionDenied()
        else:
            return car

这很好用,但在每个类中我都要覆盖get_object以防止用户弄乱别人的对象。这包括编辑和删除我拥有的每个模型,这严重违反了DRY原则。

有更好的方法吗?像login_required decorator那样的东西可能吗?

修改

DrTyrsa在答案中提出的解决方案或多或少都很简单,只有一点点不同。我创建了继承CurUserOnly而不是object的基类DetailView(我想将此类与DeleteViewUpdateView一起使用)现在{{ 1}}继承CarDetailCurUserOnlyDetailView继承CarDeleteCurUserOnly等等......

有趣的是我之前尝试过这个,但它没有用,因为我忘记了python的MRO,DeleteViewDetailView应该是继承列表中的第一个!{/ p>

最后,这里是CurUserOnly class:

CurUserOnly

如果我的模型没有与用户直接联系,我需要做的就是添加class CurUserOnly(object): def get_object(self, *args, **kwargs): obj = super(CurUserOnly, self).get_object(*args, **kwargs) user_attribute = getattr(self, 'user_attribute', 'user') user = obj for part in user_attribute.split('.'): user = getattr(user, part, None) if user != self.request.user: raise PermissionDenied() else: return obj 字段。例如,如果我将带有ForeignKey的模型user_attribute发送到Tyre,则其DeleteView将如下所示:

Car

1 个答案:

答案 0 :(得分:4)

如何定义基类(或混合)和使用继承?

class CurUserOnlyDetailView(DetailView):
    def get_object(self, *args, **kwargs):
        obj = super(CurUserOnlyDetailView, self).get_object(*args, **kwargs)
        if obj.user != self.request.user:
            raise PermissionDenied()
        else:
            return obj

class CarDetail(CurUserOnlyDetailView):
    context_object_name = 'car'
    template_name = 'my_app/car_details.html'
    model = models.Car

# another view, no DRY violation
class BikeDetail(CurUserOnlyDetailView):
    context_object_name = 'bike'
    template_name = 'my_app/bike_details.html'
    model = models.Bike