首页 > 解决方案 > 在这种情况下如何应用分页(Django Rest Framework)?

问题描述

我构建了一个简单的社交媒体应用程序。用户可以发布两种类型的帖子博客和轮播。用户可以关注其他用户,如果您关注他们,您可以看到其他用户的帖子。

因此,在实现主页 API(主页包含您关注的人的博客和轮播帖子)时,我像这样过滤掉博客和轮播。

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)
        )

它基本上过滤了您关注的人的所有博客和轮播,并在应用合适的序列化程序后将其返回。

但问题是当页面加载时,如果用户在他的主页上有 100 个帖子,所有这些帖子都会立即加载。相反,我只在开始时加载 10 个最近的帖子,并在用户到达主页底部时继续加载接下来的 10 个最近的帖子。

由于这里有两个表 Blogpost 和 Carousel 我不知道如何分页。

另外,还有一个问题?如果我以某种方式分页此内容以一次发送 10 个最近的帖子,它会在每个请求中在内部仅查询 10 个帖子,还是会一次查询所有 100 个帖子并以 10 个为一组发送?

这是主页 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)

标签: pythondjangodjango-rest-framework

解决方案


DRF 带有一个内置的分页器中间件。您只需将这些行添加到 settings.py

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
    'PAGE_SIZE': 10 # default value is 100
}

如果你想用不同的资源对每个资源进行分页PAGE_SIZE,Django 核心有一个内置的分页器类,用于各种模型对象它会是这样的:首先你 order_by("-created_at"),然后使用 Paginator 类。

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)

为了使所有资源的 PAGE_SIZE 保持一致,使用 DRF 设置似乎更合理。


推荐阅读