Почему этот вывод отличается? - PullRequest
1 голос
/ 31 марта 2020
from django.shortcuts import render
from django.contrib.auth.decorators import login_required
from django.utils import timezone
from django.db.models import Sum, Count, Max, When, Case, Value, IntegerField
from django.db.models.functions import TruncDay, TruncMonth, TruncYear
import datetime

from .models import Profile, Team

@login_required
def profile(request):
    today = timezone.now()
    user_profile = Profile.objects.filter(user=request.user).first()

    expenses = user_profile.expense_set.annotate(
        field = Case(
            When(created__year=today.year, then=1),
            When(created__month=today.month, then=2),
            When(created__day=today.day, then=3),
            default=0,
            output_field=IntegerField()
        )
    )

    curent_month_expenses = expenses.filter(created__month=today.month)

    expenses_per_day = expenses.annotate(
        day=TruncDay('created')).values('day').annotate(
            expenses=Count('id'), summary=Sum('amount')
        ).values('day', 'expenses', 'summary')

    expenses_per_month = expenses.annotate(
        month=TruncMonth('created')).values('month').annotate(
            expenses=Count('id'), summary=Sum('amount')
        ).values('month', 'expenses', 'summary')

    expenses_per_year = expenses.annotate(
        year=TruncYear('created')).values('year').annotate(
            expenses=Count('id'), summary=Sum('amount')
        ).values('year', 'expenses', 'summary')

    print(expenses_per_year[0])

    print(expenses_per_year.first())

    context = {
        'profile': user_profile,
        'curent_month_expenses': curent_month_expenses,
        'yearly_expenses': expenses_per_year,
        'dayly_expenses': expenses_per_day,
        'monthly_expenses': expenses_per_month,
    }

    return render(request, 'accounts/profile.html', context)

Почему вывод отличается в операторах печати? Выходы:

{'year': datetime.datetime(2020, 1, 1, 0, 0, tzinfo=<UTC>), 'expenses': 6, 'summary': 128400}
{'year': datetime.datetime(2020, 1, 1, 0, 0, tzinfo=<UTC>), 'expenses': 1, 'summary': 1000}

1 Ответ

0 голосов
/ 31 марта 2020

Вопреки распространенному мнению, qs.first() равно , а не эквивалентно qs[0]. qs.first() будет, если нет порядка, упорядочить по первичному ключу, как описано в документации на .first():

Возвращает первый объект, соответствующий запросу, или None, если нет соответствующего объекта. Если QuerySet имеет , порядок не определен , тогда набор запросов автоматически упорядочивается первичным ключом . Это может повлиять на результаты агрегирования , как описано в Взаимодействие с упорядочением по умолчанию или order_by().

Если вы упорядочите по первичному ключу, он, таким образом, вернет GROUP BY. Вы можете решить эту проблему, включив .order_by самостоятельно:

expenses_per_year = expenses.values(
    year=TruncYear('created')
).annotate(
    expenses=Count('id'), summary=Sum('amount')
)<b>.order_by('year')</b>

Более того, вы уже можете добавить year=TruncYear('created') в часть .values(..), и вам не нужно снова включать аннотации в .values(..) , Это делает запрос более читабельным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...