我有一个类似的模型:
class Questionnaire(models.Model):
YES_NO_CHOICES = (
(True, 'Yes'),
(False, 'No'),
)
satisfaction = models.BooleanField(choices=YES_NO_CHOICES, default=True)
register = models.DateField(auto_now_add=True)
我需要从问卷中得到答案,按月分组并计算“是”和“否”答案。
例如,我有这样的回答:
{
'2015-11-29': {True: 1, False: 2},
'2015-11-30': {True: 3, False: 1},
'2015-12-01': {True: 5, False: 2},
'2015-12-05': {True: 3, False: 6}
}
我需要一个django查询集来执行以下操作:
{
{'2015-11-01': {True: 4, False: 3},
{'2015-12-01': {True: 8, False: 8}
}
日期并不重要,在模板中我只会使用月份值(01,02,03,...,11,12)。
我正在寻找一种pythonic方法,最好使用django中的queryset,而不是字典。
答案 0 :(得分:3)
首先,我们需要提取月份和年份值以供我们的查询使用。我们使用extra()
来完成此操作。不幸的是,Django没有内置支持。
然后,我们可以使用values()
按年份和月份进行分组。
最后,我们可以使用annotate()
和条件表达式汇总是/否答案:
from django.db import connections
from django.db.models import Case, IntegerField, Sum, When
conn = connections[Questionnaire.objects.db]
Questionnaire.objects.extra(
select={
'year': conn.ops.date_trunc_sql('year', 'register'),
'month': conn.ops.date_trunc_sql('month', 'register'),
}).values(
'year', 'month'
).annotate(
yes_count=Sum(
Case(When(satisfaction=True, then=1),
output_field=IntegerField()),
),
no_count=Sum(
Case(When(satisfaction=False, then=1),
output_field=IntegerField()),
)
)
您可能还想order_by('year', 'month')
,但这不是代码工作所必需的。
结果将是这样的词典列表:
[{'year': '2015-01-01', 'month': '2015-11-01', 'yes_count': 201, 'no_count': 422},
{'year': '2015-01-01', 'month': '2015-12-01', 'yes_count': 324, 'no_count': 223},
...]
如您所见,year
和month
不是数字,而是字符串。但是,您可以通过拆分轻松提取年份和月份:
year = int(item['year'].split('-')[0])
month = int(item['month'].split('-')[1])
答案 1 :(得分:0)
将选择更改为
result = Questionnaire.objects.extra(
select={'year': "EXTRACT(year FROM register)",
'month': "EXTRACT(month FROM register)",
'yes': "satisfaction = 1",
'no': "satisfaction = 0",
}).annotate(yes_count=models.Sum("yes"),
no_count=models.Sum("no")).order_by("year", "month").values("yes_count", "no_count", "month", "year")
for row in result:
print("yes {yes_count}, no {no_count}".format(**row))
print("date {year}-{month}-01".format(**row))
然后
Repository myr = new Repository(datasource); // let constructor create connection
myr.setAutoCommit(false);
myr.DAOObject1(parms); // method wrapper
myr.DAOObject2(parms); // method wrapper
myr.commitwork(); // method in Repository that calles endAndCommitTransactionLogic
编辑,我看到你必须使用额外的,所以我不妨包括是和没有列,并让代码看起来更清洁
答案 2 :(得分:0)
对于那些仍在寻找更好方法的人:
from django.db.models import Q
from django.db.models.functions import TruncMonth
Questionnaire.object.annotate(month=TruncMonth('register'))values(month).annotate(
satisfaction_true=Count('id',filter=Q(satisfaction=True),satisfaction_false=Count('id',filter=Q(satisfaction=False))