Django rest framework создать пользователя с паролем

Использование django-rest-framework 3 и django 1.8

Я пытаюсь создать пользователя с помощью django-rest-framework ModelViewSerializer. проблема в том, что метод objects.create по умолчанию, используемый DRF, оставляет пароль как обычный текст.

Проблема заключается в том, что метод создания серийного файла DRF использует метод objects.create querysets/#create вместо использования метода objects.create_user.

код serializers.py строка 775

instance = ModelClass.objects.create(**validated_data)

Какое лучшее решение для этого? Я могу переопределить метод serializer.create для использования objects.user_create вместо objects.create, но он не похож на правильное решение.

остальная часть кода:

from django.contrib.auth.models import User
from rest_framework import viewsets

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('username', 'email','password')
        write_only_fields = ('password',)


class UserViewSet(viewsets.ModelViewSet):   
    queryset = User.objects.all()
    serializer = UserSerializer()

Ответ 1

вы можете переопределить create в UserSerilizer:

class UserSerializer(serializers.ModelSerializer):
    # ....

    def create(self, validated_data):
        user = User.objects.create_user(**validated_data)
        return user

другие решения могут переопределять perform_create в классе ViewSet, или вы можете написать свой собственный метод create в вашем классе вида

class UserViewSet(viewsets.ModelViewSet): 
    def create(self, request, format=None):
        # create user here
        # do not call seriailzer.save()

UPDATE: после комментария @freethebees, также отменяется переопределение perform_create, поэтому вот фрагмент кода:

class UserViewSet(viewsets.ModelViewSet, mixins.CreateModelMixin): 
    def perform_create(self, serializer):
        # use User.objects.create_user to create user
        pass

Примечание: этот ответ дает 3 решения, выберите тот, который, по вашему мнению, лучше соответствует вашим потребностям и экосистеме вашего проекта.

ПРИМЕЧАНИЕ 2 Я лично предпочитаю переопределять create в UserViewSet (второй фрагмент кода), потому что вы можете просто вернуть свой пользовательский Response (например, вернуть профиль пользователя после входа в систему)

Ответ 2

Есть еще лучший вариант для проверки пароля в serializer

from django.contrib.auth.hashers import make_password

class UserSerializer(serializers.ModelSerializer):
    def validate_password(self, value: str) -> str:
        return make_password(value)

Ответ 3

В дополнение к ответу @aliva, где вы упускаете функциональные возможности в serializers.Modelserializer.create() (что было бы неплохо сохранить, например, обрабатывает отношения "многие ко многим"), есть способ сохранить это.

Используя метод user.set_password(), пароль также может быть правильно установлен, например:

class UserSerializer(serializers.ModelSerializer):

    def create(self, validated_data):
        user = super().create(validated_data)
        user.set_password(validated_data['password'])
        user.save()
        return user

Это имеет преимущество сохранения функциональности суперкласса, но является недостатком дополнительной записи в базу данных. Решите, какой компромисс для вас важнее :-).

Редактировать: Исправить синтаксическую ошибку