【问题标题】:Creating a QuerySet manually in Django from list of ids从 ids 列表在 Django 中手动创建 QuerySet
【发布时间】:2020-08-24 10:47:27
【问题描述】:

假设我有一个模型My_model,并且我有这个模型的 id 列表;

my_ids = [3,2,1,42]

现在我想获得一个带有My_model.objects id 的查询集。 我已经找到了this solution,但它对我不起作用,因为我希望QuerySet 中的对象与my_ids 中的ID 顺序相同。

如何在 Django 和 Python 的 QuerySet 中转换 id 列表?

【问题讨论】:

  • 也许this 会回答你的问题?
  • 不,in_bulk() 不关心传递给它的顺序。
  • 不,确实没有
  • @Sven basicaully 你需要this 并按照建议添加订单,例如here

标签: python django sqlite django-queryset


【解决方案1】:

它确实不关心顺序,因为查询看起来像:

SELECT model.*
FROM model
WHERE model.pk IN (3, 2, 1, 42)

数据库可以按照它想要的任何顺序返回值。根据您使用的数据库、索引机制等,顺序可以是“确定性的”,但它甚至有可能返回完全随机的记录。

你可以用一个相当复杂的表达方式来订购这些:

from django.db.models import Case, IntegerField, Value, When

my_ids = [3,2,1,42]

Model.objects.filter(
    pk__in=my_ids
).order_by(
    Case(
        *[When(pk=pk, then=Value(i)) for i, pk in enumerate(my_ids)],
        output_field=IntegerField()
    ).asc()
)

这仍然是QuerySet,可用于惰性查询目的,但问题仍然是为什么要根据主键的顺序对元素进行排序。通常模型(或相关模型)包含更多“有趣”的元素排序方式。

【讨论】:

  • 请问这个问题很愚蠢,但是效率高吗?
  • @Sven:排序是在数据库端完成的,这往往更有效率。它至少比一个一个查询更有效。是否更高效取决于数据库的几个方面。最后它是懒惰的,所以如果你不使用查询集,那么它甚至永远不会对数据库进行查询。
  • @Sven:我们在数据库中做了一个表达式,表示带有pk=3 的项目的“分数”是0,对于pk=21,对于pk=12,对于pk=423,然后我们按该分数排序。
  • @Sven,只要你不“消费”一个查询集(例如不迭代它,或者调用len(..).count()等,它就不会查询到数据库)。 QuerySet 基本上是一个“承诺”,它在必要时执行查询。
  • @Sven:我忘了最后一个逗号 :)
【解决方案2】:

你可以使用in_bulk():

queryset = Foo.objects.in_bulk(my_ids)

但是,这也会有同样的问题。这不是 Django 的限制,而是 SQL 的限制。除非您明确订购,否则数据库会根据需要将数据返回给您,并且没有真正的好方法来任意订购。

所以答案是,你不能,很容易。您可能会在 SQL 中使用 CASE 做一些奇怪的事情,但这可能会很慢。

可能最简单的方法是将查询集转换为列表,然后在 Python 中进行自定义排序,例如:

objs = sorted(list(queryset), key=lambda x: my_ids.index(x.id))

编辑:Willem 的回答用case 做了一些奇怪的事情,可能比这更快,但如果你关心速度,我仍然不想按任意顺序抓取东西。

【讨论】:

    猜你喜欢
    • 2011-03-24
    • 2020-10-01
    • 2018-06-09
    • 2019-02-26
    • 2018-05-06
    • 2013-04-18
    • 1970-01-01
    • 2020-01-01
    • 2019-05-20
    相关资源
    最近更新 更多