我试图弄清楚是否可以在我的查询集上进行查看后处理,然后在使用django-endless-pagination进行无限滚动的django模板中进行渲染。
我有特定于视图的逻辑,它根据上下文忽略查询集的某些结果,以及向列表中的对象添加属性以供模板使用。此逻辑不能通过SQL执行,因为它不是模型固有的。它必须在python中完成。
使用django-endless-pagination和其他预先滚动的django分页模块,所有逻辑似乎都是由模板标签执行的,从而阻止了在渲染阶段(这是django tenet)之前执行业务逻辑的能力。
因为我的视图逻辑在模板标签执行之前运行结果集,所以我正在丢失此模块提供的优化(例如带有分页的SQL查询,例如限制20;偏移20)。每次用户页面时,我的代码遍历整个未分页的结果列表,绕过模板标记提供的惰性分页优势。
没有直接将我的代码移入分页模块(我宁愿不这样做,并且需要在请求上下文中添加一堆额外数据以用于标记),还有其他选择吗?
谢谢!
答案 0 :(得分:5)
如果您查看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
代码以及render
PaginateNode
方法,如您所见{ {3}}当它调用paginator_class
时,它不会传递任何上下文信息。以下是实现这一目标的步骤:
在__init__
中添加CustomLazyPaginator
方法:
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
重写render
PaginateNode
方法,将上下文传递给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类中访问请求上下文的第二种方法
只需安装here并将其添加到django&nbsp; settings.py中的中间件中,然后根据需要访问当前请求:
from gadjo.requestprovider.signals import get_request
http_request = get_request()