在基于函数的视图中优化分页(在 Django 中)
Optimizing pagination in function-based views (in Django)
在基于 class 的 Django listview
中,当一个值分配给 paginate_by
时,它确保 object_list
在 get_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)
在基于 class 的 Django listview
中,当一个值分配给 paginate_by
时,它确保 object_list
在 get_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)