Django REST Framework 3中的其他序列化程序字段

时间:2014-12-21 16:11:02

标签: python django django-rest-framework

场合

我正在创建一个允许创建用户的简单端点。我需要一个不在我的用户模型中的字段(即confirm_password)。我将运行验证,将此字段与模型中的另一个字段进行比较,然后再不在序列化程序中再次使用其他字段。

问题

DRF版本3已经改变了完成此任务的过程,我不太明白文档建议我做什么。有关文档,请参阅here

尝试解决方案

我创建了一个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']

我希望在confirm_password中弹出validate可以解决我的问题,但我只是得到以下内容:

  

尝试在序列化程序KeyError上获取字段confirm_password的值时获得UserSerializer。序列化程序字段可能名称不正确,与OrderedDict实例

上的任何属性或键都不匹配

2 个答案:

答案 0 :(得分:24)

您正在寻找一个只写字段,因为我假设您不想在API中显示密码确认。 Django REST Framework在2.3.x时间轴中引入了write_only参数以补充read_only参数,因此运行验证的唯一时间是进行更新时。 write_only_fields元属性大约在同一时间添加,但了解这两者如何协同工作非常重要。

write_only_fields元属性会在自动创建时自动将write_only属性添加到字段中,就像password模型上的User字段一样。对于模型上没有的任何字段,或者在序列化程序中明确指定的字段,不会执行此操作。在您的情况下,您明确指定序列化程序上的confirm_password字段,这就是它无法正常工作的原因。

  

尝试在序列化程序KeyError上获取字段confirm_password的值时获得UserSerializer。序列化程序字段可能名称不正确,与OrderedDict实例

上的任何属性或键都不匹配

在尝试序列化confirm_password字段时,在重新序列化创建的用户时会引发此问题。因为它无法在User模型上找到该字段,所以它会触发此错误,该错误会尝试解释该问题。不幸的是,因为这是在 new 用户身上,它会让您混淆地看到OrderedDict实例而不是User实例。

class UserSerializer(serializers.ModelSerializer):
    confirm_password = serializers.CharField(allow_blank=False, write_only=True)

如果您在序列化程序字段中明确指定write_only,并从write_only_fields中删除该字段,那么您应该会看到您期望的行为。

您可以在此link

上找到有关此内容的文档

答案 1 :(得分:0)

当根模型无法直接访问您要使用的字段时,对表示模型的嵌套序列化程序实现也很有用。 谢谢@vyscond;) 这是我的理由:

models.py

class Company(models.Model):
    permission_classes = (
        IsCompanyMember,
    )

    name = models.CharField(
        unique=True,
        max_length=100,
        verbose_name='company name',
        null=False
    )
class Profile(models.Model):

    company = models.ForeignKey(Company, on_delete=models.CASCADE, null=True)
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    is_company_admin = models.BooleanField(default=False, null=False)
    is_email_validated = models.BooleanField(default=False, null=False)
    is_approved_by_company_admin = models.BooleanField(default=False, null=False)

serializer.py

class CompanySerializer(serializers.ModelSerializer):
    class Meta:
        model = Company
        fields = ('name',)

class CustomUserRegistrationSerializer(serializers.ModelSerializer):
    password = serializers.CharField(style={'input_type': 'password'},
                                 write_only=True,
                                 validators=settings.get('PASSWORD_VALIDATORS'))

    company = CompanySerializer(allow_null=False, required=True,write_only=True)

    class Meta:
        model = User
        fields = ('username',
                  'email',
                  'password',
                  'company',
                  'first_name',
                  'last_name')