(Django) 如何将列表中动态对象的查询集计数添加到模板?

(Django) How to add a queryset count for dynamic objects in a list to a template?

我正在用 django 建立一个网站来存储我的大学笔记。

我有一个注释模型,它由外键link编辑到类别模型。

在我的主页上,我使用 for 循环 post 到每个类别页面 link,但在括号中我还想显示该类别中已发布的笔记数量。

例如:

生物学 (6) 化学 (4) 物理 (12)

等等等等

我使用模板标签来给出长度,例如。 for 循环中的 {{category.notes_set.all|length}} 以显示类别中的笔记数,但这会忽略笔记是否已发布或是否刚刚创建。如果我发布了 6 篇笔记和 1 篇未发表的笔记,它的值为 7 - 我希望它显示 6。我真的很想过滤(published_date__lte=timezone.now())但不要认为这个可以在模板中实现。

我是否必须为每个类别创建上下文字典并在视图中用计数对其进行注释?我觉得当类别和子类别的数量变得非常多时,这将难以管理。我可以在 views.py 中作为 for 循环执行此操作吗?

抱歉,如果这有一个明显的答案,我是一个真正的初学者。

最近的编辑:根据 Ben 的回答,似乎最优雅的解决方案是在 models.py 中向我的模型 class 添加一个函数。因此,对于案例研究登陆页面,我添加了:

def published_cases(self):
    return self.case_set.filter(published_date__lte=timezone.now())

到我的专业模型。然后我将 {{specialty.published_cases.all|length}} 添加到我的模板中。

感谢大家的帮助。

编辑:我正在尝试将注释功能合并到基于 class 的视图中。这是我的案例研究登录页面的一些示例代码。它显示了新案例研究列表、评分最高的案例研究列表和我想用已发布案例研究的数量进行注释的专业列表。我试过以下代码:

class CaseListView(TemplateView):
template_name = "case_list.html"

def get_context_data(self, **kwargs):
    context = super(CaseListView, self).get_context_data(**kwargs)
    context["cases"] = Case.objects.filter(published_date__lte=timezone.now()).order_by("-published_date")[:5]
    context["topcases"] = Case.objects.filter(published_date__lte=timezone.now()).annotate(num_upvotes=Count("upvotes")).order_by("-num_upvotes")[:5]
    context["specialtys"] = Specialty.objects.all().order_by("name").annotate(num_cases=Count("case", filter=Q(case__published_date__lte=timezone.now())))
    return context

这给我一个 NameError(异常值:name 'Q' 未定义)。

我尝试了另一种构建上下文的方法:

context["specialtys"] = Specialty.objects.all().order_by("name").annotate(num_cases=Count("case")).filter(case__published_date__lte=timezone.now())

这没有引发异常,但没有给出预期的结果,为 {{specialty.num_cases}} 给出了一个非常不正确的值,以我的知识水平,我什至无法想象如何它计算了。

您需要使用 aggregation。在您的视图中,您可以使用相关笔记的计数来注释每个类别,仅过滤已发布笔记的计数。

from django.db.models import Count, Q
categories = Category.objects.annotate(note_count=Count("note", filter=Q(note__published_date__lte=timezone.now())))

现在每个类别都有一个属性note_count,其中包含已发布笔记的数量。

您可以向仅 returns 发布的注释的类别模型添加一个方法:

class Category(models.Model):
    ... model definition ...

    def published_notes(self):
        return self.notes_set.filter(published_date__lte=timezone.now())

并在模板中改用它:

{{ category.published_notes|length }}

该方法在项目的其他地方也很有用。您可能希望在多个地方执行 only-published-notes 的相同逻辑。