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

时间:2013-09-09 18:18:25

标签: python django pagination django-endless-pagination

我试图弄清楚是否可以在我的查询集上进行查看后处理,然后在使用django-endless-pagination进行无限滚动的django模板中进行渲染。

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

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

因为我的视图逻辑在模板标签执行之前运行结果集,所以我正在丢失此模块提供的优化(例如带有分页的SQL查询,例如限制20;偏移20)。每次用户页面时,我的代码遍历整个未分页的结果列表,绕过模板标记提供的惰性分页优势。

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

谢谢!

1 个答案:

答案 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()