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

del*_*boy 2 python django permissions

这是模型:

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

网址模式如下所示:

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

并查看:

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
Run Code Online (Sandbox Code Playgroud)

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

有一个更好的方法吗?可能是login_required装饰器之类的东西?

编辑

正如Dr.Tyrsa在他的回答中所提出的,解决方案或多或少简单,只有一点点不同。我创建的基类CurUserOnly继承object,而不是DetailView(我想使用这个类DeleteViewUpdateView,太),现在CarDetail继承CurUserOnlyDetailViewCarDelete继承CurUserOnlyDeleteView等等......

有趣的是,我之前曾尝试过此方法,但由于我忘了python的MRO,并且DetailViewCurUserOnly应该成为继承列表的第一位时,它没有起作用!

最后,这是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
Run Code Online (Sandbox Code Playgroud)

如果我的模型与用户没有直接联系,我所要做的就是添加user_attribute字段。例如,如果我的模型Tyre使用ForeignKey Car为其DeleteView看起来像这样:

class TyreDelete(CurUserOnly, DeleteView):
    model = models.Tyre
    user_attribute = 'car.user'
Run Code Online (Sandbox Code Playgroud)

DrT*_*rsa 6

那么definig基类(或mixin)以及使用继承呢?

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
Run Code Online (Sandbox Code Playgroud)