DjangoRestFramework - 如何使用模型序列化程序访问 OneToOneField 反向关系的其他字段?

use*_*875 6 django django-models django-serializer django-rest-framework

我正在使用默认的 User 模型,并且还使用 UserExtended 模型对其进行了扩展:

class Country(models.Model):
    countryName = models.CharField(max_length=50, unique=True)
    countryCode = models.CharField(max_length=10, unique=True)

class UserExtended(models.Model):
    user = models.OneToOneField(User, related_name="userextended")
    country = models.ForeignKey(Country)
Run Code Online (Sandbox Code Playgroud)

我正在尝试遵循此处记录的内容:http : //www.django-rest-framework.org/api-guide/relations/#reverse-relations

这是我的 UserSerializer:

class UserSerializer(serializers.ModelSerializer):

    def __init__(self, *args, **kwargs):
            super(UserSerializer, self).__init__(*args, **kwargs) # call the super() 
            for field in self.fields: # iterate over the serializer fields
                self.fields[field].error_messages['required'] = 'Enter a valid %s.'%field # set the custom error message

    class Meta:
        model = User
        fields = ('username', 'password', 'email', 'userextended')

        extra_kwargs = {
                    'password': {
                        'write_only': True,
                    }
                }

    def create(self, validated_data):
        user = User.objects.create_user(
            email = validated_data['email'],
            username = validated_data['username'],
            password = validated_data['password'],
        )
        return user
Run Code Online (Sandbox Code Playgroud)

我的问题是,如果最终用户在提交之前没有填写表单的“国家/地区”部分,Django 会向前端发送一条错误消息,说“输入有效的用户扩展”。“userextended”是反向关系的名称,每个用户对象都链接到一个 userextended 对象,反之亦然。“userextended”是强制性的,但最终用户在创建用户对象时不必指定“userextended”字段,因为这已经是给定的(最终用户创建用户对象的那一刻,用户对象将具有反向关系默认使用 UserExtended 对象)。

最终用户必须填写表单中的“国家/地区”部分,因为国家/地区是最终用户所要求的。话虽如此,我如何让 Django 说“输入有效的国家/地区”而不是“输入有效的用户扩展名”?

如果最终用户成功保存了一个用户对象,并在表单的“国家”部分提交了“加拿大”,那么DRF如何知道将“加拿大”保存为国家?因为目前,看起来 DRF 认为表单中的“国家/地区”部分指的是“用户扩展”反向关系字段。

我期望的是,在用户序列化程序的“字段”数组中,我使用点表示法?像这样的东西?:

fields = ('username', 'password', 'email', 'userextended.country')
Run Code Online (Sandbox Code Playgroud)

编辑:我也刚刚创建了一个 UserExtended 序列化程序,如下所示:

class UserExtendedSerializer(serializers.ModelSerializer):

    class Meta:
        model = UserExtended
        fields = ('country')
Run Code Online (Sandbox Code Playgroud)

但我不知道如何将此序列化程序与原始 UserSerializer 进行“合并”。

Sac*_*pta 2

Igor 给出的解决方案仅在您想要因 read_only 字段而获取用户详细信息时才有效。默认情况下,序列化器不支持嵌套写入。要编写嵌套对象,您应该重写 UserSerializer 的 create 方法。

class UserSerializer(serializers.ModelSerializer):

    def __init__(self, *args, **kwargs):
            super(UserSerializer, self).__init__(*args, **kwargs) # call the super()
            for field in self.fields: # iterate over the serializer fields
                self.fields[field].error_messages['required'] = 'Enter a valid %s.'%field # set the custom error message

    country = serializers.RelatedField(source='userextended.country')

    class Meta:
        model = User
        fields = ('username', 'password', 'email', 'country')

        extra_kwargs = {
                    'password': {
                        'write_only': True,
                    }
                }

    def create(self, validated_data):
        user = User.objects.create_user(
            email = validated_data['email'],
            username = validated_data['username'],
            password = validated_data['password'],
        )
        country=Country.objects.get(pk=validated_data['country'])
        UserExtended.objects.create(user=user, country=country)

        return user
Run Code Online (Sandbox Code Playgroud)

创建时要发送的数据:

{'username':'sachin', 'email': 'email@gmail.com', 'password': 'abc', 'country':2}
Run Code Online (Sandbox Code Playgroud)