Situation
我正在创建一个允许创建用户的简单 endpoints . 我需要一个不在我的用户模型中的字段(即 confirm_password
) . 我将运行验证,将此字段与模型中的另一个字段进行比较,然后再从不在序列化程序中再使用其他字段 .
Problem
DRF版本3已经改变了完成此任务的过程,我不太明白文档建议我做什么 . 有关文档,请参阅here .
Attempt at Solution
我创建了一个 UserSerializer
,看起来像这样:
from django.contrib.auth import get_user_model
from rest_framework import serializers
class UserSerializer(serializers.ModelSerializer):
confirm_password = serializers.CharField(allow_blank=False)
def validate(self, data):
"""
Checks to be sure that the received password and confirm_password
fields are exactly the same
"""
if data['password'] != data.pop('confirm_password'):
raise serializers.ValidationError("Passwords do not match")
return data
def create(self, validated_data):
"""
Creates the user if validation succeeds
"""
password = validated_data.pop('password', None)
user = self.Meta.model(**validated_data)
user.set_password(password)
user.save()
return user
class Meta:
# returns the proper auth model
model = get_user_model()
# fields that will be deserialized
fields = ['password', 'confirm_password',
'username', 'first_name', 'last_name', 'email']
# fields that will be serialized only
read_only_fields = ['is_staff', 'is_superuser']
# fields that will be deserialized only
write_only_fields = ['password' 'confirm_password']
我希望在 validate
中弹出 confirm_password
可以解决我的问题,但我得到以下内容:
尝试在序列化程序UserSerializer上获取字段confirm_password的值时获得KeyError . 序列化程序字段可能名称不正确,并且与OrderedDict实例上的任何属性或键都不匹配
2 回答
您正在寻找一个只写字段,因为我想在API中显示密码确认 . Django REST Framework在2.3.x时间轴中引入了
write_only
参数以补充read_only
参数,因此运行验证的唯一时间是进行更新时 .write_only_fields
meta属性大约在同一时间添加,但了解这两者如何协同工作非常重要 .write_only_fields
元属性会在自动创建时自动将write_only
属性添加到字段中,就像User
模型上的password
字段一样 . 它不会对模型上没有的任何字段或已在序列化程序中明确指定的字段执行此操作 . 在您的情况下,您明确指定序列化程序上的confirm_password
字段,这就是它无法正常工作的原因 .这是在创建用户重新序列化时尝试序列化
confirm_password
字段时引发的 . 因为它无法在User
模型上找到该字段,所以它会触发此错误,该错误会尝试解释该问题 . 不幸的是,因为这是一个新用户,它告诉你混淆地查看OrderedDict
实例而不是User
实例 .如果在序列化程序字段中明确指定
write_only
,并从write_only_fields
中删除该字段,那么您应该会看到您期望的行为 .你可以在这个link上找到相关文档 .
当根模型不能直接访问您要使用的字段时,对表示模型的嵌套序列化程序实现也很有用 . 谢谢@vyscond;)这是我的理由:
models.py
serializer.py