Los 10 principales errores que cometen los desarrolladores de Django
Publicado: 2022-03-11En este tutorial, veremos algunos errores comunes que suelen cometer los desarrolladores de Django y las formas de evitarlos. Este tutorial es útil incluso si es un desarrollador experto de Django porque los errores, como mantener una configuración inmanejablemente grande o conflictos de nombres en activos estáticos, no se limitan a los nuevos desarrolladores que intentan Django por primera vez.
Django es un marco web de Python gratuito y de código abierto que resuelve de manera útil los desafíos de desarrollo comunes y le permite crear aplicaciones flexibles y bien estructuradas. Django tiene muchas características modernas listas para usar. Personalmente, para mí, el administrador, la herramienta de mapeo relacional de objetos (ORM), el enrutamiento y las funciones de plantillas hicieron de Django mi primera opción porque las aplicaciones requieren mucho trabajo y, aunque disfruto mi trabajo tanto como cualquier desarrollador, quiero pasar dedicar el menor tiempo posible a estas tareas básicas repetitivas. Django te permite hacer todo esto sin comprometer la flexibilidad.
La característica principal de Django es una poderosa interfaz de administración configurable que se construye automáticamente (¿automágicamente?) a partir del esquema de sus modelos y los modelos del panel de administración, lo que lo hace sentir como un mago. A través de la interfaz de administración, un usuario puede configurar muchas cosas, incluida la lista de control de acceso (ACL), permisos y acciones a nivel de fila, filtros, pedidos, widgets, formularios, ayudantes de URL adicionales y cualquier otra cosa que pueda imaginar. Creo que cada aplicación requiere un panel de administración; si aún no lo tiene, es simplemente cuestión de tiempo hasta que su aplicación básica lo necesite. Con el administrador de Django, puede crear uno de forma rápida y flexible.
Django tiene un poderoso ORM que funciona con todas las principales bases de datos listas para usar. Dado que es perezoso, accede a su base de datos solo cuando la necesita, a diferencia de otros ORM. Es compatible con todas las principales instrucciones (y funciones) de SQL que puede usar desde su código fuente de Python y se siente muy cómodo debido a las características de Python.
El motor de plantillas de Django es muy flexible y potente al mismo tiempo. Puede usar muchos filtros y etiquetas estándar, así como crear sus nuevos filtros y etiquetas personalizados para su proyecto. Django es compatible con otros motores de plantillas, así como con las plantillas de Django, y proporciona una API para facilitar la integración de otros motores de plantillas a través de funciones de acceso directo estándar para el procesamiento de plantillas.
Django tiene muchas otras características importantes, como un enrutador de URL que puede analizar las solicitudes entrantes y crear nuevas URL a partir de un esquema de enrutador. En general, el marco Django es una experiencia agradable y siempre que necesite ayuda, simplemente lea la documentación.
Error n.º 1: utilizar el entorno de Python del sistema global para las dependencias del proyecto
No utilice el entorno global de Python para las dependencias del proyecto, ya que puede producir conflictos de dependencia. Python no puede usar varias versiones de paquetes al mismo tiempo. Esto puede ser un problema si diferentes proyectos requieren diferentes versiones incompatibles del mismo paquete.
Este error generalmente lo cometen los nuevos desarrolladores de Python y Django que no conocen las características de aislamiento del entorno de Python.
Hay muchas formas de aislar su entorno, pero las formas más comunes son:
- virtualenv: un paquete de Python que genera una carpeta de entorno de Python y tiene secuencias de comandos para [des]activar el entorno y administrar los paquetes de Python instalados en el entorno. Este es mi método favorito porque es la forma más sencilla de hacer el trabajo. Por lo general, creo el entorno cerca de la carpeta del proyecto.
- virtualenvwrapper: un paquete de Python que se instala globalmente y proporciona un conjunto de herramientas para crear/eliminar/activar/etc. entornos virtuales. Todos los entornos virtuales se almacenan en una carpeta (que se puede anular mediante la variable de entorno WORKON_HOME). No veo ninguna ventaja en usar
virtualenvwrapper
en lugar devirtualenv
. - Máquinas virtuales (VM): No hay mayor aislamiento que una máquina virtual completa dedicada a su aplicación. Hay muchas herramientas para elegir, incluidas VirtualBox (gratis), VMware, Parallels y Proxmox (mi favorita personal, y tiene una versión gratuita). En combinación con una herramienta de automatización de VM como Vagrant, esta puede ser una solución extremadamente poderosa.
- Contenedores: en los últimos años, he estado usando Docker en casi todos los proyectos, especialmente en cada nuevo proyecto que empiezo desde cero. Docker es una herramienta increíble que proporciona muchas funciones y tiene muchas herramientas de terceros para la automatización de contenedores. Tiene una función de almacenamiento en caché de capas que hace que la reconstrucción de sus contenedores sea extremadamente rápida. En los contenedores, utilizo el entorno Python del sistema global, porque cada contenedor tiene su propio sistema de archivos y los proyectos están aislados en el nivel superior. Docker permite que los nuevos miembros del equipo comiencen a trabajar en el proyecto más rápido, especialmente si tienen experiencia en Docker.
Si me preguntan, prefiero el paquete Python virtualenv
y los contenedores Docker para el aislamiento y la gestión de dependencias de proyectos.
Error n.º 2: no fijar las dependencias del proyecto en un archivo requirements.txt
Cada nuevo proyecto de Python debe comenzar con un archivo requirements.txt y un nuevo entorno aislado. Normalmente, instala todos los paquetes a través de pip/easy_install
pero nunca olvide agregarlos también a su archivo requirements.txt
. Esto hace que sea más fácil ( posiblemente más apropiado) implementar su proyecto en servidores, o que un miembro del equipo arranque el proyecto en su propia máquina.
Además, es igual de importante anclar la versión específica de sus dependencias en su archivo requirements.txt
. Por lo general, las diferentes versiones de un paquete proporcionan diferentes módulos, funciones y parámetros de función; incluso un cambio de versión menor en una dependencia puede romper su paquete. Este es un problema muy grave si su proyecto está activo y tiene implementaciones programadas con regularidad, ya que, sin control de versiones, su sistema de compilación siempre instalará la última versión disponible del paquete.
¡Fije siempre sus paquetes para la producción! Personalmente, uso una herramienta muy buena llamada pip-tools que me ayuda a hacer esto. Proporciona un conjunto de herramientas de línea de comandos que ayudan a administrar sus dependencias. Genera automáticamente un requirements.txt
que fija no solo sus dependencias, sino todo su árbol de dependencias, que incluye las dependencias de sus dependencias.
A veces, desea actualizar solo algunos paquetes de su lista de dependencias (por ejemplo, solo Django/Flask/cualquier marco o utilidad), si usó "pip freeze" no sabe qué dependencias son para qué paquetes, por lo que no se puede actualizar una dependencia. Sin embargo, con pip-tools, ancla automáticamente los paquetes según la dependencia que haya anclado, por lo que resuelve automáticamente qué paquetes deben actualizarse. Como beneficio adicional, también sabe exactamente qué paquete proviene de qué dependencia debido a cómo los marca con comentarios en el archivo requirements.txt
.
Para ser más cauteloso, ¡también es una buena idea hacer una copia de seguridad de sus archivos de origen de dependencia! Mantenga una copia en su sistema de archivos, una carpeta administrada por Git, una carpeta S3, FTP, SFTP, donde sea, pero téngala a mano. Ha habido casos en los que un paquete relativamente menor que no figura en la lista rompió una gran cantidad de paquetes en npm. Pip proporciona de manera útil la herramienta para descargar todas las dependencias requeridas como archivos de origen, lea más ejecutando la pip help download
.
Error n.º 3: usar funciones de Python de estilo antiguo en lugar de vistas basadas en clases
A veces, es una buena idea usar una pequeña función de Python en el archivo views.py
de una aplicación, especialmente para pruebas o vistas de utilidades, pero, en general, debe usar vistas basadas en clases (CBV) en sus aplicaciones.
Los CBV son vistas genéricas que proporcionan clases abstractas que implementan tareas comunes de desarrollo web creadas por profesionales y cubren todos los comportamientos comunes. Tienen una API estructurada increíble y puede usar todas las ventajas de la programación orientada a objetos cuando usa CBV. Hace que su código fuente sea más claro y legible. Olvídese del dolor de usar las funciones de vista estándar de Django para listados, operaciones CRUD, procesamiento de formularios, etc. Simplemente extienda el CBV adecuado para su vista y anule las propiedades o funciones de clase (generalmente una función devuelve una propiedad y puede agregar cualquier lógica allí qué hace espagueti a partir de su código fuente en caso de usar funciones de vista en lugar de CBV) que configuran el comportamiento de la vista.
Por ejemplo, puede tener diferentes complementos en su proyecto que anulan los comportamientos básicos de CBV para crear contextos de vista, verificar la autorización en el nivel de fila, crear automáticamente rutas de plantilla desde la estructura de su aplicación, integrar el almacenamiento en caché inteligente y más.
Desarrollé el paquete llamado Django Template Names, que estandariza los nombres de las plantillas para sus vistas en función de un nombre de aplicación y un nombre de clase de vista. Lo uso todos los días y me ahorra mucho tiempo para inventar nombres. Simplemente ponga el mixin en su CBV— class Detail(TemplateNames, DetailView):
— ¡y comenzará a funcionar! Por supuesto, puede anular mis funciones y agregar plantillas de respuesta móvil, diferentes plantillas para agentes de usuario o cualquier otra cosa que desee.
Error n.º 4: Escribir vistas gordas y modelos flacas
Escribir la lógica de su aplicación en vistas en lugar de modelos significa que ha escrito código que pertenece a su modelo en la vista, haciéndolo "grueso" y su modelo "delgado".
Deberías escribir modelos gordos, vistas flacas.
Divida la lógica en pequeños métodos en sus modelos. Esto le permite usarlo varias veces desde múltiples fuentes (IU de interfaz de administración, IU de front-end, puntos finales de API, múltiples vistas) en unas pocas líneas de código en lugar de copiar y pegar toneladas de código. Entonces, la próxima vez que envíe un correo electrónico a un usuario, amplíe el modelo con una función de correo electrónico en lugar de escribir esta lógica en su controlador.
Esto también hace que su código sea más fácil de probar porque puede probar la lógica del correo electrónico en un solo lugar, en lugar de repetidamente en cada controlador donde esto ocurre.
Puede leer más sobre el problema en el proyecto Prácticas recomendadas de Django. La solución es simple: escriba modelos gordos y vistas delgadas, así que hagámoslo en su próximo proyecto (o refactorice el actual).
Error n.º 5: un archivo de configuración enorme e inmanejable
Incluso el nuevo archivo de configuración del proyecto Django tiene muchas configuraciones. En un proyecto real, un archivo de configuración crece a más de 700 líneas de configuración y se volverá difícil de mantener, especialmente cuando sus entornos de desarrollo, producción y ensayo necesitan configuraciones personalizadas.

Puede dividir el archivo de configuración manualmente y crear cargadores personalizados, pero quiero presentarle un paquete de Python agradable y bien probado, Django Split Settings, del que soy coautor.
El paquete proporciona dos funciones, optional
e include
, que admite comodines para las rutas e importa sus archivos de configuración en el mismo contexto, lo que simplifica la creación de su configuración utilizando entradas de configuración declaradas en archivos cargados previamente. No afecta el rendimiento de Django y puedes usarlo en cualquier proyecto.
Mira el ejemplo de configuración mínima:
from split_settings.tools import optional, include include( 'components/base.py', 'components/database.py', 'components/*.py', # the project different envs settings optional('envs/devel/*.py'), optional('envs/production/*.py'), optional('envs/staging/*.py'), # for any local settings optional('local_settings.py'), )
Error n.º 6: aplicación todo en uno, mala estructura de la aplicación y ubicación incorrecta de los recursos
Cualquier proyecto de Django consta de múltiples aplicaciones. En notación Django, una aplicación es un paquete de Python que contiene al menos archivos __init__.py
y models.py
; en las últimas versiones de Django, models.py
ya no es necesario. __init__.py
es suficiente.
Las aplicaciones de Django pueden contener módulos de Python, módulos específicos de Django (vistas, URL, modelos, administración, formularios, etiquetas de plantilla, etc.), archivos estáticos, plantillas, migraciones de bases de datos, comandos de gestión, pruebas unitarias y más. Debe dividir sus aplicaciones monolíticas en aplicaciones pequeñas y reutilizables utilizando una lógica simple. Debería poder describir el propósito completo de la aplicación en una o dos oraciones cortas. Por ejemplo: “Permite a los usuarios registrarse y activar su cuenta por correo electrónico”.
Es una buena idea llamar a la carpeta del proyecto project
y colocar las aplicaciones en project/apps/
. Luego, coloque todas las dependencias de la aplicación en sus propias subcarpetas.
Ejemplos:
- Archivos estáticos:
project/apps/appname/static/appname/
- Etiquetas de plantilla:
project/apps/appname/templatetags/appname.py
- Archivos de plantilla:
project/apps/appname/templates/appname/
Siempre prefije el nombre de la aplicación en las subcarpetas porque todas las carpetas estáticas se fusionan en una carpeta y, si dos o más aplicaciones tenían un archivo js/core.js
, la última aplicación en settings.INSTALLED_APPLICATIONS
anulará las anteriores. Una vez tuve este error en mi proyecto actual y perdí unas seis horas de depuración hasta que me di cuenta de que otro desarrollador había anulado static/admin/js/core.js
porque el equipo estaba implementando un panel de administración de SPA personalizado y nombró sus archivos de la misma manera.
Aquí hay una estructura de ejemplo para una aplicación de portal que tiene muchos recursos y módulos de Python.
root@c5b96c395cfb:/test# tree project/apps/portal/ project/apps/portal/ ├── __init__.py ├── admin.py ├── apps.py ├── management │ ├── __init__.py │ └── commands │ ├── __init__.py │ └── update_portal_feeds.py ├── migrations │ └── __init__.py ├── models.py ├── static │ └── portal │ ├── css │ ├── img │ └── js ├── templates │ └── portal │ └── index.html ├── templatetags │ ├── __init__.py │ └── portal.py ├── tests.py ├── urls.py └── views.py 11 directories, 14 files
Con una estructura de este tipo, en cualquier momento puede exportar la aplicación a otro paquete de Python y volver a utilizarla. Incluso puede publicarlo en PyPi como un paquete de código abierto o moverlo a otra carpeta.
Terminarás con una estructura de proyecto como esta:
root@c5b96c395cfb:/test# tree -L 3 . ├── deploy │ ├── chef │ └── docker │ ├── devel │ └── production ├── docs ├── logs ├── manage.py ├── media ├── project │ ├── __init__.py │ ├── apps │ │ ├── auth │ │ ├── blog │ │ ├── faq │ │ ├── pages │ │ ├── portal │ │ └── users │ ├── conf │ ├── settings.py │ ├── static │ ├── templates │ ├── urls.py │ └── wsgi.py └── static └── admin ├── css ├── fonts ├── img └── js 25 directories, 5 files
En un proyecto real, por supuesto, será más complejo, pero esta estructura simplifica y limpia las cosas.
Error n.º 7: STATICFILES_DIRS
y STATIC_ROOT
desarrolladores novatos de Django
Los archivos estáticos son activos que no cambian con el uso de la aplicación, por ejemplo, JavaScript, CSS, imágenes, fuentes, etc. En Django, solo se "recopilan" en un directorio público durante el proceso de implementación.
En el modo de desarrollo, python manage.py runserver
Django busca archivos estáticos utilizando la configuración STATICFILES_FINDERS
. De forma predeterminada, intenta encontrar el archivo estático solicitado en las carpetas enumeradas en la configuración STATICFILES_DIRS
. En caso de falla, Django intenta encontrar el archivo usando django.contrib.staticfiles.finders.AppDirectoriesFinder
, que busca en la carpeta static
de cada aplicación instalada en el proyecto. Esto le permite escribir aplicaciones reutilizables que se envían con sus propios archivos estáticos.
En producción, sirve su estática utilizando un servidor web independiente como Nginx. El servidor web no sabe nada sobre la estructura de las aplicaciones del proyecto Django o en qué carpetas se distribuyen sus archivos estáticos. Afortunadamente, Django le proporciona el comando de gestión de recopilación estática python manage.py collectstatic
, que recorre STATICFILES_FINDERS
y copia todos los archivos static
de las aplicaciones. carpetas y carpetas enumeradas en STATICFILES_DIRS
en el directorio que especifique en la configuración STATIC_ROOT
. Esto permite la resolución de recursos de archivos estáticos utilizando la misma lógica que el servidor en modo de desarrollo de Django y tiene todos los archivos estáticos en un solo lugar para su servidor web.
¡No olvide ejecutar collectstatic
en su entorno de producción!
Error No. 8: STATICFILES_STORAGE
defecto, cargadores de plantillas de Django en producción
STATICFILES_STORAGE
Hablemos de la gestión de activos del entorno de producción. Podemos brindar la mejor experiencia de usuario si usamos una política de "activos que nunca caducan" (sobre la cual puede obtener más información aquí). Significa que los navegadores web deben almacenar en caché todos nuestros archivos estáticos durante semanas, meses o incluso años. En otras palabras, ¡sus usuarios deben descargar sus activos solo una vez!
Eso es genial, y podemos hacerlo con unas pocas líneas en la configuración de Nginx para nuestra carpeta de archivos estáticos, pero ¿qué pasa con la invalidación de caché? Si el usuario descargará nuestros activos solo una vez, ¿qué sucede si actualizó su logotipo, fuentes, JavaScript o el color del texto de un elemento en un menú? Para evitar esto, debe generar direcciones URL y nombres de archivo únicos para nuestros archivos estáticos en cada implementación.
Podemos hacerlo simplemente usando ManifestStaticFilesStorage como STATICFILES_STORAGE
(tenga cuidado, el hashing solo está habilitado en el modo DEBUG=false
) y ejecutando el comando de administración de collectstatic
estática que se mencionó anteriormente. Esto disminuirá el número de solicitudes de activos para su sitio web de producción y hará que su sitio web se muestre mucho más rápido.
Cargador de plantillas de Django en caché
Otra característica interesante de Django es el cargador de plantillas en caché, que no vuelve a cargar ni analiza los archivos de plantilla en cada representación de plantilla. El análisis de plantillas es una operación muy costosa y consume muchos recursos. De forma predeterminada, las plantillas de Django se analizan en cada solicitud, pero esto es malo, especialmente durante la producción, donde puede procesar miles de solicitudes en un corto período de tiempo.
Consulte la sección de configuración de cached.Loader
para ver un buen ejemplo y detalles sobre cómo hacerlo. No use el cargador en el modo de desarrollo porque no recarga las plantillas analizadas desde el sistema de archivos; deberá reiniciar su proyecto usando python manage.py startapp
en cada cambio de plantilla. Esto puede resultar molesto durante el desarrollo, pero es perfecto para el entorno de producción.
Error n.º 9: scripts de Python puro para utilidades o scripts
Django proporciona una característica muy agradable llamada Comandos de administración. Simplemente utilícelo en lugar de reinventar las ruedas y escribir scripts de Python sin procesar para las utilidades de su proyecto.
Además, consulte el paquete de extensiones de Django, que es una colección de extensiones personalizadas para Django. ¡Quizás alguien ya haya implementado tus comandos! Ya hay muchos comandos de tareas comunes.
Error No. 10: Reinventar la Rueda
Django y Python tienen miles de soluciones listas para usar. Intenta buscar en Google antes de escribir algo que no sea único; probablemente ya existe una solución rica en funciones.
Solo trata de hacer las cosas simples. ¡Google primero! Instale, configure, amplíe e integre su proyecto si encuentra un paquete de buena calidad y, por supuesto, contribuya al código abierto cuando tenga la oportunidad.
Para empezar, aquí hay una lista de mis propios paquetes públicos para Django:
- Django Macros URL facilita la escritura (y lectura) de patrones de URL en sus aplicaciones Django mediante el uso de macros.
- Django Templates Names es una pequeña combinación que le permite estandarizar fácilmente los nombres de sus plantillas CBV.
- django-split-settings le permite organizar la configuración de Django en varios archivos y directorios. Anule y modifique fácilmente la configuración. Utilice comodines en las rutas de los archivos de configuración y marque los archivos de configuración como opcionales.
¡No te repitas (SECO)!
Me gusta mucho la metodología DRY; es por eso que creé Django skeleton como una herramienta de conveniencia que tiene algunas características muy buenas listas para usar:
- Imágenes de Docker para desarrollo/producción, administradas por docker-compose, lo que le permite orquestar una lista de contenedores fácilmente.
- Script de Fabric simple para implementación en producción.
- Configuración para el paquete Django Split Settings con configuraciones para fuentes base y locales.
- Webpack integrado en el proyecto: Django solo recopilará la carpeta
dist
en el comandocollectstatic
. - Configuró todas las configuraciones y funciones básicas de Django, como plantillas de Django almacenables en caché en producción, archivos estáticos hash, barra de herramientas de depuración integrada, registro, etc.
Es un Django Skeleton listo para usar para su próximo proyecto desde cero y, con suerte, le ahorrará mucho tiempo arrancando su proyecto. Webpack tiene una configuración básica mínima, pero también tiene instalado SASS preconfigurado para manejar archivos .scss
.