Django Rest Framework 基于ID的分页
我用Django Rest Framework搭建了一个API,现在想改进分页功能,让用户体验更好。
问题:
客户端发起请求,想要获取所有的帖子。请求的格式是:
http://website.com/api/v1/posts/?page=1
这会返回第一页的帖子。但是,新的帖子总是在不断被创建。所以当用户请求:
http://website.com/api/v1/posts/?page=2
返回的帖子几乎和第一页的一样(因为新数据总是不断进来,而我们是按-created
的顺序排列的)。
可能的解决方案?
我想到一个办法,就是在请求中发送一个对象的ID,这样在获取帖子的时候,就可以根据上一次的查询来获取。
http://website.com/api/v1/posts/?page=2&post_id=12345
然后在分页的时候,我们可以过滤出post_id < 12345
的帖子。
但这只适用于我们的post_id是整数的情况。
目前我只在使用一个基本的ListAPIView
。
class PostList(generics.ListAPIView):
"""
API endpoint that allows posts to be viewed
"""
serializer_class = serializers.PostSerializer # just a basic serializer
model = Post
有没有更好的分页方法?这样在用户的下一次请求中,不会因为新数据的创建而显示和第一次请求一样的内容。
3 个回答
你可以给每个对象加一个字段,比如“创建时间/更新时间”。这样的话,你就可以记录用户发出请求的时间,然后把之后的所有内容过滤掉。
我自己没试过,但我觉得这个方法可能适合你的情况。
你在找的是来自DRF文档的光标分页(CursorPagination)。
光标分页的好处有:
- 提供一致的分页视图。当正确使用光标分页时,客户端在翻页时永远不会看到同一个项目,即使在翻页过程中其他客户端正在插入新项目。
- 支持处理非常大的数据集。对于超大的数据集,使用基于偏移量的分页方式可能会变得低效或无法使用。而光标分页则有固定的时间特性,随着数据集的增大也不会变慢。
你也可以像上面提到的那样使用-created
作为排序字段。
你可以考虑缓存查询结果吗?这样下一个页面就可以直接使用之前的查询结果,而不是重新查询。你还可以用一个参数来获取新的查询结果,当你需要的时候。
大概是这样的:
from django.core.cache import cache
class PostList(generics.ListAPIView):
def get_queryset(self):
qs_key = str(self.request.user.id) + '_key'
if 'refresh' in self.request.QUERY_PARAMS:
# get a new query set
qs = Post.objects.all()
cache.set(qs_key, qs)
return cache.get(qs_key)
基本上,只有当你的网址是这样的:
http://website.com/api/v1/posts/?refersh=whatever
请求才会返回新的数据。
更新
为了给每个用户提供自己的一组帖子,缓存的关键需要包含一个唯一的标识符(比如用户的ID):我也更新了代码。
这种方法的缺点是,如果用户数量非常多,且每个用户的帖子数量也很大,可能就不太好用了。
所以,这里是我的第二个想法
为帖子模型使用一个带时间戳的模型,并根据创建时间来过滤查询结果。
我对你的模型和具体构建方式了解不多,所以我想你需要选择哪个解决方案最适合你的应用 :)