mirror of
https://github.com/Crocmagnon/checkout.git
synced 2024-11-22 08:08:04 +01:00
Load graphs asynchronously
This commit is contained in:
parent
68ba920882
commit
ae5860fc17
11 changed files with 66 additions and 20 deletions
14
poetry.lock
generated
14
poetry.lock
generated
|
@ -342,6 +342,17 @@ python-versions = ">=3.6"
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
Django = ">=3.2"
|
Django = ">=3.2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "django-htmx"
|
||||||
|
version = "1.12.2"
|
||||||
|
description = "Extensions for using Django with htmx."
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
Django = ">=3.2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "factory-boy"
|
name = "factory-boy"
|
||||||
version = "3.2.1"
|
version = "3.2.1"
|
||||||
|
@ -1153,7 +1164,7 @@ h11 = ">=0.9.0,<1"
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "1.1"
|
lock-version = "1.1"
|
||||||
python-versions = "^3.10"
|
python-versions = "^3.10"
|
||||||
content-hash = "e21ae8f93aefc631a43ccf43b79a3660ca11c6870677d60878b0adc88303953d"
|
content-hash = "e0332f1446a90fc3a5dc2fa2ca5d1745eb0d90d8f033094d79b2df9376b79639"
|
||||||
|
|
||||||
[metadata.files]
|
[metadata.files]
|
||||||
ansicon = []
|
ansicon = []
|
||||||
|
@ -1276,6 +1287,7 @@ django-environ = [
|
||||||
{file = "django_environ-0.9.0-py2.py3-none-any.whl", hash = "sha256:f21a5ef8cc603da1870bbf9a09b7e5577ab5f6da451b843dbcc721a7bca6b3d9"},
|
{file = "django_environ-0.9.0-py2.py3-none-any.whl", hash = "sha256:f21a5ef8cc603da1870bbf9a09b7e5577ab5f6da451b843dbcc721a7bca6b3d9"},
|
||||||
]
|
]
|
||||||
django-extensions = []
|
django-extensions = []
|
||||||
|
django-htmx = []
|
||||||
factory-boy = []
|
factory-boy = []
|
||||||
faker = []
|
faker = []
|
||||||
filelock = []
|
filelock = []
|
||||||
|
|
|
@ -21,6 +21,7 @@ django-crispy-forms = "^1.14.0"
|
||||||
crispy-bootstrap5 = "^0.6"
|
crispy-bootstrap5 = "^0.6"
|
||||||
matplotlib = "^3.5.1"
|
matplotlib = "^3.5.1"
|
||||||
freezegun = "^1.2.1"
|
freezegun = "^1.2.1"
|
||||||
|
django-htmx = "^1.12.2"
|
||||||
|
|
||||||
[tool.poetry.dev-dependencies]
|
[tool.poetry.dev-dependencies]
|
||||||
pre-commit = "^2.7"
|
pre-commit = "^2.7"
|
||||||
|
|
|
@ -89,6 +89,7 @@ INSTALLED_APPS = [
|
||||||
"crispy_forms",
|
"crispy_forms",
|
||||||
"crispy_bootstrap5",
|
"crispy_bootstrap5",
|
||||||
"django_extensions",
|
"django_extensions",
|
||||||
|
"django_htmx",
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
|
@ -102,6 +103,7 @@ MIDDLEWARE = [
|
||||||
"django.contrib.messages.middleware.MessageMiddleware",
|
"django.contrib.messages.middleware.MessageMiddleware",
|
||||||
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||||
"csp.middleware.CSPMiddleware",
|
"csp.middleware.CSPMiddleware",
|
||||||
|
"django_htmx.middleware.HtmxMiddleware",
|
||||||
]
|
]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
1
src/common/static/vendor/htmx-1.8.0/htmx.min.js
vendored
Normal file
1
src/common/static/vendor/htmx-1.8.0/htmx.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
@ -28,5 +28,7 @@
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
</div>
|
</div>
|
||||||
<script src="{% static "vendor/bootstrap-5.1.3-dist/js/bootstrap.bundle.min.js" %}"></script>
|
<script src="{% static "vendor/bootstrap-5.1.3-dist/js/bootstrap.bundle.min.js" %}"></script>
|
||||||
|
{% block extrascript %}
|
||||||
|
{% endblock %}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
BIN
src/purchase/static/purchase/spinner.gif
Normal file
BIN
src/purchase/static/purchase/spinner.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.4 KiB |
|
@ -1,7 +1,5 @@
|
||||||
{% extends "common/base.html" %}
|
{% extends "common/base.html" %}
|
||||||
{% load static %}
|
{% load static i18n purchase django_htmx %}
|
||||||
{% load i18n %}
|
|
||||||
{% load purchase %}
|
|
||||||
|
|
||||||
{% block extrahead %}
|
{% block extrahead %}
|
||||||
<link rel="stylesheet" href="{% static "purchase/css/reports.css" %}">
|
<link rel="stylesheet" href="{% static "purchase/css/reports.css" %}">
|
||||||
|
@ -29,18 +27,20 @@
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
{{ by_hour_plot|safe }}
|
{% include "purchase/snippets/htmx_plot.html" with url='purchase:by_hour_plot' %}
|
||||||
|
|
||||||
<h2>{% translate "Products" %}</h2>
|
<h2>{% translate "Products" %}</h2>
|
||||||
{% include "purchase/snippets/report_products.html" %}
|
{% include "purchase/snippets/report_products.html" %}
|
||||||
{{ products_plot|safe }}
|
{% include "purchase/snippets/htmx_plot.html" with url='purchase:products_plots' %}
|
||||||
{{ products_sold_pie|safe }}
|
|
||||||
{{ products_turnover_pie|safe }}
|
|
||||||
|
|
||||||
<h2>{% translate "Turnover by payment method" %}</h2>
|
<h2>{% translate "Turnover by payment method" %}</h2>
|
||||||
{% include "purchase/snippets/report_payment_methods.html" %}
|
{% include "purchase/snippets/report_payment_methods.html" %}
|
||||||
|
|
||||||
<h2>{% translate "Baskets without payment method" %}</h2>
|
<h2>{% translate "Baskets without payment method" %}</h2>
|
||||||
{% include "purchase/snippets/report_no_payment_method.html" %}
|
{% include "purchase/snippets/report_no_payment_method.html" %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block extrascript %}
|
||||||
|
<script src="{% static 'vendor/htmx-1.8.0/htmx.min.js' %}" defer></script>
|
||||||
|
{% django_htmx_script %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
7
src/purchase/templates/purchase/snippets/htmx_plot.html
Normal file
7
src/purchase/templates/purchase/snippets/htmx_plot.html
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{% load static %}
|
||||||
|
<div hx-get="{% url url %}"
|
||||||
|
hx-trigger="load"
|
||||||
|
hx-swap="outerHTML"
|
||||||
|
>
|
||||||
|
<img class="htmx-indicator" src="{% static 'purchase/spinner.gif' %}" alt="Spinner">
|
||||||
|
</div>
|
3
src/purchase/templates/purchase/snippets/plots.html
Normal file
3
src/purchase/templates/purchase/snippets/plots.html
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{% for plot in plots %}
|
||||||
|
{{ plot|safe }}
|
||||||
|
{% endfor %}
|
|
@ -1,7 +1,7 @@
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
|
|
||||||
from purchase.views import delete_basket, list_baskets, new_basket, update_basket
|
from purchase.views import delete_basket, list_baskets, new_basket, update_basket
|
||||||
from purchase.views.reports import reports
|
from purchase.views.reports import by_hour_plot_view, products_plots_view, reports
|
||||||
|
|
||||||
app_name = "purchase"
|
app_name = "purchase"
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
@ -10,4 +10,7 @@ urlpatterns = [
|
||||||
path("<int:pk>/update/", update_basket, name="update"),
|
path("<int:pk>/update/", update_basket, name="update"),
|
||||||
path("<int:pk>/delete/", delete_basket, name="delete"),
|
path("<int:pk>/delete/", delete_basket, name="delete"),
|
||||||
path("reports/", reports, name="reports"),
|
path("reports/", reports, name="reports"),
|
||||||
|
# plots
|
||||||
|
path("reports/products_plots/", products_plots_view, name="products_plots"),
|
||||||
|
path("reports/by_hour_plot/", by_hour_plot_view, name="by_hour_plot"),
|
||||||
]
|
]
|
||||||
|
|
|
@ -7,6 +7,7 @@ import numpy as np
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth.decorators import permission_required
|
from django.contrib.auth.decorators import permission_required
|
||||||
|
from django.shortcuts import render
|
||||||
from django.template.response import TemplateResponse
|
from django.template.response import TemplateResponse
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
from matplotlib import pyplot as plt
|
from matplotlib import pyplot as plt
|
||||||
|
@ -18,7 +19,30 @@ from matplotlib.figure import Figure
|
||||||
|
|
||||||
from purchase.models import Basket, PaymentMethod, Product, ProductQuerySet
|
from purchase.models import Basket, PaymentMethod, Product, ProductQuerySet
|
||||||
|
|
||||||
matplotlib.use("TkAgg")
|
matplotlib.use("Agg")
|
||||||
|
|
||||||
|
|
||||||
|
@permission_required("purchase.view_basket")
|
||||||
|
def products_plots_view(request):
|
||||||
|
products = Product.objects.with_turnover().with_sold()
|
||||||
|
(
|
||||||
|
products_plot,
|
||||||
|
products_sold_pie,
|
||||||
|
products_turnover_pie,
|
||||||
|
) = get_products_plots(products)
|
||||||
|
context = {
|
||||||
|
"plots": [products_plot, products_sold_pie, products_turnover_pie],
|
||||||
|
}
|
||||||
|
return render(request, "purchase/snippets/plots.html", context)
|
||||||
|
|
||||||
|
|
||||||
|
@permission_required("purchase.view_basket")
|
||||||
|
def by_hour_plot_view(request):
|
||||||
|
baskets = list(Basket.objects.priced().order_by("created_at"))
|
||||||
|
context = {
|
||||||
|
"plots": [by_hour_plot(baskets)],
|
||||||
|
}
|
||||||
|
return render(request, "purchase/snippets/plots.html", context)
|
||||||
|
|
||||||
|
|
||||||
@permission_required("purchase.view_basket")
|
@permission_required("purchase.view_basket")
|
||||||
|
@ -36,11 +60,6 @@ def reports(request):
|
||||||
turnover_by_day = {date: Basket.objects.by_date(date).turnover() for date in dates}
|
turnover_by_day = {date: Basket.objects.by_date(date).turnover() for date in dates}
|
||||||
|
|
||||||
products = Product.objects.with_turnover().with_sold()
|
products = Product.objects.with_turnover().with_sold()
|
||||||
(
|
|
||||||
products_plot,
|
|
||||||
products_sold_pie,
|
|
||||||
products_turnover_pie,
|
|
||||||
) = get_products_plots(products)
|
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
"turnover": Basket.objects.turnover(),
|
"turnover": Basket.objects.turnover(),
|
||||||
|
@ -48,10 +67,6 @@ def reports(request):
|
||||||
"average_basket": Basket.objects.average_basket(),
|
"average_basket": Basket.objects.average_basket(),
|
||||||
"average_basket_by_day": average_basket_by_day,
|
"average_basket_by_day": average_basket_by_day,
|
||||||
"products": products,
|
"products": products,
|
||||||
"products_plot": products_plot,
|
|
||||||
"products_sold_pie": products_sold_pie,
|
|
||||||
"products_turnover_pie": products_turnover_pie,
|
|
||||||
"by_hour_plot": by_hour_plot(baskets),
|
|
||||||
"payment_methods": PaymentMethod.objects.with_turnover().with_sold(),
|
"payment_methods": PaymentMethod.objects.with_turnover().with_sold(),
|
||||||
"no_payment_method": Basket.objects.no_payment_method().priced(),
|
"no_payment_method": Basket.objects.no_payment_method().priced(),
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue