在模板中计算几个已过滤的子查询

时间:2014-05-13 16:08:21

标签: python django django-models django-templates django-views

我最近询问如何计算模板中的文件子查询,并在此处得到答案:Get count on filtered subqueries in template

现在我意识到我需要扩展如下(我认为这比我的第一个问题要多得多,因此在这里创建一个新问题):

  1. 显示与该标记不匹配的文章,但随后将0作为计数。
  2. 扩展以允许计算不同的标记。
  3. 使用以下模型:

    class Category(models.Model):
        ...
    
    class SubCategory(models.Model):
        category = models.ForeignKey(Category)
        ....
    
    class Tag(models.Model):
        ....
    
    class Article(models.Model)
        sub_category = models.ForeignKey(SubCategory)
        tag = models.ForeignKey(Tag)
    

    我得到了以下答案(views.py),它将创建一个num_articles变量,该变量包含带有tag =' xyz'的文章数:

    def my_view(request, other, arguments):
        ...
        subcategories = category.sub_category_set.filter(tag__tagname='xyz') \ 
                                .annotate(num_articles=Count('article__id'))
    

    模板:

    {% for subcategory in subcategories %}
        {{ subcategory.name }} -- {{ subcategory.num_articles }}
    {% endfor %}
    



    但是现在,我希望能够做到这样的事情,在几个不同的标签上进行独立计数,以便计算' xyz'不依赖于' abc'的计数,反之亦然:

    def my_view(request, other, arguments):
        ...
        subcategories = category.sub_category_set. \
            filter(tag__tagname='xyz').annotate(num_articles_xyz=Count('article__id')) \
            filter(tag__tagname='abc').annotate(num_articles_abc=Count('article__id')) \
            filter(tag__tagname='def').annotate(num_articles_def=Count('article__id')) \
            ...
    

    在模板中使用:

    {% for subcategory in subcategories %}
        {{ subcategory.name }} -- {{ subcategory.num_articles_xyz }}<br />
        {{ subcategory.num_articles_abc }} -- {{ subcategory.num_articles_def }}
        ...
    {% endfor %}
    

    并且还希望显示所有子类别,即使在任何计数中都没有匹配。但是,那个计数的值为0。

1 个答案:

答案 0 :(得分:0)

使用Django ORM没有简单有效的方法。通过实现注释,ORM无法在同一查询中对不同的过滤集进行注释。即使您再次注释,过滤和注释,所有注释也将在最后一次注释时位于过滤集上。我甚至不确定你想要的是什么在原始SQL代码中是可行的,但我不是那么专家。

您可以获取所有相关标签和文章,并在Django中执行实际注释。但是,您必须小心:即使使用prefetch_related,如果您对相关集进行过滤或以实际克隆查询集的任何方式对其进行更改,您仍将为每个查询集执行数据库查询。

以下是您可以执行此操作的方法。它还将处理在该特定子类别中没有文章的任何标签。

subcategories = category.sub_category_set.prefetch_related('tags', 'articles')
for subcategory in subcategories:
    subcategory.num_articles = dict()
    for tag in tags:
        num = len([a for a in subcategory.articles.all() if a.tag_id == tag.id])
        subcategory.num_articles[tag.tag_name] = num

在你的模板中:

{% for subcategory in subcategories %}
    {{ subcategory.name }} <br />
    {% for k,v in subcategory.num_articles.iteritems %}
        {{ k }} -- {{ v }}
    {% endfor %}
{% endfor %}

这将产生3个数据库查询,无论标记的数量是多少(4包括category的查询),并将在python中执行其余的处理。但是,从数据库中获取大型数据集可能会很昂贵。如果您需要使用非常大的数据集并查看性能问题,您可能需要了解如何为每个标记执行一些优化的查询,而不是只使用python中的数据处理进行一些大型查询。