У меня есть следующая модель:
class Visit(models.Model):
...
device_id = models.CharField(...)
created_at = models.DateTimeField(auto_now_add=True)
...
Эта модель в основном обозначает посещение какого-либо места, device_id однозначно идентифицирует человека, и один и тот же человек может посещать это место несколько раз, следовательно, создавая несколько записей в этомТаблица.
Я строю аналитические методы поверх этой модели. Одна вещь, которую я хочу сделать, это показать за последние 30 дней количество людей, которые посетили только один раз в течение этого дня. Основываясь на базовом подходе, я могу выдавать запрос БД для каждого дня, например, так:
for date in dates:
start_time = date
end_time = date + datetime.timedelta(days=1)
Visitor.objects.filter(
site__in=node_descendants,
created_at__gte=start_date,
created_at__lt=end_date)
).values('device_id').annotate(visit_count=Count('device_id')).filter(visit_count=1).count()
Теперь я хочу вычислять данные для каждого дня в диапазоне 30 дней с помощью одного запроса, используя подзапрос, напримерthis:
single_visitor_query = Visitor.objects.filter(
created_at__date=OuterRef('truncated_date')
).order_by().values('device_id')
.annotate(visit_count=Count('device_id')).filter(visit_count=1)
.annotate(count=Count('*')).values('count')
chart_data_query = Visitor.objects.filter(
created_at__gte=start_date, # Start of month
created_at__lt=end_date, # End of month
).annotate(
truncated_date=TruncDay('created_at')
).values('truncated_date').distinct().annotate(
single_visitor_count=Subquery(single_visitor_query[:1], output_field=PositiveIntegerField()
)
У меня есть пара проблем с этим подходом:
- количество, полученное в результате подзапроса, не является числом всех элементов, имеющих visit_count = 1, но онивсе 1. Я знаю, что подзапрос несколько отключен, но я не могу понять, как исправить его, чтобы он возвращал счетчик для всех элементов, проходящих фильтр.
- Я бы хотел, чтобы подзапрос выполнялся для каждого truncated_date (30раз в этом случае), но кажется, что он работает для каждого экземпляра, который проходит начальный фильтр. Я проверил полученный SQL-запрос, и он не группируется по " truncated_date ". Любые идеи, почему это может иметь место?