使用absrtactuser在django中存储其他信息

时间:2018-05-23 16:48:52

标签: django serializer django-custom-user

我在django(AbstarctUser)中创建了自定义Userclass。一切正常,但即使在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

2 个答案:

答案 0 :(得分:1)

诀窍是使用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()期间再次保存) - 它没有处理序列化程序中的所有内容,部分工作正在与序列化程序和视图分开。

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

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)

答案 1 :(得分:0)

你不应该这样使用:

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()