Reputation: 837
I built a simple social media application. Users can post two types of posts Blog and Carousel. Users can follow other users, you can see other users posts if you follow them.
So, while implementing the home page API (home page consists of both blog and carousel posts of people you follow) i filter out the blog and carousel like this.
blogposts = BlogPost.objects.filter(
Q(author__profile__in=request.user.profile.followings.all())
| Q(author=request.user)
)
carouselposts = Carousel.objects.filter(
Q(author__profile__in=request.user.profile.followings.all())
| Q(author=request.user)
)
It basically filters all blogs and carousel of the people you follow and return it after applying suitable serializers.
But the problem is when the page is loaded, if a user has got 100 posts in his home page all of them are loaded at once. Instead i only wany to load 10 recent posts in the beginning and keep loading next 10 recent posts when user reaches the bottom of the home page.
Since there are two tables here Blogpost and Carousel i don't how to paginate this.
Also, one more question? If i somehow paginate this content to send 10 recent posts at once, will it be internally querying only 10 posts at each request or will it query all 100 posts at once and send them in chunks of 10?
Here is the complete code for home page API.
class HomepageBlogPostView(APIView):
permission_classes = [permissions.IsAuthenticated]
def get(self, request):
blogposts = BlogPost.objects.filter(
Q(author__profile__in=request.user.profile.followings.all())
| Q(author=request.user)
)
posts_list_serializer = BlogPostSerializer(
blogposts, many=True, context={"request": request}
)
carouselposts = Carousel.objects.filter(
Q(author__profile__in=request.user.profile.followings.all())
| Q(author=request.user)
)
carousels_list_serializer = CarouselSerializer(
carouselposts, many=True, context={"request": request}
)
blogposts_list = list(posts_list_serializer.data)
carousels_list = list(carousels_list_serializer.data)
blogposts_list.extend(carousels_list)
posts = blogposts_list
posts.sort(key=lambda post: -post["published"])
return Response(posts, status=status.HTTP_200_OK)
Upvotes: 0
Views: 1331
Reputation: 493
DRF comes with a built-in paginator middleware. You just need to add these lines to settings.py
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
'PAGE_SIZE': 10 # default value is 100
}
if you want to paginate each resource with a different PAGE_SIZE
, Django core has a built-in paginator class for all kinds of Model objects
It would be something like this: first you order_by("-created_at"), then use Paginator class.
from django.core.paginator import Paginator
class HomepageBlogPostView(APIView):
permission_classes = [permissions.IsAuthenticated]
def get_nth_page(self , n):
PAGE_SIZE = 10 # or just define it inside settings.py
blogposts = BlogPost.objects.filter(
Q(author__profile__in=request.user.profile.followings.all())
| Q(author=request.user)
).order_by('-created_at')
paginated = Paginator(blogposts,PAGE_SIZE )
return paginated.page(n).object_list
def get(self, request):
# return page number or 1
blogposts = self.get_nth_page(request.GET('page_number',1))
posts_list_serializer = BlogPostSerializer(
blogposts, many=True, context={"request": request}
)
carouselposts = Carousel.objects.filter(
Q(author__profile__in=request.user.profile.followings.all())
| Q(author=request.user)
)
carousels_list_serializer = CarouselSerializer(
carouselposts, many=True, context={"request": request}
)
blogposts_list = list(posts_list_serializer.data)
carousels_list = list(carousels_list_serializer.data)
blogposts_list.extend(carousels_list)
posts = blogposts_list
posts.sort(key=lambda post: -post["published"])
return Response(posts, status=status.HTTP_200_OK)
to keep PAGE_SIZE consistent for all resources, using the DRF setting seems more reasonable.
Upvotes: 1