mirror of
https://github.com/Crocmagnon/checkout.git
synced 2024-11-24 17:18:03 +01:00
Implement caching
This commit is contained in:
parent
3bf5ce3033
commit
3899e2a3db
10 changed files with 111 additions and 4 deletions
14
poetry.lock
generated
14
poetry.lock
generated
|
@ -353,6 +353,17 @@ python-versions = ">=3.7"
|
|||
[package.dependencies]
|
||||
Django = ">=3.2"
|
||||
|
||||
[[package]]
|
||||
name = "django-solo"
|
||||
version = "2.0.0"
|
||||
description = "Django Solo helps working with singletons"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[package.dependencies]
|
||||
django = ">=2.2"
|
||||
|
||||
[[package]]
|
||||
name = "factory-boy"
|
||||
version = "3.2.1"
|
||||
|
@ -1164,7 +1175,7 @@ h11 = ">=0.9.0,<1"
|
|||
[metadata]
|
||||
lock-version = "1.1"
|
||||
python-versions = "^3.10"
|
||||
content-hash = "e0332f1446a90fc3a5dc2fa2ca5d1745eb0d90d8f033094d79b2df9376b79639"
|
||||
content-hash = "517db1c26bc459a29fdeae5f5ea18620c54121f95110d641b740ffdc322fb584"
|
||||
|
||||
[metadata.files]
|
||||
ansicon = []
|
||||
|
@ -1288,6 +1299,7 @@ django-environ = [
|
|||
]
|
||||
django-extensions = []
|
||||
django-htmx = []
|
||||
django-solo = []
|
||||
factory-boy = []
|
||||
faker = []
|
||||
filelock = []
|
||||
|
|
|
@ -22,6 +22,7 @@ crispy-bootstrap5 = "^0.6"
|
|||
matplotlib = "^3.5.1"
|
||||
freezegun = "^1.2.1"
|
||||
django-htmx = "^1.12.2"
|
||||
django-solo = "^2.0.0"
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
pre-commit = "^2.7"
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
from django.contrib import admin
|
||||
from django.contrib.admin import register
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from solo.admin import SingletonModelAdmin
|
||||
|
||||
from purchase.models import Basket, BasketItem, PaymentMethod, Product
|
||||
from purchase.models import Basket, BasketItem, CacheEtag, PaymentMethod, Product
|
||||
from purchase.templatetags.purchase import currency
|
||||
|
||||
|
||||
|
@ -70,3 +71,6 @@ class BasketAdmin(admin.ModelAdmin):
|
|||
@admin.display(description=_("price"))
|
||||
def price(self, instance) -> str:
|
||||
return currency(instance.price)
|
||||
|
||||
|
||||
admin.site.register(CacheEtag, SingletonModelAdmin)
|
||||
|
|
|
@ -1,6 +1,17 @@
|
|||
from django.apps import AppConfig
|
||||
from django.db.models.signals import post_save
|
||||
|
||||
|
||||
class PurchaseConfig(AppConfig):
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "purchase"
|
||||
|
||||
def ready(self):
|
||||
from purchase.models import Basket, BasketItem, PaymentMethod, Product
|
||||
|
||||
from .signals import basket_item_on_save
|
||||
|
||||
post_save.connect(basket_item_on_save, sender=BasketItem)
|
||||
post_save.connect(basket_item_on_save, sender=Basket)
|
||||
post_save.connect(basket_item_on_save, sender=Product)
|
||||
post_save.connect(basket_item_on_save, sender=PaymentMethod)
|
||||
|
|
33
src/purchase/migrations/0009_basketitemetag.py
Normal file
33
src/purchase/migrations/0009_basketitemetag.py
Normal file
|
@ -0,0 +1,33 @@
|
|||
# Generated by Django 4.1.1 on 2022-09-25 19:00
|
||||
|
||||
import uuid
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("purchase", "0008_basketitem_unique_product_per_basket"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="BasketItemEtag",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("value", models.UUIDField(default=uuid.uuid4)),
|
||||
],
|
||||
options={
|
||||
"abstract": False,
|
||||
},
|
||||
),
|
||||
]
|
|
@ -0,0 +1,17 @@
|
|||
# Generated by Django 4.1.1 on 2022-09-25 19:08
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("purchase", "0009_basketitemetag"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameModel(
|
||||
old_name="BasketItemEtag",
|
||||
new_name="CacheEtag",
|
||||
),
|
||||
]
|
|
@ -1,6 +1,7 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import uuid
|
||||
|
||||
from django.db import models
|
||||
from django.db.models import Avg, Count, F, Sum, UniqueConstraint
|
||||
|
@ -9,6 +10,7 @@ from django.urls import reverse
|
|||
from django.utils.translation import gettext
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from PIL import Image, ImageOps
|
||||
from solo.models import SingletonModel
|
||||
|
||||
|
||||
class Model(models.Model):
|
||||
|
@ -220,3 +222,14 @@ class BasketItem(Model):
|
|||
constraints = [
|
||||
UniqueConstraint("product", "basket", name="unique_product_per_basket")
|
||||
]
|
||||
|
||||
|
||||
class CacheEtag(SingletonModel):
|
||||
value = models.UUIDField(default=uuid.uuid4)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return str(self.value)
|
||||
|
||||
def refresh(self):
|
||||
self.value = uuid.uuid4()
|
||||
self.save()
|
||||
|
|
4
src/purchase/signals.py
Normal file
4
src/purchase/signals.py
Normal file
|
@ -0,0 +1,4 @@
|
|||
def basket_item_on_save(sender, **kwargs):
|
||||
from purchase.models import CacheEtag
|
||||
|
||||
CacheEtag.get_solo().refresh()
|
|
@ -5,14 +5,16 @@ from django.shortcuts import get_object_or_404, redirect
|
|||
from django.template.response import TemplateResponse
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.views.decorators.http import require_http_methods
|
||||
from django.views.decorators.http import condition, require_http_methods
|
||||
|
||||
from purchase.forms import BasketForm
|
||||
from purchase.models import Basket
|
||||
from purchase.views.reports import reports_etag
|
||||
|
||||
|
||||
@require_http_methods(["GET", "POST"])
|
||||
@permission_required("purchase.add_basket")
|
||||
@condition(etag_func=reports_etag)
|
||||
def new_basket(request: HttpRequest) -> HttpResponse:
|
||||
if request.method == "POST":
|
||||
form = BasketForm(request.POST)
|
||||
|
@ -32,6 +34,7 @@ def new_basket(request: HttpRequest) -> HttpResponse:
|
|||
|
||||
@require_http_methods(["GET", "POST"])
|
||||
@permission_required("purchase.change_basket")
|
||||
@condition(etag_func=reports_etag)
|
||||
def update_basket(request: HttpRequest, pk: int) -> HttpResponse:
|
||||
basket = get_object_or_404(Basket.objects.priced(), pk=pk)
|
||||
if request.method == "POST":
|
||||
|
@ -49,6 +52,7 @@ def update_basket(request: HttpRequest, pk: int) -> HttpResponse:
|
|||
|
||||
|
||||
@permission_required("purchase.view_basket")
|
||||
@condition(etag_func=reports_etag)
|
||||
def list_baskets(request: HttpRequest) -> HttpResponse:
|
||||
context = {"baskets": Basket.objects.priced().order_by("-id")}
|
||||
return TemplateResponse(request, "purchase/basket_list.html", context)
|
||||
|
|
|
@ -10,6 +10,7 @@ from django.contrib.auth.decorators import permission_required
|
|||
from django.shortcuts import render
|
||||
from django.template.response import TemplateResponse
|
||||
from django.utils.translation import gettext as _
|
||||
from django.views.decorators.http import condition
|
||||
from matplotlib import pyplot as plt
|
||||
from matplotlib import ticker
|
||||
from matplotlib.axes import Axes
|
||||
|
@ -17,12 +18,17 @@ from matplotlib.container import BarContainer
|
|||
from matplotlib.dates import AutoDateLocator, ConciseDateFormatter, HourLocator
|
||||
from matplotlib.figure import Figure
|
||||
|
||||
from purchase.models import Basket, PaymentMethod, Product, ProductQuerySet
|
||||
from purchase.models import Basket, CacheEtag, PaymentMethod, Product, ProductQuerySet
|
||||
|
||||
matplotlib.use("SVG")
|
||||
|
||||
|
||||
def reports_etag(request):
|
||||
return str(CacheEtag.get_solo().value)
|
||||
|
||||
|
||||
@permission_required("purchase.view_basket")
|
||||
@condition(etag_func=reports_etag)
|
||||
def products_plots_view(request):
|
||||
products = Product.objects.with_turnover().with_sold()
|
||||
(
|
||||
|
@ -37,6 +43,7 @@ def products_plots_view(request):
|
|||
|
||||
|
||||
@permission_required("purchase.view_basket")
|
||||
@condition(etag_func=reports_etag)
|
||||
def by_hour_plot_view(request):
|
||||
baskets = list(Basket.objects.priced().order_by("created_at"))
|
||||
context = {
|
||||
|
@ -46,6 +53,7 @@ def by_hour_plot_view(request):
|
|||
|
||||
|
||||
@permission_required("purchase.view_basket")
|
||||
@condition(etag_func=reports_etag)
|
||||
def reports(request):
|
||||
template_name = "purchase/reports.html"
|
||||
baskets = list(Basket.objects.priced().order_by("created_at"))
|
||||
|
|
Loading…
Reference in a new issue