【问题标题】:how does django get_next_by_FOO() query work?django get_next_by_FOO() 查询是如何工作的?
【发布时间】:2020-07-26 02:27:04
【问题描述】:

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

【问题讨论】:

  • 它将使用SELECT * FROM table WHERE field > field_value ORDER BY field ASC LIMIT 1SELECT * FROM table WHERE field < field_value ORDER BY field DESC LIMIT 1 之类的内容进行查询

标签: sql django database django-orm


【解决方案1】:

方法在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_FOOis_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

【讨论】:

  • 我有一个设置为 null=True 的 publish_date 字段。即如果博客未发布,则 publish_date 为空。我可以在像 get_next_by_publish_date 这样的 publish_date 字段上使用 get_next_by_F00() 吗?
  • @ashleyparker:它不会引发错误。但问题是NULL的顺序是未指定的,所以在某些数据库中它可以在顶部(按最小元素排序),最大,甚至只是没有顺序,所以随机打乱。
  • 我正在使用 postgresql 。它可以在postgresql上运行吗? obj.get_next_by_publish_date(已发布=真)。字段是 publish_date(datetimefield,null=True)、published(booleanfield)。还是我应该自己写 get_next_by
  • @ashleyparker:您可以使用obj.get_next_by_publish_date(publish_date__isnull=False) 过滤以从publish_date 中过滤掉NULLs。
  • 感谢@Willem。还有一个问题。如果我处理一百万条记录。性能如何(获取下一项或上一项需要多少时间)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-03-14
  • 1970-01-01
  • 2018-11-25
  • 2014-02-07
  • 2019-09-16
  • 2017-05-31
  • 2014-07-20
相关资源
最近更新 更多