Подсчет уникальных значений и группировка по дате

У меня есть таблица следующего вида:

client_id action date (datetime)
1 visit 2024-10-10 10:00
1 visit 2024-10-10 12:00
1 visit 2024-10-10 13:00
2 visit 2024-10-10 13:00

Итак, мне нужно подсчитать количество уникальных клиентов с группировкой по дате. Результат должен выглядеть так {«date»: 2024-10-10, «count_visits»: 2}.

Я попробовал несколько вариантов с annotate(unique=True) и OuterRef, но сгруппировать по дате так и не получилось.

Вот решение, работающее с диктой по следующим рекомендациям Raymond Hettinger:

from collections import defaultdict

# get the first queryset:
temp_qs = MyModel.objects.filter(
    action="visits",
    date__gte=from_date,
    date__gte=to_date,
)

# get a dict with visits for each client:
visits_dict= defaultdict(list)
for temp_val in temp_qs:
visits_dict[temp_val.client].append(temp_val)

# count what you except:
count_dict = {client : defaultdict(int) for client in visits_dict}
count_dict=defaultdict(int)
for client,visits in visits_dict.items():
    count_dict[client][visits.date]+=1

# if you really want a dict as you wrote :
your_dict = dict()
for client, date in count_dict.items():
    your_dict[client]= {
        'date': date, 
        "count_visits": count_dict[client][date]
    }

Надеюсь, это поможет вам!

Для чистого ORM-решения вы должны быть в состоянии использовать это

from django.db.models import Count
from django.db.models.functions import TruncDate

YourTable.objects.annotate(pure_date=TruncDate('your_date_field_name')).values('pure_date').annotate(count_visits=Count('client_id', distinct=True))

Альтернатива решению @PTomasz для получения желаемого результата:

from django.db.models import Count, Value, CharField
from django.db.models.functions import Concat

YourModel.objects.values(
    timestamp=Concat(
        "date__year",
        Value("-"),
        "date__month",
        Value("-"),
        "date__day",
        output_field=CharField(),
    )
).annotate(count_visits=Count("client_id", distinct=True))
Вернуться на верх