【问题标题】:(Django) How to add a queryset count for dynamic objects in a list to a template?(Django)如何将列表中动态对象的查询集计数添加到模板中?
【发布时间】:2018-08-11 20:37:03
【问题描述】:

我正在建立一个使用 django 的网站作为存储我的大学笔记的地方。

我有一个通过外键链接到类别模型的笔记模型。

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

例如:

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

等等等等

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

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

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

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

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

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

感谢大家的帮助。

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

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(异常值:未定义名称“Q”)。

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

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

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

【问题讨论】:

    标签: python django templatetags


    【解决方案1】:

    您可以向 Category 模型添加一个仅返回已发布笔记的方法:

    class Category(models.Model):
        ... model definition ...
    
        def published_notes(self):
            return self.notes_set.filter(published_date__lte=timezone.now())
    

    并在模板中使用它:

    {{ category.published_notes|length }}
    

    该方法在项目的其他地方也很有用。您可能希望在多个地方执行与仅发布笔记相同的逻辑。

    【讨论】:

    • 我试试看。
    • 刚刚测试了这个方法,它似乎是最优雅的解决方案,感谢您的输入!
    【解决方案2】:

    您需要使用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,其中包含已发布笔记的数量。

    【讨论】:

    • 这不会给你任何与 OP 当前执行的方式不同的东西,当然?它不会过滤掉未发表的笔记。
    • 更新了过滤器,因此它只计算已发布的笔记。
    • 谢谢丹尼尔,我想这就是我一直在寻找的。不过,我无法将其整合到基于课程的视图中,我已经编辑了我的原始问题以展示我的尝试。
    猜你喜欢
    • 2021-04-29
    • 2012-11-27
    • 2021-09-19
    • 2019-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多