提供“ManyRelatedManager”对象的列表字段序列化程序不是 M2M 字段的可迭代错误

Posted

技术标签:

【中文标题】提供“ManyRelatedManager”对象的列表字段序列化程序不是 M2M 字段的可迭代错误【英文标题】:List Field serializer giving 'ManyRelatedManager' object is not iterable error with M2M field 【发布时间】:2019-03-01 21:26:58 【问题描述】:

我的 models.py 看起来像这样:

class IP(models.Model):
    name = models.CharField(max_length=30, unique=True)
    address = models.CharField(max_length=50, unique=True)

class IPGroup(models.Model):
    name = models.CharField(max_length=50, unique=True)
    ips = models.ManyToManyField('IP', through='IPGroupToIP')

class IPGroupToIP(BaseModel):
    ip_group = models.ForeignKey('IPGroup', on_delete=models.CASCADE)
    ip = models.ForeignKey('IP', on_delete=models.CASCADE)

现在,为了创建一个 IPGroup,我有以下序列化程序:

class IPGroupCreateSerializer(serializers.ModelSerializer):
    ips = serializers.ListField()

class Meta:
    model = IPGroup
    fields = ['name', 'ips']

@transaction.atomic()
def create(self, validated_data):
    ips_data = validated_data.pop('ips', None)
    ip_group = IPGroup.objects.create(name=validated_data['name'])

    if ips_data:
        for ip in ips_data:
            ip_obj, created = IP.objects.get_or_create(name=ip['name'], address=ip['address'])
            IPGroupToIP.objects.create(ip_group_id=ip_group.id, ip_id=ip_obj.id)
    return ip_group

我的视图是一个简单的基于类的视图,如下所示:

class IPGroupCreateView(generics.CreateAPIView):
    queryset = IPGroup.objects.get_queryset()
    serializer_class = IPGroupCreateSerializer

我的 JSON 负载如下所示:

"ips": ["name":"example.com", "address":"10.1.1.9"], “名称”:“ipgroup1”

这怎么会给我一个错误说明:

/api/v1/ip-group/处的类型错误 'ManyRelatedManager' 对象不可迭代

奇怪的是,当我检查数据库时,IPGroup 与 M2M ips 一起创建。因此,代码按预期工作,但视图以某种方式返回 500 服务器错误,而不是创建的 201。我做错了什么?

【问题讨论】:

【参考方案1】:

由于一些复杂性,ListField() 仅在 写入 到数据库时才会变得方便(我不确定为什么会出现这种行为)。 在您的上下文中,在 ListField 中添加 write_only=True 可以解决异常。因此 IPGroupCreateSerializer 将是

class IPGroupCreateSerializer(serializers.ModelSerializer):
    ips = serializers.ListField(write_only=True)


我个人建议使用 嵌套序列化器 来处理这种情况。因此,定义一个新的 IPSerializer 类并使用它来代替 serializers.ListField()

class IPSerializer(serializers.ModelSerializer):
    class Meta:
        model = IP
        fields = ('name', 'address')


class IPGroupCreateSerializer(serializers.ModelSerializer):
    ips = IPSerializer(many=True)


class Meta:
    model = IPGroup
    fields = ['name', 'ips']

【讨论】:

是的..我知道它适用于嵌套序列化程序..但是,我希望它适用于 Listfield..你知道我做错了什么吗? @Amistad 更新了答案,希望它能解决问题 成功了!! ..只是为了理解,你是怎么想出来的?..我浏览了整个文档,没有看到任何地方提到这个..【参考方案2】:

我有一个包含列表字段(命名社区)的序列化程序,并且此列表字段的子参数是 PrimaryKeyRelatedField。

我为解决这个问题所做的工作如下。

我在实例模型中定义了一个名为 get_communities 的方法。 在序列化器的 to_representation 方法中弹出列表字段。 呼叫超级。 使用更新方法更新返回值,因为它是一个字典。 并返回更新后的 ret。
def to_representation(self, instance):
    if isinstance(instance, OrderedDict):
        return super(SerializerClassName, self).to_representation(instance)
    self.fields.pop('communities')
    ret = super(SerializerClassName, self).to_representation(instance)
    ret.update('communities': instance.get_communities())
    return ret

【讨论】:

以上是关于提供“ManyRelatedManager”对象的列表字段序列化程序不是 M2M 字段的可迭代错误的主要内容,如果未能解决你的问题,请参考以下文章

XX 处的 Django 序列化程序 ManyRelatedManager 对象不是 JSON 可序列化的

对象导论系列---每个对象都提供服务

如果用户已经提供了对象,如何停止将用户提供的对象添加到数组列表中? [关闭]

从类访问时间线对象,提供空对象引用?

Oracle ASP.net 提供者模型对象性能

为其他对象提供一种代理以控制对这个对象的访问-代理模式