Discussion:
ListField in serializer giving 'ManyRelatedManager' object is not iterable error
Arjun Nambiar
2018-09-27 07:12:36 UTC
Permalink
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(models.Model):
ip_group = models.ForeignKey('IPGroup', on_delete=models.CASCADE)
ip = models.ForeignKey('IP', on_delete=models.CASCADE)


serializers.py

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


views.py

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


JSON payload

{ "ips": [{"name":"example.com", "address":"10.1.1.9"}], "name": "ipgroup1" }


Expected behavior

{"name": "ipgroup1", "ips": [{"name": "example.com", "address": "10.1.1.9"}]}


Actual behavior


*TypeError at /api/v1/ip-group/'ManyRelatedManager' object is not iterable*



This strangely works if i set write_only=True to the ListField but then the
**ips** fiels is not available in the serializer response data. I went
through the documentation and did not see this behavior mentioned anywhere.
What am I doing wrong ?
--
You received this message because you are subscribed to the Google Groups "Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-rest-framework+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Arjun Nambiar
2018-09-27 07:16:02 UTC
Permalink
The strange thing is that when i check the DB it actually created
everything..the object and the M2M relationships..Just that it is not able
to give a 201 Respone back
Post by Arjun Nambiar
models.py
name = models.CharField(max_length=30, unique=True)
address = models.CharField(max_length=50, unique=True)
name = models.CharField(max_length=50, unique=True)
ips = models.ManyToManyField('IP', through='IPGroupToIP')
ip_group = models.ForeignKey('IPGroup', on_delete=models.CASCADE)
ip = models.ForeignKey('IP', on_delete=models.CASCADE)
serializers.py
ips = serializers.ListField()
model = IPGroup
fields = ['name', 'ips']
@transaction.atomic()
ips_data = validated_data.pop('ips', None)
ip_group = IPGroup.objects.create(name=validated_data['name'])
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
views.py
queryset = IPGroup.objects.get_queryset()
serializer_class = IPGroupCreateSerializer
JSON payload
{ "ips": [{"name":"example.com", "address":"10.1.1.9"}], "name": "ipgroup1" }
Expected behavior
{"name": "ipgroup1", "ips": [{"name": "example.com", "address": "10.1.1.9"}]}
Actual behavior
*TypeError at /api/v1/ip-group/'ManyRelatedManager' object is not iterable*
This strangely works if i set write_only=True to the ListField but then
the **ips** fiels is not available in the serializer response data. I went
through the documentation and did not see this behavior mentioned anywhere.
What am I doing wrong ?
--
You received this message because you are subscribed to the Google Groups "Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-rest-framework+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Dipen bhatt
2018-10-17 19:36:35 UTC
Permalink
Well, the objects are definitely getting created in the database. But when
DRF is trying to send the output it tries to deserialize the objects in the
to_representation function, but as you are using a list field it simply
cannot deserialize as many to many relationship , since it returns a
manager and not a iterable.
Thats why you are getting a error.


Maybe one way to run your code using List Field, is to override the
to_representation function and manually add the IPs to the attribute.
But this is gonna be too much hassle and your code may become ugly.
--
You received this message because you are subscribed to the Google Groups "Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-rest-framework+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
cbertinato via Django REST framework
2018-09-27 12:44:59 UTC
Permalink
You don't need to use a ListField if you're not going to validate, and by
not passing a child parameter you are indeed not validating the items in
the list.

http://www.django-rest-framework.org/api-guide/fields/#listfield

If all you want to do is return the list of things in the many-to-many, you
don't need to explicitly specify the field in a model serializer. You can,
however, use a nested a serializer, which is probably more appropriate in
this case:

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

If you want to used the nested serializer for deserialization as well, then
you will need to also implemented an update method in your
IPGroupCreateSerializer.

http://www.django-rest-framework.org/api-guide/relations/#writable-nested-serializers
--
You received this message because you are subscribed to the Google Groups "Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-rest-framework+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Arjun Nambiar
2018-09-27 17:53:58 UTC
Permalink
I did not post it here to make the code more complex but I am performing
some validations.I understand that it works with the Nested serializers but
I need to understand what am I doing wrong that it is not working with a
ListField

On Thursday, 27 September 2018 18:14:59 UTC+5:30,
Post by cbertinato via Django REST framework
You don't need to use a ListField if you're not going to validate, and by
not passing a child parameter you are indeed not validating the items in
the list.
http://www.django-rest-framework.org/api-guide/fields/#listfield
If all you want to do is return the list of things in the many-to-many,
you don't need to explicitly specify the field in a model serializer. You
can, however, use a nested a serializer, which is probably more appropriate
ips = IPSerializer(read_only=True, many=True)
If you want to used the nested serializer for deserialization as well,
then you will need to also implemented an update method in your
IPGroupCreateSerializer.
http://www.django-rest-framework.org/api-guide/relations/#writable-nested-serializers
--
You received this message because you are subscribed to the Google Groups "Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-rest-framework+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Loading...