Метод подсчета в шаблоне Django не работает должным образом

Я создаю новостное приложение, которое позволяет участникам оставлять комментарии к статьям. Я хочу отображать статьи в моем шаблоне, а также отображать количество комментариев, которые были сделаны по каждой статье. Я попытался использовать метод подсчета, но он извлек общее количество комментариев в моей таблице комментариев вместо количества комментариев, которые есть у конкретной статьи.

#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

Мой предполагаемый результат - иметь список всех статей и сводку комментариев к этой статье под каждой статьей (например, комментарии к статье 1: 4, комментарии к статье 5: 1 и т. Д.). Сейчас я получаю: Статья 1: 4 комментария, статья 5: 4 комментария (хотя статья 5 имеет только 1 комментарий)

Любая помощь приветствуется. Я потратил 5 часов на чтение документации, но каждый пример вручную предоставляет значение для фильтрации.

1 ответ

Решение

Я не уверен, почему ты находишь это неожиданным. comments это все комментарии, так что конечно comments.count это подсчет всех комментариев. Как могло быть иначе? Вы их нигде не фильтруете.

Однако это действительно ужасный способ сделать что-то. Нет абсолютно никакой причины передавать все комментарии в шаблон, а затем проходить через них, чтобы проверить, являются ли они правильной статьей. У вас есть внешний ключ от Комментария к Статье, поэтому вы должны использовать обратную связь, чтобы получить соответствующие комментарии.

Исключите запрос Comment из своего представления, и в вашем шаблоне просто сделайте это (заменив весь этот блок вложенных fors и ifs):

{{ article.comment_set.count }}

Это, однако, делает один запрос подсчета на статью. Лучшее решение - использовать аннотации, чтобы вы могли делать все это в одном запросе. Измените ваш набор запросов, чтобы добавить аннотированное количество связанных комментариев:

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 }}
Другие вопросы по тегам