我在使用django orm执行简单转换时遇到麻烦。 所需的结果应如下所示:
2018-08
2018-07
2018-06
...
并使用此sql创建:
select
distinct
strftime('%Y',a."Buchung") || "-" ||
strftime('%m',a."Buchung") as YearMonth
from
hhdata_transaktion a
order by
1 desc
我需要ModelChoiceField作为查询集,所以我在这里绑定到ORM吗?
我的尝试
from django.db.models.functions import TruncMonth, TruncYear
Transaktion.objects
.annotate(year=TruncYear('Buchung'),
month=TruncMonth('Buchung'))
.distinct()
.order_by('-year', '-month')
.values('year','month')
返回:
<QuerySet [{'year': datetime.date(2018, 1, 1), 'month': datetime.date(2018, 8, 1)}, {'year': datetime.date(2018, 1, 1), 'month': datetime.date(2018, 7, 1)}, {'year': datetime.date(2018, 1, 1), 'month': datetime.date(2018, 6, 1)}, {'year': datetime.date(2018, 1, 1), 'month': datetime.date(2018, 5, 1)}, {'year': datetime.date(2018, 1, 1), 'month': datetime.date(2018, 4, 1)}, {'year': datetime.date(2018, 1, 1), 'month': datetime.date(2018, 3, 1)}, {'year': datetime.date(2018, 1, 1), 'month': datetime.date(2018, 2, 1)}, {'year': datetime.date(2018, 1, 1), 'month': datetime.date(2018, 1, 1)}, {'year': datetime.date(2017, 1, 1), 'month': datetime.date(2017, 12, 1)}, {'year': datetime.date(2017, 1, 1), 'month': datetime.date(2017, 11, 1)}, {'year': datetime.date(2017, 1, 1), 'month': datetime.date(2017, 10, 1)}, {'year': datetime.date(2017, 1, 1), 'month': datetime.date(2017, 9, 1)}, {'year': datetime.date(2017, 1, 1), 'month': datetime.date(2017, 8, 1)}]>
我感觉自己离预期的结果还很遥远。
答案 0 :(得分:1)
如果要获取年份或月份,可以分别使用ExtractYear
[Django-doc]和ExtractMonth
[Django-doc]。截断将为您提供年或月的开始。
因此我们可以将查询重写为:
from django.db.models.functions import ExtractMonth, ExtractYear
qs = Transaktion.objects.annotate(
year=ExtractYear('Buchung'),
month=ExtractMonth('Buchung')
).order_by('-year', '-month').values('year','month').distinct()
尽管可以在SQL级别进行处理,但我认为这会使工作更加复杂。例如,如果在SQL中连接数字,则可能需要做一些工作才能在几个月内(小于10)获得前导零。此外,该查询可能包含特定于“ SQL方言”的功能,从而使其便携性较低。
因此,我建议在Django / Python级别进行后期处理。例如:
from django.db.models.functions import ExtractMonth, ExtractYear
class MyForm(forms.Form):
my_choice_field = forms.ChoiceField()
# ...
def __init__(self, *args, **kwargs):
super(MyForm, self).__init__(*args, **kwargs)
qs = Transaktion.objects.annotate(
year=ExtractYear('Buchung'),
month=ExtractMonth('Buchung')
).order_by('-year', '-month').values('year','month').distinct()
self.fields['my_choice_field'].choices = [
(row['year']*100+row['month'], '{}-{:02d}'.format(row['year'], row['month'])
for row in qs
]
因此,我们在此处生成一个由2个元组组成的列表,其中第一个元素是用于标识选择的某种数字(我在这里将年份乘以100,因此201804是2018年4月)。元组的第二个元素是确定格式的字符串。
答案 1 :(得分:0)
如果您想要像2018-06
这样的字符串列表,类似的东西应该可以工作:
[ '%i-%02i' % (x.Buchung.year, x.Buchung.month) for x in Transaktion.objects.order_by(-Buchung) ]