Django - 在模板中显示相关 class 计数按参数过滤

Django - show in template related class count filtered by parameter

我会先给出我的模型,然后再写描述。

class Entry(models.Model):
    entry_text = models.TextField()

class Category(models.Model):
    user = models.ForeignKey(User)
    category_text = models.CharField(max_length=200)
    entries = models.ManyToManyField(Entry, through='CategoryEntry')

class CategoryEntry(models.Model):
    category = models.ForeignKey(Category)
    entry = models.ForeignKey(Entry)
    viewed = models.BooleanField(default=False)

所以我有 Entry 模型和 Category 模型,并且我创建了中间模型 CategoryEntry ,如此处所述 https://docs.djangoproject.com/en/1.7/topics/db/models/#extra-fields-on-many-to-many-relationships 因为我需要一个额外的字段 "viewed" (当用户第一次使用时标记为 True打开特定条目 link).

所以我创建了 generic.ListView 视图,我在其中显示了用户为自己创建的所有这些类别。我想要的是在每个类别名称旁边显示有多少条目以及他尚未查看的条目数。 喜欢:

Category   Total   Not_viewed
AAA        126     5
BBB        17      15

我已经通过

在模板中显示了总条目
{% for category in categories %}
    {{ category.text }}
    {{ category.entries.count }}
{% endfor %}

在我看来我get_queryset喜欢

def get_queryset(self):
    categories = Category.objects.filter(user=self.request.user.id)[:]

    return categories

据我所知,最好的方法是以某种方式添加有关 get_queryset 中查看的每个类别条目的额外信息。我四处搜索但没有发现任何有用的东西。已经尝试过使用 select_related、prefetch_related 进行注释,但不知道正确的方法是什么。 知道这是不对的,但尝试了类似的东西和其他一些东西。

categories = Category.objects.filter(user=self.request.user.id).select_related('categoryentry').filter(categoryentry__viewed=False).count()
categories = Category.objects.filter(user=self.request.user.id).annotate(not_viewed_count=Count('categoryentry')).filter(not_viewed_count__viewed=False)

希望你明白我不想实现的目标。

在您的 CategoryEntry 模型中,在类别字段中使用 related_name,如下所示:

category = models.ForeignKey(Category, related_name="related_entry_categories")

现在您可以在查询Category模型时使用这个相关名称。例如:

from itertools import chain

categories_not_viewed = Category.objects.filter(user=self.request.user.id, related_entry_categories__viewed=False).annotate(num_not_viewed=Count('related_en‌​try_categories'))
categories_viewed = Category.objects.filter(user=self.request.user.id, related_entry_categories__viewed=True).extra(select={'num_not_viewed': 0})
categories = chain(list(categories_not_viewed), list(categories_viewed))

最后我想到了这个解决方案:

categories = Category.objects.filter(user=self.request.user.id).extra(select = {
          "num_not_viewed" : """
          SELECT COUNT(*)
          FROM app_categoryentry
          WHERE app_categoryentry.category_id = app_category.id
          AND app_categoryentry.viewed = %d """ % 0,
        })

基于此资源的解决方案http://timmyomahony.com/blog/filtering-annotations-django/

如果有人有其他解决方案如何仅使用 Django ORM 获得相同的结果,我想知道。