Эффективный способ обработки данных для количества просмотров с датами

Я ищу более эффективный способ реализации представленного кода, который извлекает количество просмотров для объекта в диапазоне дат (start_date и end_date). Текущий код достигает ожидаемого результата, преобразуя данные в структуру словаря с names и соответствующими ежедневными представлениями count. Однако я считаю, что существует более оптимизированный подход.
Вот фрагмент кода для справки:
models.py

class Ad(models.Model):
    ad_type = models.ForeignKey(to=AdType, on_delete=models.CASCADE, related_name="ad")
    name = models.CharField(max_length=256)
    image = models.ImageField(upload_to="ads")
    is_active = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True)

class AdStat(models.Model):
    class StatType(models.TextChoices):
        VIEWS = "views", _("Views")
        CLICKS = "clicks", _("Clicks")

    ad = models.ForeignKey(to=Ad, on_delete=models.CASCADE, related_name="ad_stat")
    stat_type = models.CharField(max_length=10, choices=StatType.choices)
    created_at = models.DateTimeField(auto_now_add=True)

views.py

@staff_member_required
def ads_number_of_views(request):
    start_date = request.GET.get("start_date")
    end_date = request.GET.get("end_date")

    ads = (
        AdStat.objects.filter(ad__is_active=True, ad__ad_type__slug="desktop-hader")
        .select_related("ad")
        .values("ad__name", "created_at__date")
        .annotate(view_count=Count("id"))
        .order_by("created_at__date")
    )
    if start_date and end_date:
        ads = ads.filter(created_at__gte=start_date, created_at__lte=end_date)
    elif start_date:
        ads = ads.filter(created_at__gte=start_date)
    elif end_date:
        ads = ads.filter(created_at__lte=end_date)

    ads_data = []
    for item in ads:
        ad_name = item["ad__name"]
        date_str = str(item["created_at__date"])
        count = item["view_count"]
        found = False
        for entry in ads_data:
            if entry["name"] == ad_name:
                entry["number_of_views"].append({"created_at": date_str, "count": count})
                found = True
                break

        if not found:
            ads_data.append({"name": ad_name, "number_of_views": [{"created_at": date_str, "count": count}]})
    return JsonResponse(ads, safe=False)

Ожидаемый результат.
Код успешно возвращает ответ в формате JSON со следующей структурой:

[
  {
    "name": "ad1",
    "number_of_views": [
      {"created_at": "2024-03-28", "count": 18},
      {"created_at": "2024-03-30", "count": 47}
    ]
  },
  {
    "name": "ad2",
    "number_of_views": [
      {"created_at": "2024-03-30", "count": 24},
      {"created_at": "2024-03-31", "count": 33}
    ]
  }
]

Наряду с эффективностью, я хотел бы включить функцию фильтрации для Chart.js. В идеале, пользователь должен иметь возможность выбирать между просмотром данных по дням, месяцам и годам. Я готов рассмотреть альтернативные подходы с использованием ORM-возможностей Django или других оптимизаций.

Вернуться на верх