首页 > 解决方案 > django get_next_by_FOO() 查询是如何工作的?

问题描述

我想知道 get_next_by_FOO()/get_previous_by_FOO() 如何从数据库中获取数据。有人知道那个的SQL代码吗?谁能告诉我它是如何在幕后工作的?

标签: sqldjangodatabasedjango-orm

解决方案


方法在django/db/models/base.py【GitHub】文件中实现:

    def _get_next_or_previous_by_FIELD(self, field, is_next, **kwargs):
        if not self.pk:
            raise ValueError("get_next/get_previous cannot be used on unsaved objects.")
        op = 'gt' if is_next else 'lt'
        order = '' if is_next else '-'
        param = getattr(self, field.attname)
        q = Q(**{'%s__%s' % (field.name, op): param})
        q = q | Q(**{field.name: param, 'pk__%s' % op: self.pk})
        qs = self.__class__._default_manager.using(self._state.db).filter(**kwargs).filter(q).order_by(
            '%s%s' % (order, field.name), '%spk' % order
        )
        try:
            return qs[0]
        except IndexError:
            raise self.DoesNotExist("%s matching query does not exist." % self.__class__._meta.object_name)

如果is_nextTrue查询get_next_by_FOO,并且False如果您查询get_previous_by_FOO.

因此,get_next_by_FOO这将创建一个如下所示的查询:

Model.objects.filter(
    Q(FOO__gt=current_foo)
    Q(FOO=current_foo, pk__gt=current_pk)
).order_by('FOO', 'pk')[0]

因此,它将搜索字段相同但主键更大或字段(严格)更大的第一个Model对象。FOOFOO

因此,这将导致查询如下所示:

SELECT *
FROM model
WHERE FOO > current_FOO
   OR (FOO = current_FOO AND id > current_pk)
ORDER BY FOO ASC, id ASC
LIMIT 1

因此,它将旨在通过对记录进行排序并获取第一个记录来找到该元素。

对于get_previous_by_FOO,查询是类似的,只是>被替换为<并且我们以相反的方式排序:

SELECT *
FROM model
WHERE FOO < current_FOO
   OR (FOO = current_FOO AND id < current_pk)
ORDER BY FOO DESC, id DESC
LIMIT 1

推荐阅读