1

I'm trying to build an API for a picture gallery using Django and Django Rest Framework for the API.

I have set up the following two models:

class Album(models.Model):
    name = models.CharField(max_length=100)
    description = models.TextField(null=True, blank=True)
    start_date = models.DateField()
    end_date = models.DateField(null=True, blank=True)
    parent_album = models.ForeignKey('self',
                                     null=True,
                                     blank=True,
                                     on_delete=models.CASCADE
                                    )

class Picture(models.Model):
    path = models.ImageField()
    album = models.ForeignKey('Album', on_delete=models.CASCADE)

For the serializers, I have defined the following, using the official Django DRF doc:

class PictureSerializer(serializers.ModelSerializer):

    class Meta:
        model = Picture
        fields = '__all__'


class AlbumSerializer(serializers.ModelSerializer):
    pictures = PictureSerializer(many=True, read_only=True)

    class Meta:
        model = Album
        fields = '__all__'

Now, I have some objects already defined, so I wanted to try in a shell:

>>> album = Album.objects.get(pk=1)
>>> len(Picture.objects.filter(album__exact=Album.objects.get(pk=1)))
3
>>> AlbumSerializer(instance=album).data
{'id': 1, 'name': 'First album', 'description': '', 'start_date': '2019-08-15', 'end_date': None, 'parent_album': None}
>>> AlbumSerializer()
AlbumSerializer():
    id = IntegerField(label='ID', read_only=True)
    pictures = PictureSerializer(many=True, read_only=True):
        id = IntegerField(label='ID', read_only=True)
        path = ImageField(max_length=100)
        album = PrimaryKeyRelatedField(queryset=Album.objects.all())
    name = CharField(max_length=100)
    description = CharField(allow_blank=True, allow_null=True, required=False, style={'base_template': 'textarea.html'})
    start_date = DateField()
    end_date = DateField(allow_null=True, required=False)
    parent_album = PrimaryKeyRelatedField(allow_null=True, queryset=Album.objects.all(), required=False)

You will notice that there are no pictures in the serialized data, but the field is there when I print the serializer, and that's my problem... Have I missed something somewhere?

Thanks for the help!

4

1 Answer 1

1

Your problem is due to the related name given to ForeignKeys.

Right now with the code you provided the name backwards relation name should be picture_set. So for the serializer to work you should change it do the following:

class AlbumSerializer(serializers.ModelSerializer):
    picture_set = PictureSerializer(many=True, read_only=True)

    class Meta:
        model = Album
        fields = '__all__'

But, if you want to display as pictures you can also do the following:

class AlbumSerializer(serializers.ModelSerializer):
    pictures = PictureSerializer(many=True, read_only=True, source='picture_set')

    class Meta:
        model = Album
        fields = '__all__'

Finally, if you want to get rid of the picture_set you should change your code to the following:

models.py

class Picture(models.Model):
    path = models.ImageField()
    album = models.ForeignKey('Album', on_delete=models.CASCADE, related_name='pictures')

serializers.py

class AlbumSerializer(serializers.ModelSerializer):
    pictures = PictureSerializer(many=True, read_only=True)

    class Meta:
        model = Album
        fields = '__all__'
Sign up to request clarification or add additional context in comments.

3 Comments

Note that reverse relationships are not automatically included by the ModelSerializer and HyperlinkedModelSerializer classes. To include a reverse relationship, you must explicitly add it to the fields list -> django-rest-framework.org/api-guide/relations/…
@iklinac That's why he manually added the field to the serializer with pictures = PictureSerializer(..)
I added related_name='pictures' in the Picture model, and that worked fine with fields = '__all__', thanks a lot!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.