Python Django rest框架嵌套序列化程序不适用于M2M关系

Python Django rest框架嵌套序列化程序不适用于M2M关系,python,django,serialization,django-rest-framework,Python,Django,Serialization,Django Rest Framework,我的models.py如下所示: class IP(models.Model): hostname = models.CharField(max_length=50, unique=True) ip_address = models.CharField(unique=True) class IPGroup(models.Model): name = model.CharField(max_length=50, unique=True) ips = models.

我的models.py如下所示:

class IP(models.Model):
    hostname = models.CharField(max_length=50, unique=True)
    ip_address = models.CharField(unique=True)

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

class IPGroupToIP(models.Model):
    ip_group = models.ForeignKey(IPGroup)
    ip = models.ForeignKey(IP)
class IPSerializer(serializers.ModelSerializer):
    class Meta:
        model = IP
        fields = ['id', 'host_name', 'ip_address']


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

    class Meta:
        model = IPGroup
        depth = 1
        fields = '__all__'

    def create(self, validated_data):
        # Pop out ips since these are M2M relations and have to be created separately
        ips_data = validated_data.pop('ips', None)
        # Create the IPGroup object 
        ip_group_obj = IPGroup.objects.create(name=validated_data['name'])

        if ips_data:
            for ip in ips_data:
                # Get the ip object id if already created or create it on the fly and save it
                ip_obj, created = IP.objects.get_or_create(host_name=ip['host_name'], ip_address=ip['ip_address'])
                # Update through table for M2M relationship
                IPGroupToIP.objects.create(ip_group_id=ip_group_obj.id, ip_id=ip_obj.id)
        return ip_group_obj
class IPGroupCreateView(generics.CreateAPIView):
    queryset = IPGroup.objects.get_queryset()
    serializer_class = IPGroupSerializer
我的serializers.py如下所示:

class IP(models.Model):
    hostname = models.CharField(max_length=50, unique=True)
    ip_address = models.CharField(unique=True)

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

class IPGroupToIP(models.Model):
    ip_group = models.ForeignKey(IPGroup)
    ip = models.ForeignKey(IP)
class IPSerializer(serializers.ModelSerializer):
    class Meta:
        model = IP
        fields = ['id', 'host_name', 'ip_address']


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

    class Meta:
        model = IPGroup
        depth = 1
        fields = '__all__'

    def create(self, validated_data):
        # Pop out ips since these are M2M relations and have to be created separately
        ips_data = validated_data.pop('ips', None)
        # Create the IPGroup object 
        ip_group_obj = IPGroup.objects.create(name=validated_data['name'])

        if ips_data:
            for ip in ips_data:
                # Get the ip object id if already created or create it on the fly and save it
                ip_obj, created = IP.objects.get_or_create(host_name=ip['host_name'], ip_address=ip['ip_address'])
                # Update through table for M2M relationship
                IPGroupToIP.objects.create(ip_group_id=ip_group_obj.id, ip_id=ip_obj.id)
        return ip_group_obj
class IPGroupCreateView(generics.CreateAPIView):
    queryset = IPGroup.objects.get_queryset()
    serializer_class = IPGroupSerializer
最后,我的视图.py如下所示:

class IP(models.Model):
    hostname = models.CharField(max_length=50, unique=True)
    ip_address = models.CharField(unique=True)

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

class IPGroupToIP(models.Model):
    ip_group = models.ForeignKey(IPGroup)
    ip = models.ForeignKey(IP)
class IPSerializer(serializers.ModelSerializer):
    class Meta:
        model = IP
        fields = ['id', 'host_name', 'ip_address']


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

    class Meta:
        model = IPGroup
        depth = 1
        fields = '__all__'

    def create(self, validated_data):
        # Pop out ips since these are M2M relations and have to be created separately
        ips_data = validated_data.pop('ips', None)
        # Create the IPGroup object 
        ip_group_obj = IPGroup.objects.create(name=validated_data['name'])

        if ips_data:
            for ip in ips_data:
                # Get the ip object id if already created or create it on the fly and save it
                ip_obj, created = IP.objects.get_or_create(host_name=ip['host_name'], ip_address=ip['ip_address'])
                # Update through table for M2M relationship
                IPGroupToIP.objects.create(ip_group_id=ip_group_obj.id, ip_id=ip_obj.id)
        return ip_group_obj
class IPGroupCreateView(generics.CreateAPIView):
    queryset = IPGroup.objects.get_queryset()
    serializer_class = IPGroupSerializer
这将按预期工作,并向API端点发送以下JSON创建请求以完成任务:

{
"name":"TestIPGroup1",
"ips": [{"name":"host1","value":"8.8.4.4"}, {"name":"host2","value":"8.8.8.8"}]
}
但是,如果我为新IPGroup发送另一个具有相同IP的JSON create请求,如下所示:

{
"name":"TestIPGroup2",
"ips": [{"name":"host1","value":"8.8.4.4"}, {"name":"host2","value":"8.8.8.8"}]
}
它给我一个错误,指出IP地址已经存在。现在这种情况正在发生,因为嵌套的IPSerializer的IP字段unique验证检查开始生效。如何禁用默认字段唯一性检查?我的DRF版本是3.8.2

编辑

我已尝试重写以下方法,但似乎不起作用:

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

    class Meta:
        model = IPGroup
        depth = 1
        fields = '__all__'

    def run_validators(self, value):
        for validator in self.validators:
            if isinstance(validator, validators.UniqueValidator):
                self.validators.remove(validator)
        super(IPGroupSerializer, self).run_validators(value)

明确指定
id
字段,并添加
empty
验证器,如下所示:

class IPSerializer(serializers.ModelSerializer):
    id = serializers.IntegerField(validators=[])

    class Meta:
        model = IP
        fields = ['id', 'host_name', 'ip_address']
类IPSerializer(serializers.ModelSerializer):
id=序列化程序.整型字段(验证器=[])
类元:
型号=IP
字段=['id'、'host\u name'、'ip\u address']


更新

class IPSerializer(serializers.ModelSerializer):
    class Meta:
        model = IP
        fields = ['id', 'host_name', 'ip_address']

    def __init__(self, *args, **kwargs):
        nested = kwargs.pop('nested', False)
        super().__init__(*args, **kwargs)
        if nested:
            self.fields.update(
                {"id": serializers.IntegerField(validators=[])}
            )


class IPGroupSerializer(serializers.ModelSerializer):
    ips = IPSerializer(many=True, nested=True)

    # Your code
类IPSerializer(serializers.ModelSerializer):
类元:
型号=IP
字段=['id'、'host\u name'、'ip\u address']
定义初始化(self,*args,**kwargs):
nested=kwargs.pop('nested',False)
super()
如果嵌套:
self.fields.update(
{“id”:serializers.IntegerField(validators=[])}
)
类IPGroupSerializer(serializers.ModelSerializer):
ips=IPSerializer(多个=True,嵌套=True)
#你的代码

您使用的是什么版本的django,DRF?您还可以将自定义验证方法添加到上面的代码中吗?@Angela..我忽略了编辑问题..现在没有自定义验证..还指定了DRF版本我只想在创建IPGroup时禁用IP验证,因为它是M2M字段…每当创建IP导致DB中的重复ID…更新了答案,可以通过重写
\uuuu init()\uuuuu
方法来停止它。这很好。是否可以仅禁用唯一值检查,而不是该字段的所有类型的验证?您可以将验证程序解释为
整数字段(验证程序=[validator\u 1,validator\u 2])
@Jerin..请参见编辑..我也尝试重写run\u validator方法,但似乎不起作用..您对此有何想法