djangoserializationdjango-rest-framework

How to add fields to serializer


I would like to add foreign key fields to DRF serializer. I need API endpoint with information of Publication details with all Comments to this publication with all Images to this publication and with Likes number to this publication.

Models

 class Publication(models.Model):
    pub_text = models.TextField(null=True, blank=True)
    pub_date = models.DateTimeField(auto_now_add=True)
    pub_author = models.ForeignKey(User, on_delete=models.CASCADE)


class Comment(models.Model):
    com_text = models.TextField(null=True, blank=True)
    com_like = models.BooleanField(default=False)
    com_author = models.ForeignKey(User, on_delete=models.CASCADE)
    com_to_pub = models.ForeignKey(Publication, on_delete=models.CASCADE, related_name='comment_author')
    com_date = models.DateTimeField(auto_now_add=True, null=True)


class Image(models.Model):
    image = models.ImageField(upload_to='images', null=True)
    image_to_pub = models.ForeignKey(Publication, on_delete=models.CASCADE, null=True, related_name='images')

Serializers

class ImageSerializer(serializers.ModelSerializer):
    class Meta:
        model = Image
        fields = ['image']


class CommentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Comment
        fields = ['com_text', 'com_like', 'com_date', 'com_author']


class PublicationSerializer(serializers.ModelSerializer):
    class Meta:
        model = Publication
        fields = ['id', 'pub_text', 'pub_author', 'pub_date']

    def to_representation(self, instance):
        representation = super().to_representation(instance)
        representation['comment'] = CommentSerializer(instance.comment_author.all(), many=True).data
        representation['image'] = ImageSerializer(instance.images.all(), many=True).data
        return representation

Views

class PublicationViewSet(viewsets.ModelViewSet):
    queryset = Publication.objects.all()
    serializer_class = PublicationSerializer


class ImageViewSet(viewsets.ModelViewSet):
    queryset = Image.objects.all()
    serializer_class = ImageSerializer


class CommentViewSet(viewsets.ModelViewSet):
    queryset = Comment.objects.all()
    serializer_class = CommentSerializer

By my logik Like to Publication can be given by Comment author if comment was created. I used <to_represtntation> method to add fields to Publication serializer. It works as i would need but not sure that was a good way to do. Also i cannot imagine how to add Likes number to Publication serializer.


Solution

  • The approach you're using with the to_representation method is a valid way to customize the serialized data, but it can be improved for better clarity and performance, especially when dealing with nested relationships and adding computed fields (like the number of likes).

    To enhance your approach and include the number of likes in the PublicationSerializer, we can:

    Use nested serializers to display comments and images for the publication. Add a likes field to the PublicationSerializer to count the number of likes from the comments related to that publication. Optimize the to_representation approach or use SerializerMethodField to compute values like the likes count.

    In Serializers You need to Update

    from rest_framework import serializers
    from .models import Publication, Comment, Image
    
    class ImageSerializer(serializers.ModelSerializer):
        class Meta:
            model = Image
            fields = ['image']
    
    
    class CommentSerializer(serializers.ModelSerializer):
        class Meta:
            model = Comment
            fields = ['com_text', 'com_like', 'com_date', 'com_author']
    
    
    class PublicationSerializer(serializers.ModelSerializer):
        # Nested serializers for comments and images
        comment = CommentSerializer(source='comment_author', many=True, read_only=True)
        image = ImageSerializer(source='images', many=True, read_only=True)
    
        # Adding a computed field for counting likes
        likes_count = serializers.SerializerMethodField()
    
        class Meta:
            model = Publication
            fields = ['id', 'pub_text', 'pub_author', 'pub_date', 'comment', 'image', 'likes_count']
    
        def get_likes_count(self, obj):
            # Count the number of likes (True) in related comments
            return obj.comment_author.filter(com_like=True).count()
    

    Explanation:

    1. comment = CommentSerializer(source='comment_author', many=True, read_only=True): This connects the Publication model's related_name='comment_author' field to its nested comments and uses the CommentSerializer to display the comment details.

    2. image = ImageSerializer(source='images', many=True, read_only=True): Similar to comments, it connects the Publication model to its related images using the related_name='images' and uses ImageSerializer.

    3. likes_count = serializers.SerializerMethodField(): This field computes the total number of likes from the related comments for each publication. The method get_likes_count uses obj.comment_author.filter(com_like=True).count() to get the count of comments where com_like=True for the given publication.