You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django Rest Framework序列化器报错:传入含数组类型属性的JSON添加模型时出现异常

解决Django Rest Framework中IP数组序列化报错的问题

我一眼就看出问题所在了——你的序列化器期望接收的是嵌套对象数组,但你传入的是纯字符串IP数组,格式不匹配导致了报错。咱们一步步来解决:

问题根源

你的ComputerSerializer里的ip_address字段用了ComputerIPAddressSerializer(many=True),这意味着DRF会期望传入这样的结构:

{
  "hostname":"PC-01",
  "os_system":"Windows 10",
  "ip_address": [
    {"ip_address": "192.168.1.10"},
    {"ip_address": "192.168.2.10"}
  ]
}

但你实际传入的是纯字符串数组['192.168.1.10','192.168.2.10'],序列化器无法解析这种格式,自然就报错了。

解决方案:适配输入输出格式

我们需要让序列化器既能接收你给出的字符串IP数组,又能正确关联到ComputerIPAddress模型。下面是修改后的完整代码:

1. 先修改模型,添加反向关联名称

给ComputerIPAddress的外键加上related_name,让反向查询更直观:

class Computer(models.Model):
    hostname = models.CharField(max_length=32)
    os_system = models.CharField(max_length=60)

class ComputerIPAddress(models.Model):
    # 添加related_name,方便通过Computer实例访问关联的IP
    computer = models.ForeignKey(Computer,on_delete=models.CASCADE, related_name='ip_addresses')
    ip_address = models.GenericIPAddressField(protocol='ipv4')

2. 重写序列化器,适配输入输出

我们用两个字段分别处理输入(字符串数组)和输出(嵌套IP对象),同时重写create和update方法来处理IP的关联逻辑:

class ComputerIPAddressSerializer(serializers.ModelSerializer):
    class Meta:
        model = ComputerIPAddress
        fields = ('id', 'ip_address')

class ComputerSerializer(serializers.ModelSerializer):
    # 处理输入:只用于接收字符串IP数组,验证格式是否为合法IPv4
    ip_address = serializers.ListField(
        child=serializers.IPAddressField(protocol='ipv4'),
        write_only=True
    )
    # 处理输出:返回关联的IP对象数组,只读
    ip_addresses = ComputerIPAddressSerializer(many=True, read_only=True)

    class Meta:
        model = Computer
        fields = ('id', 'hostname', 'os_system', 'ip_address', 'ip_addresses')

    def create(self, validated_data):
        # 取出IP数组,剩下的字段用于创建Computer实例
        ips = validated_data.pop('ip_address')
        computer = Computer.objects.create(**validated_data)
        # 批量创建关联的IP地址,比循环创建更高效
        ComputerIPAddress.objects.bulk_create([
            ComputerIPAddress(computer=computer, ip_address=ip) for ip in ips
        ])
        return computer

    def update(self, instance, validated_data):
        # 取出可能存在的IP数组(更新时可选)
        ips = validated_data.pop('ip_address', None)
        # 更新Computer的基础字段
        instance.hostname = validated_data.get('hostname', instance.hostname)
        instance.os_system = validated_data.get('os_system', instance.os_system)
        instance.save()
        # 如果传入了新的IP数组,先删除旧的,再创建新的
        if ips is not None:
            instance.ip_addresses.all().delete()
            ComputerIPAddress.objects.bulk_create([
                ComputerIPAddress(computer=instance, ip_address=ip) for ip in ips
            ])
        return instance

3. 视图集无需修改

你的ComputerViewSet可以保持原样,现在它就能正确处理你传入的JSON格式了:

{"hostname":"PC-01","os_system":"Windows 10","ip_address":["192.168.1.10","192.168.2.10"]}

额外说明

  • write_only=True确保ip_address字段只用于接收输入,不会在返回结果中出现;read_only=True则相反,ip_addresses只用于输出。
  • IPAddressField(protocol='ipv4')会自动校验输入的IP是否为合法的IPv4地址,避免无效数据存入数据库。
  • 用bulk_create批量创建IP对象,比循环调用create性能更好,尤其是当IP数量较多时。

内容的提问来源于stack exchange,提问作者Guille

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 07:27:30