在 Django 查询集中按月份和性别分组

Group by Month and Gender in Django queryset

我有以下查询集,它适用于 按月分组

from django.db.models.functions import TruncMonth

queryset = UserProfile.objects.filter(date_created__year='2018')\
           .annotate(date=TruncMonth('date_created'))\
           .values('date').annotate(total_entries=Count('id'))

我想要的是也按 性别 进行分组,这是一个带有 gender 字段

的类似模型
class UserProfile:
    date_created = models.DateTime(auto_now_add=True)
    <b>gender = models.CharField(max_length=3,choices=[('F',"Female"),('M',"Male")],default='M')</b>

预期结果:

May: 5 users [4(Male), 1(Female)]
June: 20 users [15(Male), 5(Female)]

对于django < 2.0,您可以使用Conditional ExpressionsSum()来注释您想要的值:

from django.db.models import Sum, Case, When
from django.db.models.functions import TruncMonth

queryset = UserProfile.objects.filter(date_created__year='2018').annotate(
    date=TruncMonth('date_created'),
).values('date').annotate(
    total_entries=Count('id'),
    total_male=Sum(Case(When(gender='M', then=1), default=0, output_field=models.IntegerField())),
    total_female=Sum(Case(When(gender='F', then=1), default=0, output_field=models.IntegerField())),
)

因为 django 2.0 您可以使用 Conditional Aggregation:

from django.db.models import Count, Q
from django.db.models.functions import TruncMonth

queryset = UserProfile.objects.filter(date_created__year='2018').annotate(
        date=TruncMonth('date_created'),
    ).values('date').annotate(
        total_entries=Count('id'),
        total_male=Count('id', filter=Q(gender='M')),
        total_female=Count('id', filter=Q(gender='F')),
)