Регистрация пользователя в Django rest?

Я следую этот учебник, но перед этими проблемами я не могу исправить:

  • После регистрации пользователя я не могу войти с этим пользователем в api, потому что пароль не хеширован "Недопустимый формат пароля или неизвестный алгоритм хеширования". в admin
  • Я не могу отправлять сообщения в api/accounts или видеть форму в просматриваемом api, когда я не вошел в api

Мой код:

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

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

    def restore_object(self, attrs, instance=None):
        # call set_password on user object. Without this
        # the password will be stored in plain text.
        user = super(UserSerializer, self).restore_object(attrs, instance)
        user.set_password(attrs['password'])  #somehow not hashing
        return user

Ответ 1

Обратите внимание, что set_password() НЕ сохраняет объект, и, поскольку вы сначала вызвали супер, ваш объект уже сохранен с необработанным паролем.

Просто используйте post_save(), чтобы сохранить пароль.

def post_save(self, obj, created=False):
    """
    On creation, replace the raw password with a hashed version.
    """
    if created:
        obj.set_password(obj.password)
        obj.save()

Ответ 2

Я пробовал принятый ответ в DRF 3.0.2, и он не работал. Пароль не был хеширован.

Вместо этого переопределите метод create в сериализаторе модели

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

Это хеширует пароль при создании пользователя с использованием рамки rest, а не post_save

Ответ 3

Другой подход для DRF 3.X:

from django.contrib.auth import get_user_model
from django.contrib.auth.hashers import make_password

    def create(self, validated_data):    
        if validated_data.get('password'):
            validated_data['password'] = make_password(
                validated_data['password']
            )

        user = get_user_model().objects.create(**validated_data)

        return user

Ответ 4

Я использовал wsgeorge решение для создания собственного. Пустой объект User создается так, что я могу использовать .set_password():

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

В отличие от его ответа, я сам не сохраняю пользователя. Я оставляю это для родительского класса, вызывающего super.

Ответ 5

Мы можем написать сигнал в User, чтобы решить эту проблему.

def create_hash(sender, instance=None, *args, **kwargs):
passwd = instance.password
instance.set_password(passwd)


pre_save.connect(create_hash, sender=User)