【问题标题】:Deserialize Nested Object in Django-Rest-Framework反序列化 Django-Rest-Framework 中的嵌套对象
【发布时间】:2021-11-30 13:32:54
【问题描述】:

早安,

我正在尝试执行包含嵌套对象的 PUT 请求,但我无法让 province 正确更新。 django-rest-framework docs 中似乎没有任何明显的帮助,我已经调查了其他一些类似问题的解决方案,但没有任何帮助(设置many=false,更改为ModelSerializerspecialized serializers等)。

关于 address 的所有其他内容都将正确更新并返回 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'

任何帮助将不胜感激。

【问题讨论】:

  • 是的,您需要为嵌套序列化程序编写自定义创建和更新函数

标签: django django-rest-framework


【解决方案1】:

经过几次重读,在specialized serializers 帖子的帮助下解决了这个问题。

我将序列化程序更新为:

# 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",
}

【讨论】:

    猜你喜欢
    • 2015-08-26
    • 2014-07-07
    • 2017-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-16
    • 1970-01-01
    相关资源
    最近更新 更多