Django Paginator:paginator在哪里修改SQL查询添加LIMIT / OFFSET?

时间:2017-09-01 17:57:24

标签: django django-models

我正试图与django分页系统联系并得到一个低级别的问题。

我一直在挖掘ManagerQuerysetPaginator的代码,但我无法找到Paginator所在的地方{{3}在SQL查询上设置限制和偏移量,强制它只返回查询集的一部分。

你能找到那个地方吗?因为它不在Paginator本身的代码中。

以下是由paginator生成的SQL示例:

>>> from django.db import connection
>>>
>>> paginator = Paginator(Myobject.objects.filter(foreign_key='URS0000416056'), 1)
>>> for myobject in paginator.page(1):
>>>     print myobject
Myobject object
>>>
>>> print connection.queries
[{u'time': u'0.903', u'sql': u'SELECT COUNT(*) AS "__count" FROM "xref" WHERE "xref"."upi" = \'URS0000416056\''}, {u'time': u'0.144', u'sql': u'SELECT "xref"."id", "xref"."dbid", "xref"."ac", "xref"."created", "xref"."last", "xref"."upi", "xref"."version_i", "xref"."deleted", "xref"."timestamp", "xref"."userstamp", "xref"."version", "xref"."taxid" FROM "xref" WHERE "xref"."upi" = \'URS0000416056\' LIMIT 1 OFFSET 1'}]

1 个答案:

答案 0 :(得分:2)

感谢链接到源代码,他们让我挖掘细节。

在构造Paginator个实例时,

Page在包装的查询集上使用切片表示法:

        return self._get_page(self.object_list[bottom:top], number, self)

https://github.com/django/django/blob/master/django/core/paginator.py#L57

此处object_list是一个查询集,尽管名称如果您首先在查询集上使用了Paginator

反过来,查询集在__getitem__方法中实现切片表示法:

            qs.query.set_limits(start, stop)    

切片特定处理当前从https://github.com/django/django/blob/master/django/db/models/query.py#L260开始。

查询类使用set_limits方法将查询类转换为查询的低位和高位属性:

def set_limits(self, low=None, high=None):
    """
    Adjust the limits on the rows retrieved. Use low/high to set these,
    as it makes it more Pythonic to read and write. When the SQL query is
    created, convert them to the appropriate offset and limit values.
    Apply any limits passed in here to the existing constraints. Add low
    to the current low value and clamp both to any existing high value.
    """
    if high is not None:
        if self.high_mark is not None:
            self.high_mark = min(self.high_mark, self.low_mark + high)
        else:
            self.high_mark = self.low_mark + high
    if low is not None:
        if self.high_mark is not None:
            self.low_mark = min(self.high_mark, self.low_mark + low)
        else:
            self.low_mark = self.low_mark + low

    if self.low_mark == self.high_mark:
        self.set_empty()

(截至2017年9月的当前实施情况,未来可能会发生变化。)

低标记和高标记反过来转变为SQLCompiler as_sql方法中的LIMIT和OFFSET查询参数:

        if with_limits:
            if self.query.high_mark is not None:
                result.append('LIMIT %d' % (self.query.high_mark - self.query.low_mark))
            if self.query.low_mark:
                if self.query.high_mark is None:
                    val = self.connection.ops.no_limit_value()
                    if val:
                        result.append('LIMIT %d' % val)
                result.append('OFFSET %d' % self.query.low_mark)