From 393b39cacd8347b586dff7a8c864e31c6b664b71 Mon Sep 17 00:00:00 2001 From: Pablo Moreno Date: Fri, 31 Jul 2026 14:27:50 +0200 Subject: [PATCH] feat: websockets --- backoffice/consumers.py | 27 ++ backoffice/routing.py | 7 + .../products/_variant_form_fragment.html | 17 + backoffice/templates/backoffice/ws_demo.html | 24 + backoffice/tests/test_access.py | 14 + backoffice/tests/test_products.py | 27 ++ backoffice/urls/__init__.py | 2 + backoffice/views/products.py | 21 + backoffice/views/ws_demo.py | 11 + config/asgi.py | 17 +- config/settings/base.py | 12 + pyproject.toml | 4 + uv.lock | 445 +++++++++++++++++- 13 files changed, 626 insertions(+), 2 deletions(-) create mode 100644 backoffice/consumers.py create mode 100644 backoffice/routing.py create mode 100644 backoffice/templates/backoffice/ws_demo.html create mode 100644 backoffice/views/ws_demo.py diff --git a/backoffice/consumers.py b/backoffice/consumers.py new file mode 100644 index 0000000..f26b7c4 --- /dev/null +++ b/backoffice/consumers.py @@ -0,0 +1,27 @@ +import json + +from channels.generic.websocket import AsyncWebsocketConsumer +from django.utils.html import escape + + +class EchoConsumer(AsyncWebsocketConsumer): + """Consumer mínimo para verificar el cableado de Channels + htmx (ver + ws_demo.html). No representa ninguna funcionalidad real todavía.""" + + async def connect(self): + # Mismo criterio de acceso que BackofficeAccessMixin. + if not self.scope['user'].is_staff: + await self.close() + return + + await self.accept() + + async def receive(self, text_data): + try: + payload = json.loads(text_data) + except (TypeError, ValueError): + payload = {} + + message = escape(payload.get('message', '')) + + await self.send(text_data=f'

Eco: {message}

') diff --git a/backoffice/routing.py b/backoffice/routing.py new file mode 100644 index 0000000..a967fb2 --- /dev/null +++ b/backoffice/routing.py @@ -0,0 +1,7 @@ +from django.urls import re_path + +from backoffice.consumers import EchoConsumer + +websocket_urlpatterns = [ + re_path(r'^ws/backoffice/echo/$', EchoConsumer.as_asgi()), +] diff --git a/backoffice/templates/backoffice/products/_variant_form_fragment.html b/backoffice/templates/backoffice/products/_variant_form_fragment.html index 5aae9ed..341b4de 100644 --- a/backoffice/templates/backoffice/products/_variant_form_fragment.html +++ b/backoffice/templates/backoffice/products/_variant_form_fragment.html @@ -50,6 +50,23 @@ {{ form.attribute_values.errors }} + {% if price_form %} +
+

Precio inicial (opcional)

+
+
+ {{ price_form.price }} + {{ price_form.price.errors }} +
+
+ {{ price_form.tax }} + {{ price_form.tax.errors }} +
+
+ {{ price_form.non_field_errors }} +
+ {% endif %} + {{ form.non_field_errors }}