Есть ли способ запросить демографический источник по дням рождения? - PullRequest
0 голосов
/ 28 сентября 2019

Я пытаюсь создать демографические данные.Я сделал все отдельные запросы, потому что не мог придумать, как сделать их сразу.

from django.utils import timezone
from dateutil.relativedelta import relativedelta # $ pip install python-dateutil

teenagers_count = queryset.filter(birthday__lte=now-relativedelta(years=10), birthday__gt=now-relativedelta(years=20)).count()
twenties_count = queryset.filter(birthday__lte=now-relativedelta(years=20), birthday__gt=now-relativedelta(years=30)).count()
thirties_count = queryset.filter(birthday__lte=now-relativedelta(years=30), birthday__gt=now-relativedelta(years=40)).count()
forties_count = queryset.filter(birthday__lte=now-relativedelta(years=40), birthday__gt=now-relativedelta(years=50)).count()
fifties_and_older_count = queryset.filter(birthday__lte=now-relativedelta(years=50)).count()

Есть ли способ сделать это одним запросом?

1 Ответ

1 голос
/ 28 сентября 2019

Во-первых, укажите свой возраст для набора запросов с помощью:

age = ExpressionWrapper(datetime.now() - F('created_at'), output_field=fields.DurationField())
queryset.annotate(age=age) #=> Will add "age" on each records

Во-вторых, используйте Case / When, чтобы создать собственную логику в поле age_range

queryset.annotate(age=age).annotate(
            age_range=Case(
                When(age__gte=datetime.timedelta(years=10), age__lt=datetime.timedelta(years=20), then=Value('teens')),
                When(age__gte=datetime.timedelta(years=20), age__lt=datetime.timedelta(years=30), then=Value('twenties')),
                When(age__gte=datetime.timedelta(years=30), age__lt=datetime.timedelta(years=40), then=Value('thirties')),
                When(age__gte=datetime.timedelta(years=40), age__lt=datetime.timedelta(years=50), then=Value('fourties')),
                When(age__gte=datetime.timedelta(years=50), then=Value('fifties')),
                default=Value('Unknow'),
                output_field=fields.CharField(),
        )) #=> This will add "age_range" field on your queryset

Третье, просто агрегировать по "age_range".Все вместе:

import datetime 
from django.db.models import Case, When, Value, F, Count, ExpressionWrapper, fields

age = ExpressionWrapper(datetime.now() - F('created_at'), output_field=fields.DurationField())
counts = queryset.annotate(age=age).annotate(
            age_range=Case(
                When(age__gte=datetime.timedelta(years=10), age__lt=datetime.timedelta(years=20), then=Value('teens')),
                When(age__gte=datetime.timedelta(years=20), age__lt=datetime.timedelta(years=30), then=Value('twenties')),
                When(age__gte=datetime.timedelta(years=30), age__lt=datetime.timedelta(years=40), then=Value('thirties')),
                When(age__gte=datetime.timedelta(years=40), age__lt=datetime.timedelta(years=50), then=Value('fourties')),
                When(age__gte=datetime.timedelta(years=50), then=Value('fifties')),
                default=Value('Unknow'),
                output_field=fields.CharField(),
        )).order_by('age_range').values('age_range').annotate(count=Count('age_range'))
...