John Cardozo
Software Engineer
John Cardozo
John Cardozo
Framework web
Escrito en Python
Open source
Multiplataforma
MVC
SISTEMA OPERATIVO
Python 2.7
Python 3.2
Python 3.9
Paquetes
Paquetes
Paquetes
Proyecto 1
Proyecto 2
Proyecto 3
requirements.txt
requirements.txt
requirements.txt
Cada proyecto se ejecuta en su propio ambiente virtual
Los ambientes virtuales no se guardan en Git. Sólo el código fuente y el archivo requirements.txt
El archivo requirements.txt contiene los paquetes que se instalan en el ambiente virtual.
Los paquetes no se debe instalar en el sistema operativo
Cada ambiente virtual tiene su propia versión de Python con la cual se ejecuta el proyecto
Ambientes
Ambiente1
Ambiente2
Ambiente3
Proyectos
Proyecto1
Proyecto2
Proyecto3
Cada folder de proyecto contiene:
- Código fuente
- requirements.txt
Cada ambiente virtual se crea en un folder donde se instalan los paquetes que necesita el proyecto para ejecutarse
Git
Instalar virtualenv
pip install virtualenv
Crear ambiente virtual
virtualenv nombre_entorno
Activar un ambiente virtual
source bin/activate
Scripts/activate
Desactivar un ambiente virtual
deactivate
Generar archivo de paquetes
pip freeze > requirements.txt
Ver paquetes instalados en el ambiente virtual
pip freeze
Se debe activar los permisos de ejecución de Scripts en Powershell
Set-ExecutionPolicy Unrestricted
Instalar Django
pip install django
Actualizar Django
pip install -U django
La instalación de Django se debe hacer en el ambiente virtual activo
app
Categoria
Pelicula
*
1
django-admin startproject nombre_proyecto .
Crear proyecto
python manage.py runserver
Si no se agrega el punto al final de la instrucción, se crea un directorio con el nombre de proyecto
Ejecutar el proyecto
python manage.py runserver 0.0.0.0:8000
Ejecutar el proyecto permitiendo peticiones externas
ALLOWED_HOSTS = ['*']
Modificar settings.py para permitir peticiones externas
Navegar en el browser a
View
Model
Template
1
2
3
4
Base de Datos
Routing
5
Cliente
6
Proyecto
urls.py
Aplicación
urls.py
views.py
models
templates
Cliente
http
html
css
js
img
INSTALLED_APPS = [
'app',
]
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('', include('app.urls')),
path('admin/', admin.site.urls),
]
Se agrega la línea 2
Se agrega include a la línea 2
Se agrega la línea 5
python manage.py startapp nombre_aplicacion
Agregar una aplicación al proyecto
Este comando se debe ejecutar en el directorio del proyecto
Proyecto: settings.py
Proyecto: urls.py
from django.urls import path
from . import views
app_name = 'app'
urlpatterns = [
path('', views.index, name='index'),
]
urls.py
from django.shortcuts import render
from django.http import HttpResponse
def index(request):
return HttpResponse("Hola, mundo")
views.py
El archivo urls.py no existe y se debe crear
from django.urls import path
from . import views
app_name = 'app'
urlpatterns = [
path('', views.index, name='index'),
path('peliculas/', views.view_pelicula, name='peliculas'),
path('peliculas/<int:id>/', views.view_peliculas, name='pelicula'),
]
urls.py
def view_peliculas(request):
return HttpResponse("<h1>peliculas del catalogo</h1>")
def view_pelicula(request, id):
print(id) # Imprime el valor en consola
return HttpResponse("Esta es la pelicula " + id)
views.py
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Películas</title>
</head>
<body>
<h1>Esta es la página de películas</h1>
</body>
</html>
Crear el archivo en la carpeta templates/app/peliculas.html
from django.shortcuts import render
def view_peliculas(request):
return render(request, 'app/peliculas.html')
Desde el view se hace un render del template
from django.shortcuts import render
def view_peliculas(request):
# Crea el contexto
contexto = {
'lista_peliculas': [
{'id': 1, 'nombre': 'die hard'},
{'id': 2, 'nombre': 'lethal weapon'},
],
}
# Envía el resultado al template
return render(request, 'app/peliculas.html', contexto)
Envío de datos de view a template
<h1>Películas</h1>
{% if lista_peliculas %}
<ul>
{% for p in lista_peliculas %}
<li>{{ p.nombre }}</li>
{% endfor %}
</ul>
{% else %}
<h2>No hay pelicula!!!</h2>
{% endif %}
El template muestra los datos enviados desde el view
peliculas.html
{% for p in lista_peliculas %}
<li>
<a href="{% url 'app:pelicula' p.id %}">
{{ p.nombre }}
</a>
</li>
{% endfor %}
Se usa la función {% url 'nombre_url' %}
El parámetro 'nombre_url' se obtiene del archivo 'urls.py' en el atributo 'name' de la url.
path(
'peliculas/<int:id>/',
views.view_pelicula,
name='pelicula'
)
Crear el directorio: static/app/ dentro de la carpeta app
En esta carpeta se copian los archivos estáticos: css, js, img
Estructura de archivos
Uso de archivos estáticos en el template
{% load static %}
<link href="{% static 'app/css/estilo.css' %}" rel="stylesheet">
<script type="text/javascript"
src="{% static 'app/js/index.js' %}">
</script>
<img src="{% static 'app/img/logo.jpg' %}" alt="logo">
{% load static %}
Carga de la función static (debe ser la 1era. instrucción)
Algunas veces, el servidor de desarrollo no reconoce la nueva estructura de directorios. Reinicie el servidor y prueba de nuevo.
!
{% static 'app/folder/archivo' %}
Estructura el uso de la función static
Estructura de página
header
nav
content
footer
pagina2.html
header
nav
content
header
pagina1.html
header
nav
content
header
pagina3.html
header
nav
content
header
base.html
header
nav
content
footer
pagina2.html
content 2
pagina1.html
content 1
pagina3.html
content 3
padre
hijas
herencia
define bloques
sobreescribe bloques los bloques definidos por el padre
{% block titulo %}{% endblock %}
{% block contenido%}{% endblock %}
El template padre define los bloques
{% block titulo %}Pagina de peliculas{% endblock %}
{% block contenido %}
<h1>Movies</h1>
<p>...</p>
{% endblock %}
El template hijo sobreescribe los bloques del padre
{% extends "app/base.html" %}
El template hijo hereda del template padre
la página hija sobreescribe el bloque definido por la página padre
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block titulo %}{% endblock %}</title>
<link rel="stylesheet" href="{% static 'app/css/estilo.css' %}">
</head>
<body>
{% block contenido%}{% endblock %}
</body>
</html>
Template padre (p.e. base.html)
{% extends "app/base.html" %}
{% load static %}
{% block titulo %}Pagina de peliculas{% endblock %}
{% block contenido %}
<h1>Movies</h1>
<p>...</p>
{% endblock %}
Template hija (p.e. movies.html)
Python
Base de datos
Object Relational Mapping
creación
API
Operaciones de lectura y escritura a la base de datos utilizando objetos de la aplicación
Evita el uso de sentencias SQL
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'database_name',
'USER': 'username',
'PASSWORD': 'password',
'HOST': '127.0.0.1',
'PORT': '5432',
}
}
settings.py
PSYCOPG2
# Windows
pip install psycopg2
# Mac
pip install psycopg2-binary
from django.db import models
class Categoria(models.Model):
nombre = models.CharField(max_length=200, null=True)
descripcion = models.TextField(null=True)
fecha_creacion = models.DateTimeField(auto_now_add=True)
class Meta:
app_label = 'app'
paquete models
clase
campos
nombre = models.CharField(max_length=200, null=True)
Estructura de un campo
Estructura de un clase
nombre
tipo
opciones
activo = models.BooleanField(null=True)
BooleanField
apellidos = models.CharField(max_length=10)
# max_length: máxima longitud del campo
CharField
fecha_creacion = models.DateField(auto_now=False,
auto_now_add=False)
# auto_now: automáticamente guarda la fecha
# cada vez que se guarda el objeto
# auto_now_add: automáticamente guarda la fecha
# en que se creó el objeto
DateField
edad = models.IntegerField()
IntegerField
descripcion = models.TextField()
TextField
fecha_creacion = models.DateTimeField(auto_now=False,
auto_now_add=False)
# auto_now: automáticamente guarda la fecha
# cada vez que se guarda el objeto
# auto_now_add: automáticamente guarda la fecha
# en que se creó el objeto
DateTimeField
valor = models.DecimalField(max_digits=3, decimal_places=2)
# max_digits: máximo número de dígitos
# decimal_places: número de lugares decimales
DecimalField
class Pelicula(models.Model):
titulo = models.CharField(max_length=200, null=True)
categoria = models.ForeignKey(
Categoria,
related_name='peliculas',
on_delete=models.PROTECT
)
nombre del campo
clase con la cual se hace la relación
Acción al borrar el objeto:
- CASCADE
- PROTECT
- SET NULL
- DO NOTHING
Nombre con el que se referencia el conjunto de películas desde la clase Categoria.
class Persona(models.Model):
nombres = models.CharField(max_length=50)
apellidos = models.CharField(max_length=50)
class Pasaporte(models.model):
numero = models.CharField(max_length=20)
nacionalidad = models.CharField(max_length=50)
fecha_vencimiento = models.DateField()
persona = models.OneToOneField(
Persona,
on_delete = models.CASCADE,
null = False,
primary_key=True,
related_name='pasaporte'
)
OneToOneField
Persona
Pasaporte
1
1
class Categoria(models.Model):
nombre = models.CharField(max_length=200, null=False)
descripcion = models.TextField(null=True)
def __str__(self):
return self.nombre
class Meta:
app_label = 'app'
from django.db import models
Importar el paquete models
Clase Categoria en archivo models.py
class Pelicula(models.Model):
titulo = models.CharField(max_length=200, null=False)
year = models.IntegerField(null=True)
descripcion = models.TextField(null=True)
categoria = models.ForeignKey(Categoria,
related_name='peliculas',
null=False,
on_delete=models.PROTECT)
fecha_creacion = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.titulo
class Meta:
app_label = 'app'
Clase Pelicula en archivo models.py
python manage.py makemigrations
Crea las migraciones
python manage.py migrate
Ejecuta las migraciones
Cada vez que hay algún cambio en la estructura del modelo se debe ejecutar las siguientes instrucciones
!
1
2
Inicio de la consola del API
python manage.py shell
from app.models import Categoria
Importar una clase
# Crea el objeto
categoria = Categoria(nombre='accion')
# Guarda el objeto en la base de datos
categoria.save()
Crear y guarda un objeto en la base de datos
# Actualiza el valor del atributo
categoria.nombre = 'Drama'
# Guarda el objeto en la base de datos
categoria.save()
Actualizar un objeto en la base de datos
categoria.delete()
Eliminar un objeto
# Obtiene un objeto de tipo Categoria
cat1 = Categoria.objects.get(id=1)
# Crea una pelicula en la categoria
cat1.peliculas.create(titulo='John Wick')
Crear un objeto relacionado
related_name
# Se puede consultar por id o pk
categoria1 = Categoria.objects.get(id=2)
categoria2 = Categoria.objects.get(pk=2)
Obtener un objeto por su PK o id
id = categoria.id
nombre = categoria.nombre
Obtener los atributos de un objeto
# Implicitamente invoca el metodo __str__
print(categoria)
Obtener la versión String de un objeto
categorias = Categoria.objects.all()
Obtener todos los objetos de una tabla
Retorna una lista
Retorna un objeto
Categoria.objects.filter(id=2)
Categoria.objects.filter(nombre='Accion')
Filtrar objetos por un atributo
Categoria.objects.filter(nombre__startswith='Acc')
Categoria.objects.filter(nombre__endswith='a')
Filtrar objetos: inicio o fin de una cadena
Retorna una lista
Retorna una lista
lista = Pelicula.objects.filter(categoria__nombre='accion')
Join entre objetos
Retorna una lista
Pelicula.objects.filter(year__gt=2000)
Comparaciones: mayor
Pelicula.objects.filter(year__gte=2000)
Comparaciones: mayor o igual
Pelicula.objects.filter(year__lt=2000)
Comparaciones: menor
Pelicula.objects.filter(year__lte=2000)
Comparaciones: menor o igual
Pelicula.objects.filter(year__isnull=True)
Comparaciones: valores nulos
# Obtiene un objeto de tipo Categoria
cat1 = Categoria.objects.get(id=1)
# Obtiene las peliculas de la categoria
cat1.peliculas.all()
Obtener los objetos relacionados a otro objeto
# Obtiene un objeto de tipo Categoria
cat1 = Categoria.objects.get(id=1)
# Obtiene las cantidad de peliculas de la categoria
cantidad = cat1.peliculas.count()
Obtener la cantidad de objetos relacionados
Pelicula.objects.order_by('titulo')
Obtener objetos ordenados
lista1 = [p.titulo for p in Pelicula.objects.all()]
lista2 = [(p.titulo, p.year) for p in Pelicula.objects.all()]
Obtener datos específicos de las películas
Retorna una lista
related_name
from django.db.models import Q
# Obtiene la categoria
cat1 = Categoria.objects.get(nombre='accion')
# Obtiene las peliculas del año 2000 y
# de la categoría Acción
Pelicula.objects.filter(
Q(year=2000) & Q(categoria=cat1)
)
Q: Obtener objetos con AND
from django.db.models import Q
# Obtiene la categoria
cat1 = Categoria.objects.get(nombre='accion')
# Obtiene las peliculas del año 2000 o
# de la categoría Acción
Pelicula.objects.filter(
Q(year=2000) | Q(categoria=cat1)
)
Q: Obtener objetos con OR
from django.db.models import Q
# Obtiene la categoria
cat1 = Categoria.objects.get(nombre='accion')
# Obtiene las peliculas según el criterio
Pelicula.objects.filter(
Q(year=2000) |
Q(
Q(categoria=cat1) & Q(year=2001)
)
)
Obtener objetos: AND y OR
Obtiene todas las películas que:
from app.models import Categoria
def view_categorias(request):
# Obtiene los objetos
categorias = Categoria.objects.all()
# Crea el contexto
contexto =
{
'lista_categorias': categorias
}
# Envia el contexto al template
return render(request, 'app/categorias.html', contexto)
View view_categorias: views.py
<ul>
{% for cat in lista_categorias %}
<li>{{ cat.nombre }}</li>
{% endfor %}
</ul>
Template: categorias.html
Frontend y Backend
nombre
crear
Crear categoría
URL
frontend
backend
route
view
model
Lista de categorías
redirect
comedia
petición del cliente
URL
URL
proceso de backend
respuesta al cliente
def form_crear_categoria(request):
return render(request, 'app/form_crear_categoria.html')
View: form_crear_categoria.py
<form action="{% url 'app:crear_categoria' %}" method="post">
{% csrf_token %}
<label>Nombre</label>
<input type="text"
id="nombre" name="nombre">
<button type="submit">Crear</button>
</form>
Template: form_crear_categoria.html
{% csrf_token %}
Requerido en el formulario para peticiones POST al servidor
{% url 'app:crear_categoria' %}
URL a la que se envía la información del formulario
path('categorias/crear/', views.form_crear_categoria,
name='form_crear_categoria'),
path('categorias/crear/post/', views.post_crear_categoria,
name='post_crear_categoria'),
Routing: urls.py
from django.shortcuts import redirect
from app.models import Categoria
def post_crear_categoria(request):
# Obtiene el nombre de la categoría
nombre_categoria = request.POST['nombre']
# Crea el objeto categoría
categoria = Categoria(nombre=nombre_categoria)
# Guarda el objeto en la base de datos
categoria.save()
# Redirecciona a la página de categorías
return redirect('app:categories')
View: post_crear_categoria
nombre del campo en el formulario
título
crear
Crear película
URL
frontend
backend
route
view
model
Lista de películas
redirect
titanic
petición del cliente
URL
URL
proceso de backend
respuesta al cliente
categoría
acción
Película | Categoría |
---|---|
patch adams | comedia |
titanic | acción |
def form_crear_pelicula(request):
# Obtiene las categorias
lista_categorias = Categoria.objects.all()
# Crea el contexto
contexto = {
'lista_categorias': lista_categorias
}
return render(request, 'app/form_crear_pelicula.html', contexto)
View: form_crear_pelicula.py
<form action="{% url 'app:post_crear_pelicula' %}" method="post">
{% csrf_token %}
<label>Titulo</label>
<input type="text" id="titulo" name="titulo">
<label>Categoria</label>
<select name="categoria" id="categoria">
{% for c in lista_categorias %}
<option value="{{c.id}}">{{c.nombre}}</option>
{% endfor %}
</select>
<button type="submit">Crear</button>
</form>
Template: form_crear_pelicula.html
path('peliculas/crear/', views.form_crear_pelicula,
name='form_crear_pelicula'),
path('peliculas/crear/post/', views.post_crear_pelicula,
name='post_crear_pelicula'),
Routing: urls.py
from django.shortcuts import redirect
from app.models import Categoria, Pelicula
def post_crear_pelicula(request):
# Obtiene los datos de la pelicula
titulo = request.POST['titulo']
id_categoria = int(request.POST['categoria'])
# Obtiene la categoria
categoria = Categoria.objects.get(pk=id_categoria)
# Crea la pelicula
pelicula = Pelicula(titulo=titulo)
pelicula.categoria = categoria
pelicula.save()
# Redirecciona a la página de peliculas
return redirect('app:peliculas')
View: post_crear_pelicula
transforma el valor recibido formulario a un valor entero
User, login y logout
Atributos de la clase
Nombre | Tipo de dato | Descripción |
---|---|---|
id | int | Identificador del usuario. llave primaria de la tabla |
username | string | Username del usuario. Este campo no puede estar repetido |
first_name | string | Nombres del usuario |
last_name | string | Apellidos del usuario |
string | Email del usuario | |
is_superuser | boolean | Indica si el usuario es administrador |
is_active | boolean | Indica si el usuario está activo |
date_joined | datetime | Fecha y hora en la que se creó el usuario |
last_login | datetime | Fecha y hora de la última vez que se autenticó el usuario |
La tabla en la base de datos en la cual se almacena la información del usuario es auth_user
# Librería de la clase User
from django.contrib.auth.models import User
# Crea el objeto User
usuario = User(username='john', email='john@gmail.com')
# El método set_password encripta el password
usuario.set_password('123')
# Almacena el usuario en la base de datos
usuario.save()
Creación de un usuario en la base de datos
# Librería de la clase User
from django.contrib.auth.models import User
# Obtiene el usuario de la base de datos
usuario = User.objects.get(username='john')
# Modifica el apellido
usuario.last_name = 'Lennon'
# Modifica el password.
# El método set_password encripta el password
usuario.set_password('123')
# Guarda el usuario en la base de datos
usuario.save()
# Importar la función authenticate
from django.contrib.auth import authenticate
# Obtiene un usuario con username=john y password=123
usuario = authenticate(username='john', password='123')
La función authenticate busca el usuario en el sistema
Si el objeto usuario es diferente a None, el usuario existe en el sistema
# Importar la función login
from django.contrib.auth import login
# Inicia sesión del usuario en el sistema
login(request, usuario)
La función login inicia sesión de un usuario en el sistema
logout(request)
La función logout cierra la sesión
un usuario en el sistema
# Librerias
from django.contrib.auth import logout
# Cierra la sesión del usuario en el sistema
logout(request)
<form action="{% url 'app:registrar' %}" method="post">
{% csrf_token %}
<span>Usuario:</span>
<input type="text" name="username">
<br>
<span>Nombres:</span>
<input type="text" name="nombres">
<br>
<span>Email:</span>
<input type="email" name="email">
<br>
<span>Password:</span>
<input type="password" name="password">
<br>
<button type="submit">Crear cuenta</button>
</form>
template: registro.html
path('registro/', views.form_registro, name='form_registro'),
path('registrar/', views.registrar, name='registrar'),
urls.py
def form_registro(request):
return render(request, 'app/registro.html')
def registrar(request):
# Obtiene los datos
username = request.POST['username']
nombres = request.POST['nombres']
email = request.POST['email']
password = request.POST['password']
# Crea el objeto usuario
usuario = User(username=username, first_name=nombres, email=email)
usuario.set_password(password)
# Guarda el usuario en la base de datos
usuario.save()
return redirect('app:form_login')
views.py
path('login/', views.form_login, name='form_login'),
path('autenticar/', views.autenticar, name='autenticar'),
urls.py
from django.contrib.auth import authenticate, login
def form_login(request):
return render(request, 'app/login.html')
def autenticar(request):
# Obtiene los datos del formulario de autenticación
username = request.POST['username']
password = request.POST['password']
# Obtiene el usuario
usuario = authenticate(username=username, password=password)
# Verifica si el usuario existe en la base de datos
if usuario is not None:
# Inicia la sesión del usuario en el sistema
login(request, usuario)
# Redirecciona a una página de éxito
return redirect('app:peliculas')
else:
# Retorna un mensaje de error de login no válido
return render(request, 'app/login.html')
views.py
<form action="{% url 'app:autenticar' %}" method="post">
{% csrf_token %}
<span>Usuario:</span>
<input type="text" name="username">
<br>
<span>Password:</span>
<input type="password" name="password">
<br>
<button type="submit">Ingresar</button>
</form>
template: login.html
<span>{{ request.user.first_name }}</span>
Mostrar usuario autenticado. Template: base.html
<span>{{ request.user.is_authenticated }}</span>
Verificar si el usuario está autenticado. Template: base.html
path('logout/', views.view_logout, name='view_logout'),
urls.py
def view_logout(request):
# Cierra la sesión del usuario
logout(request)
# Redirecciona la página de login
return redirect('app:form_login')
views.py
<a href="{% url 'app:view_logout' %}">Salir</a>
Link para salir del sistema. Template: base.html
{{ request.user.first_name }}
Template: Mostrar el usuario autenticado
if request.user.is_authenticated:
# Acción si el usuario está autenticado
else:
# Acción si el usuario no está autenticado
View: Verificar si un usuario está autenticado
{% if request.user.is_authenticated %}
{{ request.user.first name }}
{% else %}
<span>Por favor, ingresar al sistema</span>
Template: Verificar si un usuario está autenticado
request.user
View: Obtener el usuario autenticado
from django.contrib.auth.decorators import login_required
@login_required
def view_peliculas(request):
pass
@login_required: views.py
LOGIN_URL='/login'
URL de login para el proyecto: settings.py
Se agrega @login_required en todos los views que estén protegidos
Si se intenta ingresar a un view que esté protegido por @login_required se redireccionará automáticamente a settings.LOGIN_URL
johncardozo@gmail.com
By John Cardozo
Django, Model View Template, routing, views, templates, ORM, modelo, migraciones, API, formularios, autenticación