方法在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)
如果您查询get_next_by_FOO,is_next 将为True,如果您查询get_previous_by_FOO,则False。
对于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]
因此它将搜索FOO 字段相同但主键更大或FOO 字段(严格)更大的第一个Model 对象。
因此,这将导致如下查询:
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