這是模型:Django的 - 對象級別premission和基於類的通用視圖
class Car(models.Model):
user = models.ForeignKey(User, related_name='cars')
name = models.CharField(max_length=64)
網址模式是這樣的:
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裝飾器可能嗎?
編輯:
溶液更多或更少的簡單DrTyrsa在他的回答提出一個差別不大。我創建的基類CurUserOnly
繼承object
,而不是DetailView
(我想使用這個類和UpdateView
,太),現在CarDetail
繼承CurUserOnly
和DetailView
,CarDelete
繼承CurUserOnly
和等等......
滑稽事情是,我以前試過,但它沒有工作,因爲我忘記了蟒蛇的MRO和DetailView
第一次在繼承名單CurUserOnly
應該是!
最後,這裏是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
如果我有沒有直接接觸到用戶模型中的所有我需要做的就是添加user_attribute
場。舉例來說,如果我有ForeignKey的到Car
模型Tyre
其DeleteView應該是這樣的:
class TyreDelete(CurUserOnly, DeleteView):
model = models.Tyre
user_attribute = 'car.user'
不是我所需要的,但給了我正確的想法,並解決了我的一個小差異的問題。我補充說明問題。 –