Django Rest Framework, как запретить пользователям менять свое имя пользователя? - PullRequest
0 голосов
/ 31 августа 2018

Я создаю UserSerializer и хочу разрешить пользователям создавать новые учетные записи, но запрещаю им изменять свои имена пользователей. Существует атрибут read_only, который я могу применить, но тогда пользователи не смогут установить имя пользователя при создании нового. Но без этого это позволяет мне изменить это. Существует также атрибут required, который, к сожалению, нельзя использовать с read_only. Нет другого соответствующего атрибута. Одно из решений - создать два разных сериализатора, один для создания пользователя, а другой - для его изменения, но это кажется уродливым и неправильным поступком. Есть ли у вас какие-либо предложения о том, как сделать это без написания 2 сериализаторов?

Спасибо за любой совет.

PS: я использую python3.6 и django2.1

РЕДАКТИРОВАТЬ: я использую generics.{ListCreateAPIView|RetrieveUpdateDestroyAPIView} классы для представлений. Как это:

class UserList(generics.ListCreateAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer


class UserDetails(generics.RetrieveUpdateAPIView):
    # this magic means (read only request OR accessing user is the same user being edited OR user is admin)
    permission_classes = (perm_or(ReadOnly, perm_or(IsUserOwner, IsAdmin)),)

    queryset = User.objects.all()
    serializer_class = UserSerializer

РЕДАКТИРОВАТЬ2: Есть дублирующий вопрос (возможно, мой дубликат) здесь

Ответы [ 3 ]

0 голосов
/ 31 августа 2018

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

А затем вы создаете еще один сериализатор UserSerializer, в котором вы вводите имя пользователя в поле read_only и используете этот сериализатор везде (например, при обновлении пользователя).

0 голосов
/ 17 октября 2018

Anwser из @JPG довольно точный, но у него есть одно ограничение. Вы можете использовать сериализатор только в представлениях DRF, потому что в других представлениях или где-либо еще контекст не будет иметь view.actions. Чтобы исправить это self.instance можно использовать. Это сделает код короче и более универсальным. Кроме того, вместо добавления поля лучше сделать его доступным только для чтения, чтобы его можно было просматривать, но нельзя было изменить.

class UserSerializer(serializers.ModelSerializer):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if self.instance is not None:  # if object is being created the instance doesn't exist yet, otherwise it exists.
            # self.fields.pop('username', None)
            self.fields.get('username').read_only = True  # An even better solution is to make the field read only instead of popping it.

    class Meta:
        ....

Другим возможным решением является использование CreateOnlyDefault (), который теперь является встроенной функцией в DRF. Подробнее об этом можно прочитать здесь, в документации

0 голосов
/ 31 августа 2018

Если вы используете класс viewset для своего представления, то вы можете переопределить метод сериализатора init как,

class UserSerializer(serializers.ModelSerializer):
    <b>def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if 'view' in self.context and self.context['view'].action in ['update', 'partial_update']:
            self.fields.pop('username', None)</b>

    class Meta:
        ....

Если вы пытаетесь обновить поле имени пользователя во время обновления (HTTP PUT) или частичного обновления (HTTP PATCH), сериализатор удалит поле username из списка полей и, следовательно, это не повлияет на данные / модель

UPDATE
Почему приведенный выше ответ не работает с документирования API ?

Из документа

Примечание. По умолчанию include_docs_urls настраивает базовый SchemaView для генерации общедоступных схем. Это означает, что представления не будут созданы с экземпляром запроса. внутри запроса self.request будет None.


В ответе поля всплывают динамически с помощью запроса объекта.
Поэтому, если вы хотите обрабатывать и документацию API, определите множественный сериализатор и эффективно используйте метод get_serializer_class(). Это способ DRF.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...