Introducción a Django (2ª parte)

Estructura de una aplicación Django

Si queremos desarrollar un proyecto Django desde 0 tenemos que generar los ficheros del proyecto, para ello debemos ejecutar:

(django)$ django-admin startproject mysite

Eso creará un directorio mysite con nuestro proyecto Django que acabamos de crear.

Nosotros no vamos a ejecutar ese comando porque partimos de un proyecto Django ya construido. En nuestro caso nuestra aplicación está en el repositorio Django Guestbook: https://github.com/josedom24/guestbook_django.

La estructura general de un proyecto Django es la siguiente:

guestbook_project/
├── manage.py
├── guestbook_project/
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   ├── wsgi.py
│   └── asgi.py
  • manage.py: La utilidad de terminal que vamos a usar para manejar nuestra aplicación.
  • El directorio guestbook_project es un paquete python (agrupa distintos módulos (ficheros python)). Esto se indica con un fichero vacío que se de be llamar __init__.py.
  • settings.py: La configuración de la aplicación.
  • urls.py: Donde se declaran las rutas que va tener la aplicación.
  • wsgi.py: Fichero wsgi para el despliegue de la aplicación utilizando el protocolo wsgi.
  • asgi.py: Fichero asgi para el despliegue de la aplicación utilizando el protocolo asgi.

Aplicaciones en un proyecto Django

Ya tenemos un proyecto Django construido. Ahora tenemos que darle funcionalidad. Cada una de las funcionalidades de un proyecto Django se llama aplicación. Por ejemplo un proyecto Django de gestión puede tener una aplicación de clientes, otra de pedidos, otra de presupuestos,…

Por defecto nuestro proyecto Django ya tiene algunas aplicaciones configuradas:

  • admin: Panel administrativo que nos permite manejar la base de datos de nuestra aplicación.
  • auth: Aplicación que me permite trabajar con usuarios en mi proyecto.

Además de las aplicaciones por defecto, el programador deberá añadir las aplicaciones adicionales para que el proyecto ofrezca distintas funcionalidades. En nuestro ejemplo, tenemos una aplicación llamada guestbook que nos permite gestionar un libro de visita, donde podemos poner comentarios que se irán guardando en una base de datos. La aplicación guestbook se encuentra en el directorio guestbook:

guestbook_project/
├── manage.py
├── guestbook_project/
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   ├── wsgi.py
│   └── asgi.py
├── guestbook/
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── forms.py
│   ├── models.py
│   ├── urls.py
│   ├── views.py
│   └── templates/
│       └── inicio.html
├── static/
│   └── style.css
└── requirements.txt

:::caution[Ejercicio]

  1. Estudia la organización de los ficheros del proyecto Django.
  2. Te tiene que quedar claro que los ficheros dentro del directorio guestbook_project son del proyecto y que los ficheros dentro de guestbook son los de la aplicación guestbook.
  3. Si este proyecto tuviera más aplicaciones tendríamos un directorio por cada una de ellas. :::

La configuración del proyecto

Veamos el ficheros settings.py que encontramos dentro del directorio guestbook_project:

  • DEBUG = True: Si está activo los errores que se produzcan en la aplicación se verán con todo lujo de detalles en el navegador. Si tenemos la aplicación en producción debería ser False.
  • ALLOWED_HOSTS = []: Una lista con los nombres con los que se va a permitir el acceso a la aplicación.
  • INSTALLED_APPS = [...]: La lista de las aplicaciones que tiene instalada el proyecto.
  • DATABASES: Configuración de la base de datos que se va a utilizar en el proyecto. Por defecto se utiliza una base de datos sqlite llamada db.sqlite3.

:::caution[Ejercicio]

  1. Estudia el contenido del fichero de configuración.
  2. Comprueba la lista de aplicaciones que tiene el proyecto.
  3. Comprueba que base de datos tiene definida el proyecto Django. :::

El modelo de la aplicación

Django incluye un ORM (Object Relational Mapper), un sistema que permite trabajar con la base de datos usando objetos Python en lugar de sentencias SQL.

El modelo nos permite diseñar las tablas y las relaciones con la que vamos a trabajar en nuestra aplicación. El modelo de Django nos independiza del motor de base de datos, es decir, vamos a trabajar con clases y objetos que representan los datos y nos da igual que los datos se guarden en cualquier tipo de base de datos.

El modelo de la aplicación guestbook se define en el fichero guestbook/models.py:

from django.db import models

class Entry(models.Model):
    content = models.CharField(max_length=255)
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.content

Cada clase representa una tabla y la definición de sus atributos.

Se crea una clase llamada Entry. Si creamos objetos de esta clase en el programa podremos gestionar los datos de una tabla dentro de la base de datos que hemos configurado en el proyecto.

La tabla tendrá tres campos:

  • Un id autoincremental, que no hemos indicado.
  • content: Cadena de caracteres con longitud 255, donde se guarda el mensaje.
  • created_at: De tipo fecha/Hora que guarda la fecha y la hora de creación del comentario-

Con los objetos de la clase Entry podremos insertar, modificar, eliminar, consultar, … los registros de la tabla.

¿Qué relación tiene el modelo con la base de datos que hemos configurado en el fichero settings.py? El programa va a trabajar para gestionar los datos con los objetos de esta clase, pero cada vez que se haga una operación en los datos se traducirá internamente a SQL para que se guarde en la base de datos configurada.

:::caution[Ejercicio]

  1. Estudia el fichero donde está definido el modelo de la aplicación. :::

Migraciones

Las migraciones son el mecanismo mediante el cual Django traduce los modelos Python a tablas reales en la base de datos.

Tenemos que trasladar a la base de datos configurada, las tablas que hemos representado con clases en el modelo.

Para ello usamos las migraciones que son ficheros con las instrucciones necesarias para que Django pueda crear o modificar el esquema de la base de datos.

Cada una de las aplicaciones puede tener un modelo, y tendrá una migración inicial. Por ejemplo, la aplicación guestbook guarda su migración inicial en el fichero guestbook/migrations/0001_initial.py.

Para aplicar la migración inicial, y crear las distintas tablas de las distintas aplicaciones del proyecto, ejecutamos:

python3 mange.py migrate

Operations to perform:
  Apply all migrations: admin, auth, contenttypes, guestbook, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying auth.0012_alter_user_first_name_max_length... OK
  Applying guestbook.0001_initial... OK
  Applying sessions.0001_initial... OK

A continuación podemos acceder a la base de datos y comprobar que se han creado las tablas:

sqlite3 db.sqlite3 
SQLite version 3.46.1 2024-08-13 09:16:08
Enter ".help" for usage hints.
sqlite> .tables
auth_group                  django_admin_log          
auth_group_permissions      django_content_type       
auth_permission             django_migrations         
auth_user                   django_session            
auth_user_groups            guestbook_entry           
auth_user_user_permissions

:::caution[Ejercicio]

  1. Comprueba las migraciones que tiene la aplicación guestbook.
  2. ¿Qué función tiene la instrucción python3 mange.py migrate?.
  3. Instala el cliente sqlite3 y accede a la base de datos. Lista las tablas y reliaza un select para ver los mensajes que tienes guardados en la aplicación guestbook. :::

Modificación del modelo

Si durante el proceso de desarrollo de nuestra aplicación, el equipo de desarrollo necesita modificar el modelo de una aplicación, por ejemplo:

  • Modificando la definición de una tributo.
  • Introduciendo otra clase que representa una nueva tabla.
  • Añadiendo un nuevo atributo.

Esta modificación en el modelo habrá que traspasarla a nuestra base de datos. Necesitamos las instrucciones para que Django pueda cambiar el esquema de la base de datos, necesitamos una nueva migración.

Para que siga funcionando bien la aplicación tendremos que crear una migración:

(django)$ python3 manage.py makemigrations

Esto creará un fichero de migración en el directorio polls/migrations. Una migración es un script que al ejecutarlo se cambia la estructura de la base de datos según el cambio del modelo. Para ejecutar la migración:

(django)$ python3 manage.py migrate

Las rutas y el controlador de la aplicación

En Django, y en general en Python, cuando programamos una aplicación web, las rutas que se usan para accedr a las distintas funcionales, son rutas virtuales, no forman parte del sistema de ficheros como en PHP.

Las rutas virtuales que vamos a usar para acceder a las distintas funciones de la aplicación se definen a nivel de proyecto y a nivel de aplicación:

  • A nivel de proyecto están definidas guestbook_project/urls.py.
  • Dentro de cada aplicación, en nuestro caso del directorio guestbook puede haber otro fichero urls.py donde se definen las rutas propias de la aplicación (en este ejemplo no existe este fichero).

Cada una de las rutas definidas en estos ficheros hacen referencia a las funciones que se ejecuta, que esstán definfidas en el fichero guestbook/views.py.

Por ejemplo en nuestro ejemplo:

  • En el fichero “guestbook_project/urls.py` nos encontramos la definición de las dos rutas siguientes:

    path("", views.inicio, name="inicio"),
    path("add/", views.add, name="add"),
  • Es decir, cuando estramos en la raíz de la aplicación, se ejecuta la función inicio que está definida en el fichero guestbook/views.py.

  • Y cuando se accede a la ruta add, se ejecuta la función add.

Las vistas de la aplicación

Las vistas en djando se implementan usando plantillas (templates). django tiene un motor de plantillas propio. Podemos encontrar las plantillas de la aplicación en dos niveles:

  • A nivel de proyecto: estarían guardadas en el directorio guestbook_project/templates.
  • A nivel de aplicación: estarían guardadas en el directorio guestbook/templates (en nuestro ejemplo no existe este directorio).

Cada una de las funciones que se definen en el fichero views.py, ejecutan un código y finalmente pueden:

  • Mostrar una página web dinámica a partir de una plantilla a la que le manda información, usando la instrucción render. En nuestro caso, la función inicio muestra una página web usando el template inicio.html al que le mandamos la lista de mensajes que tenemos guardado en la base de datos:

    ...
    return render(request, "inicio.html", {"noredis": noredis, "lista": [e.content for e in entries], "form": form})
  • Realizar una redirección a otra página. En nuestro ejemplo la función add añade el mensaje del formulario a la base de datos, y posteriormente con la instrucción redirect redirige a la función de inicio para mostrar de nuevo la página principal.

    ...
    return redirect("inicio")

Aplicación django_tutorial

Ahora vamos a trabajar con otra aplicación Django que encuentras en el repositorio https://github.com/josedom24/django_tutorial.

Esta aplicación, nos permite trabajar con encuestas. Podemos dar de alta preguntas para las encuesta e indicar las posibles respuestas para que los usuarios voten.

Esta aplicación es una variante de la aplicación que se construye en tutorial de django. Si queréis aprender un poco de django, es muy recomendable seguir el tutorial.

:::caution[Ejercicio]

  1. Realiza un fork del repositorio.
  2. Realiza los pasos necesarios para probar la aplicación en el entorno de desarrollo.
  3. Da de alta una encuesta en la zona de administración y comprueba la funcionalidad de la aplicación accediendo con un navegador web.
  4. Estudia el modelo de la aplicación y determina que tablas se van a crear y que atributos tiene cada una. ¿Existe alguna relación entre las tablas?.
  5. ¿Cómo se crean las tablas en la base de datos?
  6. Comprueba la base de datos que está configurada en el proyecto.
  7. Accede a la base de datos y comprueba las tablas que se han creado. realiza una consulta para seleccionar la pregunta que has creado para la encuesta. :::

Las rutas virtuales que vamos a usar para acceder a las distintas funciones de la aplicación se definen a nivel de proyecto y a nivel de aplicación:

  • A nivel de proyecto estudiamos el fichero django_tutorial/urls.py:
    • Donde se ha definido que cuando se acceda a la ruta polls/ se utilizaran las rutas definidas en la aplicación polls.
    • Y cuando se acceda a la ruta admin/ se utilizarán las rutas definidas en la aplicación admin (panel de administración).
  • A nivel de aplicación, vemos el fichero polls/urls.py y comprobamos que se han definido 4 rutas:
    • La ruta principal ”: Donde se va a ejecutar la función index, que muestra la lista de encuestas. Ejemplo: http://localhost:8000/polls.
    • La ruta <int:pk>/: Cuando se ponga un entero se mostrará información de esa encuesta. Esto se hace en la función detail. Ejemplo: http://localhost:8000/polls/1/.
    • La ruta '<int:pk>/results/: Donde se nos mostrará los resultados de la encuesta identificada por su código. Esto se realiza con la función results. Ejemplo: http://localhost:8000/polls/1/results/.
    • La ruta <int:question_id>/vote/: Nos permite votar una opción de una encuesta. Esto lo realiza la función vote. Por ejemplo: http://localhost:8000/polls/100/vote/.