Фильтр Django путем перебора каждого дня диапазона дат

У меня есть модель Orders, которая предназначена для веб-приложения электронной коммерции, и я хотел бы узнать, сколько заказов было сделано за каждый день в прошлом году. Поэтому я отфильтровал заказы следующим образом:

    product_orders = Order.objects.filter(
        ordered=True, variant__product=self, date__range=[(timezone.now() - timedelta(weeks=52)), timezone.now()])

Я бы хотел просмотреть каждый день из этого временного диапазона и получить количество заказов за каждый день, результат должен выглядеть примерно так:

[
    {
        date: "2021-06-21",
        quantity: 6
    },
    {
        date: "2021-06-22",
        quantity: 0
    }
]

где количество составляет Order.objects.filter(...).count()

Вы можете аннотировать свой Order числом Order с:

from django.utils.timezone import now
from django.db.models import Count
from django.db.models.functions import TruncDate

now_ = now()

product_orders = Order.objects.filter(
    ordered=True,
    variant__product=self,
    created_at__range=(now_-timedelta(weeks=52)), now_())
).values(
    date=TruncDate('created_at__date')
).annotate(
    quantity=Count('pk')
).order_by('date')

Это вернет QuerySet со словарями в качестве элементов, таким образом, они выглядят как:

<QuerySet [
    {'date': date(2021, 6, 21), 'quantity': 6 },
    {'date': date(2021, 6, 23), 'quantity': 3 }
]>

Если на определенную дату нет заказов, то эта дата не будет включена в вывод. Таким образом, нам придется выполнить постобработку данных.

Мы можем сделать это, сначала работая со словарем, который отображает даты на количества, мы можем сделать это с помощью:

temp = { po['date'].date(): po['quantity'] for po in product_orders }

и затем установите значение по умолчанию 0 для date и добавьте их в список result:

result = [
    {'date': (now_-timedelta(days=dy)).date(), 'quantity': temp.setdefault((now_-timedelta(days=dy)).date(), 0)}
    for dy in range(52*7+1)
]

then result содержит список словарей с date и quantity.

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

product_orders = Order.objects.filter(
            ordered=True,
            variant__product=self,
            ordered_date__range=(timezone.now()-timedelta(weeks=52), timezone.now()))

        result = []
        # looping through to get each day from now to a year ago
        for day in range(52*7+2):
            date = (timezone.now()-timedelta(days=day)).date().isoformat()
            result.append({
                "day": date,
                "quantity": product_orders.filter(ordered_date__date=date).count()
            })

это решение дало мне точные результаты, если у вас есть более эффективный способ, я открыт для него. BTW Я изменил created_at на ordered_date

БОЛЕЕ ЭФФЕКТИВНОЕ РЕШЕНИЕ

        now_ = timezone.now
        product_orders = Order.objects.filter(
            ordered=True,
            variant__product=self,
            ordered_date__range=((now_()-timedelta(weeks=52)), now_())
        ).annotate(date=functions.TruncDay("ordered_date")).values("date").annotate(quantity=Count("id")).values("date", "quantity").order_by('date')
        temp = {po['date'].date(): po['quantity'] for po in product_orders}
        result = [
            {'date': (now_()-timedelta(days=dy)).date(),
             'quantity': temp.setdefault((now_()-timedelta(days=dy)).date(), 0)}
            for dy in range(52*7+1)
        ]
Вернуться на верх