Метод подсчета в шаблоне 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 }}