为什么输出不同?

时间:2020-03-31 10:29:58

标签: python django

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 :(得分:0)

与普遍的看法相反,qs.first() 等同于qs[0]qs.first()将在没有排序的情况下按主键排序,如documentation on .first()中所述:

返回与查询集匹配的第一个对象;如果存在,则返回None 没有匹配的对象。如果QuerySet没有未定义顺序, 然后查询集通过主键自动排序。 如Interaction with default ordering or order_by()中所述,这可以影响聚合结果

如果您通过主键订购,它将因此还原GROUP BY。您可以自己加入.order_by来解决此问题:

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

您还可以在year=TruncYear('created')部分中添加.values(..),并且无需再次在.values(..)中包含注释。这使查询更具可读性。