0

我有类别和项目。这些项目有一个结束字段(日期时间)。现在我需要列出所有类别并显示相关项目数和未来项目的项目数。举个例子:

  • Cat Foo,2 项,未来 1 项。
  • 猫 n,未来 n 件物品。

名单会很大。因此,数据库必须承担繁重的工作并同时注释item_countfuture_item_count

楷模:

from django.db import models

class Cat(models.Model):
    title = models.CharField(max_length=200)

class Item(models.Model):
    cat = models.ForeignKey(Cat)
    title = models.CharField(max_length=200)
    end = models.DateTimeField()

创建一个类别和两个相关项目。一个过去,一个未来:

from datetime import timedelta
from django.utils import timezone

cat = Cat(title='Cat 1')
cat.save()

item_1 = Item(cat=cat, title="Item 1", end=timezone.now() - timedelta(days=1))
item_1.save()

item_2 = Item(cat=cat, title="Item 2", end=timezone.now() + timedelta(days=1))
item_2.save()

当我注释 item_count 时,它按预期工作:

from django.db.models import Count

Cat.objects.all().annotate(
    item_count=Count('item')).values('title', 'item_count')
# [{'item_count': 2, 'title': u'Cat 1'}]

我不能注释由 Item.end (日期时间)过滤。这完全可以通过 Django 查询实现吗?

Cat.objects.all().annotate(
    item_count=Count('item'),
    future_item_count=Count('item').filter(
        end__gt=timezone.now())
    ).values(
        'title', 
        'item_count', 
        'future_item_count'
    )
# AttributeError: 'Count' object has no attribute 'filter'

我希望得到:[{'item_count': 2, 'future_item_count': 1, 'title': u'Cat 1'}]

我也尝试过 RawSQL,但缺乏 SQL 技能:

from django.db.models.expressions import RawSQL

Cat.objects.all().annotate(
    item_count=Count('item'), 
    future_item_count=RawSQL(
        """SELECT COUNT(*) 
           FROM project_item 
           JOIN project_item 
           AS foo 
           ON foo.cat_id = project_cat.id 
           WHERE project_item.end < NOW()""",
        ""
    )).values(
        'title', 
        'item_count', 
        'future_item_count'
    )
# [{'item_count': 2, 'future_item_count': 2L, 'title': u'Cat 1'}]

但是当我改变时WHERE project_item.end < NOW()"WHERE project_item.end > NOW()"我得到了相同的结果:

[{'item_count': 2, 'future_item_count': 2L, 'title': u'Cat 1'}]

如何格式化原始 SQL?或者这可以用 Django 查询来完成吗?

4

1 回答 1

1

我个人没有使用RawSQL(仍然使用.extra),但我认为您不需要JOIN project_item在您的RawSQL声明中使用。只需尝试:

RawSQL("""SELECT COUNT(*) 
            FROM project_item 
            WHERE 
                project_item.cat_id = project_cat.id 
                AND project_item.end < NOW()
""")

还有一件事我认为你不应该使用.values AFTER .annotate,而是在注释之前使用。所以你的完整 QuerySet 应该是这样的:

Cat.objects.values('title')\
    .annotate(
        item_count=Count('item'),
        future_item_count=RawSQL("""
            SELECT COUNT(*) 
            FROM project_item 
            WHERE 
                project_item.cat_id = project_cat.id
                AND project_item.end < NOW()
            """)
    )
于 2016-07-14T14:12:44.170 回答