Django模板:检查空查询集

39
有没有一种方法可以在Django模板中检查空查询集?在下面的示例中,我只想在有注释时显示NOTES标题。
如果我在“for”中放置{% empty %},那么它会显示空标记内的内容,因此它知道它是空的。
我希望有一些不涉及两次运行查询的方法。
{% if notes - want something here that works %}
     NOTES:
     {% for note in notes %}
         {{note.text}}  
     {% endfor  %}
{% endif  %}

澄清:以上“if notes”示例不起作用-即使是空查询集,它仍然显示标题。
以下是该视图的简化版本。
sql = "select * from app_notes, app_trips where"
notes = trip_notes.objects.raw(sql,(user_id,))

return render_to_response(template, {"notes":notes},context_instance=RequestContext(request))  

编辑:视图选择从多个表中选择。


你确定它会运行两次查询吗?一个简单的建议是“缓存”,但这并不能回答你的问题。 - Joseph Victor Zammit
我的问题不是它运行了两次查询。我的示例无法正常工作。即使查询集为空,它仍然显示标题。 - user984003
请发表您的观点 - Thomas Schwärzl
为什么 {% if notes %} 不起作用? - karthikr
应该吗?我希望它会,但它没有。我使用“if”来处理单个变量,但对于查询结果来说,它从来没有起作用(至少对我来说是这样)。 - user984003
3
notes是一个原始的查询集,与常规的查询集不同,它没有定义__nonzero__方法。因此,即使为空,它们也会被视为True。参考链接:http://docs.python.org/2/reference/datamodel.html#object.__nonzero__ - Peter DeGlopper
9个回答

51

请看文档中的{% empty %}标签示例。

<ul>
{% for athlete in athlete_list %}
    <li>{{ athlete.name }}</li>
{% empty %}
    <li>Sorry, no athletes in this list.</li>
{% endfor %}
</ul>

链接:https://docs.djangoproject.com/en/1.8/ref/templates/builtins/#for-empty

如果您需要一个表格或者在有结果时添加标题,请添加 forloop.first

    {% for athlete in athlete_list %} {% if forloop.first %} 运动员名称: {% endif %}
  • {{ athlete.name }}
  • {% empty %}
  • 很抱歉,此列表中没有运动员。
  • {% endfor %}


1
虽然非常有用,但它实际上并没有回答问题。empty将在没有元素时运行一次。在问题中,OP希望在列表中有元素时显示文本。(但只显示一次) - T'n'E
@T'n'E 看一下我的更新,其中包括列表。 - chris Frisina

39
尝试使用{% if notes.all %}。 这对我有效。

2
对我来说也管用,并且我更喜欢使用这个方法而不是 .count,因为后者会发出 select count(*) 查询,但我认为这个方法会在查询集缓存时更有效。 - Chris
7
不要将查询集作为布尔值使用:不要使用 if queryset:,而要使用 if queryset.exists():。请记住,查询集是惰性的,如果将查询集用作布尔值,则可能会执行不合适的数据库查询操作。@Chris 的方法更好。 - Kishor Pawar
3
感谢 @KishorPawar 提供的解决方案,不过在模板中它没有括号:if queryset.exists - S_M
1
@KishorPawar 使用 if queryset: 是可以的,因为 QuerySet 类覆盖了 __bool__ 魔法方法。请参见 https://github.com/django/django/blob/ca9872905559026af82000e46cde6f7dedc897b6/django/db/models/query.py#L283。 - Rune Kaagaard
1
是的,这是@RuneKaagaard。尽管文档建议使用exists()函数,请查看bool()函数的解释。 https://docs.djangoproject.com/en/3.2/ref/models/querysets/#when-querysets-are-evaluated - Kishor Pawar

8
很遗憾,您只能使用原始查询集 - 它们缺少许多有用的功能。
您可以在视图中将原始查询集转换为列表:
notes_as_list = list(notes)
return render_to_response(template, {"notes":notes_as_list},context_instance=RequestContext(request))

在模板中将其作为布尔值进行检查:

{% if notes %}
    Header
    {% for note in notes %}
        {{ note.text }}
    {% endfor %}
{% endif %}

您也可以使用forloop.first来避免转换:

{% for note in notes %}
    {% if forloop.first %}
         Header
    {% endif %}
    {{ note.text }}
{% endfor %}

forloop.first 对我有用。很棒的技巧。另一个不行。它列出了查询本身的所有字母:R A W Q U E R Y S E L E。 - user984003
是的,我检查了make_list的源代码,但忽略了它被注册为stringfilter,这意味着如果参数不是Unicode对象,它会将其转换为Unicode对象。我会更新我的答案。 - Peter DeGlopper

6

在您的代码中检查 notes 是否为空。如果是空的,则传递 None:

{"notes": None}

在你的模板中,你像平常一样使用了{% if notes %}

这需要运行两次,对吗? - user984003
1
什么?为什么?你应该将查询分配给一个变量notes,然后执行类似于{"notes": notes if len(notes) else None}的操作,然后您可以像Simeon建议的那样在模板中检查notes是否为None。这是正确的做法。 - Samuele Mattiuzzo
2
我认为最好使用notes.count() - 我上次检查时,len(notes)会从数据库中提取每个记录,而count只会发出计数查询。 - Tim Sutton

4

关于什么:

{% if notes != None %}
    {% if notes %}
        NOTES:
        {% for note in notes %}
            {{ note.text }}  
        {% endfor  %}
    {% endif %}
{% else %}
    NO NOTES AT ALL
{% endif %}

不行,它仍然打印标题(但没有注释)。 - user984003

3
您的原始解决方案
{% if notes %}
    Header
    {% for note in notes %}
        {{ note.text }}
    {% endfor %}
{% endif %}

现在可以与Django 1.7一起使用,并且由于QuerySet缓存的存在,它不会产生额外的查询成本。


3
通常做法是使用{% with ... %}标签来实现。这样可以缓存查询结果,只运行一次,并且比使用{% empty %}标签更灵活。
{% with notes as my_notes %}
{% if my_notes %}
<ul>
  {% for note in my_notes %}
  <li>{{ note }}</li>
  {% endfor %}
</ul>
{% else %}
<p>Sorry, no notes available</p>
{% endif %}
{% endwith %}

对于这个特定的例子,我不确定它有多大用处,但如果你正在查询Many-to-Many字段,那么它很可能是你想要做的。


1

Use {% empty %} in django templates

{% if list_data %}
    {% for data in list_data %}
        {{ data.field_1 }}
    {% endfor %}
{% else %}
    <p>No data found!</p>
{% endif %}

我们可以使用 {% empty %} 写上述代码。
{% for data in list_data %}
    {{ data.field_1 }}
{% empty %}
    <p>No data found!</p>
{% endfor %}

0

你可以在“for循环”中使用{% empty %},例如:

{% for object in list %}
<p>{{ object }}</p>
{% empty %}
<p>list is empty</p>
{% endfor %}

使用'.all'
{% if object.something.all %}

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