gpt4 book ai didi

python - 如何在使用 django 无尽分页渲染之前进行结果后处理?

转载 作者:太空狗 更新时间:2023-10-29 21:05:49 27 4
gpt4 key购买 nike

我想弄清楚是否有可能在使用 django-endless-pagination 进行无限滚动的 django 模板中呈现之前对我的查询集进行 View 后处理。

我有特定于 View 的逻辑,它根据上下文从查询集中省略某些结果,并向列表中的对象添加属性以供模板使用。此逻辑不能通过 SQL 执行,因为它不是模型固有的。它必须在 python 中完成。

使用 django-endless-pagination 和其他预滚动的 django 分页模块,所有逻辑似乎都由 templatetags 执行,从而阻止了在渲染阶段之前执行业务逻辑的能力(这是 django 的原则)。

因为我的 View 逻辑在模板标签执行之前遍历结果集,所以我失去了这个模块提供的优化(比如带分页的 SQL 查询,例如 limit 20;offset 20)。每次用户翻页时,我的代码都会遍历整个未分页的结果列表,从而绕过了模板标签提供的惰性分页优势。

除了将我的代码直接移动到分页模块中(我宁愿不这样做并且需要将一堆额外的数据添加到请求上下文中以用于标记中),还有其他选择吗?

谢谢!

最佳答案

如果你看lazy_paginate标签使用 LazyPaginator处理查询集的类。您可以覆盖该类以满足您的目的。为此,您需要编写 Custom Template Tag .更多说明在代码注释中。

*my_app/templatetags/custom_pagination_tags.py*

from django import template
from endless_pagination.templatetags.endless import paginate
from endless_pagination.paginators import LazyPaginator

register = template.Library()

Class CustomLazyPaginator(LazyPaginator):

def page(self, number):
page_obj = super(CustomLazyPaginator, self).page(number)
# page function returns page object from that you could access object_list
object_list = page_obj.object_list
# Do some processing here for your queryset
# Do not remove elements otherwise you will put your self in trouble
# Just add some values in objects as you wanted to
page_obj.object_list = object_list # override here
return page_obj

@register.tag
def custom_lazy_paginate(parser, token):
return paginate(parser, token, paginator_class=CustomLazyPaginator)

现在在模板中加载您的自定义模板标签并改用它:

{% load custom_pagination_tags %}

{% custom_lazy_paginate queryset %}

困难:在 CustomLazyPaginator 类中访问请求上下文的第一种方法

是的,有一种方法可以传递请求上下文,但是为了做到这一点,您需要覆盖 paginate 标记以及 PaginateNode 的 render 方法 如你所见 here当它调用 paginator_class 时,它不会传递任何上下文信息。以下是实现该目标的步骤:

CustomLazyPaginator中添加__init__方法:

def __init__(self, *args, **kwargs):
self.context = kwargs.pop('context', None)
super(CustomLazyPaginator, self).__init__(*args, **kwargs)

复制 paginate 标签并将 return 语句从 PaginateNode(paginator_class, objects, **kwargs) 更改为 CustomPaginateNode( paginator_class, objects, **kwargs) 我们将在下面编写 CustomPaginateNode

from endless_pagination.templatetags.endless import PAGINATE_EXPRESSION

@register.tag
def paginate(parser, token, paginator_class=None):
# Validate arguments.
try:
tag_name, tag_args = token.contents.split(None, 1)
except ValueError:
msg = '%r tag requires arguments' % token.contents.split()[0]
raise template.TemplateSyntaxError(msg)

# Use a regexp to catch args.
match = PAGINATE_EXPRESSION.match(tag_args)
if match is None:
msg = 'Invalid arguments for %r tag' % tag_name
raise template.TemplateSyntaxError(msg)

# Retrieve objects.
kwargs = match.groupdict()
objects = kwargs.pop('objects')

# The variable name must be present if a nested context variable is passed.
if '.' in objects and kwargs['var_name'] is None:
msg = (
'%(tag)r tag requires a variable name `as` argumnent if the '
'queryset is provided as a nested context variable (%(objects)s). '
'You must either pass a direct queryset (e.g. taking advantage '
'of the `with` template tag) or provide a new variable name to '
'store the resulting queryset (e.g. `%(tag)s %(objects)s as '
'objects`).'
) % {'tag': tag_name, 'objects': objects}
raise template.TemplateSyntaxError(msg)

# Call the node.
return CustomPaginateNode(paginator_class, objects, **kwargs)

删除我们之前调用的以下导入以避免调用原始的 paginate 函数:

from endless_pagination.templatetags.endless import paginate

覆盖 PaginateNoderender 方法以将上下文传递给我们的 CustomLazyPaginator 类:

from endless_pagination.templatetags.endless import PaginateNode
from endless_pagination import (
settings,
utils,
)

class CustomPaginateNode(PaginateNode):
def render(self, context):
# Handle page number when it is not specified in querystring.
if self.page_number_variable is None:
default_number = self.page_number
else:
default_number = int(self.page_number_variable.resolve(context))

# Calculate the number of items to show on each page.
if self.per_page_variable is None:
per_page = self.per_page
else:
per_page = int(self.per_page_variable.resolve(context))

# Calculate the number of items to show in the first page.
if self.first_page_variable is None:
first_page = self.first_page or per_page
else:
first_page = int(self.first_page_variable.resolve(context))

# User can override the querystring key to use in the template.
# The default value is defined in the settings file.
if self.querystring_key_variable is None:
querystring_key = self.querystring_key
else:
querystring_key = self.querystring_key_variable.resolve(context)

# Retrieve the override path if used.
if self.override_path_variable is None:
override_path = self.override_path
else:
override_path = self.override_path_variable.resolve(context)

# Retrieve the queryset and create the paginator object.
objects = self.objects.resolve(context)
paginator = self.paginator(
objects, per_page, first_page=first_page, orphans=settings.ORPHANS,
context=context) # <--- passing context here

# Normalize the default page number if a negative one is provided.
if default_number < 0:
default_number = utils.normalize_page_number(
default_number, paginator.page_range)

# The current request is used to get the requested page number.
page_number = utils.get_page_number_from_request(
context['request'], querystring_key, default=default_number)

# Get the page.
try:
page = paginator.page(page_number)
except EmptyPage:
page = paginator.page(1)

# Populate the context with required data.
data = {
'default_number': default_number,
'override_path': override_path,
'page': page,
'querystring_key': querystring_key,
}
context.update({'endless': data, self.var_name: page.object_list})
return ''

简单:在 CustomLazyPaginator 类中访问请求上下文的第二种方法

只需安装 django-contrib-requestprovider并将它添加到 django 的 settings.py 的中间件中,并在任何你想要的地方访问当前请求:

from gadjo.requestprovider.signals import get_request

http_request = get_request()

关于python - 如何在使用 django 无尽分页渲染之前进行结果后处理?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18704459/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com