Sobre este documento

Este guión de prácticas ha sido elaborado a partir de los tutoriales de introducción a Django que se pueden encontrar en la página de Django. Han sido adaptados y modificados específicamente para las clases de SAT y SARO de los Grados que se imparten en la Escuela de Ingeniería de Telecomunicación de la Universidad Rey Juan Carlos.

Instalación de Django

Usaremos una versión de Django 3.1.7, instalándola con pip3 desde la línea de shell. pip3 es un instalador de paquetes Python3 disponible para todas las distribuciones de Linux, MacOS y Windows.

Antes de eso, para no interferir con otras versiones de Django ni otras bibliotecas de Python3 que tengamos instaladas, lo que vamos a hacer es crearnos un entorno virtual. Un entorno virtual python es un mecanismo que me permite gestionar programas y paquetes Python sin tener permisos de administración, es decir, cualquier usuario sin privilegios puede tener uno o más espacios aislados donde poder instalar distintas versiones de programas y paquetes python. A continuación, se puede ver cómo creamos ese entorno virtual, que llamaremos en este caso "cursosweb":

$ python3 -m venv cursosweb

Una vez creado el entorno virtual "cursosweb", lo activaremos de la siguiente manera:

$ source cursosweb/bin/activate

Al activarlo, estaremos accediendo a ese entorno virtual. Es ahora cuando podemos instalar django con pip3. Para ello, ejecutamos:

$ pip3 install django==3.1.7

Para comprobar que se ha instalado correctamente, ejecutamos:

$ python3 -m django --version
...\> py -m django --version

Si Django está instalado, deberías ver la versión de tu instalación (en nuestro caso, la 3.1.7). Si no es así, obtendrás un error indicando que «No existe el módulo llamado Django». Si es así, pregunta en el Microsoft Teams al profesor para que te ayude.

Introducción a Django

A continuación, mostraremos cómo crear una aplicación Django que ofrezca funcionalidad de una calculadora básica.

Creando un proyecto

Si esta es la primera vez que utilizas Django, tendrás que primero crear un proyecto Django, que a su vez contendrá aplicaciones Django. Siendo breve (y un poco inexacto), los proyectos Django los podemos ver como contenedores de aplicaciones Django, que son las que ofrecen las funcionalidades. Así, por ejemplo, los proyectos Django se asemejarían al servidor que recibe las peticiones y maneja las respuestas. Las aplicaciones, por su parte, contienen la lógica -- son las que hacen algo (una calculadora, un blog, un servicio de información bursátil...). En nuestro caso, crearemos un proyecto Django llamado "proyecto", que contendrá una aplicación Django llamada "calc".

Desde la línea de comandos, cambia a un directorio donde te gustaría almacenar tu código, y ejecuta el siguiente comando:

$ django-admin startproject proyecto
...\> django-admin startproject proyecto

Esto creará un directorio proyecto en tu directorio actual. Si no funcionó, es que no has instalado Django de manera correcta. Prueba a preguntar al profesor.

Veamos lo que el comando startproject ha creado:

proyecto/
    manage.py
    proyecto/
        __init__.py
        settings.py
        urls.py
        asgi.py
        wsgi.py

Estos archivos son:

  • El directorio proyecto/ es el directorio raíz y es el contenedor de todo lo que va a ser nuestro proyecto Django. Su nombre no es importante para Django, lo podríamos hasta renombrar en el futuro.
  • manage.py: Un programa de la línea de comandos que permite interactuar con este proyecto Django de diferentes formas: lanzar el servidor (como veremos hoy), actualizar las bases de datos (como veremos la próxima vez), pasar los tests (como también veremos)...
  • En interior del directorio proyecto/ es el propio paquete de Python para su proyecto. Su nombre es el nombre del paquete de Python que tendrás que utilizar para importar todo dentro de este (por ejemplo, proyecto.urls).
  • proyecto/__init__.py: Un archivo vacío que le indica a Python que este directorio debería ser considerado como un paquete Python.
  • proyecto/settings.py: Ajustes/configuración para este proyecto Django. Es un fichero en Python con variables de configuración. Iremos poco a poco conociéndolas.
  • proyecto/urls.py: Las direcciones URL para este proyecto Django y sus aplicaciones; es una «tabla de contenidos» del sitio Django donde a partir de una URL dada se indica qué se ha de ejectuar. Las veremos hoy mismo, más abajo.
  • proyecto/asgi.py: Un punto de entrada para que los servidores web compatibles con ASGI puedan servir su proyecto, como Node.js u otros. Nada que nos interese mucho en esta asignatura.
  • proyecto/wsgi.py: Un punto de entrada para que los servidores web compatibles con WSGI puedan servir su proyecto, como Apache. Quizás si os pedimos desplegar vuestra práctica final, tengáis que tocarlo, pero será algo que os preocupará dentro de dos meses como pronto.

En pocas palabras, los ficheros a tener en cuenta hoy son manage.py (que ejecuta el servidor) y proyecto/urls.py (donde a partir de la URL de entrada se dirige a una acción). En la clase de la semana que viene también tocaremos las configuraciones en proyecto/settings.py.

El servidor de desarrollo

Comprobemos que tu proyecto Django funciona. Cambia al subdirectorio proyecto, si todavía no lo has hecho, y ejecuta el siguiente comandos:

$ python3 manage.py runserver
...\> py manage.py runserver

Verá la siguiente salida en la línea de comandos:

Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).

You have 17 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.

March 24, 2021 - 21:16:06
Django version 3.1.7, using settings 'proyecto.settings'

Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

Nota

Ignora por ahora la advertencia sobre las migraciones de bases de datos sin aplicar, nos ocuparemos de la base de datos dentro de poco (la semana que viene).

Has iniciado el servidor en desarrollo de Django, un servidor web ligero escrito puramente en Python. Este servidor viene con Django para que puedas desarrollar cosas rápidamente sin tener que lidiar con la configuración de un servidor en producción, como Apache, hasta que esté listo para la producción.

Ahora es un buen momento para tener en cuenta que: no debes utilizar este servidor en algo parecido a un entorno de producción. Está pensado sólo para usarse durante el desarrollo (nuestro trabajo es crear frameworks Web, no servidores web.)

Ahora que el servidor está funcionando, visita http://127.0.0.1:8000/ con su navegador Web. Verás la página «¡Enhorabuena!», con un cohete despegando. ¡Funcionó!

Cambiando el puerto

De forma predeterminada, el comando runserver inicia el servidor de desarrollo en el interfaz interno (localhost) en el puerto 8000.

Si deseas cambiar el puerto del servidor, pásalo como un argumento de la línea de comandos. Por ejemplo, este comando inicia el servidor en el puerto 8080:

$ python3 manage.py runserver 8080
...\> py manage.py runserver 8080

Si deseas cambiar el interfaz (y la dirección IP) del servidor, pásela junto con el puerto. Por ejemplo para escuchar en todas las IPs públicas (útil si estás ejecutando desde el laboratorio docente y quieres verlo desde tu ordenador de casa), utiliza:

$ python3 manage.py runserver 0:8000
...\> py manage.py runserver 0:8000

0 es un atajo para 0.0.0.0.

Recarga automática del comando runserver

El servidor de desarrollo recarga de forma automática el código Python para cada petición cuando sea necesario. No es necesario reiniciar el servidor para que los cambios de código surtan efecto. Sin embargo, algunas acciones como la adición de archivos no provoca un reinicio, por lo que tendrá que reiniciar el servidor en estos casos.

Creando la aplicación calc

Ahora que tu entorno, un «proyecto», se ha configurado, estamos listos para empezar a trabajar.

Cada aplicación que desarrollas en Django consiste en un paquete de Python que sigue una determinada convención. Django tiene una utilidad que genera automáticamente la estructura básica de directorios de una aplicación, por lo que puedes centrarse en la escritura de código en lugar de crear directorios.

Sus aplicaciones se pueden ubicar en cualquier parte dependiendo de la configuración de PYTHONPATH. Pero en estas prácticas vamos a crear nuestra aplicación calc junto al archivo manage.py para que pueda ser importado como su propio módulo de nivel superior, en lugar de un submódulo de proyecto.

Para crear tu aplicación, asegúrate de que estás en el mismo directorio que el archivo manage.py y escribe este comando:

$ python3 manage.py startapp calc
...\> py manage.py startapp calc

Veamos lo que el comando startapp ha creado:

calc/
    __init__.py
    admin.py
    apps.py
    migrations/
        __init__.py
    models.py
    tests.py
    views.py

Estos archivos son:

  • calc/__init__.py: Un archivo vacío que le indica a Python que este directorio debería ser considerado como un paquete Python.
  • calc/admin.py: Un archivo que permite indicar qué tablas de la base de datos podremos gestionar a través de la interfaz de administración vía web. La semana que viene veremos qué significa esto.
  • calc/apps.py: Aquí vienen parámetros de configuración específicos para esta app. Recuerda que settings.py lo hacía para el proyecto.
  • calc/migrations/: Un directorio que contiene todas las versiones de la base de datos, para realizar migraciones de una versión a otra. Veremos qué significa esto la semana que viene.
  • calc/migrations/__init__.py: Un archivo vacío que le indica a Python que este directorio debería ser considerado como un paquete Python.
  • calc/models.py: El modelo es nuestro esquema de base de datos. Hablaremos de ello la semana que viene.
  • calc/tests.py: Aquí vendrán los tests automáticos que podemos hacer. Los tests nos permiten diseñar una batería de pruebas que podemos pasar automáticamente. Así, si tenemos una buena batería, podemos realizar cambios y ver después de manera automática si no hemos roto nada que antes funcionara.
  • calc/views.py: Éste es el archivo con las vistas. Las vistas es lo que hemos venido llamando el "process" en nuestros programas hasta ahora. Lo que el profe en clase llamaba la "lógica del negocio" o la cocina.

En resumen, hoy será de gran importancia el fichero calc/views.py, porque ahí irá el código que se ejecutará cuando sea pertinente.

La semana que viene manejaremos contenidos con bases de datos, que vendrán definidas en calc/models.py, se podrán ver las diferentes vesiones en calc/migrations/ y las podremos manejar vía web con lo que pongamos en calc/admin.py.

Escribe tu primera vista

Vamos a escribir la primera vista. Abre el archivo calc/views.py y pon el siguiente código Python en ella:

calc/views.py
from django.http import HttpResponse


def index(request):
    return HttpResponse("Hola, mundo. Estás en la página de inicio de tu app llamada calc.")

Esta es la vista más simple posible en Django. Nótese que una vista es una función, cuyo primer parámetro, request, es una variable que contiene la información de la petición de manera que podamos acceder fácilmente a la misma (como veremos más adelante). Las vistas han de responder HTTP; en este caso, devolvemos un objeto HttpResponse (que hemos importado de django.http) al cual le podemos pasar como parámetro el contenido de lo que se va a mostrar en el navegador (o sea, la página web).

Para conseguir llamar esta vista, tenemos que asignarle a una URL -- y para ello necesitamos lo que en Django se conoce como una URLconf. Una URLconf es un mecanismo mediante el cual ligamos una URL a una vista. En otras palabras, es una manera de decir que si nos piden la /, se ejecute la vista llamada index. O, como veremos más adelante, habrá una URL que será /sumar/1/2. Pues entonces tendremos que crear una URLconf que haga que se ejecute la función suma con los sumandos 1 y 2. Pero eso lo veremos más adelante.

La URLconf puede ser a nivel de proyecto (por defecto), para lo cual todas las URLs de todas las aplicaciones se encontrarán en proyecto/urls.py. Pero lo mejor es distribuir la URLconf entre las aplicaciones, de manera que cada una de las aplicaciones que creemos tengan la suya propia. Nosotros utilizaremos la segunda opción, por lo que necesitaremos hacer dos cosas: (1) crear una URLconf en calc y (2) indicar en la URLconf del proyecto (la URLconf raíz) que habrá ciertas URLs que las tratará la URLconf de calc.

Para crear una URLconf en el directorio calc, crea un archivo nuevo llamado urls.py. El directorio de tu aplicación debe verse ahora así:

calc/
    __init__.py
    admin.py
    apps.py
    migrations/
        __init__.py
    models.py
    tests.py
    urls.py
    views.py

Incluye el siguiente código en el archivo calc/urls.py (recuerda que este fichero lo vas a tener que crear):

calc/urls.py
from django.urls import path

from . import views

urlpatterns = [
    path('', views.index),
]

El siguiente paso es señalar la URLconf de calc en el raíz. Así, en proyecto/urls.py añade un import para django.urls.include e introduce un include() en la lista urlpatterns, para obtener:

proyecto/urls.py
from django.contrib import admin
from django.urls import include, path

urlpatterns = [
    path('calc/', include('calc.urls')),
    path('admin/', admin.site.urls),
]

La función include() permite hacer referencia a otros URLconfs. Cada vez que Django encuentra include() corta cualquier parte de la URL que coincide hasta ese punto y envía la cadena restante a la URLconf incluida para seguir el proceso, que es justo lo que queremos hacer ahora, que vaya a la URLconf de nuestra app calc. En otras palabras, lLaa idea detrás de include() es facilitar la conexión y ejecución inmediata de las URLs. Dado que la calculadora estará en tu propia URLconf (calc/urls.py) se pueden ubicar en «/calc/», «/fun_calc /», «/content/calc/» o en cualquier otra ruta raíz , y la aplicación todavía seguirá funcionando.

Cuándo utilizar include()

Siempre debe usar include() cuando incluye otros patrones de URL. admin.site.urls es la única excepción a esto.

Hecho esto, hemos conectado la vista index en URLconf. Veamos si funciona correctamente. Lancemos el servidor:

$ python manage.py runserver
...\> py manage.py runserver

Y ve a http://localhost:8000/calc/ con tu navegador. Deberías ver el texto «Hola, mundo. Estás en la página de inicio de tu app llamada calc.» que pusimos en la vista index.

¿Página no encontrada?

Si obtienes aquí una página de error, revisa que estés dirigiéndote a la dirección URL http://localhost:8000/calc/ y no a la dirección URL http://localhost:8000/.

El método path() función puede recibir hasta cuatro argumentos, dos requeridos route y view, que veremos ahora; y dos opcionales kwargs y name, que veremos más adelante:

  • route es una cadena que contiene un patrón de URL. Cuando Django procesa una petición comienza por el primer patrón en urlpatterns y continua hacia abajo por la lista comparando la URL solicitada con cada patrón hasta encontrar aquel que calza. Ten en cuenta que estas expresiones regulares no buscan parámetros GET y POST o el nombre de dominio. Por ejemplo en una petición a la dirección URL https://www.example.com/myapp/, la URLconf buscará myapp/. En una petición a https://www.example.com/myapp/?page=3 la URLconf también buscará myapp/.
  • Cuando Django encuentra una coincidencia de expresiones regulares llama a la función de la vista especificada con un objeto HttpRequest como primer argumento y cualquiera de los valores «capturados» de la ruta como argumentos de palabra clave. Veremos un ejemplo de esto en un momento.

Hacia la calculadora

Una vez que hemos visto cómo hacer que Django reaccione a partir de una petición del navegador, pongámonos manos a la obra para termimar nuestra calculadora. Lo primero que haremos es definir las URLs (en calc/urls.py):

calc/urls.py
from django.urls import path

from . import views

urlpatterns = [
    path('', views.index),
    path('sumar/<int:op1>/<int:op2>', views.add),
    path('restar/<int:op1>/<int:op2>', views.sub),
    path('multiplicar/<int:op1>/<int:op>', views.multi),
    path('dividir/<int:op1>/<int:op2>', views.div),
]

Y ahora vayamos a por las vistas. En calc/views.py pondremos lo siguiente:

calc/views.py
from django.http import HttpResponse


def index(request):
    return HttpResponse("Hola, mundo. Estás en la página de inicio de tu app llamada calc.")

def add(request, op1, op2):
    return HttpResponse(op1+op2)

def sub(request, op1, op2):
    return HttpResponse(op1-op2)

def multi(request, op1, op2):
    return HttpResponse(op1*op2)

def div(request, op1, op2):
    try:
        result = op1/op2
    except ZeroDivisionError:
        result = "No division by zero allowed!"
    return HttpResponse(result)

Prueba a ir a http://localhost:8000/calc/sumar/1/2 con tu navegador... si todo ha ido bien, debería dar 3.

Si has llegado hasta aquí y todavía tienes tiempo, prueba a resumir las cuatro vistas en una única vista (que haga sumar, restar, multiplicar y dividir -- si int es para enteros en URLconf, str lo será para cadenas de caracteres). Puedes para ello también cambiar el URLconf y tener sólo dos líneas (la de index y la de calcular).