Dado que Django se ha diseñado para aplicaciones controladas por datos, incluye numerosas utilidades integradas para simplificar la cantidad de código necesario. Un área clave donde Django facilita la vida del desarrollador es proporcionando vistas genéricas, que están generadas previamente con todo el código necesario para realizar operaciones básicas, como mostrar y editar datos.
Las aplicaciones controladas por datos a menudo comparten una estructura parecida. Tiene una página en la que se muestra una lista de los elementos, una página para mostrar los detalles de un elemento y, después, las páginas adecuadas para permitir la creación, las actualizaciones y las eliminaciones. Tener que crear cada una de estas páginas a mano puede resultar tedioso, especialmente porque gran parte del código y HTML es repetitivo.
Para ayudar a simplificar la creación de aplicaciones controladas por datos, Django proporciona vistas genéricas. Las vistas genéricas son vistas basadas en clases diseñadas para realizar todas estas operaciones comunes. Podemos usar vistas genéricas para crear rápidamente páginas con el fin de mostrar y editar datos. Estas vistas pueden incluso generar los formularios HTML de forma automática.
En este módulo, trabajaremos en un sitio web de refugios para perros. Este proyecto se centra en recopilar información sobre los refugios para perros existentes y los perros que esperan ser adoptados en Estados Unidos. La esperanza ficticia de esta aplicación es que los perros podrían encontrar hogares adecuados con más rapidez, ya que habría personas de todo Estados Unidos que querrían adoptarlos, y no solo del área local del refugio.
git clone https://github.com/MicrosoftDocs/ms-learn-django-generic-views.git
cd ms-learn-django-generic-views/starter
py -3 -m venv venv
.\\venv\\Scripts\\activate
pip install -r requirements.txt
python manage.py runserver
El sistema de vistas genéricas de Django simplifica la creación de código repetitivo. Las operaciones comunes que realiza en una aplicación controlada por datos comparten el mismo patrón. Por ejemplo, para mostrar un elemento individual por su id o clave principal, el flujo de trabajo siempre es el siguiente:
- Cargue el elemento de la base de datos por id.
- Si no se encuentra el elemento, devuelve un mensaje de error 404.
- Si se encuentra el elemento, páselo a una plantilla para mostrarlo.
El sistema de vistas genéricas confirma este hecho y proporciona clases que se pueden usar y que contienen el código principal ya escrito. Herede de la clase adecuada, establezca un par de propiedades y, después, registre una ruta adecuada en el elemento URLconf. El resto se hace de forma automática.
Django incluye dos vistas genéricas para mostrar datos: DetailView
y ListView
.
La vista genérica DetailView
se usa para mostrar una página de detalles de un elemento. DetailView
recupera el elemento del elemento model
especificado por la clave principal y lo pasa a la plantilla. Puede establecer template_name
en el nombre de la plantilla que se va a usar. De manera predeterminada, es <model>_detail.html
. Por último, podemos establecer context_object_name
en el nombre de la variable que se quiere usar en nuestra plantilla.
Para crear una vista de detalles de un perro mediante la vista genérica, podría usar el código siguiente:
from . import models
from django.views import generic
class DogDetailView(generic.DetailView):
model = models.Dog
template_name = 'dog_detail.html'
context_object_name = 'dog'
El registro de DogDetailView
es similar a cualquier otra entrada de path. El elemento clave para asegurarse de que se incluye es un parámetro denominado pk
. Django usa esta convención para identificar la clave principal. También deberá tener en cuenta que usamos el método as_view()
para convertir la clase en una vista.
path('dog/<int:pk>', views.DogDetailView.as_view(), name='dog_detail')
La vista genérica ListView
se comporta de manera similar a DetailView
. Puede establecer context_object_name
para el nombre de la variable en la vista y template_name
para el nombre de la plantilla.
La principal diferencia es que ListView
está diseñada para trabajar con cualquier forma de una consulta que devuelve varios elementos. Como resultado, debe invalidar la función get_queryset
. El sistema de vista genérico llama a la función get_queryset
para recuperar los elementos de la base de datos, lo que permite ordenar o filtrar los elementos según sea necesario.
Para crear una vista que muestre la lista de todos los refugios mediante la vista genérica ListView
, podría usar el código siguiente:
from . import models
from django.views import generic
class ShelterListView(generic.ListView):
template_name = 'shelter_list.html'
context_object_name = 'shelters'
def get_queryset(self):
return models.Shelter.objects.all()
El registro de la vista se realiza de forma muy similar a nuestro elemento DetailView
.
path('', ShelterListView.as_view(), name='shelter_list')
Queremos crear una nueva página de detalles para perros. Vamos a usar la vista genérica DetailView
para simplificar la cantidad de código que necesitamos crear.
- Abra dog_shelters/views.py.
- Debajo de la línea que lee
# TODO: Import generic views
, agregue el código siguiente para importar el módulo de vistas genéricas.# TODO: Import generic views from django.views import generic
- Agregue el código siguiente a la parte inferior de views.py a fin de crear la vista genérica para
DogDetail
y establecer el modelo, la plantilla y el objeto de contexto.class DogDetailView(generic.DetailView): model = models.Dog template_name = 'dog_detail.html' context_object_name = 'dog'
- Abra dog_shelters/urls.py.
- Debajo de la línea que lee
# TODO: Register detail view
, agregue el código siguiente para registrar la ruta de nuestro elementoDogDetailView
.# TODO: Register detail view path('dog/<int:pk>', views.DogDetailView.as_view(), name='dog_detail'),
- Cree un archivo dentro de dog_shelters/templates denominado dog_detail.html.
- Agregue el código siguiente a dog_detail.html para crear la plantilla para mostrar los detalles del perro.
{% extends 'base.html' %} {% block title %} {{ dog.name }} {% endblock %} {% block content %} <h2>{{ dog.name }}</h2> <div>About {{ dog.name }} - {{ dog.description }}</div> {% endblock %}
- Abra dog_shelters/templates/shelter_detail.html.
- Debajo de la línea que lee
{# TODO: Add link to dogs #}
, agregue el código siguiente para crear un vínculo de cada perro a la vista de detalles.{# TODO: Add link to dogs #} <a href="{% url 'dog_detail' dog.id %}"> {{dog.name}} </a>
- Guarde todos los archivos.
- En el explorador, vaya a http://localhost:8000.
- En la lista de refugios, seleccione Contoso.
- En la lista de perros, seleccione Roscoe.
Al igual que ocurre con el código necesario para mostrar los datos, el código para permitir que los usuarios modifiquen los datos es repetitivo. También puede resultar tedioso, ya que se requieren varios pasos para asegurarse de que los datos son válidos y se envían correctamente. Afortunadamente, el sistema de vistas genéricas puede simplificar la cantidad de código que necesitamos para habilitar esta función.
A primera vista, el código para permitir que un usuario cree un elemento podría parecer trivial. Pero, por lo visto, se trata de un proceso aparentemente complicado.
- El usuario envía una solicitud GET para indicar que quiere que el formulario cree un elemento.
- El servidor envía el formulario con un token especial para evitar la falsificación de solicitud entre sitios (CSRF).
- El usuario completa el formulario y selecciona Enviar, que envía una solicitud POST para indicar que el formulario se ha completado.
- El servidor valida el token CSRF para asegurarse de que no se ha producido ninguna alteración.
- El servidor valida toda la información para asegurarse de que cumple las reglas. En caso de que se produzca un error de validación, se devolverá un mensaje de error.
- El servidor intenta guardar el elemento en la base de datos. Si se produce un error, se devuelve al usuario un mensaje de error.
- Después de guardar correctamente el elemento nuevo, el servidor redirige al usuario a una página de éxito.
¡Este proceso requiere bastante código! La mayor parte de este es reutilizable, lo que significa que es el mismo cada vez que se crea.
La creación de un formulario HTML puede ser un proceso tedioso. Los desarrolladores a menudo copian y pegan etiquetas input
, recorren listas para crear listas desplegables y configuran botones de radio. Cada vez que el modelo cambia, debe actualizarse el formulario.
Es posible que haya observado que los modelos que creamos en Django contienen todo lo necesario para crear el formulario. Cuando agregamos los distintos campos, indicamos los tipos de datos, que se acoplan con distintos elementos HTML. Por ejemplo, un campo booleano sería una casilla y una clave externa normalmente sería una lista desplegable.
Uno de los objetivos clave de Django es eliminar la necesidad de volver a crear constantemente los mismos bloques de código una y otra vez. Para que este objetivo sea compatible con las modificaciones de datos, Django proporciona una recopilación de clases y formularios genéricos con el fin de administrar esta carga de trabajo. Como veremos, incluye todo el código necesario y puede incluso crear el formulario por nosotros dinámicamente. Las clases utilizadas para crear, actualizar y eliminar datos se denominan CreateView
, UpdateView
y DeleteView
respectivamente.
La clase CreateView
se utiliza para permitir a los usuarios crear elementos. Le guía por el proceso anterior y crea dinámicamente el formulario. Una vez que se ha realizado correctamente, muestra la página de detalles del elemento recientemente creado.
Se debe especificar el elemento model
y template_name
que quiere asociar, tal como se haría con las otras vistas genéricas. La diferencia clave de CreateView
es la inclusión de una propiedad fields
en la que se muestra una lista de los campos modificables. Con esta propiedad, puede asegurarse de que los campos que no se deben editar, como una fecha de creación, no aparecen en el formulario. La vista para crear un perro podría ser similar a la del ejemplo siguiente:
from . import models
from django.views import generic
class DogCreateView(generic.CreateView):
model = models.Dog
template_name = 'dog_form.html'
fields = ['name', 'description', 'shelter']
La clase UpdateView
se comporta de manera idéntica a CreateView
. La única diferencia es que carga automáticamente un elemento basado en el parámetro pk
. Django usa esta convención para la clave principal de un elemento.
from . import models
from django.views import generic
class DogUpdateView(generic.CreateView):
model = models.Dog
template_name = 'dog_form.html'
fields = ['name', 'description', 'shelter']
Después de crear o actualizar correctamente un elemento, Django redirige a la página de detalles del elemento. Recupera la dirección URL de los detalles mediante el uso de get_absolute_url
en el modelo asociado. Para implementar este método, devuelva la dirección URL correcta. Puede recuperar la dirección URL apropiada de URLconf mediante reverse
. Tenga en cuenta que kwargs
se usa para pasar pk
o el parámetro de clave principal o a la ruta.
from django.db import models
# TODO: Import reverse
from django.urls import reverse
class Dog(models.Model):
# Existing code
def get_absolute_url(self):
return reverse('dog_detail', kwargs={"pk": self.pk})
La clase DeleteView
es parecida a UpdateView
. Permite a un usuario eliminar un elemento e identifica el elemento que se va a eliminar mediante pk
. A diferencia de UpdateView
, fields
no se necesita porque se eliminará todo el elemento. Además, dado que no se ha creado ni actualizado ningún elemento recientemente, necesitamos determinar dónde queremos redirigir al usuario. Podemos crear un redireccionamiento estableciendo success_url
en el valor adecuado. Puede buscar una dirección URL mediante reverse_lazy
.
from . import models
from django.views import generic
from django.urls import reverse_lazy
class AuthorDelete(DeleteView):
model = Author
success_url = reverse_lazy('author-list')
Las vistas genéricas pueden crear el formulario HTML por nosotros dinámicamente. Todo lo que debemos proporcionar es una plantilla que actúe como el marcador de posición del formulario. La plantilla de marcador de posición garantiza que el formulario coincida con el resto de nuestro sitio. Afortunadamente, no necesitamos mucho código para crearla.
Las vistas genéricas crean automáticamente una variable form
para que la use nuestra plantilla. Los elementos del formulario que proporciona Django se pueden mostrar dentro de las etiquetas <p>
o como un elemento <table>
.
La variable form
contiene todo el HTML adecuado para crear los controles del formulario. No contiene la propia etiqueta <form>
o un botón de envío. Nuestra plantilla debe incluir cuatro elementos:
- El elemento
form
conmethod
establecido en POST, porque esta configuración desencadena la operación de almacenamiento en el servidor. - El código
{% csrf_token %}
para agregar el token CSRF a fin de evitar la suplantación de identidad. - El código
{{ form.as_p }}
o{{ form.as_table }}
para mostrar el formulario generado de forma dinámica. - El botón
submit
.
El código siguiente puede actuar como el host para cualquier formulario de vista genérica.
<form method="post">{% csrf_token %}
{{ form.as_p }}
<button type="submit">Save</button>
</form>
Para permitir que los usuarios registren nuevos perros en un refugio, usaremos CreateView
.
- Abra dog_shelters/models.py.
- Agregue el código siguiente debajo de la línea que lee
# TODO: Import reverse
para importar la funciónreverse
.# TODO: Import reverse from django.urls import reverse
- Agregue el código siguiente a la clase
Dog
inmediatamente en la línea que lee# TODO: Add get_absolute_url
para leer la ruta dog_detail de URLconf y pasar el identificador como parámetro.# TODO: Add get_absolute_url def get_absolute_url(self): return reverse('dog_detail', kwargs={"pk": self.pk})
- Abra dog_shelters/views.py.
- Al final de views.py, agregue el código siguiente para crear
DogCreateView
.class DogCreateView(generic.CreateView): model = models.Dog template_name = 'dog_form.html' fields = ['shelter', 'name', 'description']
- Abra dog_shelters/urls.py.
- Debajo de la línea que lee
# TODO: Register create view
, agregue el código siguiente para registrar la ruta.# TODO: Register create view path('dog/register', views.DogCreateView.as_view(), name='dog_register'),
- Cree un archivo dentro de dog_shelters/templates denominado dog_form.html.
- Agregue el código siguiente a dog_form.html para crear la plantilla que hospedará el formulario.
{% extends 'base.html' %} {# TODO: Register crispy_forms_tags #} {% block title %} Register dog at shelter {% endblock %} {% block content %} <h2>Register dog at shelter</h2> <form method="POST"> {% csrf_token %} {{ form.as_p }} <button type="submit" class="btn btn-primary">Save</button> </form> {% endblock %}
- Abra dog_shelters/templates/shelter_list.html.
- Debajo de la línea que lee
{# TODO: Add link to registration page #}
, agregue el código siguiente para crear el vínculo.{# TODO: Add link to registration page #} <div> <a href="{% url 'dog_register' %}">Register a dog available for adoption</a> </div>
- Guarde todos los archivos.
- En el explorador, vaya a http://localhost:8000.
- Seleccione Register a dog available for adoption.
- Elija un refugio y agregue un nombre y una descripción para un perro.
- Seleccione Guardar.
Después de ver el formulario creado, es posible que observe que el formato no es el mismo que en el resto de la página. Estamos usando Bootstrap, pero el formulario todavía no. Afortunadamente, existe una biblioteca que puede garantizar que nuestros formularios también usan Bootstrap.
La biblioteca django-crispy-forms mejora el modo en que Django genera los formularios.
- Abra requirements.txt.
- En la parte inferior del archivo, agregue una nueva línea que lea lo siguiente:
django-crispy-forms crispy-bootstrap4
- Instale todos los paquetes mediante la ejecución del comando siguiente:
pip install -r requirements.txt
- Abra project/settings.py.
- Debajo de la línea que lee
# TODO: Register crispy_forms
, agregue el código siguiente para registrar django-crispy-forms.# TODO: Register crispy_forms 'crispy_forms', 'crispy_bootstrap4',
- Debajo de la línea que lee
# TODO: Set template_pack
, agregue el código siguiente para configurar django-crispy-forms a fin de que use Bootstrap 4.
# TODO: Set template_pack
CRISPY_TEMPLATE_PACK = 'bootstrap4'
CRISPY_ALLOWED_TEMPLATE_PACKS = 'bootstrap4'
- Abra dog_shelters/templates/dog_form.html.
- Debajo de la línea que lee
{# TODO: Load crispy_forms_tags #}
, agregue el código siguiente para cargar el filtro o la etiqueta.{# TODO: Load crispy_forms_tags #} {% load crispy_forms_tags %}
- Reemplace la línea que lee
{{ form.as_p }}
por el código siguiente para usar el filtrocrispy
.{{ form | crispy }}
- Guarde todos los archivos.
- En el explorador, vaya a http://localhost:8000/dog/register.