在基于函数的视图中优化分页(在 Django 中)

Optimizing pagination in function-based views (in Django)

在基于 class 的 Django listview 中,当一个值分配给 paginate_by 时,它确保 object_listget_context_data 方法中可用仅限于只有那些特定页面需要的对象

例如get_queryset 可能 return 1000 个对象,但如果单个页面要显示 20 个对象,则只有 20 个对象可用,如 object_list in get_context_data。在处理大型查询集时,这是一个很好的优化。

如何在基于函数的视图中创建相同的行为?在典型的实现下(并以上述示例为例),将评估所有 1000 个对象,然后将其用于分页。这意味着在这种特殊情况下,CBV 绝对优于基于功能的视图。基于功能的视图能否提供相同的功能?一个说明性的例子会很好(或者“不,他们不能”的回答也有效)。


这是实际的 CBV:

class PostListView(ListView):
    model = Post
    paginate_by = 20
    template_name = "post_list.html"

    def get_queryset(self):
        return all_posts()

    def get_context_data(self, **kwargs):
        context = super(PostListView, self).get_context_data(**kwargs)
        posts = retrieve_posts(context["object_list"]) #retrieves 20 posts
        return context

这是实际的 FBV:

def post_list(request, *args, **kwargs):
    form = PostListForm()
    context = {}
    obj_list = all_posts()
    posts = retrieve_posts(obj_list) #retrieves 1000 posts
    paginator = Paginator(posts, 20)
    page = request.GET.get('page', '1')
    try:
        page = paginator.page(page)
    except PageNotAnInteger:
        page = paginator.page(1)
    except EmptyPage:
        page = paginator.page(paginator.num_pages)

retrieve_posts()函数:

def retrieve_posts(post_id_list):
    my_server = redis.Redis(connection_pool=POOL)
    posts = []
    pipeline1 = my_server.pipeline()
    for post_id in post_id_list:
        hash_name="pt:"+str(post_id)
        pipeline1.hgetall(hash_name)
    result1 = pipeline1.execute()
    count = 0
    for hash_obj in result1:
        posts.append(hash_obj)
        count += 1
    return posts

all_posts()函数:

def all_posts():
    my_server = redis.Redis(connection_pool=POOL)
    return my_server.lrange("posts:1000", 0, -1) #list of ids of 1000 posts

两种方法的响应时间差异(通过 newrelic):

蓝色部分是视图的处理。

不要用原始对象列表调用 retreive_posts。分页后使用页面的对象列表。

posts = retrieve_posts(page.obj_list)