Django: 随机排序(order_by('?'))会增加额外的查询

14

这里是Django的示例代码。

[案例1]

views.py

from sampleapp.models import SampleModel
from django.core.cache import cache

def get_filtered_data():

    result = cache.get("result")

    # make cache if result not exists
    if not result:
         result = SampleModel.objects.filter(field_A="foo")
         cache.set("result", result)

    return render_to_response('template.html', locals(), context_instance=RequestContext(request))

模板.html

  {% for case in result %}
  <p>{{ case.field_A}}</p>
  {% endfor %}
在这种情况下,在缓存之后没有生成的查询。我通过Django Debug Toolbar进行了检查。

[案例2]

views.py - 添加了一行result = result.order_by('?')

from sampleapp.models import SampleModel
from django.core.cache import cache

def get_filtered_data():

    result = cache.get("result")

    # make cache if result not exists
    if not result:
         result = SampleModel.objects.filter(field_A="foo")
         cache.set("result", result)

    result = result.order_by('?')

    return render_to_response('template.html', locals(), context_instance=RequestContext(request))

template.html - 与之前的相同

在这种情况下,即使我缓存了过滤查询,它也会生成新的查询


如何在不使用额外查询集的情况下适应随机排序?

  • 当进行缓存时,我不能添加order_by('?')。 (例如:result = SampleModel.objects.filter(field_A="foo").order_by('?')) 因为它会连随机排序一起缓存。

  • 这是否与“Django查询集是延迟查询”有关?

提前感谢您的回答。

1个回答

29

.order_by 在数据库层面进行排序。

这里是一个例子。我们将懒惰查询集存储在变量 results 中。尚未进行任何查询:

results = SampleModel.objects.filter(field_A="foo")

通过迭代方式触摸results,例如:

for r in results:  # here query was send to database
    # ...

现在,如果我们再次执行相同的查询,将不会尝试访问数据库,因为我们已经有了这个准确的查询:

for r in results:  # no query send to database
    # ...

然而,当你使用.order_by时,查询将会有所不同。因此,Django 必须向数据库发送新的请求:

for r in results.order_by('?'):  # new query was send to database
    # ...

解决方案

当在Django中进行查询时,如果你知道你将获取查询结果的所有元素(即没有OFFSET和LIMIT限制),那么你可以在从数据库中获取这些元素后,在Python中对它们进行处理。

results = list(SampleModel.objects.filter(field_A="foo"))  # convert here queryset to list

在那一行进行了查询,您现在拥有results中的所有元素。

如果需要随机顺序,请在Python中执行:


from random import shuffle
shuffle(results)

此后,结果将随机排序,无需发送额外的查询到数据库。


哇,你提出的解决方案真的很棒。谢谢! - Chemical Programmer
4
太棒了!Stack Overflow的美妙之处在于我可以在一个三年半前的答案中找到有价值的东西。我想知道Django是否有计划实现类似的功能。 - Lewis Menelaws

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接