More Efficient List Views with Pagination:

We will apply pagination in views

  • use paginator for tweet_feed_view in /tweets/api/views.py ```python from rest_framework.pagination import PageNumberPagination # new

@api_view([‘GET’]) @permission_classes([IsAuthenticated]) def tweet_feed_view(request, args, *kwargs): paginator = PageNumberPagination() # new paginator.page_size = 20 # new

  1. user = request.user
  2. qs = Tweet.objects.feed(user)
  3. paginated_qs = paginator.paginate_queryset(qs, request) # new
  4. # serializer = TweetSerializer(qs, many=True)
  5. serializer = TweetSerializer(paginated_qs, many=True)
  6. # return Response(serializer.data, status=200)
  7. return paginator.get_paginated_response(serializer.data)
  1. after this setup, each page of [http://localhost/api/tweets/feed/](http://localhost/api/tweets/feed/) will only show a query set of 20 tweets, but also provides a link to its next and previous page.
  2. to test, runserver, access [http://localhost/api/tweets/feed/?page=2](http://localhost/api/tweets/feed/?page=2)<br />![image.png](https://cdn.nlark.com/yuque/0/2020/png/1243266/1596817561794-5ec0c546-24b7-4671-b64a-0ee5a6d165a0.png#align=left&display=inline&height=473&margin=%5Bobject%20Object%5D&name=image.png&originHeight=945&originWidth=1675&size=96049&status=done&style=none&width=837.5)<br />Here we only can see 20 tweets, and 2 urls called "next" and "previous".<br />We are on page 2, so we have a "next" to page 3, and "previous" to page 1 (or homepage because there is no "?page="), and those are also pages with 20 tweets.
  3. - we better split feed view and pagination into tweet_feed_view and get_paginated_queryset_response in /tweets/api/views.py
  4. ```python
  5. '''
  6. @api_view(['GET'])
  7. @permission_classes([IsAuthenticated])
  8. def tweet_feed_view(request, *args, **kwargs):
  9. paginator = PageNumberPagination()
  10. paginator.page_size = 20
  11. user = request.user
  12. qs = Tweet.objects.feed(user)
  13. paginated_qs = paginator.paginate_queryset(qs, request)
  14. serializer = TweetSerializer(paginated_qs, many=True)
  15. return paginator.get_paginated_response(serializer.data)
  16. '''
  17. def get_paginated_queryset_response(qs, request):
  18. paginator = PageNumberPagination()
  19. paginator.page_size = 20
  20. paginated_qs = paginator.paginate_queryset(qs, request)
  21. serializer = TweetSerializer(paginated_qs, many=True)
  22. return paginator.get_paginated_response(serializer.data)
  23. @api_view(['GET'])
  24. @permission_classes([IsAuthenticated])
  25. def tweet_feed_view(request, *args, **kwargs):
  26. user = request.user
  27. qs = Tweet.objects.feed(user)
  28. return get_paginated_queryset_response(qs, request)

nothing changes in actually shown feed view.

User Profile Serializer:

timestamp and user id:

  • we add a user variable for all tweets in /tweets/serializers.py

    1. # ...
    2. class TweetSerializer(serializers.ModelSerializer):
    3. user = serializers.SerializerMethodField(read_only=True) # new
    4. likes = serializers.SerializerMethodField(read_only=True)
    5. parent = TweetCreateSerializer(read_only=True)
    6. class Meta:
    7. model = Tweet
    8. # fields = ['id', 'content', 'likes', 'is_retweet']
    9. fields = ['user', 'id', 'content', 'likes', 'is_retweet', 'parent'] # new
    10. def get_likes(self, obj):
    11. return obj.likes.count()
    12. def get_user(self, obj): # new
    13. return obj.user.id

    runserver, and access http://localhost/api/tweets/
    image.png
    we can see the user id of the sender of each tweet is shown.

  • further in /tweets/serializers.py

    • also setup user in TweetCreateSerializer
    • both add “timestamp” ```python class TweetCreateSerializer(serializers.ModelSerializer): user = serializers.SerializerMethodField(read_only=True) # new likes = serializers.SerializerMethodField(read_only=True)

      class Meta: model = Tweet

      fields = [‘id’, ‘content’, ‘likes’]

      fields = [

      1. 'user',
      2. 'id',
      3. 'content',
      4. 'likes',
      5. 'timestamp'

      ]

      def get_likes(self, obj): return obj.likes.count()

      def validate_content(self, value): if len(value) > MAX_TWEET_LENGTH:

      1. raise serializers.ValidationError("This tweet is too long")

      return value

      def get_user(self, obj): # new return obj.user.id

class TweetSerializer(serializers.ModelSerializer): user = serializers.SerializerMethodField(read_only=True) likes = serializers.SerializerMethodField(read_only=True) parent = TweetCreateSerializer(read_only=True)

  1. class Meta:
  2. model = Tweet
  3. # fields = ['user', 'id', 'content', 'likes', 'is_retweet', 'parent']
  4. fields = [
  5. 'user',
  6. 'id',
  7. 'content',
  8. 'likes',
  9. 'is_retweet',
  10. 'parent',
  11. 'timestamp'
  12. ]
  13. def get_likes(self, obj):
  14. return obj.likes.count()
  15. def get_user(self, obj):
  16. return obj.user.id
  1. <a name="XJoDg"></a>
  2. #### create user profile serializer and show that in tweets list:
  3. - create /profiles/serializers.py
  4. ```python
  5. from rest_framework import serializers
  6. from .models import Profile
  7. class PublicProfileSerializer(serializers.ModelSerializer):
  8. first_name = serializers.SerializerMethodField(read_only=True)
  9. last_name = serializers.SerializerMethodField(read_only=True)
  10. username = serializers.SerializerMethodField(read_only=True)
  11. follower_count = serializers.SerializerMethodField(read_only=True)
  12. following_count = serializers.SerializerMethodField(read_only=True)
  13. class Meta:
  14. model = Profile
  15. fields = [
  16. "first_name",
  17. "last_name",
  18. "id",
  19. "bio",
  20. "location",
  21. "follower_count",
  22. "following_count",
  23. "username",
  24. ]
  25. def get_first_name(self, obj):
  26. return obj.user.first_name
  27. def get_last_name(self, obj):
  28. return obj.user.last_name
  29. def get_username(self, obj):
  30. return obj.user.username
  31. def get_following_count(self, obj):
  32. return obj.user.following.count()
  33. def get_follower_count(self, obj):
  34. return obj.followers.count()
  • apply PublicProfileSerializer in /tweets/serializers.py ```python

    from profiles.serializers import PublicProfileSerializer # new

class TweetCreateSerializer(serializers.ModelSerializer):

  1. # user = serializers.SerializerMethodField(read_only=True)
  2. user = PublicProfileSerializer(source='user.profile', read_only=True)
  3. likes = serializers.SerializerMethodField(read_only=True)
  4. class Meta:
  5. model = Tweet
  6. # fields = ['id', 'content', 'likes']
  7. fields = [
  8. 'user',
  9. 'id',
  10. 'content',
  11. 'likes',
  12. 'timestamp'
  13. ]
  14. def get_likes(self, obj):
  15. return obj.likes.count()
  16. def validate_content(self, value):
  17. if len(value) > MAX_TWEET_LENGTH:
  18. raise serializers.ValidationError("This tweet is too long")
  19. return value
  20. #def get_user(self, obj):
  21. # return obj.user.id

class TweetSerializer(serializers.ModelSerializer):

  1. # user = serializers.SerializerMethodField(read_only=True)
  2. likes = serializers.SerializerMethodField(read_only=True)
  3. user = PublicProfileSerializer(source='user.profile', read_only=True)
  4. parent = TweetCreateSerializer(read_only=True)
  5. class Meta:
  6. model = Tweet
  7. # fields = ['user', 'id', 'content', 'likes', 'is_retweet', 'parent']
  8. fields = [
  9. 'user',
  10. 'id',
  11. 'content',
  12. 'likes',
  13. 'is_retweet',
  14. 'parent',
  15. 'timestamp'
  16. ]
  17. def get_likes(self, obj):
  18. return obj.likes.count()
  19. # def get_user(self, obj):
  20. # return obj.user.id

``` runserver and access http://localhost/api/tweets/
image.png
At present, “user” is modified from id to a long serializer, while we can see first_name, last_name, etc.