Django ORM выбрать, согласовать, извлечь из данных и упорядочить по - PullRequest
0 голосов
/ 01 сентября 2018

У меня проблемы с выполнением простого преобразования с помощью 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)}]>

У меня такое ощущение, что я далеко от желаемого результата ..

Ответы [ 2 ]

0 голосов
/ 01 сентября 2018

Если вы хотите получить год или месяц, вы можете использовать ExtractYear [Django-doc] и ExtractMonth [ Джанго-док] соответственно. Усечение даст вам начало года или месяца.

Таким образом, мы можем переписать запрос на:

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
        ]

Здесь мы, таким образом, генерируем список из двух кортежей, где первый элемент - это некое число, которое мы используем для определения выбора (здесь я умножил год на 100, так что 201804 год - апрель 2018 года). Вторым элементом кортежа является строка, определяющая формат.

0 голосов
/ 01 сентября 2018

Если вы хотите список строк типа 2018-06, то что-то вроде этого должно работать:

[ '%i-%02i' % (x.Buchung.year, x.Buchung.month) for x in Transaktion.objects.order_by(-Buchung) ]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...