【问题标题】:Count method in Django template not working as expectedDjango模板中的计数方法没有按预期工作
【发布时间】:2014-07-29 19:53:32
【问题描述】:

我正在构建一个允许成员在文章上发布 cmets 的新闻应用程序。我想在我的模板中显示文章,并显示在每篇文章上制作的 cmets 数量。我尝试使用 count 方法,但它检索到我的 cmets 表中的 cmets 总数,而不是特定文章的 cmets 数。

#models.py
class Article(models.Model):
    #auto-generate indices for our options
    ENTRY_STATUS = enumerate(('no', 'yes'))
    #this will be a foreign key once account app is built
    author = models.CharField(default=1, max_length=1)
    category = models.ForeignKey(Category)
    title = models.CharField(max_length=50)
    entry = models.TextField()
    dateposted = models.DateTimeField(default=timezone.now, auto_now_add=True)
    draft = models.IntegerField(choices=ENTRY_STATUS, default=0)
    lastupdated = models.DateTimeField(default=timezone.now, auto_now=True)

    #prevents the generic labeling of our class as 'Classname object'
    def __unicode__(self):
        return self.title


class Comment(models.Model):
    #this will be a foreign key once account app is built
    author = models.CharField(default=1, max_length=1)
    article = models.ForeignKey(Article)
    dateposted = models.DateTimeField(auto_now_add=True)
    comment = models.TextField()

    def __unicode__(self):
        #returns the dateposted as a unicode string
        return unicode(self.dateposted)

#templates/list_articles.html
{% for comment in comments %}
    {% if comment.article_id == article.id %}
        {% if comments.count < 2 %}
            #this is returning all comments in comment table
            <b>{{ comments.count }} comment</b>
        {% else %}
            <b>{{ comments.count }} comments</b>
        {% endif %}
    {% endif %}
{% endfor %}

到目前为止,我看到的所有示例都手动提供了一个过滤值(例如 Comment.objects.filter(article_id=x).count() )在我的情况下,我只能通过模板访问。

#views.py
class ArticlesListView(ListView):
    context_object_name = 'articles'
    # only display published pieces (limit 5)
    queryset = Article.objects.select_related().order_by('-dateposted').filter(draft=0)[:5]
    template_name = 'news/list_articles.html'

    # overide this to pass additional context to templates
    def get_context_data(self, **kwargs):
        context = super(ArticlesListView, self).get_context_data(**kwargs)
        #get all comments
        context['comments'] = Comment.objects.order_by('-dateposted')
        #get all article photos
        context['photos'] = Photo.objects.all()
        #context['total_comments'] = Comment.objects.filter(article_id=Article)
        return context

我的预期结果是列出所有文章并在每篇文章下方对该文章进行 cmets 汇总(例如,第 1 条:4 条 cmets,第 5 条:1 条评论,等等...)现在我得到:第 1 条:4 cmets,第 5 条:4 cmets(尽管第 5 条只有 1 条评论)

感谢任何帮助。我花了 5 个小时阅读文档,但每个示例都手动提供了一个过滤值。

【问题讨论】:

    标签: django django-templates django-views django-class-based-views


    【解决方案1】:

    我不知道你为什么会觉得这出乎意料。 comments所有 cmets,所以comments.count 当然是所有 cmets 的计数。不然怎么可能?您不会在任何地方过滤它们。

    然而,这是一种非常可怕的做事方式。绝对没有理由将所有 cmets 传递给模板,然后遍历它们以检查它们是否是正确的文章。您有一个从评论到文章的外键,因此您应该使用反向关系来获取相关评论。

    从您的视图中完全忽略 Comment 查询,并在您的模板中执行此操作(替换整个嵌套 fors 和 ifs 块):

    {{ article.comment_set.count }}
    

    但是,这会为每篇文章执行一次计数查询。更好的解决方案是使用注释,这样您就可以在一个查询中完成所有操作。更改您的查询集以添加相关 cmets 的注释计数:

    from django.db.models import Count
    
    class ArticlesListView(ListView):
        queryset = Article.objects.select_related().annotate(comment_count=Count('comments')).order_by('-dateposted').filter(draft=0)
    

    现在你可以这样做了

    {{ article.comment_count }}
    

    【讨论】:

    • 谢谢@DanielRoseman。我将阅读更多关于注释和聚合以及重构我的代码的内容。正如你所指出的,这是一种可怕的做事方式。我期待comments.count 在模板中工作,因为它是嵌套的。不确定,但我猜 5 小时后,事情变得模糊不清,沮丧情绪开始显现。再次感谢!
    猜你喜欢
    • 2021-01-31
    • 1970-01-01
    • 2019-08-30
    • 2018-09-11
    • 2020-07-14
    • 2021-05-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多