Django. Правильный способ получения и передачи сложных данных в шаблон

Моя проблема заключается в том, что мне нужно вывести данные из моделей Report и Plan в эту таблицу в шаблоне введите описание изображения здесь Это календарь, который выводит данные из Отчетов и Планов в правильные ячейки по их .дате (строки) и .машине (столбцы).

То, как я это делаю... отстой. Время загрузки безумное из-за количества запросов по daterange в get_shifts_tables() и код нечитабельный. Но я не могу придумать альтернативу.

Вот он.

views.py

@login_required(login_url="login_user")
@allowed_user_roles(["ADMIN", "MODERATOR"])
def stats(request):
    leftovers = get_leftovers()

    orders = Order.objects.all().order_by("-id")
    order_entries_leftovers = {}
    for order_entry in OrderEntry.objects.all():
        order_entries_leftovers[order_entry.id] = order_entry.quantity
        for report_entry in ReportEntry.objects.filter(report__order=order_entry.order):
            order_entries_leftovers[order_entry.id] -= report_entry.quantity

    current_date = Table.objects.all()[0].current_date
    today = now()
    today = today - datetime.timedelta(days=6)
    today = today.replace(hour=current_date.hour % 12, minute=current_date.minute,
                          second=current_date.second, microsecond=current_date.microsecond)
    Table.objects.all().update(current_date=today)
    active_step_pk, machines, table = get_shifts_table()
    context = {
        "orders": orders,
        "leftovers": leftovers,
        "order_entries_leftovers": order_entries_leftovers,
        "steps": Step.objects.all(),
        "active_step_pk": active_step_pk,
        "machines": machines,
        "table": table
    }
    return render(request, "core/stats.html", context)

get_shifts_table() - из scripts.py

def get_shifts_table(
        shifts_count=28):
    from_date = Table.objects.all()[0].current_date
    step = Table.objects.all()[0].current_step
    table = []
    timestamps = [
        from_date + datetime.timedelta(
            hours=12 * i) for i in range(0, shifts_count)]
    machines = Machine.objects.filter(step=step)
    for i in range(len(timestamps) - 1):
        row_report_entries = ReportEntry.objects.filter(
            report__date__range=(timestamps[i], timestamps[i + 1]),
            report__step=step)
        if timestamps[i].hour < 12:
            txt = str(timestamps[i].strftime("%d.%m")) + " день"
            txt = str(timestamps[i].strftime("%d.%m"))
            cls = "day"
        else:
            txt = str(timestamps[i].strftime("%d.%m")) + " ночь"
            txt = str(timestamps[i].strftime("%d.%m"))
            cls = "night"
        row = [{
            "class": cls,
            "text": txt
        }]
        for machine in machines:
            report_entries = row_report_entries.filter(machine=machine)
            if report_entries:
                cell = {"class": "done", "report_entries": []}
                for report_entry in report_entries:
                    d = {
                        "pk": report_entry.pk,
                        "detail": report_entry.detail,
                        "quantity": report_entry.quantity,
                    }
                    cell["report_entries"].append(d)
                row.append(cell)
            else:
                plan, created = Plan.objects.get_or_create(
                    machine=machine,
                    date=timestamps[i],
                    step=step,
                )
                cell = {
                    "class": "plan",
                    "plan": plan,
                }
                row.append(cell)
        table.append(row)
    return step.pk, machines, table

Шаблон таблицы partial

    <tbody>
    {% for row in table %}
      <tr>
        {% for cell in row %}
          {% if cell.text %}
            <td class="{{ cell.class }}">
              <div>
                {{ cell.text }}
                <br/>
                {% if cell.class == 'day' %}
                  <i class="bi bi-sun-fill"></i>
                {% else %}
                  <i class="bi bi-moon-stars-fill"></i>
                {% endif %}
              </div>
            </td>
          {% elif cell.plan %}
            <td class="{{ cell.class }}"
                hx-trigger="click"
                hx-get='{% url 'plan_modal' %}'
                hx-target="#modals-here"
                hx-vals='{"pk": {{ cell.plan.pk }}}'
                data-bs-toggle="modal"
                data-bs-target="#modals-here">
              {% for plan_entry in cell.plan.planentry_set.all %}
                <div class={{ plan_entry.detail|get_detail_class }}>
                  <div class="detail-name">
                    {{ plan_entry.detail }}
                  </div>
                  <div class="quantity">
                    {{ plan_entry.quantity }}
                  </div>
                </div>
              {% endfor %}
            </td>
          {% else %}
            <td class="{{ cell.class }}">
              {% for report_entry in cell.report_entries %}
                <div class="{{ report_entry.detail|get_detail_class }}"
                     hx-trigger="click"
                     hx-get='{% url 'report_modal' %}'
                     hx-target="#modals-here"
                     hx-vals='{"pk": {{ report_entry.pk }}}'
                     data-bs-toggle="modal"
                     data-bs-target="#modals-here">
                  {{ report_entry.report }}
                  <div class="detail-name">
                    {{ report_entry.detail }}
                  </div>
                  <div class="quantity">
                    {{ report_entry.quantity }}
                  </div>
                </div>
              {% endfor %}
            </td>
          {% endif %}
        {% endfor %}
      </tr>
    {% endfor %}
    </tbody>

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

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

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