我有分类和物品。这些项目有一个结束字段(日期时间)。现在我需要列出所有类别并显示相关项目数和未来项目的项目数。举个例子:
列表很大。因此,数据库必须进行繁重的工作并对item_count
和future_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(datetime)进行过滤。这有可能与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查询完成吗?
答案 0 :(得分: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()
""")
)