Creado para la comunidad de programadores de habla hispana
Cyber Coffe es un blog de programación dedicado a tutoriales y ejemplos de proyectos usando
varios lenguajes, frameworks y herramientas, explicando estos de manera fácil y objetiva
desde como crearlos hasta el uso de GIT/GitHub y su despliegue
"Antes que nada quisiera aclarar que esto es solo por aportar mi pedacito en apoyar a las personas de habla hispana que están iniciando en este mundo por lo
que cada vez que los invite a ver la explicación detallada en mis videos no es necesario dar un like ni subscribirse si no lo desean
es solo porque creo que con palabras y ejemplos pueden llegar a entender mucho mejor"
Requisitos para este proyecto:
Conocimientos previos de Python
Conocimientos basicos de Django
En este proyecto vamos a desarollar un ToDo List utilizando el patrón de arquitectura de software Modelo-Vista-Template
(MVT) o como bien se conoce Modelo-Vista-Controlador(MVC).
IMPORTANTE: Todo el código se encuentra disponible en GitHub por lo que debajo de cada foto de cada archivo que estemos modificando
se encontrará el link para obtener el código en GitHub, aunque si eres principiante te recomendaría escribirlo entero tu mismo
Instalación y Configuración
Para ello primero vamos a asegurarnos de tener instalado Python en nuestra PC o Laptop, luego vamos a crear nuestro entorno
de desarrollo para el proyecto de la siguiente manera:
Nos ubicamos en nuestra carpeta raíz del proyecto y ejecutamos el comando:
python -m venv nombre-entorno
Con esto ya debe crearse nuestro entorno y ahora procedemos a activarlo con el siguiente comando:
nombre_entorno\scripts\activate
Luego de ejecutar esto deberias ver tu consola de la siguiente manera:
El siguiente paso sera instalar django en nuestro entorno y para ellos ejecutaremos el siguiente comando:
pip install django
"Por favor asegurarnos de que en todo momento tengamos nuestro entorno activado"
Ahora vamos a iniciar nuestro proyecto de django con el comando
django-admin-startproject ToDo .
Es importante luego del nombre que deseamos darle a nuestro proyecto colocar espacio+punto " ."
ya que con esto nos aseguramos de que el proyecto se cree dentro de la carpeta que designamos para este
en lugar de crearse otra adicional.
Para verificar que nuestro proyecto ha sido creado con exito ejecutamos el siguiente comando:
python manage.py runserver
"Esto permitira correr nuestro servidor de desarrollo local y si copiamos la url donde se encuentra corriendo el servidor
que por defecto es http://localhost:8000 y la insertamos en nuestro navegador tendremos esto:"
Ya tenemos nuestro entorno creado y activo, tenemos instalado Django y nuestro proyecto creado; Ahora procederemos a
crear nuestra app la cual gestionará nuestras tareas para ello ejecutamos el siguiente comando:
python manage.py startapp task
"Es importante que sepan que muchas de las cosas que voy a tratar se las daré en inglés excepto las explicaciones,
con el fin de que se familiaricen con el idioma debido a su gran importancia en el mundo profesional"
En este punto nuestro directorio debería verse algo así:
Luego necesitaremos ubicar nuestro settings.py dentro de la carpeta de nuestro proyecto y dirigirnos hacia
las INSTALLED_APPS ahí incluiremos la aplicación tarea que hemos creado y asi quedará registrada:
Es necesario aclarar que ya deben tener conocimientos mínimos de Django ya que solo estaré explicando todas las partes
necesarias especificamente para este proyecto. Para explicación mas detallada sobre la parte de los modelos en Django te invito a visitar el
video sobre Models de mi canal de YouTube:
Si se fijaron luego de correr nuestro servidor local se creó un archivo llamado db.sqlite3 en nuestro directorio raíz el
cual sera nuestra base de datos local o de desarrollo
Teniendo en cuenta lo antes visto ahora vamos a crear nuestro modelo para la app de tarea
Primero ubicamos nuestro archivo models.py y dentro de él agregamos los siguientes campos los cuales nos permitirán crear
las columnas dentro de nuestra tabla tarea en la base de datos para luego guardar la información necesaria
from django.db import models
class Task(models.Model):
title = models.CharField(max_length = 50, null = False)
body = models.TextField(max_length= 200, null =True, blank = True)
objects = models.Manager() # The default manager.
class Meta:
verbose_name = 'Task'
verbose_name_plural = 'Tasks'
db_table = 'Task'
def __str__(self):
return self.title
Luego de crear nuestro modelo necesitamos registrar esta nueva tabla en nuestra base de datos y para ello ejecutamos el
comando:
python manage.py makemigrations
Con esto se nos creara una carpeta dentro de nuestra app, llamada migrations
en la cual estará guardado todos los cambios en la estructura de nuestro modelo, es importante aclarar que cada vez que se
realice un cambio en nuestro modelo debemos crear la migracion con el comando antes mencionado
Ya creamos nuestras migraciones pero aun no existen en nuestra base de datos para ello vamos a ejecutar el comando:
python manage.py migrate
Con esto nuestro modelo con sus respectivos campos quedaran registrados en la base de datos. Y para comprobar esto podemos instalar la aplicación DB Browser para poder visualizar nuestra base de datos sqlite3
y comprobar que se creo nuestra tabla con exito o bien si estamos usando Vs Code instalar la extension SQLite Viewer y solo necesitan
hacer click en el archivo .sqlite3 para abrirlo con esta extensión
La razón de que este salga con letra mayúscula en la base de datos es porque antes en nuestro modelo estuvimos
personalizando los metadatos de este a través de su clase META al igual que el método string al final del modelo
que nos permite definir cuales son los campos que queremos mostrar en la vista previa del panel de administración
de django. Pero como dije antes sería mucho mas fácil para ustedes entender esto con palabras por lo que pueden ver
la explicación completa de lo que estuvimos haciendo acá: Link del Video
ADMIN SITE
Ahora vamos a interactuar un poco con nuestro modelo ya creado y para ello utilizaremos el Admin Site de django
Antes debemos registrar nuestro modelo en el sitio de administracion para que este aparezca por lo que vamos a nuestro
admin.py dentro de nuestra app tarea y dentro de el escribimos el siguiente código:
from django.contrib import admin
from .models import Task
admin.site.register(Task)
Debemos fijarnos bien en las importaciones que estoy mostrando en el código ya que evidentemente antes de usar una clase que esta contenida
dentro de otro archivo debemos importarlo
Luego de esto nuestro modelo ya aparecerá en nuestro panel de administración
Para visitarlo volvemos a levantar nuestro servidor de desarrollo con el comando antes mencionado para esto y visitar nuevamente la url
con nuestro navegador pero con la particularidad de que agregamos admin/ a nuestra ruta:
http://localhost:8000/admin/
Como resultado tendremos esto y es que antes debemos crear nuestro super usuario y para ello cancelamos nuestro servidor local
con "Ctrl+C", si al igual que yo no les gusta ver la consola muy cargada pueden limpiarla escribiendo "cls" en Windows o "Ctrl+L"
en Linux
Dicho esto vamos a crear nuestro super usuario y lo haremos con el comando:
python manage.py createsuperuser
Nos saldrá esto y solo ponemos el usuario, email y la contraseña que deseamos, es importante aclarar que cuando escriban la contraseña no la podrán visualizar
porque es un mecanismo de seguridad que utiliza Django por defecto. Ya podemos iniciar sesión en nuestro sitio de administración
con las credenciales que hemos creado
Volvemos a correr el servidor y entramos a la URL de admin y como pueden ver ya está nuestro modelo acá
Podemos crear nuevas tareas, eliminarlas y actualizarlas dentro de nuestro Admin Site
VIEWS
Ahora debemos manejar la lógica para tratar la información de nuestra base de datos y mostrala en nuestro plantilla html (Template) par ello
nos dirigimos a nuestro archivo views.py dentro de nuestra app tarea e introducimos el siguiente código:
from django.shortcuts import render, redirect
from .models import Task
from .forms import TaskForm
from django.db.models import Q
def home(request):
"""View function for home page of site."""
# Render the HTML template index.html with the data in the context variable
data = Task.objects.all()
return render(request, 'all.html', context={'tasks':data})
def add(request):
form = TaskForm()
if request.method == "POST":
form = TaskForm(request.POST)
if form.is_valid():
title=request.POST['title']
body=request.POST['body']
new_task = Task(title=title, body=body)
new_task.save()
return redirect('home')
return render(request, 'add.html', {"form":form})
def search(request, name):
task = Task.objects.filter(Q(title__icontains=name) | Q(body__icontains=name))
if len(task) >= 0:
context = {"tasks":task}
return render(request, 'all.html',context=context)
else:
context= {}
return render(request, 'all.html', context=context)
def delete(request, pk):
Task.objects.filter(id=pk).delete()
return redirect("home")
def detail(request, id):
task = Task.objects.get(id=id)
context= {"task":task}
return render(request, 'detail.html', context=context)
Para la explicación detallada de que hace cada linea de este código te invito a que veas el video en mi canal de YouTube sobre las Views: Link del Video
TEMPLATES
Te estarás preguntando donde estan las plantillas que debo renderizar para mostrar la información de mi base de datos, pues aqui estan.
Para esto dentro de nuestra app tarea necesitaremos crear una carpeta llamada templates y dentro de ella colocamos nuestras plantillas html.
Primeramente como buena práctica y siempre lo recomiendo mucho es hacer nuestro base.html o como deseen llamarlo, basicamente es la plantilla por
la cual se van a regir las demás, por ejemplo si se han fijado instagram en casi todas las vistas de su app mantiene las barras superior e
inferior de navegacion, nosotros usaremos una lógica similar para esta app y es necesario aclarar que esto depende mucho de tus necesidades y el
resultado que quieras lograr con tus vistas.
Dentro de nuestra carpeta templates vamos a crear 5 archivos html: base.html,
topbar.html,
all.html,
add.html y
detail.html
En este punto ya no estaremos usando el panel de administración de django por lo que para crear nuestras tareas necesitaremos un formulario y una plantilla
para mostrarlo y asi poder crearlas desde el FrontEnd de nuestra app, por lo que necesitamos nuestro archivo html y ademas un formulario
add.html
{% extends "base.html" %}
{% load static %}
{% block content %}
<div class="box">
<form class="form" method="post">
{% csrf_token %}
{% for field in form %}
<div class="form-group">
<label for="{{ field.id_for_label }}">{{ field.label }}</label>
{{ field }}
</div>
{% endfor %}
<button type="submit">Add</button>
</form>
</div>
{% endblock %}
Para la plantilla de agregar nuestras tareas habiamos dicho anteriormente que necesitabamos un formulario y te lo muestro a continuación
Primeramente debemos ir a nuestra carpeta de tarea y crearemos dentro un archivo llamado forms.py, dentro de él introduciremos el siguiente código
from django import forms
class TaskForm(forms.Form):
title = forms.CharField(max_length=50, label='Title', required=True)
body = forms.CharField(widget=forms.Textarea(attrs={"rows":"5"}),label='Body')
Detalles acerca de los Forms.py de Django ver video: Link del Video
URLS
Ahora te estarás preguntando como hacer que nuestras funciones creadas en views.py se ejecuten y si eres observador debes tener una idea ya que algo
llamado {% url '' %} dentro de los templates te llamo la atención; y si debemos definir nuestras urls o rutas para que cuando el navegador visite
cada una de estas se ejcute la función que tiene asociada dicha ruta
Para ello crearemos nuestro archivo urls.py dentro de nuestra carpeta de la app tarea y escribiremos el siguiente código
Ahora debemos irnos a nuestro archivo urls.py dentro de nuestro proyecto principal ToDo e incluir estas urls que acabamos de crear en la app
tarea para esto necesitamos importar la función include y lo haremos de la siguiente manera
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('',include('task.urls')),
]
Finalmente al visitar la pagina principal de nuestro proyecto estaran registradas las urls para manejar la logica de nuestras tareas
Visita mi video para una mejor explicación de las urls en django: Link del Video
STATIC FILES(ARCHIVOS ESTATICOS)
Los archivos estáticos en nuestro proyecto no es mas que las imágenes, estilos y scripts que necesitamos para cada una de nuestras apps
"Nota:" En este proyecto no usamos imágenes porque no fueron necesarias ya que utilizamos elementos svg en nuestro html
Dentro de nuestra app tarea vamos a crear una carpeta llamada static dentro de la cual crearemos 2 carpetas mas llamadas(css y scripts)
Dentro de scripts creamos nuestro archivo main.js con el siguiente codigo Java Script
function searchTask() {
var searchInput = document.getElementById('search');
var searchText = searchInput.value;
window.location.href = '/search/' + searchText + '/';
}
Ahora ya tenemos todo listo pero lo habras encontrado un poco feo no?
No te preocupes ahora necesitamos estilar nuestras plantillas HTML con CSS y dentro de nuestra carpeta css crearemos el archivo styles.css
dentro del cual introduciremos el código que les voy a dejar acá
Explicación de la funcionalidad del archivo main.js y la manera de darle estilos a cada elemento de las plantillas en mi video: Link del video
Ahora necesitaremos correr nuestro servidor local de la manera que ya aprendimos y pues visitar el sitio en el navegador y ya podemos utilizar nuestra
aplicación de gestionar tareas y no se preocupen por si se les cierra el navegador ya que estas están guardadas en nuestra base de datos por lo que
siempre que no las eliminen estas se conservarán intactas y se mostrarán en nuestra aplicación.
En este proyecto estaremos haciendo un chat en tiempo real usando django-channels para el control de websockets por parte del
servidor y daphne como web server para que nuestro servidor corra correctamente nuestra app de tipo asíncrona ya que el servidor
de django solo corre las apps de tipo wsgi.
ASGI - Asyncronus Service Gateway Interface
WSGI - Web Service Gateway Interface
Recomendación: Este tutorial es nivel avanzado en Django por favor ver tutoriales anteriores si aún no tienen suficiente
habilidad y conocimiento sobre el Framework.
Dato del Autor: Cada uno de los pasos de este tutorial y su explicación a fondo esta disponible en mi canal de YouTube
Link del video
Primeramente ya debemos tener nuestro entorno de desarrollo listo con django instalado y nuestro proyecto creado al cual le daremos el nombre de ChatApp
Vamos a crear además nuestra app que va a tener el nombre de chat
Nuestro directorio en este punto debería verse de la siguiente manera
Primero debemos instalar django channels y daphne en nuestro entorno de desarrollo y para ello ejecutamos los comandos:
pip install channels
pip install daphne
Luego debemos ubicarnos en nuestras INSTALLED_APPS en el settings.py de nuestro proyecto y colocar channels y daphne y en lugar de colocar
nuestra app chat lo haremos de la siguiente manera:
Es muy importante que ChatConfig se encuentre de primero en nuestra lista y daphne justo debajo
ASGI CONFIGURACION
Luego debemos configurar nuestro archivo asgi.py dentro de nuestro proyecto y lo haremos de la siguiente manera:
Realizamos las siguientes importaciones:
from channels.auth import AuthMiddlewareStack
from channels.routing import URLRouter,
ProtocolTypeRouter
from chat.routing import websocket_urlpatterns
Ahora personalizamos un poco nuestra variable application usando lo que estuvimos importando:
Importante: El editor de texto que usen puede marcarles como un error
la importación de websocket_urlpatterns proveniente de nuestra app chat ya que aun no hemos creado nuestro archivo
routing.py pero no se preocupen porque mas adelante lo estaremos creando.
Ahora en el archivo settings.py dentro de nuestro proyecto
ChatApp colocamos lo siguiente:
Lo que estamos haciendo acá es asignandole a la variable ASGI_APPLICATION de Django el contenido de la
configuración que antes hicimos en asgi.py. Además en el diccionario
CHANNEL_LAYERS estamos definiendo las capas de canales para nuestro websocket y el comportamiento asincrónico.
URLS
Ahora debemos manejar las rutas de nuestro proyecto y lo haremos creando un archivo llamado urls.py
dentro de nuestra app chat con el siguiente código:
from django.urls import path
from views import *
from django.contrib.auth.views import LogoutView
urlpatterns = [
path('', user_login, name='login'),
path('54465488fsdfsd/', home, name='chat-page'),
path('auth/logout/', LogoutView.as_view(), name='logout-user')
]
Como pudiste ver estamos utilizando una clase llamada LogoutView del archivo views de la librería auth que
contiene django pero ahora nos hace falta definir la variable LOGOUT_REDIRECT_URL que es a la url que
nos va a redirigir cuando cerremos sesión en nuestra aplicación
Para hacer esto vamos a nuestro settings.py y definimos lo siguiente:
LOGOUT_REDIRECT_URL = "login"
Luego necesitamos incluir las urls de nuestra app en el patrón de rutas principal de nuestro proyecto y para ellos vamos a nuestro
archivo urls.py de nuestro proyecto ChatApp y nos aseguramos que quede de la siguiente manera:
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('chat.urls'))
]
VIEWS
Ahora necesitaremos nuestra vista para la autenticación de usuarios y para enviar los datos necesarios
de estos a nuestros templates
Para ello vamos al archivo views.py dentro de nuestra app chat y le introducimos el siguiente código:
from django.shortcuts import render
from .forms import FormLogin
from django.contrib.auth import authenticate, login
def user_login(request):
if request.method == 'POST':
form = FormLogin(request.POST)
if form.is_valid():
username = form.cleaned_data['username']
password = form.cleaned_data['password']
user = authenticate(username=username, password=password)
if user is not None:
login(request, user)
return redirect('chat-page')
else:
form = FormLogin()
return render(request, 'login.html', {'form': form})
def home(request):
context={}
return render(request, 'chatPage.html', context=context)
Luego creamos nuestro formulario para capturar las credenciales de nuestros usuarios y validarlas
Para esto crearemos un archivo llamado forms.py
dentro de nuestra app chat con el siguiente código:
from django import forms
class FormLogin(forms.Form):
username = forms.CharField(max_length=100, label="Username")
password = forms.CharField(label="Password", widget=forms.PasswordInput)
Si te habrás dado cuenta la ruta de websocket definida dentro del archivo routing.py
tenía asociada una clase llamada ChatConsumer dicha clase será la encargada de
manejar toda nuestra lógica para el chat por parte del servidor
Vamos a crear nuestro archivo consumers.py dentro de nuestra app
chat
La estructura de este estará compuesta por una Clase controladora llamada ChatConsumer
y dentro de ella varias funciones asíncronas
Ahora necesitamos estilar nuestro html y para esto vamos a utilizar CSS, primero necesitamos crear nuestra
carpeta static dentro de nuestra app chat
y dentro de ella creamos nuestro archivo styles.css dentro del cual
vamos a introducir el siguiente código, si desean pueden modificarlo o hacerlo por ustedes mismos
Esto es solo los pasos para poder crear tu aplicación de chat en tiempo real bastante básico y fácil de entender si ya posees
los requisitos que deje en la parte superior de esta sección.
Si deseas ver la explicación más a fondo y detallada sobre este contenido no dudes en visitar mi
video de YouTube sobre este contenido: Link del video
En este proyecto estaremos explicando paso por paso lo necesario para crear una API con la arquitectura REST
para esto estaremos utilizando el módulo Django Rest Framework.
Importante:Acá solo estaremos haciendo el rol de desarrollo
BACKEND por lo tanto no estaremos renderizando templates.
API - Application Programming Interface REST - Representational State Transfer
Dato del Autor: Cada uno de los pasos de este tutorial y su explicación a fondo esta disponible en mi canal de YouTube
Link del video
Recomendaciones:
Si nunca has visto o hecho una API
usando arquitectura REST y no sabes la manera en que se trabaja es de vital importancia que veas el video de
la explicación acerca de esto. Apuesto a que después podrás entender todo con mejor claridad; Debajo dejo el
link del video
Si aún estas comenzando en Django y notas que este tutorial no lo estás entendiendo y necesitas más
conocimientos sobre el framework te recomiendo que hagas los demás tutoriales sobre Django Básico como el del
proyecto TO DO List donde está explicado
paso por paso todo para empezar con el framework o si eres de los que necesita escuchar y ver ejemplos prácticos
para entender mejor puedes ver mi video de introducción en Django, te dejo el link debajo
Primero que nada creamos nuestro entorno, instalamos django en el y creamos nuestro proyecto
Luego vamos a instalar en nuestro entorno el paquete de rest framework de la siguiente manera:
pip install djangorestframework
Luego necesitamos crear una app llamada api y para ello vamos a ejecutar el siguiente comando:
py manage.py startapp api_rest
"Por favor asegurarse en todo momento de tener el entorno activado"
Luego nos dirigmos a las INSTALLED_APPS dentro de nuestro archivo settings.py en la carpeta del proyecto
e instalaremos nuestra app creada y además el módulo rest_framework agregándolos al final de la lista
como se muestra a continuación:
Luego creamos nuestro modelo para establecer la estructura de nuestra api en la base de datos
en este caso estaremos utilizando la tabla producto como ejemplo
Lo haremos de la siguiente manera iremos a nuestro archivo models.py dentro
de nuestra app api_rest y le introducimos lo siguiente:
Ahora necesitamos crear nuestras migraciones para nuestro modelo y para ello abrimos nuestra terminal
y nos aseguramos siempre de que nuestro entorno este activo en todo momento
y ejecutamos el comando:
py manage.py makemigrations api_rest
Ya estan lista nuestras migraciones para ser migradas a la base de datos y para esto ejecutamosel comando:
py manage.py migrate
Ahora registraremos nuestro modelo en el panel de administracion de Django para poder realizar acciones
en el desde ahí y lo haremos de la siguiente manera; Nos ubicamos en el archivo
admin.py dentro de nuestra app api_rest y dentro de el colocamos lo siguiente:
from django.contrib import admin
from .models import Producto
admin.site.register(Producto)
Ya tenemos nuestro modelo creado y registrado en la base de datos y visible en el panel de administración
SERIALIZERS
La información desde un puerto a otro no puede viajar en forma de objeto python por lo que necesitaremos
serializar estos objetos para poder enviar la respuesta a nuestra peticiones en formato JSON "JavaScript Object Notation"
Importante saber que no es el unico formato de objeto que existe para transferencia de datos sin embargo es el
mas utilizado.
Ahora vamos a crear nuestra clase serializadora para los objetos de nuestro modelo y lo haremos de la siguiente manera
Dentro de nuestra app api_rest creamos un archivo llamado serializers.py y dentro
de este colocamos el siguiente código:
from rest_framework.serializers import ModelSerializer
from .models import Producto
class ProductoSerializer(ModelSerializer):
class Meta:
model= Producto
fields= '__all__'
Con esto definimos el modelo que queremos serializar dentro de nuetra clase serializadora
y establecemos que esto sucederá con todos los campos de nuestro modelo
VIEWS
Ahora necesitaremos manejar la lógica de nuestras peticiones y respuestas y como trataremos los datos
Para ello ubicamos el archivo views.py dentro de nuestra app api_rest
y colocamos el siguiente código:
Importante acá este ejemplo es bastante básico, por lo que les recomiendo mucho ver el video de explicación ya que esta lógica para tratar la información tiene
muchas maneras diferentes y mas óptimas de hacerse y con diferentes métodos, en el video de explicación explico y muestro
algunas de ellas y muestro ejemplos.
from rest_framework.response import Response
from .models import Producto
from .serializers import ProductoSerializer
from rest_framework.decorators import api_view
# Función para obtener nuestros productos
@api_view(['GET'])
def obtener(request):
producto = Producto.objects.all()
serializer = ProductoSerializer(producto, many = True)
return Response(serializer.data)
# Función para crear un nuevo producto
@api_view(['POST'])
def crear(request):
serializer = ProductoSerializer(data= request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response({"message":"Ops hay algo mal en la petición"})
# Función para actualizar un producto existente
@api_view(['PUT'])
def actualizar(request, pk):
data = Producto.objects.get(id=pk)
serializer = ProductoSerializer(data=request.data, instance=data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response({"message":"Ops hay algo mal en la petición"})
# Función para eliminar un producto
@api_view(['DELETE'])
def eliminar(request, pk):
data = Producto.objects.get(id=pk)
data.delete()
return Response ({"message": "Se eliminó correctamente"})
Necesitamos una herramienta para interactuar con nuestra api de manera mas cómoda existen varias
alguna de las mas famosas Thunder Client(extensión de Vs Code),
Postman y RapidApi
Por razones de gusto personal uso Thunder Client, pero son libres de elegir y utilizar la que deseen
Para la la Instalación e Interacción con nuestra API REST desde Thunder Client
ver el video que les dejo en el siguiente link:
En esta sección estaremos realizando una calculadora con Python utilizando la librería Tkinter
Importante: No se preocupen por la explicación de cada una de las lineas de este código porque se
que muchas cosas acá puede que no les suenen familiar como las funciones lambdas por lo que el video de este tutorial
esta disponible gratis en mi canal de YouTube y les explico el ejercicio paso por paso
Primeramente creamos nuestra carpeta de proyecto y la abrimos con nuestro editor de texto en mi caso yo utilizo
VS Code y dentro de la carpeta creamos nuestro archivo llamado calculadora.py
Luego dentro del archivo que acabamos de crear introducimos el siguiente código:
En este tutorial estaremos aprendiendo a hacer una aplicación de escritorio con python usando la librería
PyQt
para la interfaz gráfica de usuario y MySql como sistema gestor de base de datos
Primero que nada necesitaremos un proyecto de Python y un entorno una vez creados estos procederemos a
activar nuestro entorno y e instalar PyQt en él, y para ellos necesitamos ejecutar el siguiente comando en nuesra
terminal:
pip install PyQt5
Luego vamos a instalar el conector de mysql para python que necesitamos para la conexión y lo haremos
con el siguiente comando:
pip install mysql-connector-python
Ya hemos instalado todo lo necesario referente a la parte de nuestro proyecto en Python, ahora necesitamos
instalar MySql en nuestro dispositivo y crear nuestra base de datos
Para ellos vamos a la página oficial de MySql presionando
AQUI
Procedemos a descargar el que se encuentra señalado en la foto:
Luego abrimos el instalador de MySql en linea por lo que debemos estar conectados a internet luego
procedemos a agregar a nuestra lista de instalación lo que deseamos en el caso de este proyecto usamos
mysql 8.0.36 por lo que seleccionamos dentro de mysql servers la version 8.0.36 y la herramienta MySql
Workbench 8.0.36 la cual estaremos utilizando para gestionar nuestra base de datos y nuestro servidor local:
En este caso no me aparecen a mi esas versiones porque ya las tengo instaladas pero simplemente es seleccionar
las dos mysql server 8.0.36 y Workbench 8.0.36 y en cada una tocar la flecha verde del medio para agregarlos
a nuestra lista de instalación y continuar siguiendo los pasos recomendados de instalación en ambos casos
Para ver la explicación paso por paso de como crearemos nuestro servidor local y nuestra base de datos relacional
por favor ver el video de explicación ya que en texto plano es complicado explicar este contenido:
Para crear la interfaz gráfica estaremos utilizando la herramienta Qt Designer al ser muy complicado
explicar paso por paso el trabajo en ella mediante texto en este blog pueden ver el video tutorial dedicado
especificamente a crear esta interfaz en esa herramienta en muy poco tiempo alrededor de 10 min les tomará
ver el video y seguir los pasos que voy haciendo desde descargar e instalar Qt Designer hasta consumir de él cargándolo
en nuestro main.py:
Dentro de nuestro proyecto crearemos un archivo llamado main.py
donde tendremos nuestra interfaz gráfica y lo que haremos será cargar el archivo ui con el método loadUi de la librería
PyQt5 en lugar de convertirlo a .py, para ello debemos tener dentro de nuestra carpeta raíz del proyecto el archivo
.ui generado en la herramienta Qt Designer y te los dejo debajo para que lo descargues; dentro de nuestro main.py introducimos
el siguiente código
Ahora crearemos nuestra clase controladora llamada conexion.py donde estaremos conectando la base de datos con sus respectivos parámetros
y definiremos las funciones con los scripts que enviaremos a nuestra base de datos a través del uso del cursor de nuestra librería
mysql-connector-python que antes descargamos y para ello introduciremos el siguiente código
dentro del archivo conexion.py que acabamos de crear:
import mysql.connector
class Comunicacion():
def __init__(self):
self.conexion = mysql.connector.connect(user = 'root', password = '12345',
host='localHost',
database = 'inventario',
port = '3306')
def insertar_productos(self, nombre, cantidad, restaurante):
cur = self.conexion.cursor()
sql = ''' INSERT INTO product (NAME, QUANTITY,RESTAURANT)
VALUES('{}', '{}', '{}')'''.format(nombre, cantidad, restaurante)
cur.execute(sql)
self.conexion.commit()
cur.close()
def insertar_restaurante(self, nombre):
cur = self.conexion.cursor()
sql = ''' INSERT INTO restaurant (NAME)
VALUES('{}')'''.format(nombre)
cur.execute(sql)
self.conexion.commit()
cur.close()
def mostrar_productos(self):
cursor = self.conexion.cursor()
sql = "SELECT * FROM product"
cursor.execute(sql)
registro = cursor.fetchall()
return registro
def mostrar_restaurantes(self):
cursor = self.conexion.cursor()
sql = "SELECT * FROM restaurant"
cursor.execute(sql)
registro = cursor.fetchall()
return registro
def eliminar_productos(self,nombre):
cur = self.conexion.cursor()
sql = '''DELETE FROM product WHERE NOMBRE= {}'''.format(nombre)
cur.execute(sql)
self.conexion.commit()
cur.close()
def eliminar_restaurante(self,nombre):
cur = self.conexion.cursor()
sql = '''DELETE FROM restaurant WHERE NAME= {}'''.format(nombre)
cur.execute(sql)
self.conexion.commit()
cur.close()
Luego necesitaremos crear nuestra base de datos y sus tablas y para ellos te dejo el script que debes ejecutar en
MySql Workbench la herramienta que antes descargamos:
-- MySQL Script generated by MySQL Workbench
-- Tue Feb 6 20:01:39 2024
-- Model: New Model Version: 1.0
-- MySQL Workbench Forward Engineering
SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';
-- -----------------------------------------------------
-- Schema mydb
-- -----------------------------------------------------
-- -----------------------------------------------------
-- Schema inventario
-- -----------------------------------------------------
-- -----------------------------------------------------
-- Schema inventario
-- -----------------------------------------------------
CREATE SCHEMA IF NOT EXISTS `inventario` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci ;
USE `inventario` ;
-- -----------------------------------------------------
-- Table `inventario`.`restaurant`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `inventario`.`restaurant` (
`id` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(45) NOT NULL,
PRIMARY KEY (`id`))
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `inventario`.`product`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `inventario`.`product` (
`id` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(45) NOT NULL,
`quantity` INT NOT NULL,
`restaurant_id` INT NOT NULL,
PRIMARY KEY (`id`),
INDEX `fk_product_restaurant_idx` (`restaurant_id` ASC) VISIBLE,
CONSTRAINT `fk_product_restaurant`
FOREIGN KEY (`restaurant_id`)
REFERENCES `inventario`.`restaurant` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
Corremos nuestro main.py y como resultado tendremos nuestra aplicación de escritorio
y debería verse de la siguiente manera:
En este proyecto estaremos realizando una aplicación de escritorio simulando el control de personal
de un evento de cocina aficionada, para ellos utilizaremos PyQt para la interfaz gráfica y PostgreSQL como sistema gestor
de base de datos
Primero que nada necesitaremos crear la carpeta donde queremos crear nuestro proyecto
y un entorno dentro de ella una vez creados estos procederemos a
activar nuestro entorno y e instalar PyQt en él, y para ellos necesitamos ejecutar el siguiente comando en nuesra
terminal:
python -m venv nombre_del_entorno
nombre_del_entorno\scripts\activate
pip install PyQt5
Ahora necesitamos instalar nuestro gestor de base de datos que será Postgre y el conector de este para Python,
para ellos haremos lo siguiente:
Iremos a la página oficial de PostgreSQL haciendo click
AQUI
y luego abrimos la terminal en nuestro proyecto para descargar la librería psycopg2 y lo haremos de la siguiente
manera:
pip install psycopg2
INTERFAZ GRAFICA DE USUARIO
Luego de haber instalado todo lo necesario empezaremos con crear nuestra interfaz gráfica de usuario y para esto
utilizaremos la herramienta Qt Designer
En mi canal de YouTube esta el video completo del diseño de esta aplicación utilizando Qt Designer desde cero
les dejo el link debajo:
Luego vamos a crear las diferentes funciones de la aplicación y para eso vamos a crear un archivo llamado
main.py y dentro introduciremos este código que explico paso por paso en mi
video de YouTube, te dejare el link debajo del código:
import sys
import logo
from turtle import width
from PyQt5.QtWidgets import QApplication, QMainWindow, QHeaderView
from PyQt5.QtCore import QPropertyAnimation, QEasingCurve
from PyQt5 import QtCore, QtWidgets
from PyQt5.uic import loadUi
from conexionA import Comunicacion
class VentanaPrincipal(QMainWindow):
def __init__(self):
super(VentanaPrincipal, self).__init__()
loadUi('Master Chef/Master Chef.ui', self)
self.boton_menu.clicked.connect(self.mover_menu)
self.database = Comunicacion()
#oculta el boton minSize
self.boton_minSize.hide()
#funciones de los botones de la ventana
#self.boton_minimizar.clicked.connect(self.control_boton_minimizar)
self.boton_minSize.clicked.connect(self.control_boton_minSize)
self.boton_maxSize.clicked.connect(self.control_boton_maxSize)
self.boton_cerrar.clicked.connect(lambda: self.close())
#elimina barra de titulo -opacidad
self.setWindowFlag(QtCore.Qt.FramelessWindowHint)
self.setWindowOpacity(1)
#SizeGrip
self.gripSize = 10
self.grip = QtWidgets.QSizeGrip(self)
self.grip.resize(self.gripSize, self.gripSize)
#mover la ventana
self.frame_superior.mouseMoveEvent = self.mover_ventana
#funciones botones del menu lateral
self.boton_organizador.clicked.connect(lambda: self.stackedWidget.setCurrentWidget(self.pagina_organizador))
self.boton_registro.clicked.connect(lambda: self.stackedWidget.setCurrentWidget(self.pagina_registro))
self.boton_chef.clicked.connect(lambda: self.stackedWidget.setCurrentWidget(self.pagina_chef))
self.boton_patrocinador.clicked.connect(lambda: self.stackedWidget.setCurrentWidget(self.pagina_patrocinador))
self.boton_asistente.clicked.connect(lambda: self.stackedWidget.setCurrentWidget(self.pagina_asistente))
self.boton_Menu.clicked.connect(lambda: self.stackedWidget.setCurrentWidget(self.pagina_menu))
self.boton_recetas.clicked.connect(lambda: self.stackedWidget.setCurrentWidget(self.pagina_receta))
self.boton_ingrediente.clicked.connect(lambda: self.stackedWidget.setCurrentWidget(self.pagina_ingredientes))
self.boton_clasificacion.clicked.connect(lambda: self.stackedWidget.setCurrentWidget(self.pagina_clasificacion))
self.boton_contacto.clicked.connect(lambda: self.stackedWidget.setCurrentWidget(self.pagina_contacto))
self.boton_premio.clicked.connect(lambda: self.stackedWidget.setCurrentWidget(self.pagina_premio))
self.boton_organizador.clicked.connect(self.mostrar_elementos)
self.boton_registro.clicked.connect(self.mostrar_elementos)
self.boton_chef.clicked.connect(self.mostrar_elementos)
self.boton_patrocinador.clicked.connect(self.mostrar_elementos)
self.boton_asistente.clicked.connect(self.mostrar_elementos)
self.boton_Menu.clicked.connect(self.mostrar_elementos)
self.boton_recetas.clicked.connect(self.mostrar_elementos)
self.boton_ingrediente.clicked.connect(self.mostrar_elementos)
self.boton_clasificacion.clicked.connect(self.mostrar_elementos)
self.boton_contacto.clicked.connect(self.mostrar_elementos)
self.boton_premio.clicked.connect(self.mostrar_elementos)
#funciones de los botones de registrar de las paginas
self.btn_registrarOrg.clicked.connect(self.insertar_elementos)
self.btn_registrarReg.clicked.connect(self.insertar_elementos)
self.btn_registrarChef.clicked.connect(self.insertar_elementos)
self.btn_registrarPatroc.clicked.connect(self.insertar_elementos)
self.btn_registrarAsist.clicked.connect(self.insertar_elementos)
self.btn_registrarMenu.clicked.connect(self.insertar_elementos)
self.btn_registrarReceta.clicked.connect(self.insertar_elementos)
self.btn_registrarIngred.clicked.connect(self.insertar_elementos)
self.btn_registrarClasif.clicked.connect(self.insertar_elementos)
self.btn_registrarContac.clicked.connect(self.insertar_elementos)
# # Botones de Eliminar de las paginas
self.btn_eliminarOrg.clicked.connect(self.eliminar_elemento)
self.btn_eliminarReg.clicked.connect(self.eliminar_elemento)
self.btn_eliminarChef.clicked.connect(self.eliminar_elemento)
self.btn_eliminarPatroc.clicked.connect(self.eliminar_elemento)
self.btn_eliminarAsist.clicked.connect(self.eliminar_elemento)
self.btn_eliminarMenu.clicked.connect(self.eliminar_elemento)
self.btn_eliminarReceta.clicked.connect(self.eliminar_elemento)
self.btn_eliminarIngred.clicked.connect(self.eliminar_elemento)
self.btn_eliminarClasif.clicked.connect(self.eliminar_elemento)
self.btn_eliminarContac.clicked.connect(self.eliminar_elemento)
#ancho de columna adaptable
self.tabla_organizador.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.tabla_registro.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.tabla_chef.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.tabla_patrocinador.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.tabla_asistentes.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.tabla_Menu.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.tabla_receta.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.tabla_ingredientes.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.tabla_clasificacion.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.tabla_contacto.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.tabla_premio.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
def control_boton_minSize(self):
self.showNormal()
self.boton_minSize.hide()
self.boton_maxSize.show()
def control_boton_maxSize(self):
self.showMaximized()
self.boton_maxSize.hide()
self.boton_minSize.show()
#mover ventana
def mousePressEvent(self, event):
self.click_position = event.globalPos()
def mover_ventana(self, event):
if self.isMaximized() == False:
if event.buttons()== QtCore.Qt.LeftButton:
self.move(self.pos() + event.globalPos() - self.click_position)
self.click_position = event.globalPos()
event.accept()
if event.globalPos().y() <=10:
self.showMaximized()
self.boton_maxSize.hide()
self.boton_minSize.show()
else:
self.showNormal()
self.boton_minSize.hide()
self.boton_maxSize.show()
#mover el menu lateral izquierdo
def mover_menu(self):
if True:
width = self.frame_control.width()
normal = 0
if width == 0:
extender = 300
else:
extender = normal
self.animacion = QPropertyAnimation(self.frame_control, b'minimumWidth')
self.animacion.setDuration(300)
self.animacion.setStartValue(width)
self.animacion.setEndValue(extender)
self.animacion.setEasingCurve(QtCore.QEasingCurve.InOutQuart)
self.animacion.start()
# FUNCIONES
def mostrar_elementos(self):
datos = self.database.mostrar_productos()
i = len(datos)
self.tabla_premio.setRowCount(i)
tablerow = 0
for row in datos:
self.codigo = row[0]
self.tabla_premio.setItem(tablerow,0,QtWidgets.QTableWidgetItem(row[1]))
self.tabla_premio.setItem(tablerow,1,QtWidgets.QTableWidgetItem(row[2]))
self.tabla_premio.setItem(tablerow,2,QtWidgets.QTableWidgetItem(row[3]))
self.tabla_premio.setItem(tablerow,3,QtWidgets.QTableWidgetItem(row[4]))
tablerow +=1
def insertar_elementos(self):
nombre = self.entry_nombreOrg.text().upper()
apellido1 = self.entry_apellidoOrg.text().upper()
apellido2 = self.entry_apellido2Org.text().upper()
nacimiento = self.entry_fechaOrg.text().upper()
edad = self.entry_edadOrg.text().upper()
supervisor = self.entry_supervOrg.text().upper()
if nombre != '' and apellido1 != '' and apellido2 != '' and nacimiento != '' and edad != '' and supervisor != '' :
self.naodatabase.insertar_productos(nombre, apellido1, apellido2, nacimiento, edad, supervisor)
self.entry_nombreOrg.clear()
self.entry_apellidoOrg.clear()
self.entry_apellido2Org.clear()
self.entry_fechaOrg.clear()
self.entry_edadOrg.clear()
self.entry_supervOrg.clear()
else:
self.signal_registro.setText('Hay espacios vacios')
def eliminar_elemento(self):
self.row_flag = self.tabla_eliminar.currentRow()
if self.row_flag == 0:
self.tabla_eliminar.removeRow(0)
self.naodatabase.eliminar_productos("'"+ self.producto_a_borrar +"'")
self.signal_eliminar.setText('Producto Eliminado')
if __name__ == "__main__":
app = QApplication(sys.argv)
mi_app = VentanaPrincipal()
mi_app.show()
sys.exit(app.exec_())
Ahora crearemos nuestra clase controladora que será la encargada de manejar la lógica de la conexión entre nuestra
base de datos Postgre y nuestra Interfaz Gráfica, para ellos creamos un nuevo archivo en nuestro proyecto llamado
conexion.py y dentro de el introducimos el siguiente código:
Es importante aclarar que en los parámetros del método connect de la clase psycopg2 debes sustituirlos por las
credenciales correctas que definas en tu base de datos en Postgre, por lo que les recomiendo ver el video tutorial
completo de esta sección si es que tienen dudas ya que les explicaré paso a paso con palabras y asi entenderán mejor
import psycopg2
class Comunicacion():
def __init__(self):
self.conexion = psycopg2.connect("dbname=nombre_de_tu_BaseDeDatos user = tu_usuario password = tu_contraseña")
def insertar_productos(self, nombre, apeellido1, apellido2, nacimiento, edad, supervisor):
cur = self.conexion.cursor()
sql = ''' INSERT INTO organizador (NOMBRE_ORG, APELLIDO_1, APELLIDO_2, FECHA_NAC, EDAD_ORG, IS_SUPERVISOR)
VALUES('{}', '{}', '{}', '{}', '{}', '{}', '{}')'''.format(nombre, apeellido1, apellido2, nacimiento, edad, supervisor)
cur.execute(sql)
self.conexion.commit()
cur.close()
def mostrar_productos(self):
cursor = self.conexion.cursor()
sql = "SELECT * FROM premio"
cursor.execute(sql)
registro = cursor.fetchall()
return registro
def eliminar_productos(self,nombre):
cur = self.conexion.cursor()
sql = '''DELETE FROM inventario WHERE CODIGO or PRODUCTO = {}'''.format(nombre)
cur.execute(sql)
self.conexion.commit()
cur.close()
Base De Datos
Ahora necesitamos abrir la herramienta PgAdmin y dentro de un nuevo Query Tab ejecutamos el siguiente script:
-- This script was generated by the ERD tool in pgAdmin 4.
-- Please log an issue at https://redmine.postgresql.org/projects/pgadmin4/issues/new if you find any bugs, including reproduction steps.
BEGIN;
CREATE TABLE IF NOT EXISTS public.asistente
(
id_asistente serial NOT NULL,
nombre_asistente character varying(100) COLLATE pg_catalog."default" NOT NULL,
apellido_1 character varying(50) COLLATE pg_catalog."default" NOT NULL,
apellido_2 character varying(50) COLLATE pg_catalog."default" NOT NULL,
edad_asistente integer NOT NULL,
is_confirm boolean NOT NULL,
codigo_registro_registro integer NOT NULL,
CONSTRAINT asistente_pk PRIMARY KEY (id_asistente)
);
CREATE TABLE IF NOT EXISTS public.chef
(
id_chef serial NOT NULL,
nombre_chef character varying(50) COLLATE pg_catalog."default" NOT NULL,
apellido_1 character varying(50) COLLATE pg_catalog."default" NOT NULL,
apellido_2 character varying(50) COLLATE pg_catalog."default" NOT NULL,
edad_chef integer NOT NULL,
codigo_registro integer NOT NULL,
CONSTRAINT chef_pk PRIMARY KEY (id_chef)
);
CREATE TABLE IF NOT EXISTS public.clasificacion
(
id_clasificacion serial NOT NULL,
nombrechef character varying(50) COLLATE pg_catalog."default" NOT NULL,
apellido1 character varying(50) COLLATE pg_catalog."default" NOT NULL,
apellido2 character varying(50) COLLATE pg_catalog."default" NOT NULL,
plato_popular character varying(50) COLLATE pg_catalog."default" NOT NULL,
puesto_clasif character varying(10) COLLATE pg_catalog."default" NOT NULL,
codigo_registro integer NOT NULL,
id_chef_chef integer NOT NULL,
CONSTRAINT "Clasificacion_pk" PRIMARY KEY (id_clasificacion)
);
CREATE TABLE IF NOT EXISTS public.contacto_organizador
(
id_organizador_organizador serial NOT NULL,
telefono character varying(20) COLLATE pg_catalog."default" NOT NULL,
email character varying(50) COLLATE pg_catalog."default",
CONSTRAINT contacto_organizador_pk PRIMARY KEY (id_organizador_organizador)
);
CREATE TABLE IF NOT EXISTS public.ingrediente
(
codigo_ingredient serial NOT NULL,
nombre_producto character varying(100) COLLATE pg_catalog."default" NOT NULL,
cantidad_ing integer NOT NULL,
unidad character varying(50) COLLATE pg_catalog."default",
codigo_menu_menu integer NOT NULL,
codigo_receta_receta integer NOT NULL,
CONSTRAINT ingredientes_pk PRIMARY KEY (codigo_ingredient)
);
CREATE TABLE IF NOT EXISTS public.many_registro_has_many_organizador
(
codigo_registro_registro integer NOT NULL,
id_organizador_organizador integer NOT NULL,
CONSTRAINT many_registro_has_many_organizador_pk PRIMARY KEY (codigo_registro_registro, id_organizador_organizador)
);
CREATE TABLE IF NOT EXISTS public.menu
(
codigo_menu serial NOT NULL,
cant_platos integer NOT NULL,
id_chef_chef integer NOT NULL,
id_producto integer NOT NULL,
CONSTRAINT menu_pk PRIMARY KEY (codigo_menu, id_producto),
CONSTRAINT menu_uq UNIQUE (id_chef_chef)
);
CREATE TABLE IF NOT EXISTS public.organizador
(
id_organizador serial NOT NULL,
nombre_org character varying(50) COLLATE pg_catalog."default" NOT NULL,
apellido_1 character varying(50) COLLATE pg_catalog."default" NOT NULL,
apellido_2 character varying(50) COLLATE pg_catalog."default" NOT NULL,
fecha_nac date NOT NULL,
edad_org integer NOT NULL,
is_supervisor boolean NOT NULL,
CONSTRAINT organizador_pk PRIMARY KEY (id_organizador)
);
CREATE TABLE IF NOT EXISTS public.patrocinador
(
id_patrocinador serial NOT NULL,
nombre_patroc character varying(100) COLLATE pg_catalog."default" NOT NULL,
apellido_1 character varying(50) COLLATE pg_catalog."default" NOT NULL,
apellido_2 character varying(50) COLLATE pg_catalog."default" NOT NULL,
edad_patroc integer NOT NULL,
codigo_registro_registro integer NOT NULL,
CONSTRAINT patrocinador_pk PRIMARY KEY (id_patrocinador)
);
CREATE TABLE IF NOT EXISTS public.receta
(
codigo_receta serial NOT NULL,
nombre character varying(100) COLLATE pg_catalog."default" NOT NULL,
tipo_receta character varying(50) COLLATE pg_catalog."default" NOT NULL,
codigo_menu_menu integer NOT NULL,
CONSTRAINT receta_pk PRIMARY KEY (codigo_receta)
);
CREATE TABLE IF NOT EXISTS public.registro
(
codigo_registro serial NOT NULL,
cant_chef integer NOT NULL,
cant_patroc integer NOT NULL,
cant_asistentes integer NOT NULL,
plato_popular character varying(100) COLLATE pg_catalog."default" NOT NULL,
ingred_popular character varying(100) COLLATE pg_catalog."default" NOT NULL,
CONSTRAINT codigo_registro PRIMARY KEY (codigo_registro)
);
ALTER TABLE IF EXISTS public.asistente
ADD CONSTRAINT registro_fk FOREIGN KEY (codigo_registro_registro)
REFERENCES public.registro (codigo_registro) MATCH FULL
ON UPDATE CASCADE
ON DELETE SET NULL;
ALTER TABLE IF EXISTS public.chef
ADD CONSTRAINT codigo_registro FOREIGN KEY (codigo_registro)
REFERENCES public.registro (codigo_registro) MATCH FULL
ON UPDATE CASCADE
ON DELETE SET NULL;
ALTER TABLE IF EXISTS public.clasificacion
ADD CONSTRAINT chef_fk FOREIGN KEY (id_chef_chef)
REFERENCES public.chef (id_chef) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION
NOT VALID;
ALTER TABLE IF EXISTS public.clasificacion
ADD CONSTRAINT codigo_registro FOREIGN KEY (codigo_registro)
REFERENCES public.registro (codigo_registro) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION
NOT VALID;
ALTER TABLE IF EXISTS public.contacto_organizador
ADD CONSTRAINT organizador_fk FOREIGN KEY (id_organizador_organizador)
REFERENCES public.organizador (id_organizador) MATCH FULL
ON UPDATE CASCADE
ON DELETE SET NULL;
CREATE INDEX IF NOT EXISTS contacto_organizador_uq
ON public.contacto_organizador(id_organizador_organizador);
ALTER TABLE IF EXISTS public.ingrediente
ADD CONSTRAINT receta_fk FOREIGN KEY (codigo_receta_receta)
REFERENCES public.receta (codigo_receta) MATCH FULL
ON UPDATE CASCADE
ON DELETE SET NULL;
ALTER TABLE IF EXISTS public.many_registro_has_many_organizador
ADD CONSTRAINT organizador_fk FOREIGN KEY (id_organizador_organizador)
REFERENCES public.organizador (id_organizador) MATCH FULL
ON UPDATE CASCADE
ON DELETE RESTRICT;
ALTER TABLE IF EXISTS public.many_registro_has_many_organizador
ADD CONSTRAINT registro_fk FOREIGN KEY (codigo_registro_registro)
REFERENCES public.registro (codigo_registro) MATCH FULL
ON UPDATE CASCADE
ON DELETE RESTRICT;
ALTER TABLE IF EXISTS public.menu
ADD CONSTRAINT chef_fk FOREIGN KEY (id_chef_chef)
REFERENCES public.chef (id_chef) MATCH FULL
ON UPDATE CASCADE
ON DELETE SET NULL;
CREATE INDEX IF NOT EXISTS menu_uq
ON public.menu(id_chef_chef);
ALTER TABLE IF EXISTS public.menu
ADD FOREIGN KEY (codigo_menu)
REFERENCES public.ingrediente (codigo_ingredient) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION
NOT VALID;
ALTER TABLE IF EXISTS public.patrocinador
ADD CONSTRAINT registro_fk FOREIGN KEY (codigo_registro_registro)
REFERENCES public.registro (codigo_registro) MATCH FULL
ON UPDATE CASCADE
ON DELETE SET NULL;
-- Creando la vista PREMIO (CHEF - REGISTRO - CLASIFICACION)
CREATE VIEW PREMIO AS
SELECT
C.NOMBRE_CHEF,
A.PLATO_POPULAR,
G.PUESTO_CLASIF,
A.CODIGO_REGISTRO
FROM
(CHEF C JOIN REGISTRO A ON C.CODIGO_REGISTRO = A.CODIGO_REGISTRO)
JOIN CLASIFICACION G ON C.CODIGO_REGISTRO = G.CODIGO_REGISTRO
END;
Luego de ejecutar el script se crearan todas las tablas, las relaciones entre ellas y la vista llamada Premio y ya estaría lista nuestra base
de datos, si no sabes los pasos a seguir para crear correctamente la base de datos a traves del script puedes ver
el video tutorial en mi canal de YouTube donde explico todos los pasos detalladamente:
En este proyecto estaremos realizando un programa en C++ para principiantes, el cual trata de calcular estadísticas
de los jugadores de un torneo de Dota2
Primero que nada crearemos una carpeta y la abriremos con un IDE de C++ como Dev C++ o como en mi caso que estaré
usando VS Code como editor de texto pero es importante tener instalada(s) la(s) extension(es) ya que es un editor
de texto como antes dije y no un IDE de desarrollo en C++
Luego de instalar nuestra extension de soporte para C++ en VS Code debemos crear un archivo llamado
dota.cpp y dentro de el incluir este código:
#include<iostream>
#include<conio.h>
using namespace std;
int DiaMasProductivo(int num, int num2){ //Funcion que devuelve el mayor valor de las partidas ganadas(1ra fila)
int mayor =num; // Se iguala la variable mayor al primer numero que entra en la fila
if(num2>mayor){ //Y si el segundo numero que entra es mayor al anterior ,
mayor=num2; //la variable mayor toma el valor de dicho numero
}
return mayor;
}
int DiaMenosProductivo(int num, int num2){ //Funcion que devuelve el mayor valor de las partidas perdidas(2da fila)
int mayor =num;
if(num2>mayor){
mayor=num2;
}
return mayor;
}
int main(){
int cant_partic,numero[3][8],filas=2,columnas=7; //Declarando las variables
int mayor=0;
int opc,SioNo;
int totalwin=0;
int promediowin=0;
int totallose=0;
int promediolose=0;
cout<<"..........................BIENVENIDO AL CENTRO DE ESTADISTICA DEL X TORNEO NACIONAL DE DoTa2............................"<<endl;
cout<<"\n";
cout<<"\n";
cout<<"A continuacion le pediremos la introduccion de la cantidad de jugadores acerca de los que desea saber: "<<endl;
cout<<"\n";
cout<<"Digite la cantidad de jugadores del torneo de videojuegos: ";//se le pide al usuario que introduzca la cantidad de partic. del torneo
cin>cant_partic;
for(int a=0;a<cant_partic;a++) //Ciclo que se repetiras mientras que a sea menor que la cantidad de jugadores
{
for(int i=1;i<=filas;i++) // Ciclo para que el usuario introduzca las partidas del jugador
{
if(i==1){ //Si se esta rellenando la fila 1 se le pedira al usuario solo las partidas ganadas
cout<<"Introduzca la cantidad de partidas ganadas del jugador: \n";
}else{ //sino se le pediran las partidas perdidas
cout<<"Introduzca la cantidad de partidas perdidas del jugador: \n";
}
for(int j=1;j<=columnas;j++) //el usuario rellenara primero todas las columnas que corresponde con los dias por cada una de las filas
{
cout<<"[Dia "<<j<<" ]: "; //Se muestra la palabra Dia con el valor de la iteracion de J en ese momento y se pide introducir el valor correspondiente
cin>numero[i][j];
}
cout<<"\n";
}
for(int i=1;i<=filas;i++){ //Se muestra la matriz antes rellenada por el usuario mediante un bucle anidado
if(i==1){
cout<<"partidas ganadas: "; // Se imprimira en consola partidas g o p segun la fila e la que se encuentre la iteracion
}else{
cout<<"partidas perdidas: ";
}
for(int j=1;j<=columnas;j++){ //Se mustran en columnas los valores de la fila 1 y la 2
cout<<" "<<numero[i][j];
cout<<"| ";
}
cout<<"\n";
cout<<"\n";
}
cout<<"\n";
cout<<"Desea conocer detalles sobre este jugador?"<<endl;
cout<<"1- Si \n";
cout<<"0- No \n";
cout<<"\n";
cin>SioNo; //Se introduce 0 o 1 para dar respuesta negativa o positiva respectivamente
if(SioNo==1){ //Si se responde positivamente el usuario accedera a un menu con opciones
cout<<"....Opciones: \n";
cout<<"1- Dia que mas partidas gano \n";
cout<<"2- Dia que mas partidas perdio \n";
cout<<"3- Cantidad total de partidas ganadas \n";
cout<<"4- Promedio de partidas ganadas en la semana \n";
cout<<"5- Cantidad total de partidas perdidas \n";
cout<<"6- Promedio de partidas perdidas en la semana \n";
cout<<"7- Salir \n";
for(opc=1;opc!=7;){
cin>opc; //El usuario debe digitar la opcion deseada
switch(opc){ //Evalua los casos y se ejecuta el correspondiente a la opcion seleccionada
case 1:
for(int x=1; x<=7; x++){ //Ciclo usado para comparar los valores de la funcion DiaMasProductivo y se muestre en consola el mayor valor de la fila 1 (PG)
mayor=DiaMasProductivo(mayor,numero[1][x]);
}
for(int x=1; x<=7; x++){
if(numero[1][x]==mayor){
cout<<"El dia que mas partidas ganadas tuvo fue el dia ["<<x<<"]: " <<mayor<< " partidas\n";
}
}
break;
case 2:
for(int x=1; x<=7; x++){ //Ciclo usado para comparar los valores de la funcion DiaMenosProductivo y se muestre en consola el mayor valor de la fila 2 (PP)
mayor=DiaMenosProductivo(mayor,numero[2][x]);
}
for(int x=1; x<=7; x++){
if(numero[2][x]==mayor){
cout<<"El dia que mas partidas perdio fue el dia ["<<x<<"]: " <<mayor<< " partidas\n";
}
}
break;
case 3:
for(int j=1;j<=7;j++){
totalwin += numero[1][j];
}
cout<<"El total de partidas ganadas en la semana fue: "<<totalwin<<endl;
break;
case 4:
promediowin+=totalwin/7;
cout<<"El promedio de partidas que gano en la semana fue: "<<promediowin<<endl;
break;
case 5:
for(int i=2;i<=7;i++){
totallose += numero[2][i];
}
cout<<"El total de partidas perdidas en la semana fue: "<<totallose<<endl;
break;
case 6:
promediolose+=totallose/7;
cout<<"El promedio de partidas que perdio en la semana fue: "<<promediolose<<endl;
break;
case 7:
break;
}
cout<<"\n";
cout<<"\n";
}
}
cout<<"\n";
cout<<"\n";
}
cout<<"..........GRACIAS POR USAR NUESTRA PLATAFORMA.......... :)\n";
cout<<"\n";
cout<<"\n";
getch(); //funcion que se encuentra en la libreria conio.h usada para usar el ejecutable de nuestro programa directamente
return 0;
}
Sugiero ver el video de YouTube donde explico cada una de las líneas de este código por paso y detalladamente
Json Web Token (JWT) es un estándar abierto (RFC 7519) que define un formato compacto y autónomo para transmitir de manera segura la información entre dos partes como un objeto JSON. Un JWT puede ser utilizado para autenticar usuarios y compartir información de forma segura entre el cliente y el servidor.
En esta sección estaremos tocando especificamente la integración de JWT con el framework Django con el uso
de la librería djangorestframework-simplejwt y acá te enseñaremos como.
INSTALACION
Primero debemos instalar la librería en el entorno de desarrollo de nuestro proyecto a traves de pip
pip install djangorestframework-simplejwt
Si planeas hacer modificaciones de codificación o decodificación de tokens usando algoritmos
criptográficos RSA y ECDSA necesitamos instalar ademas como requisito de la librería simple-jwt
la librería de criptografía (RECOMENDABLE)
pip install djangorestframework-simplejwt[crypto]
CONFIGURACION
Luego debemos configurar simple-jwt en nuestro proyecto Django de la siguiente manera:
Ahora comprobaremos si esta funcionando de una manera sencilla levantamos el servidor de desarrollo
y en la url escribimos la ruta exacta que le definimos a la vista TokenObtainPairView por ejemplo:
http://127.0.0.1:8000/app/token/
Cuando el token de acceso tiene una corta duración de validez podemos utilizar el token de refresh
para obtener un nuevo token de acceso a traves de la ruta
http://127.0.0.1:8000/app/token/refresh/
Ahora en el settings.py de nuestro proyecto pegaremos estas
configuraciones de simple-jwt, las cuales puedes modificar según las necesidades de tu proyecto
Importante: Antes de realizar cualquier modificación en estas configuraciones
recomiendo una buena lectura de la documentación oficial de la librería para mas información que necesiten
Si deseas mas información detallada sobre el uso de JWT con Django configuraciones adicionales, interactuar
en proyecto real con la autenticación de usuarios, customizar reclamos del token y mucho mas. Te invito a
ver el video que tengo en mi canal de YouTube acerca del tema!
El intercambio de recursos de origen cruzado CORS, por sus siglas en inglés es un mecanismo de seguridad que permite a un servidor indicar cualquier dominio,
esquema o puerto con un origen distinto del suyo desde el que un navegador debería permitir la carga de recursos.
En esta seccion estaremos tratando temas referentes a la instalación de la librería django-cors-headers; desde como instalarla y configurarla en nuestro proyecto hasta
manejar los permisos de Cross Origin Resource Sharing "CORS" en español Transferencia de Recursos de Origen Cruzado.
INSTALACION
Para instalar la libreria que usaremos en nuestro proyecto usaremos el siguiente comando de pip:
pip install django-cors-headers
Luego de instalarla agregaremos la app corsheaders en nuestra lista de INSTALLED_APPS en el
settings.py de nuestro proyecto:
INSTALLED_APPS = [
...
'corsheaders',
...
]
Luego debemos de incluir el middleware que propone corsheaders en nuestra lista de middleware de nuestro
proyecto en settings.py:
Por favor asegurate de colocar el middleware de corsheaders encima de 'SecurityMiddleware'
Ahora empezaremos a utilizar algunas variables de entorno para habilitar o deshabilitar segun nuestras
necesidades las transferencias de origen cruzado
Por ejemplo si quieres permitir que desde cualquier sitio se le haga una petición a tu servidor una vez
esté en producción puedes utilizar la variable de entorno siguiente en el
settings.py de nuestro proyecto:
CORS_ALLOW_ALL_ORIGIN = True
Si en caso contrario no deseas esto solo cambias el valor de esta variable por False
CORS_ALLOW_ALL_ORIGIN = False
En otro caso si deseas solo habilitar algunos dominios especificos seria de la siguiente manera:
Finalmente con esto podemos hacer basicamente un manejo de permisos de peticiones a nuestro servidor
WHITENOISE
WhiteNoise es una biblioteca de Python que simplifica enormemente la tarea de servir archivos estáticos en aplicaciones web.
Muchas veces cuando estamos intentando desplegar,es decir cuando la variable
DEBUG en nuestro settings.py es False nuestras aplicaciones web creadas con Django tenemos problemas
con la carga de nuestros estilos y demas archivos estáticos, pues aqui te muestro una solución bastante efectiva.
INSTALACION
Primeramente necesitaremos instalar la biblioteca de whitenoise en nuestro entorno y lo haremos de la siguiente
manera:
pip install whitenoise
Ahora necesitamos incluir el middleware de whitenoise en nuestra lista de MIDDLEWARE en
settings.py
Luego necesitamos recuperar todos estos estilos y archivos estáticos que debemos tener definidos en la carpeta
static de cada app que tenga nuestro proyecto; por lo que vamos a ejecutar lo siguiente en la terminal:
manage.py collectstatic
Luego de ejecutar esto se te creará en tu directorio raiz una carpeta llamada
staticfiles que es donde se encuentra todos los estilos y contenido
estático de todo nuestro proyecto
Si estas utilizando alguna plataforma de PAAS como render para desplegar tu aplicación o alguna otra de este tipo
y estas conectando el despliegue desde un repositorio de GitHub; En ese caso no debes ignorar esta carpeta
en el archivo .gitignore y asegurate de que se ha subido correctamente la
carpeta staticfiles a tu repositorio remoto.