使用 absrtactuser 在 django 中存储附加信息

Storing additional information in django using absrtactuser

我在 django(AbstarctUser) 中创建了自定义用户类。一切正常,但即使在 admin.py 中注册后,我的密码仍以纯文本形式存储在数据库中。我没有明确定义任何 forms.py。

我还在 tutorial 之后使用嵌套序列化器。

我的代码如下

from django.contrib import admin
from .models import BasicUserInfo
from django.contrib.auth.admin import UserAdmin


class BasicUserAdmin(UserAdmin):
    pass

admin.site.register(BasicUserInfo, BasicUserAdmin)

编辑以添加模型和视图

Models.py

class BasicUserInfo(AbstractUser):
    email = models.EmailField(primary_key=True, unique=True, db_index=True)

class UserInfo(models.Model):
    user = models.ForeignKey(BasicUserInfo, on_delete=models.CASCADE)

Views.py

serializer = AddUserSerializer(data=request.data)
if serializer.is_valid(raise_exception=ValueError):
    serializer.create(validated_data=request.data)

Serializers.py

class BasicUserSerializer(serializers.ModelSerializer):
    class Meta:
        model = BasicUserInfo
        fields = ('username', 'password', 'email')

    print("hete")

    def create(self, validated_data):
        retval =  BasicUserInfo.objects.create(**validated_data)
        password = validated_data.pop('password')
        self.password = make_password(password)
       # self._password = password
        return retval

class AddUserSerializer(serializers.ModelSerializer):
    user = BasicUserSerializer(required=True)

    class Meta:
        model = UserInfo
        fields = ('phoneNo')

    def create(self, validated_data):
        user_data = validated_data.pop('user')
        user = BasicUserSerializer.create(BasicUserSerializer(), validated_data=user_data)
        user_info, created = UserInfo.objects.update_or_create(user=user, phoneNo=validated_data.pop('phoneNo'))
        return user_info

你不应该这样使用:

serializer = AddUserSerializer(data=request.data)
if serializer.is_valid(raise_exception=ValueError):
    serializer.create(validated_data=request.data)

如果密码在验证数据中

最好这样使用:

password = request.data.pop('password', '')
if not password:
    raise ValidationError('password must not be empty')
serializer = AddUserSerializer(data=request.data)
serializer.is_valid(raise_exception=ValueError):
user = serializer.create(validated_data=request.data)
user.set_password(password)
user.save()

诀窍是使用 user.set_password(password) -> 这会在内部触发密码哈希机制:这是执行此操作的 Django 代码:

def set_password(self, raw_password):
    self.password = make_password(raw_password)
    self._password = raw_password

def make_password(password, salt=None, hasher='default'):
    """
    Turn a plain-text password into a hash for database storage

    Same as encode() but generate a new random salt. If password is None then
    return a concatenation of UNUSABLE_PASSWORD_PREFIX and a random string,
    which disallows logins. Additional random string reduces chances of gaining
    access to staff or superuser accounts. See ticket #20079 for more info.
    """
    if password is None:
        return UNUSABLE_PASSWORD_PREFIX + get_random_string(UNUSABLE_PASSWORD_SUFFIX_LENGTH)
    hasher = get_hasher(hasher)
    salt = salt or hasher.salt()
    return hasher.encode(password, salt)

所以问题是 serializers.create(**validated_data) 没有执行 make_password 操作。上面的答案工作得很好,除了它做了两件事不同 - 它为用户保存两次(一次在 serailizer.create 期间,另一次在 `user.save() 期间) - 它不会处理序列化程序中的所有内容,部分工作正在拆分 b/w 序列化程序和视图。

如果要将其全部保留在序列化程序中,可以执行以下操作:

class AddUserSerializer(serializers.ModelSerializer):
    class Meta:
        model = BasicUserInfo

    def validate_password(self, value):
        return make_password(value)

更新:

我做了很多编辑;并试图解释原因。请耐心阅读,并根据需要进行修改。

class BasicUserSerializer(serializers.ModelSerializer):
    class Meta:
        model = BasicUserInfo
        fields = ('username', 'password', 'email')

    def validate_password(self, value):
        return make_password(value)

class AddUserSerializer(serializers.ModelSerializer): 
    user = BasicUserSerializer(required=True) 
    class Meta: 
        model = UserInfo 
        fields = ('phoneNo') 

    def create(self, validated_data): 
        user_data = validated_data.pop('user') 
        user_serializer = BasicUserSerializer(data=user_data)
        if user_serializer.is_valid(raise_exception=True):
            user = user_serializer.save()
        validated_data['user'] = user
        return UserInfo.objects.create(**validated_data)