DjangoVue: mi full-stack favorito para desarrollo web

- Andrés Cruz

Cuando se desarrolla una aplicación web, hay algunos pilares que no se pueden cambiar y que indican "Estamos haciendo las cosas bien". Si usas React, Angular o Vue como interfaz para la aplicación web es una de esas balizas.

Al trabajar con big data, mi aplicación web siempre se crea con Django, por delante y por detrás. Me refiero a datos que se muestran en una página web, formularios para almacenar más datos o recuperar más datos según las necesidades del usuario.

No busco una fachada elegante ni una característica muy complicada digna de ser nominada como el sitio del día en Awwwards. Sin embargo, para mí, eso es en lo que React, Angular o Vue son muy buenos.

Sin embargo, hay una especificidad que hace que todos en el campo de big data utilicen esos marcos de JavaScript: los componentes HTML reactivos. Y parece excesivo utilizar un marco completo sólo para lograr una tarea tan simple.

Después de algunas experimentaciones y ajustes, finalmente encontré una alternativa. No involucra NodeJS, pero es elegante, simple y sensato.

DESCARGO DE RESPONSABILIDAD: Este artículo no es un tutorial paso a paso. Haré hincapié sólo en los archivos que son importantes para mi integración personalizada del marco Vue dentro del marco Django.

Suena genial ! Pero ¿qué es un componente HTML reactivo?

Para explicar qué es un componente HTML reactivo, describiré cómo funciona tradicionalmente un sitio web. Antes de que existiera el "sitio web de una página", los describiré más adelante.

Probablemente ya haya leído o visto un esquema que describe cómo un cliente (su computadora) y un servidor (“la aplicación web”) se comunican a través de solicitudes y respuestas: solicitudes enviadas por el cliente, esperando una respuesta del servidor.

Pero nunca he visto un esquema lo suficientemente bueno para explicar y hacer comprensible lo que implica una solicitud enviada desde un componente HTML no reactivo a un servidor. 

Estamos lanzando la aplicación web

Cuando se abre una aplicación web por primera vez, el cliente envía una solicitud al servidor. Solicita todas las funciones disponibles en una página web (o punto final) determinada. Las características pueden ser imágenes, textos, formularios, etc.

Una vez enviada la solicitud (resaltada en rojo), el servidor inicia los servicios para recopilar lo que se necesita (en azul). En este caso, todo desde que lanzamos la página web por primera vez.

Para ser más concreto, la solicitud pedía al servidor que recuperara datos para las funciones 1, 2 y 3. Para hacerlo, el servidor llamó a los servicios necesarios (aquí llamados api call 1, 2 y 3) para obtener algunos datos de la base de datos. Luego se ejecutan algunas consultas para recuperar datos de la base de datos; puede llevar un tiempo. Una vez que se recuperan los datos, los servicios pueden procesarlos (validación de datos, cambio de zona horaria de fechas, mensajes de éxito o error, etc.).

Lo que debe comprender aquí es que enviar una respuesta requiere “mucho” trabajo. Como es la primera vez que lanzamos el sitio web, no podemos evitar hacerlo.

No me malinterpretes, el “mucho” trabajo no disminuye el rendimiento del sitio web. Estamos en la escala de milisegundos. Sin embargo, hay varias llamadas a la API y se envían varias consultas a la base de datos. Cuantos menos, mejor tarifa.

Comportamiento sin componente HTML reactivo
El sitio web no tiene ningún componente HTML reactivo y el usuario está a punto de recargar la primera función. Es un formulario que envía datos para almacenarlos en la base de datos. Preste atención a la interacción entre el frente y la espalda.

Desde la perspectiva del cliente, solo la característica 1 ha cambiado. Pero con HTML no reactivo, el servidor se comporta como si el cliente solicitara cargar toda la página nuevamente, incluidas todas sus funciones.

En lugar de tener 1 llamada a la API, 1 consulta de base de datos y 1 función recargada, hay 3 llamadas a la API, 3 consultas de base de datos y 3 funciones recargadas. Esto está "bien", funcionó así durante años. Pero espero que sientas que algo anda mal y que hay margen de mejora.

Comportamiento con componente HTML reactivo

Para evitar este comportamiento, en el caso de una aplicación web, podemos dejar que JavaScript maneje casi exclusivamente el HTML: maneja el envío de la solicitud, la respuesta enviada por el servidor y la visualización del HTML. Si has jugado un poco con JavaScript básico, es un trabajo tedioso.

Es por eso que la gente diseñó marcos para organizar y mejorar la mantenibilidad del código. Lo que dio origen a componentes reactivos. Esta es la razón por la que los marcos de JavaScript son tan populares para manejar la interfaz de aplicaciones web.

Bien, entonces, ¿cómo reproducir componentes HTML reactivos sin esos marcos?
Respuesta: utilice únicamente las piezas correctas que necesite de esos marcos.

Vue se usa solo para crear componentes HTML reactivos, el resto de la infraestructura (enrutador, controlador, arquitectura, backend, plantillas, etc.) lo maneja Django.

Para demostrar mi punto, crearé una aplicación de libro de registro muy simple. Un usuario puede ingresar una entrada en el libro de registro, que se mostrará en la pantalla con un sello de fecha y hora.

En otras palabras, tendremos una característica que se espera que funcione como se muestra en el último esquema.

Hay archivos clave para la integración de DjangoVue: logbook.html, logbook.js, views.py y form.py.

Configure las partes de Django primero

Si no tienes idea de cómo empezar desde cero, no dudes en leer mi artículo sobre ese tema.

base.html

Para este archivo, tenga en cuenta que debe ajustar correctamente el alcance de sus archivos js estáticos: los archivos necesarios en todas partes deben llamarse desde base.html y los archivos necesarios desde el contenido que extiende base.html deben llamarse desde un bloque.

En este ejemplo, logbook.html utilizará {% block js %} para llamar a logbook.js.

El archivo utils.js contiene 2 funciones que ayudarán a crear la consulta con fetch() y enviar datos de adelante hacia atrás en logbook.js.

vue-3.2.47.js contiene toda la inteligencia del marco Vue necesaria para la tarea. No contiene todas las funciones de Vue, como el enlace de enrutador, realmente puede crear componentes en el "modo Vue" y está limitado a la opción API. Pero puedes mejorar la redacción de tu código javascript y explotar las plantillas de Vue junto con las plantillas de Django en las páginas HTML.

Aunque la función es simple, la plantilla html parece un poco complicada y extraña. Esto se debe a que Django y Vue están intrincados para crear este componente HTML reactivo. Descompongamos un poco.

Puede distinguir 2 partes: la parte donde se muestran las entradas del libro de registro y la parte donde las entradas se ingresan en un formulario.

Al principio, la plantilla de Django maneja entradas que ya están almacenadas en la base de datos. Una vez cargada la página, Django maneja la visualización de las entradas.

Para las entradas agregadas mientras el usuario está en la página, Vue las muestra. Unas breves palabras para aquellos que no están familiarizados con Vue:

v-for es la sintaxis del bucle for
@click es el detector de eventos de clic
:key es una forma que utiliza Vue para vincular el valor de un elemento html a una variable de JavaScript; llamémoslo así por ahora
Tanto para Django como para Vue, agregué getEntry, una función de JavaScript, o debería decir, un método de nuestra aplicación Vue de registro, para obtener la identificación de una entrada determinada para enviar esta identificación al backend y realizar operaciones CRUD. en eso.

Luego, tenemos el formulario “DjangoVue” donde:

@submit.prevent se utiliza para evitar el comportamiento predeterminado del formulario y reemplazarlo con el método de registro submitForm.
Dado que la ciberseguridad no es una opción, el envío de datos se realiza con el método POST junto con la etiqueta django csrk_token
Finalmente, las entradas de formulario definidas en form.py
forms.py

Nada muy complicado para las personas que tienen experiencia con Django, quienes se supone que son la audiencia principal de este artículo. Así que simplemente describiré este modelo v de atributo HTML de vue.

v-model permite que la “variable javascript” introducida anteriormente realice un seguimiento de lo que está escrito en la entrada del formulario. Sin él, nuestra solicitud POST estará vacía. Debe usarse junto con el otro atributo HTML: clave también presentado anteriormente.

libro de registro.js

Como puede ver, no ha cambiado mucho con respecto al viejo JavaScript vainilla. Solo respeté la sintaxis de la API de opción del marco Vue.

Tenga en cuenta que el libro de registro es un objeto. Con métodos, atributos y referencia a sí mismo (o debería decirlo... lo siento). Pero también puedes declarar y usar variables de JavaScript como csrftoken en la línea 10 o consulta en la línea 18 en la ilustración anterior.

Lo primero que hay que notar es que Django y Vue tienen por defecto el mismo delimitador para las plantillas: {% %}. Como es de esperar, surge un conflicto si no los distingues. Afortunadamente, Vue propone una manera de resolver el conflicto de una manera sencilla con el campo delimitadores; no lo llamo propiedad porque los objetos Vue también tienen propiedades en ese nivel.

Los datos son el lugar principal donde están las variables interactivas. Actúan como atributos del objeto del libro de registro y pueden manipularse a través de métodos, propiedades, cálculos, etc.
montado() es uno de los ganchos del ciclo de vida de Vue. Para este proyecto, he usado mount() como alcance donde declaro mis variables una vez que se carga el elemento HTML.
métodos es el lugar donde configuro mis funciones
mount() toma como parámetro un selector css para determinar el alcance del objeto Vue dentro de HTML

¿Por qué utilizar fetch() cuando todos los tutoriales que tratan del mismo tema utilizan axios?

Como puede observar, no utilicé axios para enviar mi solicitud POST al servidor. fetch() es muy adecuado para el trabajo y ya está integrado en ECMAscript. Además, no creo que haya una razón específica para elegir axios en lugar de buscar para la mayoría de las aplicaciones web.

Aquí hay una conferencia que encontré instructiva sobre axios y diferencias de búsqueda.

views.py

En esta parte, quiero describir lo que hace get_latest_entry de fetch().

Puede parecer extraño recuperar la última entrada del libro de registro escrita por el usuario desde la base de datos, cuando ya está en el lado del cliente. Pero tengo una muy buena razón.

La aplicación de mi libro de registro no solo muestra la entrada, sino también la fecha y hora. Y tengo que solucionar 2 restricciones:

Los campos de fecha y hora se almacenan en la zona horaria UTC en la base de datos. Es una buena práctica porque permite que la aplicación web alcance una escala internacional sin tener que lidiar con diferentes zonas horarias almacenadas en la base de datos.
El formato de fecha debe ser así: día/mes/año, horas:minutos:segundos; sí, la coma es parte del formato de fecha.
Para solucionar esas restricciones, hay 2 opciones:

del lado del cliente con javascript creando un objeto con la entrada y la marca de fecha y hora, en el formato correcto, luego insértelo en la plantilla entre las demás entradas del libro de registro. Por supuesto, antes de hacer todo eso, debemos asegurarnos de que la entrada esté almacenada en el servidor.
del lado del servidor con Python recuperando la entrada de la base de datos, ajustando la zona horaria y enviando la entrada en la respuesta de recuperación
¿Estamos considerando seriamente la segunda opción?

Saber que la reputación de JavaScript es una pesadilla a la hora de manejar fechas y horas y formatearlos, sí.

Hice un benchmark mínimo sobre esas opciones y… el resultado te sorprenderá. ¡Espero que a mí también me sorprenda a mí!

 

Artículo original:

https://wbarillon.medium.com/djangovue-my-favorite-full-stack-for-web-development-69c0f4198606

Andrés Cruz

Desarrollo con Laravel, Django, Flask, CodeIgniter, HTML5, CSS3, MySQL, JavaScript, Vue, Android, iOS, Flutter

Andrés Cruz en Udemy

Acepto recibir anuncios de interes sobre este Blog.