Cómo escribir vistas, modelos y consultas eficientes en Django

Me gusta Django. Es un marco intuitivo y bien considerado con un nombre que puedo pronunciar en voz alta. Puede usarlo para poner en marcha rápidamente un proyecto del tamaño de un fin de semana, y también puede usarlo para ejecutar aplicaciones de producción en toda regla a escala.

He hecho ambas cosas y, a lo largo de los años, he descubierto cómo utilizar algunas de las funciones de Django para lograr la máxima eficiencia. Estos son:

  • Vistas basadas en clases versus vistas basadas en funciones
  • Modelos de Django
  • Recuperar objetos con consultas

Veamos cómo estas herramientas le permiten crear una aplicación Django de alto rendimiento que sea agradable de construir y mantener.

Vistas basadas en clases versus vistas basadas en funciones

Recuerda que Django es todo Python bajo el capó. Cuando se trata de vistas, tiene dos opciones: funciones de vista (a veces llamadas "vistas basadas en funciones") o vistas basadas en clases.

Hace años, cuando construí ApplyByAPI por primera vez, inicialmente estaba compuesto completamente de vistas basadas en funciones. Estos ofrecen control granular y son buenos para implementar lógica compleja. Al igual que en una función de Python, tiene un control total (para bien o para mal) sobre lo que hace la vista.

Pero un gran control conlleva una gran responsabilidad, y las vistas basadas en funciones pueden ser un poco tediosas de utilizar. Usted es responsable de escribir todos los métodos necesarios para que la vista funcione; esto es lo que le permite personalizar completamente su aplicación.

En el caso de ApplyByAPI, solo había unos pocos lugares donde ese nivel de funcionalidad personalizada era realmente necesario. En todos los demás lugares, las vistas basadas en funciones comenzaron a hacerme la vida más difícil. Escribir lo que es esencialmente una vista personalizada para operaciones corrientes, como mostrar datos en una página de lista, se volvió tedioso, repetitivo y propenso a errores.

Con las vistas basadas en funciones, necesitará averiguar qué métodos de Django implementar para manejar solicitudes y pasar datos a las vistas. Las pruebas unitarias pueden requerir algo de trabajo para escribirlas. En resumen, el control granular que ofrecen las vistas basadas en funciones también requiere algo de tedio granular para implementarlo correctamente.

Terminé reteniendo ApplyByAPI mientras refactorizaba la mayoría de las vistas en vistas basadas en clases. Esta no fue una pequeña cantidad de trabajo y refactorización, pero cuando terminé, tuve un montón de pequeñas vistas que marcaron una gran diferencia. Quiero decir, solo mira este:

class ApplicationsList(ListView): model = Application template_name = "applications.html" 

Son tres líneas. Mi ergonomía de desarrollador y mi vida se volvieron mucho más fáciles.

Puede pensar en las vistas basadas en clases como plantillas que cubren la mayor parte de la funcionalidad que necesita cualquier aplicación. Hay vistas para mostrar listas de cosas, para ver una cosa en detalle y editar vistas para realizar operaciones CRUD (Crear, Leer, Actualizar, Eliminar).

Debido a que la implementación de una de estas vistas genéricas requiere solo unas pocas líneas de código, la lógica de mi aplicación se volvió dramáticamente concisa. Esto me dio un código menos repetido, menos lugares para que algo saliera mal y una aplicación más manejable en general.

Las vistas basadas en clases son rápidas de implementar y usar. Las vistas genéricas integradas basadas en clases pueden requerir menos trabajo para probar, ya que no es necesario escribir pruebas para la vista base que proporciona Django. (Django hace sus propias pruebas para eso; no es necesario que su aplicación vuelva a verificar).

Para ajustar una vista genérica a sus necesidades, puede crear una subclase de una vista genérica y anular atributos o métodos. En mi caso, dado que solo necesitaba escribir pruebas para las personalizaciones que agregué, mis archivos de prueba se acortaron dramáticamente, al igual que el tiempo y los recursos necesarios para ejecutarlos.

Cuando esté sopesando la elección entre vistas basadas en funciones o basadas en clases, considere la cantidad de personalización que necesita la vista y el trabajo futuro que será necesario para probarla y mantenerla.

Si la lógica es común, es posible que pueda comenzar a trabajar con una vista genérica basada en clases. Si necesita suficiente granularidad como para que volver a escribir los métodos de una vista base lo haga demasiado complicado, considere una vista basada en funciones.

Modelos de Django

Los modelos organizan los conceptos centrales de su aplicación Django para ayudar a que sean flexibles, robustos y fáciles de trabajar. Si se usan con prudencia, los modelos son una forma poderosa de recopilar sus datos en una fuente definitiva de verdad.

Al igual que las vistas, Django proporciona algunos tipos de modelos integrados para la conveniencia de implementar la autenticación básica, incluidos los modelos de usuario y permiso. Para todo lo demás, puede crear un modelo que refleje su concepto heredando de una clase de modelo principal.

class StaffMember(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) company = models.OneToOneField(Company, on_delete=models.CASCADE) def __str__(self): return self.company.name + " - " + self.user.email 

Cuando creas un modelo personalizado en Django, subclases la clase Model de Django y aprovechas todo su poder. Cada modelo que crea generalmente se asigna a una tabla de base de datos. Cada atributo es un campo de base de datos. Esto le brinda la capacidad de crear objetos con los que trabajar y que los humanos puedan comprender mejor.

Puede hacer que un modelo le resulte útil definiendo sus campos. Se proporcionan convenientemente muchos tipos de campos integrados. Estos ayudan a Django a determinar el tipo de datos, el widget HTML que se utilizará al representar un formulario e incluso los requisitos de validación del formulario. Si es necesario, puede escribir campos de modelo personalizados.

Las relaciones de la base de datos se pueden definir utilizando un campo ForeignKey (muchos a uno) o ManyToManyField (le da tres suposiciones). Si eso no es suficiente, también hay un OneToOneField.  

Juntos, estos le permiten definir relaciones entre sus modelos con niveles de complejidad limitados solo por su imaginación. (Dependiendo de la imaginación que tenga, esto puede ser una ventaja o no).

Recuperar objetos con consultas

Utilice el Administrador de su modelo ( objectspor defecto) para construir un QuerySet. Esta es una representación de objetos en su base de datos que puede refinar, usando métodos, para recuperar subconjuntos específicos. Todos los métodos disponibles están en la API de QuerySet y se pueden encadenar para divertirse aún más.

Post.objects.filter( type="new" ).exclude( title__startswith="Blockchain" ) 

Algunos métodos devuelven nuevos QuerySets, como filter(), o exclude(). Encadenarlos puede brindarle consultas poderosas sin afectar el rendimiento, ya que los QuerySets no se obtienen de la base de datos hasta que se evalúan. Métodos que evalúan un QuerySet incluyen get(), count(), len(), list(), o bool().

La iteración sobre un QuerySet también lo evalúa, así que evite hacerlo cuando sea posible para mejorar el rendimiento de la consulta. Por ejemplo, si solo desea saber si un objeto está presente, puede usarlo exists()para evitar iterar sobre los objetos de la base de datos.

Úselo get()en los casos en los que desee recuperar un objeto específico. Este método aumenta MultipleObjectsReturnedsi sucede algo inesperado, así como la DoesNotExistexcepción, si, adivine.

If you’d like to get an object that may not exist in the context of a user’s request, use the convenient get_object_or_404() or get_list_or_404() which raises Http404 instead of DoesNotExist. These helpful shortcuts are suited to just this purpose. To create an object that doesn’t exist, there’s also the convenient get_or_create().

Efficient essentials

You’ve now got a handle on these three essential tools for building your efficient Django application – congratulations!

There’s a lot more that Django can do for you, so stay tuned for future articles.

If you’re  going to build on GitHub, you may like to set up my django-security-check GitHub Action. In the meantime, you’re well on your way to building a beautiful software project.