Как связать «владельца» с моделью пользователя по умолчанию? - PullRequest
0 голосов
/ 29 декабря 2018

Я пытаюсь научить себя Django и Django Rest Framework, но мне трудно понять, как определяется владение объектом.

Я хочу применить пользовательские разрешения «IsOwnerOrReadOnly», указанные вдокументация DRF с моделью пользователя по умолчанию.Моя цель: пользователи смогут помещать / исправлять / удалять информацию в своей учетной записи, но не смогут изменять информацию других пользователей.

Мой пользовательский сериализатор:

class UserSerializer(serializers.ModelSerializer):

    rides = serializers.PrimaryKeyRelatedField(many = True, queryset = Ride.objects.all())

    class Meta:
        model = User
         fields = [
            'pk',
            'username',
            'first_name',
            'last_name',
            'email',
            'password',
            'rides'
        ]
        write_only_fields = ['password']
        read_only_fields = ['pk', 'username']

Код IsOwnerOrReadOnly:

class IsOwnerOrReadOnly(permissions.BasePermission):

    def has_object_permission(self, request, view, obj):
        if request.method in permissions.SAFE_METHODS:
            return True
        return obj.owner == request.user

Проблема со строкой return obj.owner == request.user.Всегда возвращает AttributeError: 'User' object has no attribute 'owner’.Почему «владелец» пользователя не сам пользователь?Как я могу сказать «владелец = этот объект», чтобы мои классы разрешений работали?

Дополнительный вопрос: я хотел бы в конечном итоге расширить модель пользователя по умолчанию, добавив больше полей.Будут ли мои разрешения работать, если я создаю новую модель User путем наследования от AbstractBaseUser?(Я только начал изучать Django, поэтому я не совсем уверен, каков будет процесс создания новой модели User. Но я подумал, что было бы полезно упомянуть в случае, если это изменит способ определения разрешений.)

Ответы [ 2 ]

0 голосов
/ 29 декабря 2018

Владение

Скажем, есть Model A.Чтобы определить владельца, вам нужно создать поле в Model A, которое будет указывать на User модель.Вы можете сделать это легко.Убедитесь, что вы используете django.contrib.auth.get_user_model для того же.

Получение списка принадлежащих объектов из API

Когда дело доходит до получения списка объектов, принадлежащих аутентифицированному пользователю (request.user),вы смотрите на создание фильтра.Для этого существует два способа:

  • Создать класс фильтра и использовать в нем generic views.Это более расширяемо.Я сделал то же самое в drfaddons.filters.IsOwnerFilterBackend.Вот исходный код .
  • Переопределение def filter_queryset(self, queryset) в каждом классе API.

Обеспечение при получении / обновлении / удалении

На этот разВы хотите убедиться, что проверка разрешения применяется.Здесь вы захотите реализовать has_object_permission и has_permission из permissions.BasePermission, которые вы делаете.

В общем, вы захотите использовать как filtering, так и permission check.

Реализация по всему проекту

Чтобы реализовать это по всему проекту, вам необходимо установить filter и permission в качестве значения по умолчанию в конфигурации settings.py REST_FRAMEWORK.Вам также необходимо убедиться, что поле владельца (с тем же именем предпочтительно) присутствует в каждой модели.(Проверьте Abstract модель).

Я сделал то же самое во всех моих проектах, и, следовательно, я создал такой же пакет.Проверьте DRF Addons .Вы также можете установить его через pip: pip install drfaddons.Это выполнит все вышеупомянутые задачи.

0 голосов
/ 29 декабря 2018

Вы получаете ошибку, потому что нет такого абстрактного понятия как владелец для всех моделей.Вам нужно будет определить отношения между объектом и пользователем в модели и применить их в разрешении для каждой модели.

В этом случае вы хотите быть уверены, что пользователь пытается изменить свое собственноепользовательский объект, так что вы можете просто сделать это:

class IsOwnerOrReadOnly(permissions.BasePermission):

    def has_object_permission(self, request, view, obj):
        if request.method in permissions.SAFE_METHODS:
            return True
        return obj == request.user

Таким образом, по сути, это будет работать только для модели User, и вам придется расширить его для работы с другими моделями, основываясь на отношениях модели сПользователь.

Возможно, вы захотите определить разные классы разрешений для каждого ресурса, чем пытаться поместить всю логику в один и тот же класс разрешений.

Что касается вашего вопроса о расширении пользовательской модели.Эта страница в документации объясняет различные методы расширения существующей пользовательской модели, которая в основном либо расширяется от AbstractUser или AbstractbaseUser.Структура разрешений Django будет по-прежнему работать, поскольку она реализована для этих базовых классов.

Однако имейте в виду, что классы разрешений DRF отличаются от разрешений Django.Вы можете использовать разрешения Django для реализации логики внутри классов разрешений, но они могут быть реализованы без разрешений.

РЕДАКТИРОВАТЬ ИЗ КОММЕНТАРИИ

Если у вас есть модель Rideс владельцем, вы можете сделать это, чтобы объединить их.

 class IsOwnerOrReadOnly(permissions.BasePermission):

        def has_object_permission(self, request, view, obj):
            if request.method in permissions.SAFE_METHODS:
                return True
            if isinstance(obj, Ride):
                return obj.owner == request.user
            return obj == request.user
...