diff --git a/python-total/dia_16/README.md b/python-total/dia_16/README.md index 552580b..9d82c90 100644 --- a/python-total/dia_16/README.md +++ b/python-total/dia_16/README.md @@ -31,14 +31,305 @@ ## 16.1. - Entornos Virtuales +Un entorno virtual de Python es una herramienta que permite aislar y gestionar de forma independiente los paquetes y dependencias de un proyecto Python específico. Permite crear un entorno de desarrollo aislado donde se pueden instalar versiones específicas de bibliotecas y paquetes, sin interferir con otros proyectos de Python en el mismo sistema. + +![](../img/dia16_01.png) + +Cuando se trabaja en proyectos de Python, es común tener diferentes versiones de paquetes y dependencias para cada proyecto. Esto puede generar conflictos si se instalan globalmente en el sistema, ya que un proyecto podría depender de una versión específica de una biblioteca, mientras que otro proyecto puede requerir una versión diferente. + +Al utilizar un entorno virtual, se crea un directorio separado con su propia instalación de Python y su propio espacio de trabajo aislado. Dentro de este entorno, se pueden instalar los paquetes y dependencias necesarios para el proyecto sin afectar el sistema global. + +Existen varias herramientas populares para crear y gestionar entornos virtuales en Python, como virtualenv, venv (incorporado en Python 3.3 y versiones posteriores) y conda (utilizado con el gestor de paquetes Anaconda). +Al activar un entorno virtual, se configuran las variables de entorno y se modifica el PATH para que el sistema utilice la instalación y las bibliotecas específicas del entorno virtual. Esto asegura que el proyecto utilice las versiones correctas de las bibliotecas y evita conflictos con otras instalaciones globales. + +En resumen, un entorno virtual de Python es una herramienta que permite crear un espacio de trabajo aislado con su propia instalación de Python y bibliotecas. Se utiliza para gestionar y mantener las dependencias de un proyecto específico, evitando conflictos con otras instalaciones y versiones globales de paquetes. Esto facilita el desarrollo y la colaboración en proyectos de Python al garantizar la consistencia en las dependencias utilizadas. +Instalación de virtualenv: + +```shell +pip install virtualenv +``` +`pip freeze` es un comando utilizado en Python para generar una lista de todas las bibliotecas instaladas y sus versiones en un entorno virtual. +Ahora se hace una estructura de carpetas para diferenciar entornos + +![](../img/dia16_02.png) + +En el proyecto1 ejecutamos el comando: +```shell +virtualenv p1 +``` + +Creará la estructura de un entorno + +![](../img/dia16_03.png) + +Para activar el entorno se hace con el comando: +```shell +source p1/bin/activate +``` + +Aparecerá el nombre del entorno en el prompt + +![](../img/dia16_04.png) + +Para desactivar: +```shell +deactivate +``` + +Cuando este el entorno virtual activado, si probamos el comando «pip freeze» veremos que no tenemos ningún módulo instalado en el entorno virtual. + +Para instalar una versión distinta, que no sea la última, podemos escogerla con doble igual. Por ejemplo: +```shell +pip install pyjokes==0.4.0 +``` + +Ahora si lo instalamos en el proyecto2 tendremos dos versiones distintas en cada uno de los entornos. + +![](../img/dia16_05.png) + ## 16.2. - Módulos +- **asgiref** es un paquete de referencia para la especificación ASGI (Asynchronous Server Gateway Interface), que es una interfaz estándar para servidores web y aplicaciones web en Python. Proporciona una serie de utilidades y adaptadores para facilitar el desarrollo de aplicaciones web asíncronas con soporte para ASGI. *Documentación oficial*: https://asgiref.readthedocs.io/ +- **Django** es un framework de desarrollo web de alto nivel y de código abierto, escrito en Python. Proporciona una estructura sólida y un conjunto de herramientas para simplificar el desarrollo de aplicaciones web complejas y escalables. Django se basa en el patrón de diseño MVC (Modelo-Vista-Controlador) y ofrece características como ORM (Object-Relational Mapping), enrutamiento de URLs, autenticación de usuarios, generación de formularios, administración de bases de datos y mucho más. *Documentación oficial*: https://docs.djangoproject.com/ *Tutorial de mozilla*: https://developer.mozilla.org/es/docs/Learn/Server-side/Django/Introduction +- **sqlparse** es un analizador y formateador de SQL para Python. Permite analizar consultas SQL y dividirlas en componentes lógicos como palabras clave, identificadores, literales, etc. Además, puede formatear consultas SQL para mejorar su legibilidad al agregar sangría y espacios en blanco adecuados. sqlparse es útil para tareas como resaltar la sintaxis SQL en aplicaciones, depurar consultas SQL y generar consultas SQL legibles. *Documentación oficial*: https://sqlparse.readthedocs.io/ +- **tzdata** es un módulo de Python que proporciona información sobre zonas horarias. Contiene una base de datos actualizada con información sobre zonas horarias de todo el mundo, como nombres de zonas horarias, desplazamientos de tiempo, reglas de horario de verano, entre otros. Este módulo es útil para trabajar con conversiones de tiempo y fechas en diferentes zonas horarias. Sin embargo, ten en cuenta que tzdata se utiliza principalmente como dependencia interna y es posible que no encuentres documentación específica para este módulo en sí. + ## 16.3. - Preparación de estructura de trabajo +Creamos una carpeta que se llame mi_web y dentro de ella creamos el entorno virtual de la web: +```shell +virtualenv web +``` + +Debemos instalar django en el entorno virtual. +```shell +Pip install django +``` + +![](../img/dia16_06.png) + +Se instalan 3 módulos, pero también instalamos tzdata. +```shell +pip install tzdata +``` + +Ahora creamos una carpeta que hará de fuente, que tradicionalmente es src + +![](../img/dia16_07.png) + + +Dentro de la carpeta src iniciamos el proyecto django con: +```shell +django-admin startproject proyecto1 +``` + +![](../img/dia16_08.png) + +En «manage.py» se administra todo del proyecto. + +Ahora iniciamos desde la carpeta proyecto el servidor para correr la web dentro: +```shell +python manage.py runserver +``` + +Indica que tenemos 18 migración sin aplicar + +![](../img/dia16_09.png) + +También vemos el enlace donde podemos ver la web de django: + +![](../img/dia16_10.png) + +Antes de seguir, vamos a migrar los fichero pendientes con el comando: +```shell +python manage.py migrate +``` + +Y volvemos a ejecutar el servidor + +![](../img/dia16_11.png) + +Vemos que ya no tiene esos problemas de migración por aplicar. + +En /admin tenemos la entrada del administrador. + +![](../img/dia16_12.png) + +Pero Django no tiene un nombre de usuario y contraseña por defecto establecidos. Cuando se crea un proyecto Django, se configura un archivo de configuración llamado "settings.py" donde se definen varias opciones, incluyendo la configuración de la base de datos. + +En la configuración de la base de datos, se especifican las credenciales de acceso, como el nombre de usuario y la contraseña para acceder a la base de datos. Estas credenciales deben ser configuradas por el desarrollador según los requisitos del proyecto y la base de datos que se esté utilizando. + +Por defecto, Django utiliza una base de datos SQLite, y en la configuración inicial de un proyecto, se establece un archivo de base de datos local. En este caso, no se requiere un nombre de usuario ni contraseña para acceder a la base de datos SQLite. + +Sin embargo, es importante tener en cuenta que en un entorno de producción, es recomendable utilizar una base de datos más robusta como MySQL o PostgreSQL, y en esos casos, se deben configurar las credenciales de acceso correspondientes en la configuración de la base de datos de Django. + +Para crear el superusuario lo hacemos con el comando: +```shell +python manage.py createsuperuser +``` + +![](../img/dia16_13.png) + +Voy a dejar que el usuario sea el de mi pc, el correo electrónico lo dejo vacío y es password, que tiene que ser mínimo de 8 caracteres, pongo LaDeSiempre. + +Después de ingresar la clave ya veo un escritorio estilo CMS. + +![](../img/dia16_14.png) + ## 16.4. - Configurar url +Creamos el fichero de la app donde estará el núcleo de nuestro código, su estructura, los ajustes principales, su lógica principal, etc. Iniciamos la app con el nombre base: +```shell +python manage.py startapp base +``` + +Esto creará otra estructura de carpetas + +![](../img/dia16_15.png) + +Para conectar "base" con "proyecto" vamos a ir al fichero proyecto/settings.py y en INSTALLED_APPS añadimos la línea para que conecte con la clase dentro de apps.py: +```python +'base.apps.BaseConfig', +``` + +![](../img/dia16_16.png) + +Ahora creamos el fichero urls.py en base e importamos las librerias necesarias y creamos una lista de urls: +```python +from django.urls import path +from . import views +urlpatterns = [] +``` + +Y en base/views.py añadimos esta línea: +```python +from django.http import HttpResponse +``` + +Además creamos nuestra primera vista: +```python +def lista_pendientes(pedido): + return HttpResponse('Lista de pendientes') +``` + +Con lo que en la lista de urls de base/urls.py debemos añadirla: +```python +urlpatterns = [ + path('', views.lista_pendientes, name='pendientes') +] +``` + +Pero para que el proyecto conozca esta url debemos añadir en proyecto/urls.py la función include: +```python +from django.urls import path, include +``` + +Además de ioncluir el path en urlpatterns. +```python +Urlpatterns = [ + path('admin/', admin.site.urls), + path('', include('base.urls')), +] +``` + +Ahora, en la misma url de django veremos el texto que incluimos en la vista: + +![](../img/dia16_17.png) + ## 16.5. - Crear tabla de tareas +Necesitamos que la base de datos almacena las tareas creadas por el usuario. + +En Django, la base de datos por defecto que viene integrada se llama SQLite. SQLite es una base de datos ligera y de fácil configuración que se almacena en un archivo local en lugar de ejecutarse en un servidor separado. Esto hace que sea conveniente para el desarrollo y pruebas, ya que no requiere una configuración adicional del servidor de base de datos. + +Al trabajar con Django, la configuración de la base de datos se especifica en el archivo settings.py de tu proyecto. Dentro de este archivo, encontrarás una sección llamada DATABASES que contiene la configuración de la base de datos por defecto. Para SQLite, la configuración típica se ve así: +```python +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': BASE_DIR / 'db.sqlite3', + } +} +``` +En este ejemplo, `'ENGINE'`: 'django.db.backends.sqlite3' indica que se utilizará el motor de base de datos **SQLite**, y '`NAME': BASE_DIR / 'db.sqlite3'` especifica la ruta del archivo de base de datos, que se ubicará en el directorio del proyecto. + +Es importante tener en cuenta que SQLite es adecuada para proyectos más pequeños o de desarrollo, pero para aplicaciones en producción con requisitos de alto rendimiento o concurrencia, es posible que desees considerar otras bases de datos como PostgreSQL, MySQL o Oracle, entre otras. En esos casos, deberás actualizar la configuración de la base de datos en el archivo settings.py para utilizar el motor y los detalles de conexión correspondientes a la base de datos que elijas. +Documentación bbdd django: https://docs.djangoproject.com/en/3.2/topics/db/ + +Para crear las tablas debemos hacerlo en base/models.py creando una clase que represente cada tabla. Sus atributos serán las columnas o los campos. +- En **usuario** especificamos el usuario en concreto mediante un módulo de django que tenemos que importar. Con una relación de 1:n. La función ForeignKey es una clave externa con la que podremos asociar usuarios que se repitan. La función responderá a: + - **User** que es la biblioteca anterior + - Definimos un atributo **on_delete** para cuando se elimine un usuario se elimine en cascada sus tareas. + - **null y blank** en True para poder dejar este campo en blanco + - En **titulo** haremos que responda a **CharField** que es el campo de caracteres donde ajustamos el valos máximo de carácteres con max_length +- En **descripción** haremos que responda a **TextField** que es parecido al campo de caracteres anterior però tiene algunos atributos extra que no tiene el anterior. Lo único que indicamos es que puede quedar vacío el campo. +- En **completo** vamos a añadir la función **BooleanField** de campo booleano que por defecto este False. +- En **creado** le vamos a indicar el momento en el que se creó la tarea con la función **DateTimeField** y con los atributos le indicamos que se autoconfigure con la fecha now + +Ahora vamos a definir un valor STR que es el que nos va a reflejar como valor string si pedimos que imprima una tarea. Será el contenido de titulo. + +Además le indicamos en Meta como se va a ordenar las tareas dentro de la tabla, que será por completo. + +El documento queda así: +```python +from django.db import models +from django.contrib.auth.models import User +# Create your models here. +class Tarea(models.Model): + + usuario = models.ForeignKey( + User, + on_delete=models.CASCADE, + null=True, + blank=True + ) + + titulo = models.CharField(max_length=200) + descripcion = models.TextField( + null=True, + blank=True + ) + + completo = models.BooleanField(default=False) + + creado = models.DateTimeField(auto_now_add=True) + + def __str__(self): + return self.titulo + + class Meta: + ordering = ['completo'] +``` + +Pero ahora tenemos que migrar la tabla en la terminal, primero creando el fichero con: +```shell +python manage.py makemigrations +``` + +Esto creará una carpeta migrations en base. Dentro tendrá un fichero 0001_initial.py donde indica que esta preparado para migrar. Con el siguiente comando hacemos efectiva la migración: +```shell +python manage.py migrate +``` + +![](../img/dia16_18.png) + +Ahora tenemos que registrar el modelo en base/admin.py . Tenemos que importar la función Tarea y añadir la tabla: +```shell +from django.contrib import admin +from .models import Tarea + +# Register your models here. +admin.site.register(Tarea) +``` + +Con lo cual, si vamos a la url de nuestro sitio a /admin veremos que tenemos un nuevo campo de Tareas: + +![](../img/dia16_19.png) + +Si añadimos una nueva tarea veremos que nos permite añadir los campos que indicamos a nuestra tabla: + +![](../img/dia16_20.png) + ## 16.6. - Configurar la vista ## 16.7. - Configurar la vista de Detalle diff --git a/python-total/dia_16/mi_web/src/proyecto/base/__init__.py b/python-total/dia_16/mi_web/src/proyecto/base/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/python-total/dia_16/mi_web/src/proyecto/base/admin.py b/python-total/dia_16/mi_web/src/proyecto/base/admin.py new file mode 100644 index 0000000..d3cbbf6 --- /dev/null +++ b/python-total/dia_16/mi_web/src/proyecto/base/admin.py @@ -0,0 +1,5 @@ +from django.contrib import admin +from .models import Tarea +# Register your models here. + +admin.site.register(Tarea) diff --git a/python-total/dia_16/mi_web/src/proyecto/base/apps.py b/python-total/dia_16/mi_web/src/proyecto/base/apps.py new file mode 100644 index 0000000..05011e8 --- /dev/null +++ b/python-total/dia_16/mi_web/src/proyecto/base/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class BaseConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'base' diff --git a/python-total/dia_16/mi_web/src/proyecto/base/migrations/0001_initial.py b/python-total/dia_16/mi_web/src/proyecto/base/migrations/0001_initial.py new file mode 100644 index 0000000..d464444 --- /dev/null +++ b/python-total/dia_16/mi_web/src/proyecto/base/migrations/0001_initial.py @@ -0,0 +1,31 @@ +# Generated by Django 4.2.1 on 2023-05-20 20:20 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Tarea', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('titulo', models.CharField(max_length=200)), + ('descripcion', models.TextField(blank=True, null=True)), + ('completo', models.BooleanField(default=False)), + ('creado', models.DateTimeField(auto_now_add=True)), + ('usuario', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + options={ + 'ordering': ['completo'], + }, + ), + ] diff --git a/python-total/dia_16/mi_web/src/proyecto/base/migrations/__init__.py b/python-total/dia_16/mi_web/src/proyecto/base/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/python-total/dia_16/mi_web/src/proyecto/base/models.py b/python-total/dia_16/mi_web/src/proyecto/base/models.py new file mode 100644 index 0000000..b79f727 --- /dev/null +++ b/python-total/dia_16/mi_web/src/proyecto/base/models.py @@ -0,0 +1,26 @@ +from django.db import models +from django.contrib.auth.models import User + +# Create your models here. + + +class Tarea(models.Model): + usuario = models.ForeignKey( + User, + on_delete=models.CASCADE, + null=True, + blank=True + ) + titulo = models.CharField(max_length=200) + descripcion = models.TextField( + null=True, + blank=True + ) + completo = models.BooleanField(default=False) + creado = models.DateTimeField(auto_now_add=True) + + def __str__(self): + return self.titulo + + class Meta: + ordering = ['completo'] diff --git a/python-total/dia_16/mi_web/src/proyecto/base/tests.py b/python-total/dia_16/mi_web/src/proyecto/base/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/python-total/dia_16/mi_web/src/proyecto/base/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/python-total/dia_16/mi_web/src/proyecto/base/urls.py b/python-total/dia_16/mi_web/src/proyecto/base/urls.py new file mode 100644 index 0000000..49cbcbb --- /dev/null +++ b/python-total/dia_16/mi_web/src/proyecto/base/urls.py @@ -0,0 +1,7 @@ +from django.urls import path +from . import views + + +urlpatterns = [ + path('', views.lista_pendientes, name='pendientes') +] diff --git a/python-total/dia_16/mi_web/src/proyecto/base/views.py b/python-total/dia_16/mi_web/src/proyecto/base/views.py new file mode 100644 index 0000000..79a076f --- /dev/null +++ b/python-total/dia_16/mi_web/src/proyecto/base/views.py @@ -0,0 +1,8 @@ +from django.shortcuts import render +from django.http import HttpResponse + +# Create your views here. + + +def lista_pendientes(pedido): + return HttpResponse('Lista de pendientes') diff --git a/python-total/dia_16/mi_web/src/proyecto/proyecto/settings.py b/python-total/dia_16/mi_web/src/proyecto/proyecto/settings.py index 03a7d65..9ebf15b 100644 --- a/python-total/dia_16/mi_web/src/proyecto/proyecto/settings.py +++ b/python-total/dia_16/mi_web/src/proyecto/proyecto/settings.py @@ -37,6 +37,7 @@ INSTALLED_APPS = [ 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', + 'base.apps.BaseConfig', ] MIDDLEWARE = [ diff --git a/python-total/dia_16/mi_web/src/proyecto/proyecto/urls.py b/python-total/dia_16/mi_web/src/proyecto/proyecto/urls.py index f02c849..bdbb4ff 100644 --- a/python-total/dia_16/mi_web/src/proyecto/proyecto/urls.py +++ b/python-total/dia_16/mi_web/src/proyecto/proyecto/urls.py @@ -15,8 +15,9 @@ Including another URLconf 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin -from django.urls import path +from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), + path('', include('base.urls')), ] diff --git a/python-total/img/dia16_01.png b/python-total/img/dia16_01.png new file mode 100644 index 0000000..dcbc795 Binary files /dev/null and b/python-total/img/dia16_01.png differ diff --git a/python-total/img/dia16_02.png b/python-total/img/dia16_02.png new file mode 100644 index 0000000..f059110 Binary files /dev/null and b/python-total/img/dia16_02.png differ diff --git a/python-total/img/dia16_03.png b/python-total/img/dia16_03.png new file mode 100644 index 0000000..979c637 Binary files /dev/null and b/python-total/img/dia16_03.png differ diff --git a/python-total/img/dia16_04.png b/python-total/img/dia16_04.png new file mode 100644 index 0000000..180c4c0 Binary files /dev/null and b/python-total/img/dia16_04.png differ diff --git a/python-total/img/dia16_05.png b/python-total/img/dia16_05.png new file mode 100644 index 0000000..764b7b4 Binary files /dev/null and b/python-total/img/dia16_05.png differ diff --git a/python-total/img/dia16_06.png b/python-total/img/dia16_06.png new file mode 100644 index 0000000..b35d3d9 Binary files /dev/null and b/python-total/img/dia16_06.png differ diff --git a/python-total/img/dia16_07.png b/python-total/img/dia16_07.png new file mode 100644 index 0000000..a8fd933 Binary files /dev/null and b/python-total/img/dia16_07.png differ diff --git a/python-total/img/dia16_08.png b/python-total/img/dia16_08.png new file mode 100644 index 0000000..e25fb6d Binary files /dev/null and b/python-total/img/dia16_08.png differ diff --git a/python-total/img/dia16_09.png b/python-total/img/dia16_09.png new file mode 100644 index 0000000..7b94d84 Binary files /dev/null and b/python-total/img/dia16_09.png differ diff --git a/python-total/img/dia16_10.png b/python-total/img/dia16_10.png new file mode 100644 index 0000000..640fcfc Binary files /dev/null and b/python-total/img/dia16_10.png differ diff --git a/python-total/img/dia16_11.png b/python-total/img/dia16_11.png new file mode 100644 index 0000000..b2f70a4 Binary files /dev/null and b/python-total/img/dia16_11.png differ diff --git a/python-total/img/dia16_12.png b/python-total/img/dia16_12.png new file mode 100644 index 0000000..dd91747 Binary files /dev/null and b/python-total/img/dia16_12.png differ diff --git a/python-total/img/dia16_13.png b/python-total/img/dia16_13.png new file mode 100644 index 0000000..f216d5b Binary files /dev/null and b/python-total/img/dia16_13.png differ diff --git a/python-total/img/dia16_14.png b/python-total/img/dia16_14.png new file mode 100644 index 0000000..95500ca Binary files /dev/null and b/python-total/img/dia16_14.png differ diff --git a/python-total/img/dia16_15.png b/python-total/img/dia16_15.png new file mode 100644 index 0000000..973b32b Binary files /dev/null and b/python-total/img/dia16_15.png differ diff --git a/python-total/img/dia16_16.png b/python-total/img/dia16_16.png new file mode 100644 index 0000000..4fb4a23 Binary files /dev/null and b/python-total/img/dia16_16.png differ diff --git a/python-total/img/dia16_17.png b/python-total/img/dia16_17.png new file mode 100644 index 0000000..6601ce3 Binary files /dev/null and b/python-total/img/dia16_17.png differ diff --git a/python-total/img/dia16_18.png b/python-total/img/dia16_18.png new file mode 100644 index 0000000..3f5bb40 Binary files /dev/null and b/python-total/img/dia16_18.png differ diff --git a/python-total/img/dia16_19.png b/python-total/img/dia16_19.png new file mode 100644 index 0000000..0ea6db4 Binary files /dev/null and b/python-total/img/dia16_19.png differ diff --git a/python-total/img/dia16_20.png b/python-total/img/dia16_20.png new file mode 100644 index 0000000..d190158 Binary files /dev/null and b/python-total/img/dia16_20.png differ