8

I'm serialzing a Product model and its comments. Here's my simple code:

class ProductSerializer(serializers.HyperlinkedModelSerializer):
    comment_set = CommentSerializer(many=True, read_only=True)
    class Meta:
        model = Product
        fields = [
            'title',
            'comment_set'
        ]


class CommentSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Comment
        fields = [
            'text',
        ]


class Comment(models.Model):
    product = models.ForeignKey(Product, null=True, blank=True, db_index=True)


class Product(models.Model):
    title = models.CharField(max_length=50)
    ...

Problem: If the product has many comments. For example, 500 comments. All 500 of them got serialized.

How to limit the result to a number of my own choosing, like 100 comments?

I've done some research before posting this but only found questions about filtering.

Thank you.

1

3 Answers 3

10

Define a new method on the Product model that returns a query set with a limited number of comments.

Then pass that method as the source of the CommentSerializer inside your ProductSerializer.

class Product(models.Model):
    title = models.CharField(max_length=50)


    def less_comments(self):
        return Comment.objects.all().filter(product=self).order_by("-id")[:100]

Then in the ProductSerializer:

class ProductSerializer(serializers.HyperlinkedModelSerializer):
    comment_set = CommentSerializer(many=True, read_only=True, source="less_comments")

PS: Wrote the codes from memory, didn't test them. But should work.

Sign up to request clarification or add additional context in comments.

Comments

5

You can write custom ListSerializer and put in CommentSerializer, then create custom field in ProductSerializer, wich source based on default related name:

class LimitedListSerializer(serializers.ListSerializer):

    def to_representation(self, data):
        data = data.all()[:100]
        return super(FilteredListSerializer, self).to_representation(data)

class CommentSerializer(serializers.HyperlinkedModelSerializer):

    class Meta:
            list_serializer_class = LimitedListSerializer
            model = Comment
            fields = [
                'text',]

class Product(serializers.HyperlinkedModelSerializer):
    related_comments = CommentSerializer(many=True, read_only=True, source='comment_set')

when you pass many=True, list serrializer will be called.

Comments

2

You'll want to work on the CommentSerializer's queryset to control which ones you keep.

You'll be able to do that by overriding get_queryset. For example, to filter them against the current user. Note that I took this example because it highlights how to use the request's context to filter against:

class CommentSerializer(serializers.HyperlinkedModelSerializer):
    def get_queryset(self):
        user = self.context['request'].user
        queryset = Comment.objects.filter(user=user)
        return queryset

    class Meta:
        model = Comment
        fields = [
            'text',
        ]

2 Comments

Thanks. Works perfectly and thanks for pointing out the request context. Also thank you for other answers too although I haven't tested your solutions yet. But they should also work.
As of 2020, this code won't let you limit the query results

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.