My models.py looks like this:
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)
Now, in order to create an IPGroup, I have the following serializer:
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
My views are a simple class based view as follows:
class IPGroupCreateView(generics.CreateAPIView):
queryset = IPGroup.objects.get_queryset()
serializer_class = IPGroupCreateSerializer
My JSON payload looks like this:
{ "ips": [{"name":"example.com", "address":"10.1.1.9"}], "name": "ipgroup1" }
This how ever gives me an error stating:
TypeError at /api/v1/ip-group/
'ManyRelatedManager' object is not iterable
The strange thing is that when i check the DB, the IPGroup is created along with the M2M ips. So, the code is working as expected but the view is somehow returning a 500 server error instead of a 201 created. What am i doing wrong ?
Due to some complications, ListField()
will become handy only while writing to the DB ( I'm not sure why this behavior).
In your context, adding write_only=True
in ListField
solve the exception. Hence the IPGroupCreateSerializer
will be as
class IPGroupCreateSerializer(serializers.ModelSerializer):
ips = serializers.ListField(write_only=True)
I personally reccomend to use Nested Serializers to handle this situation. So,define a new IPSerializer
class and use it instead of 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']