Python Django rest框架嵌套序列化程序不适用于M2M关系
我的models.py如下所示: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.
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方法,但似乎不起作用..您对此有何想法