获取查询集中元素的索引

Den*_*gan 37 python django indexing django-queryset

我有一个QuerySet,让我们调用它qs,它由一些与此问题无关的属性排序.然后我有一个对象,让我们称之为obj.现在,我想知道在什么指数objqs作为有效越好.我知道我可以使用.index()Python或者可能循环qs比较每个对象obj,但是这样做的最佳方法是什么?我正在寻找高性能,这是我唯一的标准.

在Windows上使用Python 2.6.2和Django 1.0.2.

drd*_*man 59

紧凑,可能是最有效的:

for index, item in enumerate(your_queryset):
    ...
Run Code Online (Sandbox Code Playgroud)


Ric*_*ard 31

如果您只想知道对象在哪里(例如在确定等级时),您可以通过在您之前计算对象来快速完成:

    index = MyModel.objects.filter(sortField__lt = myObject.sortField).count()
Run Code Online (Sandbox Code Playgroud)

  • 在这种情况下,您还希望`sortField`是唯一的,否则您将获得第一个元素的位置,其中`sortField`等于`myObject.sortField`. (4认同)
  • 不应该是`.count() - 1`吗?例如,如果查询集中有 1 个对象,则索引为 0。 (2认同)

rob*_*rob 16

Django中的QuerySets实际上是生成器,而不是列表(有关详细信息,请参阅QuerySets上的Django文档).
因此,没有获取元素索引的快捷方式,我认为普通迭代是最好的方法.

首先,我会以最简单的方式实现您的需求(如迭代); 如果你确实遇到性能问题,那么我会使用一些不同的方法,比如构建一个具有较少字段数量的查询集,或者其他什么.
无论如何,当你肯定知道你需要它们时,我们的想法就是尽可能晚地留下这些技巧.
更新:您可能希望直接使用一些SQL语句来获取rownumber(有些谎言.但是,Django的ORM本身不支持这种情况,您必须使用原始SQL查询(请参阅文档).我认为这可能是最佳选择,但又一次 - 只有你真的看到了真正的性能问题.


Vin*_*jip 12

假设为了说明的目的,您的模型是标准的主键id,然后进行评估

list(qs.values_list('id', flat=True)).index(obj.id)
Run Code Online (Sandbox Code Playgroud)

会发现指数objqs.虽然使用list评估查询集,但它不会评估原始查询集,而是评估派生查询集.此评估运行SQL查询以仅获取id字段,而不是浪费时间获取其他字段.


小智 9

可以使用简单的 Python 方式来查询查询集中元素的索引:

(*qs,).index(instance)
Run Code Online (Sandbox Code Playgroud)

这个答案将把查询集解压到一个列表中,然后使用内置的 Python 索引函数来确定它的位置。


Jia*_*aro 5

您可以使用queryset.extra(\xe2\x80\xa6)一些原始 SQL 来完成此操作,如下所示:

\n\n
queryset = queryset.order_by("id")\nrecord500 = queryset[500]\n\nnumbered_qs = queryset.extra(select={\n    \'queryset_row_number\': \'ROW_NUMBER() OVER (ORDER BY "id")\'\n})\n\nfrom django.db import connection\ncursor = connection.cursor()\ncursor.execute(\n    "WITH OrderedQueryset AS (" + str(numbered_qs.query) + ") "\n    "SELECT queryset_row_number FROM OrderedQueryset WHERE id = %s",\n    [record500.id]\n    )\nindex = cursor.fetchall()[0][0]\n\nindex == 501 # because row_number() is 1 indexed not 0 indexed\n
Run Code Online (Sandbox Code Playgroud)\n