Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django serializer ManyRelatedManager object at XX is not JSON serializable

I'm trying to use a ModelSerializer for a Model that has a Many to Many field.

This is part of my model:

class BaseSearchService(models.Model):

advertisements = models.ManyToManyField(Advertisement, null=False,
    blank=False)

And this is the serializer

class SearchTransportSickPersonSerializer(serializers.ModelSerializer):

person = TransportPersonComponentSerializer()
owner = serializers.ReadOnlyField(source='owner.username')
advertisements = serializers.ReadOnlyField()

class Meta:
    model = SearchTransportSickPerson
    fields = ('name', 'description',
        'date_service_full_day', 'date_service', 'origin_lat',
        'origin_long', 'destinity_lat', 'destinity_long', 'multiple_stops',
        'person', 'owner', 'advertisements')

def create(self, validated_data):

    user_data = validated_data.pop('owner')
    advs = validated_data.pop('advertisements')

    user = User.objects.get(email=user_data.email)

    person_data = self.validated_data.pop('person')
    person = TransportPersonComponent.objects.create(**person_data)

    sickPerson = SearchTransportSickPerson.objects.create(person=person,
        owner=user, **self.validated_data)

    for adv in advs:
        a = Advertisement.objects.get(id=adv.id)
        sickPerson.advertisements.add(a)

    sickPerson.save()

    return sickPerson

I have writen a unit test that replicates the error:

def test_serializer_2(self):
    transportSickPerson = SearchTransportSickPerson(name="name",
        description="desc", date_service=date_serv, date_service_full_day=
        True, person=self.component, owner=self.user)

    transportSickPerson.save()

    transportSickPerson.advertisements.add(advertise)

    serializer = SearchTransportSickPersonSerializer(transportSickPerson)
    content = JSONRenderer().render(serializer.data)

When I try to render the serializer with the JSON Renderer, the following error gets thrown:

TypeError: .ManyRelatedManager object at 0x7f648017bfd0> is not JSON serializable

And when i print the serializer data, the dict type has the advertisements field as the ManyRelatedManager representation.

How can i solve this error? Is there any way to tell the serializer how to render that specific field?

Thank you for any help that you can provide.

like image 564
guilleHeuer Avatar asked Dec 26 '15 20:12

guilleHeuer


1 Answers

TL;DR: The answer is class.property.all().


The problem here lies in the fact that a ManyRelatedManager is NOT the actual list of related objects, but a Django class from which you have to call all() (or filter() or get()) in order to get to your data. Trying to serialize the related manager makes no sense.

Look at this example:

class SomeClass(models.Model):
    friends = models.ManyToManyField(User)

if I have an instance of SomeClass called some_class, calling some_class.friends will return:

<RelatedManager>

while some_class.friends.all() will return

[<User>, <User>, ecc]

Side note:

you should not use null=False on ManyToManyField: it is useless. As you already know, when you create a new BaseSearchService your advertisements field is empty (thus, demonstrating that null=False serves no purpose). This is because, at database level, M2M fields are not a column in your BaseSearchService table but a table in itself.

Every time you call .add() (or any other manager methods like .remove()) a call to the database is made, independently from the .save() method of the model instance on which there is the M2M field. In other words, no need to call sickPerson.save() also.

like image 83
Saturnix Avatar answered Oct 16 '22 12:10

Saturnix