使用 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)
我在 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)