Tutorial - Desarrollando Una Aplicación Web Con Python y Django
Tutorial - Desarrollando Una Aplicación Web Con Python y Django
Fuente: pildorasinformaticas
En junio de 2008 fue anunciado que la recién formada Django Software Foundation se haría
cargo de Django en el futuro.
Instalación
>>pip freeze
Django divide el proyecto en varias apps que constan de diferentes partes, las apps realizan
una tarea concreta. La carpeta que se crea al crear el proyecto es la main app. Esta
división está enfocada a mejorar la modularización y reutilización de código entre proyectos.
Otra app en el proyecto agregaría una nueva característica a la aplicación web. Desde la
main app se apuntará a las demás apps.
Crear Proyecto
Archivos creados:
manage.py: Una utilidad de la línea de comandos que le permite interactuar con este
__init__.py: Un archivo vacío que le indica a Python que este directorio debería ser
urls.py: Las declaraciones URL para este proyecto Django; una «tabla de contenidos» de
wsgi.py: Un punto de entrada para que los servidores web compatibles con WSGI puedan
servir su proyecto.
Django trabaja con la clase Request para hacer peticiones y para enviar la respuesta utiliza
HttpResponse.
Una función de vista, o "view" para abreviar, es simplemente una función de Python que
toma una web request y devuelve una web response. Esta respuesta puede ser el
contenido HTML de una página web, o una redirección, o un error 404, o un documento
XML, o una imagen, etc. Ejemplo: Ten en cuenta que necesitas asociar una vista a una URL
para verla como una página web.
Cada vez que se hace un request de una página, Django crea un objeto HttpRequest que
contiene metadatos sobre el request. Después, Django carga la vista apropiada pasando el
objeto HttpRequest como primer argumento a la función de la vista. Cada vista es
responsable de devolver un HttpResponse. Ambos objetos están definidos en django.http.
1) Crear archivo donde se almacenan las vistas que vayamos creando, se llama
views.py por convención dentro de la carpeta de la main app. Posteriormente este
paso no lo haremos en la main app, pero si en las apps.
2) Cada función dentro del archivo views.py es una vista. Se puede pasar HTML como
respuesta pero no se debe hacer así, para eso se utilizarán las plantillas.
def saludo(request):
return HttpResponse("Hola a todos!")
def saludo_html(request):
documento="""<html><body><h1>Hola a todos!</h1></body></html>"""
return HttpResponse(documento)
def despedida(request):
return HttpResponse("Hasta luego!")
3) Hay que enlazar una URL para que devuelva la vista cuando accedemos a las vistas
en el navegador. Se agrega dicha información en urls.py.
Cuando un usuario realiza una solicitud de una página de tu aplicación web, el controlador
Django se encarga de buscar la vista correspondiente a través del archivo url.py, y luego
devuelve la respuesta HTML o un error 404 no encontrado, si no se encuentra. En url.py, lo
más importante es la lista "urlpatterns". Es donde se define el mapeo entre los URLs y las
vistas.
urlpatterns=[
path("admin/",admin.site.urls),
path("saludo/",saludo),
path("saludohtml/",saludo_html),
path("despedida/",despedida)
]
Primero hay que importar la función saludo del archivo correspondiente, y posteriormente
enlazar un path para acceder a dicha vista dentro de la lista urlpatterns. No es necesario
que el nombre del path coincida con el de la vista.
localhost:8000/saludo/
localhost:8000/saludohtml/
localhost:8000/despedida/
(En views.py)
import datetime
def get_fecha(request):
fecha_actual=datetime.datetime.now()
documento="""<html><body><h1>Fecha: %s</h1></body></html>"""%fecha_actual
return HttpResponse(documento)
urlpatterns=[
path("admin/",admin.site.urls),
path("saludo/",saludo),
path("saludohtml/",saludo_html),
path("despedida",despedida),
path("fecha/",get_fecha)
]
(En views.py)
def calcular_edad(request,edad,agno):
periodo=agno-2020
edad_futura=edad+periodo
documento="<html><body><h2>En el año %s tendrás %s años"%(agno,edad_futura)
return HttpResponse(documento)
urlpatterns=[
path("admin/",admin.site.urls),
path("saludo/",saludo),
path("saludohtml/",saludo_html),
path("despedida",despedida),
path("fecha/",get_fecha),
path("edades/<int:edad>/<int:agno>",calcular_edad)
]
Es necesario castear el año que se pasa por parámetro en la URL a entero, por defecto es
string. Testear la vista corriendo el servidor y accediendo a:localhost:8000/edades/60/2029
Plantillas
Son cadenas de texto que tendrán HTML (casi siempre). Sirven para separar la lógica
(datos) de la parte visual (presentación) de un documento web.
Las plantillas se guardan en un archivo diferente y se cargan desde la vista.
1) Crear objeto de tipo template en views.py e importar las clases Template y Context
2) Crear contexto, que son datos adicionales para el template (variables, funciones,
etc, útiles cuando se usa contenido dinámico)
3) Renderizar el contenido con render(contexto)
Proyecto
|--templates
| |--*aquí irán las plantillas*
|--Proyecto
|--__init__.py
|--settings.py
|--urls.py
|--views.py
|--wsgi.py
def saludo(request):
arch=open("C:/Users/usuario/Desktop/Proyecto/Proyecto/templates/plantilla.html")
plt=Template(arch.read())
arch.close()
ctx=Context()
documento=plt.render(ctx)
return HttpResponse(documento)
También se puede pasar el valor directamente en el Contexto sin crear una variable.
ctx=Context({"nombre_persona":"Juan","apellido_persona":"Gonzalez","now":fecha})
Al ser fecha un objeto datetime, se puede acceder a su propiedad day para mostrar solo el
día actual
En este caso, no se deben usar los paréntesis, sólo se pone el nombre del método a llamar.
Cuando Django se encuentra con una instrucción como nombre.upper lo primero que
comprueba es que se trate de un diccionario, sino, de un atributo, después de un método y
por último un índice de lista.
Filtros
El sistema de plantillas de Django tiene etiquetas y filtros incorporados, que son funciones
dentro de la plantilla para representar contenido de una manera específica. Se pueden
especificar varios filtros con canalizaciones y los filtros pueden tener argumentos
Al aplicar estos dos filtros se mostrará sólo la primera letra de cada tema convertida en
minúsculas.
Comentarios en las plantillas
import os
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
Método Shortcut render()
Teniendo el path a las plantillas se puede simplificar aún más el código en las vistas
importando el siguiente recurso.
def saludo(request):
nombre = "Juan"
return render(request,"plantilla.html",{"nombre_persona":nombre})
Plantillas incrustadas
Son plantillas dentro de otras, útiles para reutilizar código que se repite entre páginas. Lo
primero que hay que hacer es determinar dónde se quiere incrustar las plantillas.
Ejemplo:
Proyecto
|--templates
| |--plantilla.html
| |--barra.html
|--Proyecto
|--__init__.py
|--settings.py
|--urls.py
|--views.py
|--wsgi.py
(En plantilla.html modificando la plantilla creada anteriormente)
<html>
<body>
{% include 'barra.html' %}
<ul>
{% if temas_curso %}
{% for tema in temas_curso %}
<li>{{tema|first|lower}}</li>
{% endfor %}
{% else %}
<p>No hay temas que mostrar</p>
{% endif %}
</ul>
</body>
</html>
Proyecto
|--templates
| |--plantilla.html
| |--superior
| |--barra.html
|--Proyecto
|--__init__.py
|--settings.py
|--urls.py
|--views.py
|--wsgi.py
Surge en los casos que se repite el formato de las páginas, pero cambia su contenido.
Consiste en crear una plantilla en base a la cual se van a basar las demás plantillas del
sitio. Al cambiar contenido en la plantilla padre, cambia automáticamente en todas las que
hereden.
} } }
Ejemplo:
Con la etiqueta dentro del <title> se le indica a Django que dicho contenido va a cambiar en
cada plantilla.
Proyecto
|--templates
| |--plantilla.html
| |--base.html
| |--curso.html
| |--superior
| |--barra.html
|--Proyecto
|--__init__.py
|--settings.py
|--urls.py
|--views.py
|--wsgi.py
(En base.html)
<html>
<head>
<title>{% block title %} {% endblock %} </title>
</head>
<body>
{% block content %}
{% endblock %}
</body>
</html>
(En curso.html)
{% extends "base.html" %}
{% block title %} Curso {% endblock %}
{% block content %}
<p>Fecha: {{now}}</p>
{% endblock %}
(En views.py)
from django.http import HttpResponse
import datetime
from django.template import Template,Context
from django.template.loader import get_template
from django.shortcuts import render
def curso(request):
fecha = datetime.datetime.now()
return render(request,"curso.html",{"now":fecha})
(En urls.py)
from django.contrib import admin
from django.urls import path
from Proyecto.views import curso
urlpatterns=[
path("curso/",curso)
]
Botón derecho sobre la base de datos -> Create Database. Posteriormente hacer un
refresh.
Instalar la librería psycopg2 para conectar el proyecto con la base de datos de
PostgreSQL, con un terminal en el directorio del proyecto:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'nombrebasededatos',
'USER': 'postgres',
'PASSWORD': 'contraseña_user',
'HOST': '127.0.0.1',
'PORT': '5432',
}
}
Realizar migraciones
Para crear la base de datos se trabajará con el archivo models.py. Dentro de dicho archivo
se creará una clase por cada tabla que necesitemos en la base de datos. Esto es útil porque
posteriormente se ejecutará el código necesario para el motor de bases de datos que
elijamos, por lo tanto nos abstrae de la sintaxis específica de cada motor.
class Clientes(models.Model):
nombre=models.CharField(max_length=30)
direccion=models.CharField(max_length=50)
email=models.EmailField()
telefono=models.CharField(max_length=7)
class Articulos(models.Model):
nombre=models.CharField(max_length=30)
seccion=models.CharField(max_length=20)
precio=models.IntegerField()
class Pedidos(models.Model):
numero=models.IntegerField()
fecha=models.DateField()
entregado=models.BooleanField()
(En settings.py)
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'gestionPedidos',
]
Los siguientes comandos ejecutarán las sentencias SQL para estructurar la base de datos.
El dato final es el número de migración que figura al haber ejecutado el comando
makemigrations.
Cada vez que se hace un cambio en el modelo hay que volver a migrar
(makemigrations y migrate)
Insertar registros
Con esta primera forma se harán operaciones con registros hasta que sepamos usar los
formularios.
Lo primero que se debe hacer es abrir el shell. El shell se cierra con exit()
Y el registro se ingresa de forma par llave-valor, de esta forma Django creará la consulta,
pero después hay que ejecutarla.
>>art=Articulos(nombre='mesa',seccion='decoracion',precio=90)
>>art.save()
>>art3=Articulos.objects.create(nombre='taladro',seccion='ferreteria',precio=65)
Actualizar registros
>>art3.precio=95
>>art3.save()
Borrar registros
>>art5=Articulos.objects.get(id=6)
>>art5.delete()
>>Lista=Articulos.objects.all()
>>Lista.query.__str__()
#Resultado
>>'SELECT "gestionPedidos_articulos"."id", "gestionPedidos_articulos"."nombre"...'
Introducir registro
class Articulos(models.Model):
nombre=models.CharField(max_length=30)
seccion=models.CharField(max_length=20)
precio=models.IntegerField()
def __str__(self):
return 'El nombre es %s la sección %s y el precio
%s'%(self.nombre,self.seccion,self.precio)
>>Articulos.objects.filter(nombre='mesa',seccion='decoracion')
>>Articulos.objects.filter(seccion='deportes',precio__gte=100)
Order By (ASC)
>>Articulos.objects.filter(precio__gte=50).order_by('precio')
Order By (DESC)
>>Articulos.objects.filter(precio__gte=50).order_by('-precio')
Documentación: https://docs.djangoproject.com/en/3.1/ref/models/querysets/
Panel de Administración
Sirve para manejar el contenido del sitio de una forma más sencilla. Mantiene actualizado el
sitio dado que permite agregar/quitar usuarios, contenido, etc.
Está habilitado por defecto en todos los proyectos de Django. El archivo admin.py sirve
para modificar todo lo relativo al panel de administración. La idea de usar el panel radica en
no tener que escribir las consultas constantemente para cambiar los modelos del proyecto.
urlpatterns=[
path('admin/',admin.site.urls),
]
Django nos pedirá crear un nombre de usuario, un email y contraseña para el usuario.
Cuando se ingresa la contraseña no hay un feedback visual de que insertamos
caracteres, pero los está incluyendo.
No hay que olvidarse de ejecutar el servidor con python manage.py runserver para ver los
cambios impactados en el proyecto.
En la base de datos de PostgreSQL podemos ver la tabla auth_users, Se ven los usuarios
creados con la contraseña encriptada.
En admin.py se codifica lo necesario para modificar los modelos. Hay que importar los
modelos. Django le agrega una s al final todas las tablas en el panel de administrador.
(En admin.py)
from django.contrib import admin
from gestionPedidos.models import Clientes, Articulos, Pedidos
class ClientesAdmin(admin.ModelAdmin):
list_display=("nombre","direccion","telefono",)
admin.site.register(Clientes,ClientesAdmin)
Si está incluido el método __str__() los registros se van a ver de la siguiente manera:
Para hacer que un campo sea opcional hay que modificar el modelo y posteriormente hacer
makemigrations y migrate. No hay que olvidarse tampoco de correr el servidor.
(En models.py)
email=models.EmailField(blank=True,null=True)
Django pone automáticamente en el panel los campos de los modelos con otro formato, lo
cual no quiere decir que los cambie en el modelo, simplemente los formatea en la vista.
(En models.py)
direccion=models.CharField(max_length=50,verbose_name="La dirección")
Resultado final (en models.py)
class Clientes(models.Model):
nombre=models.CharField(max_length=30)
direccion=models.CharField(max_length=50,verbose_name="La dirección")
email=models.EmailField(blank=True,null=True)
telefono=models.CharField(max_length=7)
def __str__(self):
return self.nombre
Si queremos mostrar sólo algunos campos de los modelos desde el panel de administración
tenemos que trabajar con clases que hereden de ModelAdmin. Hay que detener y volver a
arrancar el servidor.
(En admin.py)
from django.contrib import admin
from gestionPedidos.models import Clientes,Articulos,Pedidos
class ClientesAdmin(admin.ModelAdmin):
list_display=("nombre","direccion","telefono",)
admin.site.register(Clientes,ClientesAdmin)
Campo de búsqueda en el Panel
Se utilizará search_fields(), a dicho método hay que indicarle por qué campos necesitamos
hacer las búsquedas.
(En admin.py)
from django.contrib import admin
from gestionPedidos.models import Clientes,Articulos,Pedidos
class ClientesAdmin(admin.ModelAdmin):
list_display=("nombre","direccion","telefono",)
search_fields=("nombre","telefono",)
admin.site.register(Clientes,ClientesAdmin)
Filtros
Crear una nueva clase que herede de ModelAdmin. Con list_filter especificamos el campo a
filtrar. Los campos deben ser escritos de la misma forma que están en la base de datos.
(En admin.py)
from django.contrib import admin
from gestionPedidos.models import Clientes,Articulos,Pedidos
class ClientesAdmin(admin.ModelAdmin):
list_display=("nombre","direccion","telefono",)
search_fields=("nombre","telefono",)
class ArticulosAdmin(admin.ModelAdmin):
list_filter=("seccion",)
admin.site.register(Clientes,ClientesAdmin)
admin.site.register(Articulos,ArticulosAdmin)
Filtrar por fecha
Como el panel está en Inglés, las fechas deben ser agregadas en ese formato:
(En admin.py)
from django.contrib import admin
from gestionPedidos.models import Clientes,Articulos,Pedidos
class ClientesAdmin(admin.ModelAdmin):
list_display=("nombre","direccion","telefono",)
search_fields=("nombre","telefono",)
class ArticulosAdmin(admin.ModelAdmin):
list_filter=("seccion",)
class PedidosAdmin(admin.ModelAdmin):
list_display=("numero","fecha",)
list_filter=("fecha",)
admin.site.register(Clientes,ClientesAdmin)
admin.site.register(Articulos,ArticulosAdmin)
admin.site.register(Pedidos,PedidosAdmin)
Agregar Breadcrumbs
(En admin.py)
from django.contrib import admin
from gestionPedidos.models import Clientes,Articulos,Pedidos
class ClientesAdmin(admin.ModelAdmin):
list_display=("nombre","direccion","telefono",)
search_fields=("nombre","telefono",)
class ArticulosAdmin(admin.ModelAdmin):
list_filter=("seccion",)
class PedidosAdmin(admin.ModelAdmin):
list_display=("numero","fecha",)
list_filter=("fecha",)
date_hierarchy="fecha"
admin.site.register(Clientes,ClientesAdmin)
admin.site.register(Articulos,ArticulosAdmin)
admin.site.register(Pedidos,PedidosAdmin)
(en settings.py)
LANGUAGE_CODE = 'es-eu'
Usuarios
Al primer usuario del panel Django lo asigna como Superusuario. El campo Es Staff
permite que el usuario entre al Panel.
Los pertenecientes a un grupo tienen una serie de permisos asociados, aunque también se
pueden definir más permisos.
Creación de Grupo
Formularios
icontains funciona como el like en SQL: SELECT * FROM Articulos LIKE nombre=" "
Todo aquel registro que tenga la palabra en algún lugar que se ingresó en el formulario se
mostrará.
(En views.py)
from django.shortcuts import render
from django.http import HttpResponse
from gestionPedidos.models import Articulos
def busqueda_productos(request):
return render(request,"busqueda_productos.html")
def buscar(request):
if request.GET["prd"]:
producto=request.GET["prd"]
articulos=articulos.objects.filter(nombre__icontains=producto)
return
render(request,"resultados_busqueda.html",{"articulos":articulos,"query":producto})
else:
mensaje="No has introducido ningún dato"
return HttpResponse(mensaje)
(En urls.py)
from django.contrib import admin
from django.urls import path
from gestionPedidos import views
urlpatterns=[
path('admin/',admin.site.urls),
path('busqueda_productos/',views.busqueda_productos),
path('buscar/',views.buscar),
]
Con la información introducida en el formulario, que llegó al servidor con el GET del objeto
request, podemos hacer una consulta a la base de datos.
Limitar caracteres de búsqueda en consulta a Base de Datos
(En views.py)
from django.shortcuts import render
from django.http import HttpResponse
from gestionPedidos.models import Articulos
def busqueda_productos(request):
return render(request,"busqueda_productos.html")
def buscar(request):
if request.GET["prd"]:
producto=request.GET["prd"]
if len(producto)>20:
mensaje="Texto de búsqueda demasiado largo"
else:
articulos=Articulos.objects.filter(nombre__icontains=producto)
return
render(request,"resultados_busqueda.html",{"articulos":articulos,"query":producto})
else:
mensaje="No has introducido ningún dato"
return HttpResponse(mensaje)
Este error no impide el correcto funcionamiento del proyecto, pero si queremos desactivarlo
necesitamos instalar pylint-django y configurarlo
"python.linting.pylintArgs": [ "--load-plugins=pylint_django", ]
Forms API
Hay que crear un archivo llamado forms.py que tendrá una clase por formulario existente
en el proyecto. Se crea en el mismo directorio que el archivo views.py
(En forms.py)
from django import forms
class FormularioContacto(forms.Form):
asunto=forms.CharField()
email=forms.EmailField()
mensaje=forms.CharField()
Se puede probar con el shell que hay en la instancia del formulario una vez creado. El
método .as_*() siendo * p, ul, etc, formateara el formulario.
>>print(miFormulario.as_p())
>><p><label for="id_asunto">Asunto:</label><input type="text" name="asunto" required
id="id_asunto"></p>
<p><label for="id_email">Email:</label><input type="email" name="email" required
id="id_email"></p>
<p><label for="id_mensaje">Mensaje:</label><input type="text" name="mensaje" required
id="id_mensaje"></p>
>>print(miFormulario.as_ul())
>><li><label for="id_asunto">Asunto:</label><input type="text" name="asunto" required
id="id_asunto"></li>
<li><label for="id_email">Email:</label><input type="email" name="email" required
id="id_email"></li>
<li><label for="id_mensaje">Mensaje:</label><input type="text" name="mensaje" required
id="id_mensaje"></li>
is_valid() es un método de API Forms que si devuelve True (cuando los datos ingresados
en él son válidos) podemos usar la propiedad cleaned_data que devuelve un diccionario
con la información insertada en el formulario.
(En views.py)
def contacto(request):
if request.method=="POST":
miFormulario=FormularioContacto(request.POST)
if miFormulario.is_valid():
infForm=miFormulario.cleaned_data
#Realizar operación con los datos aquí e incluir gracias.html
return render(request,"gracias.html")
else:
miFormulario=FormularioContacto()
return render(request,"formulario_contacto.html",{"form":miFormulario})
Agregar a urls.py
urlpatterns=[
path('admin/',admin.site.urls),
path('busqueda_productos/',views.busqueda_productos),
path('buscar/',views.buscar),
path('contacto/',views.contacto),
]
Podemos comenzar por las vistas, hay que tener tantas vistas como páginas tenga el sitio.
(En views.py)
def home(request):
return HttpResponse("Home")
def servicios(request):
return HttpResponse("Servicios")
def blog(request):
return HttpResponse("Blog")
def tienda(request):
return HttpResponse("Tienda")
def contacto(request):
return HttpResponse("Contacto")
Para tener mejor organizadas las urls es conveniente crear un archivo de urls que va a ser
válido para solo una aplicación. Dentro de ProyectoWebApp crear un archivo urls.py.
(En urls.py dentro de la carpeta de la app)
urlpatterns=[
path('admin/',admin.site.urls),
path('',views.home, name="Home"),
path('servicios',views.servicios,name="Servicios"),
path('tienda',views.tienda,name="Tienda"),
path('contacto',views.contacto,name="Contacto"),
path('blog',views.blog,name="Blog"),
]
urlpatterns=[
path('admin/',admin.site.urls),
path('',include('ProyectoWebApp.urls')),
]
Crear una carpeta dentro de la carpeta del proyecto llamada templates, y dentro de ella una
ProyectoWeb
|--templates
|--ProyectoWebApp
INSTALLED_APPS=[
'django.contrib.admin',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'ProyectoWebApp',
]
...
def servicios(request):
return render(request,"servicios.html")
def blog(request):
return render(request,"blog.html")
def tienda(request):
return render(request,"tienda.html")
def contacto(request):
return render(request,"contacto.html")
Archivos Estáticos
Ir a la carpeta ProyectoWebApp y crear una carpeta para contener a los archivos estáticos.
Será llamada static. Dentro de static se crea otra carpeta con el nombre de la app
“ProyectoWebApp”.
Descargar zip del video de Curso Django - Píldoras Informáticas - Clase 29. Copiar el
contenido de ese zip dentro de la carpeta creada anteriormente.
ProyectoWebApp
|--static----------|
ProyectoWebApp
|--css
|--img
|--vendor
|--home.html
Para cargar los contenidos de la carpeta static (al principio del head):
<head>
{% load static %}
<link href="{% static 'ProyectoWebApp/vendor/bootstrap/css/bootstrap.min.css'%}"
rel="stylesheet">
<link href="{% static 'ProyectoWebApp/css/gestion.css'%}" rel="stylesheet">
</head>
<body>
<script src="{% static 'ProyectoWebApp/vendor/jquery/jquery.min.js' %}"></script>
</body>
El header y el footer deberían ser comunes a todas las páginas, por lo tanto se creará la
herencia de plantillas.
Hacemos una copia de home.html y la renombramos base.html. En la plantilla base.html
se quitan los contenidos que cambiarán entre las páginas que son los siguientes:
Y se agregan en su lugar los bloques que indican que dicha parte del HTML cambiará en las
plantillas que hereden de base.html.
Hay que modificar todas las urls de base.html para que no haya problemas al acceder a las
demás páginas. Hay que hacer coincidir el nombre después de cada url con lo que pusimos
en urls.py. Replicar para todos los enlaces.
<body>
<ul class="navbar-nav mx-auto">
<li class="nav-item active px-lg-4">
<a class="nav-link text-uppercase text-expanded" href="{%url
'Home'%}">Inicio</a>
</li>
</ul>
</body>
En home.html hay que borrar todo lo que es de base.html. Básicamente se borra todo
menos el section heading y el section message.
El block content se abre cuando empiezan los contenidos propios de home.html y se
cierra cuando terminan.
{% extends "ProyectoWebApp/base.html" %}
{% load static %}
{% block content %}
<!-- Heading -->
<section class="page-section clearfix"></section>
<!-- Message -->
<section class="page-section cta"></section>
{% endblock %}
(En settings.py)
...
INSTALLED_APPS=[
'django.contrib.admin',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'ProyectoWebApp',
'servicios',
]
Mapeo ORM: Mapeo Objeto-Relacional: Se crea un objeto en código que representa a la
tabla de la Base de Datos con sus propiedades.
Ir a servicios/models.py
class Servicio(models.Model):
titulo=models.CharField(max_length=50)
contenido=models.CharField(max_length=50)
imagen=models.ImageField()
created=models.DateTimeField(auto_now_add=True)
updated=models.DateTimeField(auto_now_add=True)
class Meta:
verbose_name='servicio'
verbose_name_plural='servicios'
def __str__(self):
return self.titulo
Cuando se quiera subir el proyecto al servidor hay que setear el Debug en False.
(En settings.py)
DEBUG = True
Crear dentro de la carpeta del proyecto una carpeta media. En esa carpeta se subirán las
fotos cargadas en servicios, dentro del panel de administrador.
ProyectoWeb
|--media
|--ProyectoWeb
|--ProyectoWebApp
|--servicios
(En settings.py)
import os
STATIC_URL = '/static/'
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR,'media')
Al modificar el modelo agregar para la imagen upload_to para crear una subcarpeta
“servicios” dentro de media y que las imágenes que se suban dentro de esa app lo hagan
allí.
(En servicios/models.py)
from django.db import models
class Servicio(models.Model):
titulo=models.CharField(max_length=50)
contenido=models.CharField(max_length=50)
imagen=models.ImageField(upload_to="servicios")
created=models.DateTimeField(auto_now_add=True)
updated=models.DateTimeField(auto_now_add=True)
class Meta:
verbose_name='servicio'
verbose_name_plural='servicios'
def __str__(self):
return self.titulo
urlpatterns=[
path('',views.home, name="Home"),
path('servicios',views.servicios,name="Servicios"),
path('tienda',views.tienda,name="Tienda"),
path('contacto',views.contacto,name="Contacto"),
path('blog',views.blog,name="Blog"),
]
urlpatterns+=static(settings.MEDIA_URL,document_root=settings.MEDIA_ROOT)
(En servicios/admin.py)
from django.contrib import admin
from .models import Servicio
class ServicioAdmin(admin.ModelAdmin):
readonly_fields=('created','updated')
admin.site.register(Servicio,ServicioAdmin)
(En views.py)
from django.shortcuts import render,HttpResponse
from servicios.models import Servicio
def home(request):
return render(request,"home.html")
def servicios(request):
servicios=Servicio.objects.all()
return render(request,"servicios.html",{"servicios":servicios})
def blog(request):
return render(request,"blog.html")
def tienda(request):
return render(request,"tienda.html")
def contacto(request):
return render(request,"contacto.html")
(En servicios.html)
{% extends "ProyectoWebApp/base.html" %}
{% load static %}
{% block content %}
{% for servicio in servicios %}
<section class="page-section clearfix">
<div class="container">
<div class="intro">
<img class="intro-img img-fluid mb-3 mb-lg-0 rounded"
src="{{servicio.imagen.url}}" alt="" style="width: 50%;">
<div class="intro-text left-0 text-center bg-faded p-5 rounded">
<h2 class="section-heading mb-4">
<span class="section-heading-lower">{{servicio.titulo}}</span>
<span class="section-heading-upper">{{servicio.contenido}}</span>
</h2>
</div>
</div>
</div>
</section>
{% endfor %}
{% endblock %}
App Blog
Todos los post creados por un usuario deben ser dados de baja cuando el mismo da de
baja su cuenta en el sitio. Eso se hace con el atributo on_delete=models.CASCADE.
Una categoría puede estar en varios post y un post puede estar en varias categorías, esa
relación se define con models.ManyToManyField(Categoria).
(En blog/models.py)
from django.db import models
from django.contrib.auth.models import User
class Categoria(models.Model):
nombre=models.CharField(max_length=50)
created=models.DateTimeField(auto_now_add=True)
updated=models.DateTimeField(auto_now_add=True)
class Meta:
verbose_name="categoria"
verbose_name_plural="categorias"
def __str__(self):
return self.nombre
class Post(models.Model):
titulo=models.CharField(max_length=50)
contenido=models.CharField(max_length=50)
imagen=models.ImageField(upload_to="blog")
autor=models.ForeignKey(User,on_delete=models.CASCADE)
categorias=models.ManyToManyField(Categoria)
created=models.DateTimeField(auto_now_add=True)
updated=models.DateTimeField(auto_now_add=True)
class Meta:
verbose_name="post"
verbose_name_plural="posts"
def __str__(self):
return self.titulo
...
INSTALLED_APPS=[
'django.contrib.admin',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'ProyectoWebApp',
'servicios',
'blog',
]
...
Crear migraciones.
(En blog/admin.py)
from django.contrib import admin
from .models import Categoria,Post
class CategoriaAdmin(admin.ModelAdmin):
readonly_fields=("created","updated")
class PostAdmin(admin.ModelAdmin):
readonly_fields=("created","updated")
admin.site.register(Categoria,CategoriaAdmin)
admin.site.register(Post,PostAdmin)
def home(request):
return render(request,"home.html")
def servicios(request):
servicios=Servicio.objects.all()
return render(request,"servicios.html",{"servicios":servicios})
def blog(request):
posts=Post.objects.all()
return render(request,"blog.html",{"posts":posts}})
def tienda(request):
return render(request,"tienda.html")
def contacto(request):
return render(request,"contacto.html")
(En blog.html)
{% extends "ProyectoWebApp/base.html" %}
{% load static %}
{% block content %}
{% for post in posts %}
<section class="page-section clearfix">
<div class="container">
<div class="intro">
<img class="intro-img img-fluid mb-3 mb-lg-0 rounded"
src="{{post.imagen.url}}" alt="" style="width: 50%;">
<div class="intro-text left-0 text-center bg-faded p-5 rounded">
<h2 class="section-heading mb-4">
<span class="section-heading-lower">{{post.titulo}}</span>
<span class="section-heading-upper">{{post.contenido}}</span>
</h2>
<div style="text-align: left; font-size: 15px;">
Autor: {{post.autor}}
</div>
</div>
</div>
</div>
</section>
{% endfor %}
<section>
<div style="width: 75%; margin: auto; text-align: center; color: white;">
Categorías:
{% for post in posts %}
{% for categoria in post.categorias.all %}
{{categoria.nombre}}
{% endfor %}
{% endfor %}
</div>
</section>
{% endblock %}
Deployment
Leer artículo:
https://developer.mozilla.org/es/docs/Learn/Server-side/Django/Deployment
Video: https://www.youtube.com/watch?v=XdZeg3iP5BM&ab_channel=codigofacilito
Fuente: tecon.es
La nube es un tipo de tecnología que permite tener todos nuestros archivos y ficheros en
Internet, sin tener que preocuparnos por si hay capacidad suficiente para almacenar
información o programas en nuestro ordenador o servidor local. ¿Qué tipos de nube existen
y cómo funcionan? Te explicamos las diferencias entre los tipos de infraestructura cloud:
IaaS, PaaS y SaaS.
En primer lugar, hay que destacar que las tres modalidades de hosting cloud tienen varios
aspectos en común:
1. Proporcionan acceso a unos recursos que se encuentran en la nube – datacenters
con gran cantidad de servidores – a los que se accede mediante Internet.
2. Pagas por el espacio o rendimiento que usas.
3. Pueden ser utilizadas por las empresas para crear aplicaciones o soluciones con
poca inversión. Cuando se han probado, es muy fácil ampliar recursos.
4. La administración del hardware la lleva a cabo el proveedor del servicio cloud,
ahorrando costes de mantenimiento a las empresas.