在 Django-Rest-Framework 中反序列化嵌套对象

Deserialize Nested Object in Django-Rest-Framework

美好的一天,

我正在尝试执行包含嵌套对象的 PUT 请求,但我无法使 正确更新。 django-rest-framework docs to help with this and I've investigated the solutions of a few other similar problems but none have helped (set many=false, change to ModelSerializer, 等似乎没有什么明显的。

关于 地址 的所有其他内容将正确更新并且 return 200 响应(django 日志中也没有错误)。我是否认为 django-rest-framework 免费为我处理这一切是错误的?我是否必须覆盖序列化程序中的更新和创建方法来验证和保存嵌套对象?

我认为这是因为我在 address 序列化程序中将 province 序列化程序设置为 read_only。但是,如果我删除 province 序列化器上的 read_only 修饰符,它会给出有关 province 已经存在的错误:

{
    "province": {
        "province": [
            "valid province with this province already exists."
        ]
    }
}

这是我不希望也不知道如何解决的行为。我不是要添加或更新 。我只想更改 address.province 字段中的省份代码,我不能使用字符串“MB”,因为它需要一个对象。我实际上想要这种行为:

UPDATE agent_business_address
  SET province = 'MB'
WHERE agent_id = 12345;

-- agent_business_address.province has a foreign key constraint on valid_province.province
-- valid_province is populated with all the 2-letter abbreviations for provinces(

我向 /api/agent-business-address/

发出此 PUT 请求
{
    "address": "123 Fake St",
    "agent_id": 12345,
    "city": "Calgary",
    "dlc": "2021-10-11 14:03:03",
    "operator_id": 4,
    "postal_code": "A1B 2C3",
    "province": {
        "description": "Manitoba",
        "province": "MB"
    },
    "valid_address": "N"
}

被这个 ViewSet 接收:

class AgentBusinessAddressViewSet(viewsets.ModelViewSet):
    queryset = AgentBusinessAddress.objects.all()
    serializer_class = AgentBusinessAddressSerializer

相关序列化程序:

class AgentBusinessAddressSerializer(serializers.HyperlinkedModelSerializer):
    province = ValidProvinceSerializer(read_only=True) # Removing the read_only causes the error above.
    class Meta:
        model = AgentBusinessAddress
        fields = ('agent_id', 'operator_id', 'dlc', 'address', 'city', 'province', 'postal_code', 'valid_address')

class ValidProvinceSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = ValidProvince
        read_only_fields = ('operator_id', 'dlc')
        fields = ('province', 'description')

相关机型:

class AgentBusinessAddress(models.Model):
    agent = models.OneToOneField(Agent, models.DO_NOTHING, primary_key=True)
    operator_id = models.SmallIntegerField()
    dlc = models.DateTimeField()
    address = models.CharField(max_length=100)
    city = models.CharField(max_length=80)
    province = models.ForeignKey('ValidProvince', models.DO_NOTHING, db_column='province')
    postal_code = models.CharField(max_length=7)
    valid_address = models.CharField(max_length=1)

    class Meta:
        managed = False
        db_table = 'agent_business_address'

class ValidProvince(models.Model):
    province = models.CharField(primary_key=True, max_length=2)
    operator_id = models.SmallIntegerField()
    dlc = models.DateTimeField()
    description = models.CharField(max_length=30, blank=True, null=True)

    class Meta:
        managed = False
        db_table = 'valid_province'

如有任何帮助,我们将不胜感激。

post 的帮助下重新阅读了几次后解决了这个问题。

我将序列化程序更新为:

# This gets called for non-GET requests.
class AgentBusinessAddressSerializer(serializers.ModelSerializer):
    class Meta:
        model = AgentBusinessAddress
        fields = ('__all__')

# This get called for GET requests.
class AgentBusinessAddressReadSerializer(AgentBusinessAddressSerializer):
    province = ValidProvinceSerializer(read_only=True)
    class Meta:
        model = AgentBusinessAddress
        fields = ('__all__')

我将视图集更新为:

class AgentBusinessAddressViewSet(viewsets.ModelViewSet):
    queryset = AgentBusinessAddress.objects.all()
    
    def get_serializer_class(self):
        if self.request.method in ['GET']:
            return AgentBusinessAddressReadSerializer
        return AgentBusinessAddressSerializer

现在我只在 PUT 请求中发送省份的主键:

{
    "address": "123 Fake St",
    "agent": 10000003,
    "city": "Calgary",
    "dlc": "2021-10-11 19:47:38",
    "operator_id": 4,
    "postal_code": "A1B 2C3",
    "province": "NS",
    "valid_address": "N"
}

我收到 PUT 200 响应并在数据库中验证该省现在是 'NS'。

{
    "agent": 10000003,
    "operator_id": 4,
    "dlc": "2021-10-11T19:47:38",
    "address": "123 Fake St",
    "city": "Calgary",
    "postal_code": "A1B 2C3",
    "valid_address": "N",
    "province": "NS",
}