Django - представление уровня объекта и общие представления на основе классов - PullRequest
1 голос
/ 21 октября 2011

Это модель:

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, чтобы пользователь не связывался с чужими объектами.Это включает в себя редактирование и удаление для каждой модели, которая у меня есть, и это серьезное нарушение принципа СУХОЙ.

Есть ли лучший способ сделать это?Может быть, что-то вроде декоратора login_required?

РЕДАКТИРОВАТЬ :

Решение было более или менее простым, как предложил Д-р Тырса в своем ответе, с одним небольшим отличием.Я создал базовый класс CurUserOnly, который наследует object вместо DetailView (я хотел использовать этот класс с DeleteView и UpdateView тоже), и теперь CarDetail наследует CurUserOnly и DetailView,CarDelete наследует CurUserOnly и DeleteView и так далее ...

Забавно, что я пробовал это раньше, но это не сработало, потому что я забыл MRO в Python и DetailView был первым всписок наследования, когда CurUserOnly должно быть!

В конце концов, вот CurUserOnly class:

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 поле.Например, если у меня есть модель Tyre с ForeignKey для Car, ее DeleteView будет выглядеть так:

class TyreDelete(CurUserOnly, DeleteView):
    model = models.Tyre
    user_attribute = 'car.user'

1 Ответ

5 голосов
/ 21 октября 2011

Как насчет определения базового класса (или миксина) и использования наследования?

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
...