From 391677c850385d12ac16eb7628a7c485cd32633d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Alvari=C3=B1o?= Date: Thu, 8 Feb 2024 12:43:19 +0100 Subject: [PATCH] doc: Add kicad and py4web notes --- .../notes_kicad/featured-image-preview.png | Bin 0 -> 13031 bytes content/posts/notes_kicad/featured-image.png | Bin 0 -> 26641 bytes content/posts/notes_kicad/index.es.md | 249 ++++ .../notes_py4web/featured-image-preview.png | Bin 0 -> 23646 bytes content/posts/notes_py4web/featured-image.png | Bin 0 -> 68108 bytes content/posts/notes_py4web/index.es.md | 1289 +++++++++++++++++ 6 files changed, 1538 insertions(+) create mode 100644 content/posts/notes_kicad/featured-image-preview.png create mode 100644 content/posts/notes_kicad/featured-image.png create mode 100644 content/posts/notes_kicad/index.es.md create mode 100644 content/posts/notes_py4web/featured-image-preview.png create mode 100644 content/posts/notes_py4web/featured-image.png create mode 100644 content/posts/notes_py4web/index.es.md diff --git a/content/posts/notes_kicad/featured-image-preview.png b/content/posts/notes_kicad/featured-image-preview.png new file mode 100644 index 0000000000000000000000000000000000000000..155fa491a6e041f747d521c146c04fd03f67526b GIT binary patch literal 13031 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 literal 0 HcmV?d00001 diff --git a/content/posts/notes_kicad/featured-image.png b/content/posts/notes_kicad/featured-image.png new file mode 100644 index 0000000000000000000000000000000000000000..b710101b18e803fa290989e333f59f598817552f GIT binary patch literal 26641 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 N^3p0&74M({{{@BDcx?ax literal 0 HcmV?d00001 diff --git a/content/posts/notes_kicad/index.es.md b/content/posts/notes_kicad/index.es.md new file mode 100644 index 0000000..0975fc8 --- /dev/null +++ b/content/posts/notes_kicad/index.es.md @@ -0,0 +1,249 @@ +--- +weight: 4 +title: "Notas de KiCAD" +date: 2021-05-12T12:10:36+0200 +draft: false +summary: "Notas sobre KiCAD" +resources: +- name: "featured-image" + src: "featured-image.png" +- name: "featured-image-preview" + src: "featured-image-preview" +categories: + - notes +tags: + - pcb + - electronica + - kicad +--- + +Apuntes **muy incompletos** sobre _KiCAD_. + + + + +{{< admonition type=warning title="Work in progress" open=true >}} +Estos apuntes son personales y no valen para aprender a usar KiCAD, mejor búscate un buen tutorial en la red +{{< /admonition >}} + + +## Notas sueltas de KiCAD 6 + +### Schematic Editor + +- Nueva opción para buscar y sustituir símbolos: _Edit->Change Symbols_ o botón derecho del ratón sobre el símbolo a cambiar. Hay que mirar las opciones con atención para hacer los cambios deseados. +- Se puede seleccionar por rectángulos añadiendo "pedacitos" manteniendo pulsada la tecla de mayúsculas y quitando "pedacitos" sin soltar la mayúscula y pulsando Control. + +## Import dxf file as _Edge Cut_ + +### Pasos básicos + +Estas notas están basadas en la importación del silk para la Badge de la OSHwdem + +1) Abri el PDF desde Inkscape + +2) Me pasé un buen rato limpiándolo + +3) Hice unas cuantas operaciones para dejar la silueta como un solo +'Path' en Inkscape + +4) Me hice un fichero solo con la silueta y lo salve como DXF, puede +haber más caminos, pero yo siempre uso DXF (LibreCAD) para diseñar los +contornos de las placas). Use "Autocad DXF R14" en la +opción 'Save as' + +5) Importe el DXF en KiCAD, asegurándome de importarlo en la capa Edge +Cut (que es el contorno físico de la PCB) + +Pruebas con KiCAD 7 + +**Desde LibreCAD** + +- LibreCAD con un círculo simple: OK +- LibreCAD con un círculo simple (R14): No conserva bien el tamaño (sale muy grande) +- LibreCAD complejo con una sola capa: OK +- LibreCAD complejo capa visible exportada a svg: OK + + +## Crear silks + +Partimos de un fichero svg que gestionamos con Inkscape. + +- El fichero tiene que ser en blanco y negro. Desde KiCAD vamos a + poder gestionar el fichero y su negativo +- No puede tener canal alfa, hay que añadir un fondo, blanco o negro. +- Tenemos que exportar el fichero a png, al menos con 1200 dpi +- Para no liarnos es mejor dimensionar el fichero en Inkscape al tamaño + que queramos en la placa +- Lo que vemos negro en la pantalla del Bitmap será entintado en el silk +- Si vemos el logo muy pequeño en la pantalla del _Bitmap Converter_ es + señal de que hay que aumentar los dpi en el export de Inkscape. + +## Usar Bibliotecas de terceros (por ejemplo las de Bricolabs) + +Tendremos dos maneras de usar las Bibliotecas + +* Globalmente en nuestro sistema +* Como submodulos de nuestro proyecto + +### Globalmente + +Esta es la forma más simple de tener las bibliotecas disponibles para todos nuestros proyectos y también facilita poder contribuir con nuevos componentes a esas bibliotecas. Pero si queremos distribuir nuestro proyecto no será tan elegante. + +Clonamos el [repo de las bibliotecas](https://gitlab.com/brico-labs/bricolabs_kicad_library) en algún directorio de nuestro ordenador (p.ej. `~/Resources/KiCAD/`) + +En el propio _KiCAD_ añadimos las bibliotecas como bibliotecas globales: desde la ventana principal de KiCAD menu `Preferences::Manage Symbol Libraries`, para los símbolos de esquema, y `Preferences::Manage Footprint Libraries` para las huellas. + +Alternativamente si queremos añadir las bibliotecas de forma que solo afecten al proyecto en el que estamos trabajando podemos añadirlas en la pestaña de Proyecto en lugar de en la global. + +### Como submodulos git de nuestro proyecto + +Aquí presuponemos que usas git para el control de versiones de tu proyecto KiCAD. + +Las bibliotecas se añaden como submodulos git en el directorio del proyecto y se añaden después mediante las preferencias de KiCAD como dijimos en el punto anterior. + +Las ventajas de hacerlo así son que facilita la distribución del proyecto y que se fija la versión de las bibliotecas que estamos usando. + +## Crear un nuevo símbolo de componente para nuestros esquemas + +{{< admonition type=info title="Referencias" open=false >}} +- [KiCAD: _Getting Started_](https://docs.kicad.org/5.1/es/getting_started_in_kicad/getting_started_in_kicad.html#make-schematic-symbols-in-kicad) +- [Creating Schematic components and libraries](https://michd.me/blog/kicad-working-with-schematic-components-and-libraries/) +- [Hackaday: KiCAD Best Practices, library management](https://hackaday.com/2017/05/18/kicad-best-practises-library-management/) +{{< /admonition >}} + + +Es super fácil crear un nuevo símbolo para los esquemas y hace falta a menudo. Merece la pena aprender a hacerlo. + + +{{< admonition type=warning title="git submodules" open=true >}} +No es muy conveniente cambiar el contenido de bibliotecas que se han añadido como submodulos git a nuestro proyecto. Salvo que controles bien el git te vas a meter en problemas. Mejor añadir las bibliotecas desde un directorio independiente y entonces las puedes editar sin problemas (aunque las propias bibliotecas las controles con git) +{{< /admonition >}} + + +## De Inkscape a KiCAD (extensión shenzhen) + +Aparentemente la extensión [shenzhen](https://github.com/badgeek/svg2shenzhen) no funciona para Inkscape 1.1 + +Podemos hacerla funcionar: + +* Descargamos la [AppImage para Inkscape 1.0.2](https://inkscape.org/release/all/gnulinux/appimage/). Yo la dejo en mi directorio `~/apps/inkscape` +* Creamos un enlace simbólico a la *AppImage* más reciente (esto es para facilitar los cambios de versión) + ```bash + cd ~/apps/inkscape + ln -s current + ``` + +* Creamos un script `shenzhen` con el siguiente contenido + + ```bash + #!/usr/bin/env bash + + export HOME=/home/salvari/apps/inkscape + ~/current + ``` +* Una vez ejecutado el script para comprobar que se abre correctamente el Inkscape, bajamos el fichero de la extensión desde el [github](https://github.com/badgeek/svg2shenzhen#install) y lo descomprimimos en el directorio `~/apps/inkscape/.config/inkscape/extensions` + +* Si rearrancamos nuestro Inkscape 1.0.2 con el script `shenzhen` veremos que ya tenemos la extensión funcionando. + +## Crear ficheros de huellas (_footprints_) + + +## De Eagle a KiCAD + +Vamos a usar [estos scripts](https://github.com/lachlanA/eagle-to-kicad) + +## Notas sueltas + +* Para **copiar un símbolo entre bibliotecas**: Abrir el _Symbol Editor_ navegar hasta el símbolo a copiar y con el +botón derecho seleccionar _Salvar Copia como.._ Y seleccionamos en que +librería se quiere salvar. + +* Para poner un **texto negado** (con una raya por arriba) se rodea el texto con tildes `~negado~` + +* Para **copiar entre esquemas de distintos proyectos**. Hay que usar la aplicación _eeschema_ independiente para abrir los esquemas, no se puede copiar entre proyectos + +## Huella mixta (tht smd) + +Copiamos la THT desde la biblio de KiCAD + + +## KiCAD 6, módulos Python para Pcbnew + +Podemos acceder a la consola (intérprete) de Python desde _pcbnew_. + +```python +Py 0.9.8 +Python 3.8.10 (default, Jun 22 2022, 20:18:18) +[GCC 9.4.0] on linux +Type "help", "copyright", "credits" or "license" for more information. +Startup script executed: /home/salvari/.config/kicad/6.0/PyShell_pcbnew_startup.py +>>> + +## Para averiguar el python que estamos usando: +>>> import sys +>>> print(sys.executable) +/usr/bin/python3 +>>> + + +import pip + +pip.main(['install', 'kikit']) +``` + + + + +## Referencias + +### KiCAD +- [KiCAD: _Getting Started_](https://docs.kicad.org/5.1/es/getting_started_in_kicad/getting_started_in_kicad.html#make-schematic-symbols-in-kicad) +- [Creating Schematic components and libraries](https://michd.me/blog/kicad-working-with-schematic-components-and-libraries/) +- [Hackaday: KiCAD Best Practices, library management](https://hackaday.com/2017/05/18/kicad-best-practises-library-management/) +- [Build minimal STM32 development board](https://vivonomicon.com/2018/05/05/your-own-hardware-designing-an-stm32-development-board/) +- [Componentes habituales en PCBs por Luis Llamas](https://www.luisllamas.es/componentes-habituales-en-pcbs/) +- [Bibliotecas que puedes usar en KiCAD](https://michd.me/blog/kicad-working-with-schematic-components-and-libraries/) +- [SnapEDA KiCAD Libraries](https://www.elcorteingles.es/electrodomesticos/A30031273-plancha-de-vapor-rowenta-dw8221-pro-master-con-vapor-extra/) +- [Ultra Libraria KiCAD Libraries](https://www.ultralibrarian.com/cad-vendors/kicad/) + +### Diseño PCB +- [Libro: Fundamentals of Circuit Design by Hongshen Ma](http://www-mdp.eng.cam.ac.uk/web/library/enginfo/electrical/hong1.pdf) +- [PCB Design Tutorial by David L. Jones](https://www.alternatezone.com/electronics/files/PCBDesignTutorialRevA.pdf) +- [Guia de la Universidad de Toronto](http://www.karadev.net/uroci/filespdf/files/pcb_tutorial_rev1.pdf) +- [Una guía de Analog Devices](https://www.analog.com/media/en/training-semininars/design-handbooks/Basic-Linear-Design/Chapter12.pdf) +- [Una playlist de Phil's Lab](https://invidious.projectsegfau.lt/playlist?list=PLXSyc11qLa1b9VA7nw8-DiLRXVhZ2iUN2) +- Algunos tutoriales: + - https://learn.sparkfun.com/tutorials/pcb-basics/all + - https://www.powerelectronicsnews.com/step-by-step-example-for-practical-pcb-design-power-supply-design-tutorial-section-3-3/ + - https://www.circuitstoday.com/pcb-design-basics + +### Relacionadas con electrónica + +- [LastMinuteEngineers](https://lastminuteengineers.com/) +- [STM32 step by step tutorial](https://blog.st.com/stm32-step-by-step-tutorial/) + +### Proveedores de PCB + +-[Aisler](https://aisler.net/) fabrican en Europa + +### Plugins to review + +- [KiBuzzard](https://github.com/gregdavill/KiBuzzard) +- [Interactive html BOM](https://github.com/openscopeproject/InteractiveHtmlBom) +- [KiKit](https://github.com/yaqwsx/KiKit) +- [KiCAD footprint generator](https://gitlab.com/kicad/libraries/kicad-footprint-generator) +- [KiCAD and FreeCAD](https://www.kicad.org/external-tools/stepup/) +- [KiCAD action plugins](https://github.com/MitjaNemec/Kicad_action_plugins) +- [KiCAD checklist](https://github.com/azonenberg/pcb-checklist) + + +### TBR + +- https://www.pcbway.com/blog/PCB_Design_Tutorial/Using_Git_with_KiCad.html +- https://medium.com/inventhub/better-manage-kicad-projects-using-git-8d06e1310af8 +- https://www.youtube.com/playlist?list=PLn6004q9oeqGl91KifK6xHGuqvXGb374G + +### Proveedores de componentes +- [TME](https://www.tme.eu/) +- [LCSC](https://lcsc.com/) diff --git a/content/posts/notes_py4web/featured-image-preview.png b/content/posts/notes_py4web/featured-image-preview.png new file mode 100644 index 0000000000000000000000000000000000000000..0e12c6c6c6c74b3a6042ea0d6efd26d1db5fae24 GIT binary patch literal 23646 zcmV)JK)b(*P)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00006 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 + +Apuntes de py4web, muy incompletos. + +De momento son una copia descarada del [curso de Luca de Alfaro](https://learn-py4web.github.io/) (que está genial para aprender) + +{{< /admonition >}} + +{{< admonition type=info title="Referencias" open=true >}} + +- [El tutorial de Luca de Alfaro](https://learn-py4web.github.io/) Pero mejor usa los videos de la siguiente referencia. +- [El video-tutorial de Luca de Alfaro](https://www.youtube.com/watch?v=hv3aEaT6ulI&list=PLAVb3DQlAH4tIvdAsmese0_xRkvZYlox0 "El video-tutorial de Luca de Alfaro") (muy bueno) +- [El video-tutorial en Invidious](https://invidious.namazso.eu/playlist?list=PLAVb3DQlAH4tIvdAsmese0_xRkvZYlox0) +- [Bulma CSS crash course](https://www.youtube.com/watch?v=IiPQYQT2-wg) by Traversy Media + +{{< /admonition >}} + + + +## ¿Que aplicación queremos crear? + +Una aplicación de inventario que llamaremos _Cornucopia_. + +## Instalación de _py4web_ + +### Clonando py4web desde github + +1. Como de costumbre creamos un entorno virtual para trabajar. Con un entorno virtual independiente podremos instalar todas las bibliotecas python que queramos sin interferir con el *python del sistema*. + Personalmente uso `pyenv` para gestionar los entornos virtuales en mi sistema por que me permite usar cualquier versión de Python. (Echa un ojo a los [apuntes de python]({{< relref "notes_python" >}} "apuntes de python") si quieres saber mas de `pyenv`) + + ```bash + pyenv virtualenv 3.9.7 ve_py4web + ``` + +1. Creamos un directorio de trabajo y asignamos el entorno virtual. Es decir que usando otra vez `pyenv` vamos a asociar el entorno virtual que creamos en el paso anterior a un directorio de nuestro disco (como *entorno virtual local*). Nuestro sistema, (gracias a `pyenv` sabrá que hay que activar el *virtualenv local* si estamos trabajando en este directorio o en cualquiera de sus descendientes. En otras palabras estamos activan el virtualenv automáticamente si estamos en algún directorio del proyecto. + + ```bash + mkdir webdev + cd webdev + pyenv local ve_py4web + myve # Esta macro se encarga de instalar lsp en mi entorno python + ``` + + El alias `myve` en mi ordenador equivale a ejecutar las lineas de abajo. Es decir instala en nuestro nuevo entorno virtual algunas bibliotecas básicas para gestionar entornos virtuales e instalar otras bibliotecas. Además también instala el **L**anguage **S**erver **Protocol** server, que nos valdrá para tener facilidades adicionales al editar ficheros de Python: + + ```bash + pip install --upgrade pip setuptools wheel pipx virtualenv virtualenvwrapper + pip install 'python-lsp-server[all]' + ``` + + +1. Clonamos el `py4web`: + ```bash + git clone https://github.com/web2py/py4web.git + ``` + +1. Instalamos las dependencias de ___py4web___, es decir las bibliotecas de python que el programa ___py4web___ necesita para funcionar. + + ```bash + cd py4web + pip install -r ./requirements.txt + ``` + +1. Ya estamos listos para arrancar nuestra nueva instancia de ___py4web___, podemos comprobar que funciona con `./py4web.py version`. Para arrancar la aplicación, establecemos la password de administración y lanzamos la aplicación especificando en que directorio residen las aplicaciones. + + ```bash + ./py4web.py set_password + ./py4web.py run apps + ``` + +### Instalando py4web con pip +Seguimos las instrucciones del github de py4web, coincide con lo que comenta Luca de Alfaro en este segundo video. + +```bash + pyenv virtualenv 3.11.4 ve_p4w_311 + amd p4w_311 + pyenv local ve_p4w_311 + myve # esta macro se encarga de instalar LSP en mis entornos python + pip install --upgrade --no-cache-dir py4web + + py4web setup apps # Instalar todas contestando a todo que si + py4web set_password # Configurar password de administración + py4web run apps # Arrancar el sistema + + py4web -h # resumen de comandos +``` + +Siempre podemos añadir el _scaffold\_bulma_ como comentamos en el apartado anterior. + + +## Preparando la primera _app_ + +Pasos a seguir: + +1. Crear la _app_ dentro de nuestro ___py4web___ +1. Decidir la base de datos +1. Decidir el tipo de _session_ (fichero `settings.py`) +2. Cambiar el `SESSION_SECRET_KEY` en el fichero `settings.py` + {{< admonition type=tip title="login con username" open=true >}} + + Si queremos activar el uso de usernames (un nombre de usuario abreviado para el login) tenemos que cambiar la opción `auth.use_username` en el fichero `common.py`. + + Si hacemos este cambio y usamos ___sqlite3___ como base de datos ___py4web___ no será capaz de cambiar la estructura de la tabla "al vuelo". Tendremos que cambiarla a mano en la base de datos si ya está creada, o directamente borrar la base de datos y permitir que ___py4web___ la genere de nuevo. + {{< /admonition >}} + +3. Configurar el modelo de nuestra _app_ (la estructura de la base de datos) + + +### Crear la _app_ dentro de nuestro py4web + +En la instalación que hemos propuesto, tendremos ___py4web___ instalado en el directorio `..../webdev/py4web`, podemos crear una nueva aplicación desde el _dashboard_ del propio ___py4web___ o crearla nosotros a mano en el directorio `..../webdev/py4web/apps` + +Tenemos varios _templates_ para escoger a la hora de crear una nueva aplicación: + +_minimal_ + +: es un _template_ que contiene lo mínimo imprescindible para empezar + +_scaffold_ + +: Un _template_ creado por Maximo Di Pietro, mucho más completa que _minimal_. Basado en [no.css](https://github.com/mdipierro/no.css/) un framework [CSS]^(Cascade Style Sheets) extremadamente simple. + +_scaffold\_bulma_ + +: Un _template_ creado por Luca de Alfaro, basado en [Bulma](https://bulma.io) otro framework CSS (con la particularidad de que no necesita JavaScript). Este _template_ no venía por defecto con ___py4web___ lo he descargado del [Bitbucket de Luca de Alfaro](https://bitbucket.org/luca_de_alfaro/workspace/projects/PY4WEB). + +Vamos a usar como punto de partida la propuesta de Luca De Alfaro, un _Template_ basado en _Bulma_ para la parte CSS. Podemos pasarle la dirección del github al _Dashboard_ y crear una nueva aplicación o clonarlo con git con: + +```bash +cd py4web/apps +git clone git@bitbucket.org:luca_de_alfaro/scaffold_bulma.git cornucopia +``` + +Con esto tendremos un nuevo directorio `..../webdev/py4web/apps/cornucopia` que contendrá nuestra nueva aplicación. Como queremos tener nuestra aplicación en nuestro propio git tenemos que cambiar la URL asociada a nuestra propia dirección (p.ej. ) para ello: + +```bash +cd cornucopia +git remote -v +git remote set-url origin git@git.comacero.com:py4web/cornucopia.git +git remote -v +git push --set-upstream --all +``` + +Así conseguimos que el directorio `..../webdev/py4web` esté apuntando al git original de ___py4web___ (para poder actualizar fácilmente), y el directorio de nuestra _app_ apuntando a nuestro propio git para tener controlada el desarrollo del software. + + +#### Estructura de nuestra aplicación + +En el nuevo directorio de nuestra aplicación tenemos los siguientes subdirectorios: + +```bash +tree -d cornucopia +cornucopia +├── databases +├── __pycache__ +├── static +│   ├── css +│   ├── font-awesome-4.7.0 +│   │   ├── css +│   │   ├── fonts +│   │   ├── less +│   │   └── scss +│   └── js +├── templates +├── translations +└── uploads +``` + +`static` + +: Almacena el contenido _estático_, aquí nos encontraremos imágenes (como logos por ejemplo), ficheros CSS y JavaScript. + +`databases` + +: En este directorio se almacena la base de datos, se usa principalmente en el desarrollo con motores de base de datos como SQLite, en producción lo normal es usar motores de base de datos más potentes; como MariaDB o Postgresql que no almacenarán sus datos en este directorio. + +`templates` + +: Aquí residen las plantillas de las páginas web de nuestra aplicación + +`translations` + +: En este directorio tenemos los ficheros de I18n para nuestra aplicación. + +`uploads` + +: Aquí se almacenan los contenidos de tipo `upload` que usemos en nuestra applicación (si es que los usamos, claro) + +___py4web___ va a cargar nuestra aplicación como un módulo Python. Por eso en el directorio `cornucopia` tenemos un fichero `__init__.py` +Si vemos el contenido del fichero veremos que hace tres cosas: +- Carga el módulo general `py4web` +- Importa la definición de `db` desde el fichero `models.py` +- Importa los controladores desde el fichero `controllers.py` + +En el fichero `controllers.py` es donde definimos todas las __rutas__ que tendrá nuestra aplicación. Un ejemplo chorras de ruta sería: + +```python3 +@action('sample-page') +@action.uses('spage.html') +def serve_sample_page(): + return dict() +``` + +- El decorador `@action` define la ruta, es decir la URL asociada que en nuestro caso con el servidor local sería +- El decorador `@action.uses` define los recursos necesarios para esta nueva ruta, en este caso solo especificamos un _html template_ que tiene que existir en el directorio `cornucopia/templates` +- Por último definimos la función que implementa el controlador de la ruta, es imprescindible que esta función devuelva un diccionario. El diccionario sirve para pasar valores al _html template_, pero en nuestro caso no son necesarios así que devolvemos un diccionario vacío. + +Otros ficheros de la aplicación: + +`settings.py` + +: contiene declaraciones de valores usados por la aplicación. Por ejemplo que base de datos usamos, etc. etc. + +`models.py` + +: contiene las definiciones de las tablas de la base de datos + +`common.py` + +: Define varias valores fundamentales para el funcionamiento de la aplicación. Entre otros: + * La conexión a la base de datos + * El tipo de sesión que usaremos + * El mecanismo de autenticación que usará la aplicación + + +#### El flujo de trabajo durante el desarrollo + +Nos vamos a pasar la mayor parte del tiempo escribiendo _controllers_ y _templates_ para cada ruta que necesitemos en nuestra aplicación vamos a tener que codificar un _controller_ y casi con toda seguridad su correspondiente _template html_ + +Para la parte de los _templates_ vamos a usar un lenguage de _templates_: [YATL]^(Yet Another Template Language) (ver [documentación de YATL](https://py4web.com/_documentation/static/en/chapter-09.html))aunque ___py4web___ soporta también _Renoir_ (aparentemente usa los dos tras las bambalinas y de forma transparente para nosotros) + +{{< admonition type=tip title="Lenguajes de _template_" open=true >}} + +Los lenguajes de _template_ permiten definir plantillas de documentos (de cualquier tipo), donde se hacen operaciones de sustitución de parámetros o incluso secciones de código de programa, para generar el documento final. + +El concepto ha demostrado ser tan potente que hay implementaciones en practicamente todos los lenguajes de programación (cuando no se implementa directamente en el propio lenguaje) + +Hay muchos lenguajes de _template_ para Python, probablemente ___Jinja___ sea el más conocido. En ___py4web___ se usa ___YATL___. + +{{< /admonition >}} + + + +### Decidir que motor de base de datos vamos a usar. + +Por defecto ___py4web___ va a usar _SQLite_ como motor de base de datos, pero soporta muchos más. + +Podemos seguir con nuestro desarrollo en _SQLite_ sin más. En ese caso puedes saltarte la instalación de _MariaDB_. + +Para el caso de que alguien quiera hacer el desarrollo con un motor de base de datos más potente que _SQLite_ vamos a describir como usar _MariaDB_ (instrucciones también válidas para _MySQL_) para tener al menos dos opciones y por si alguien quiere experimentar con un motor de base de datos más potente que _SQLite_. + +Yo voy a instalar _MariaDB_ como un contenedor _Docker_ para el desarrollo va perfecto. + +Cuando se pase la aplicación a producción habrá que ver cual es la mejor opción. Se podría seguir con el servidor "dockerizado" o decidir si se quiere una instalación de _MariaDB_ en el servidor real (el _host_ si hablamos la jerga de contenedores) o incluso podría ser que tuviéramos un servidor de base de datos en nuestra red y quisieramos usarlo para nuestra aplicación. Hay muchas posibilidades. + +#### Usando MariaDB como base de datos + +{{< admonition type=tip title="MySQL" open=true >}} + +Si queremos usar _MySQL_ en lugar de _MariaDB_ el procedimiento sería exactamente el mismo que el descrito. + +{{< /admonition >}} + +Como ya comenté, me voy a instalar la base de datos en Docker, prefiero tenerla lo más aislada posible en el portatil. + +```bash +# Bajamos la imagen del hub de Docker +docker pull mariadb:10.7.3 + +# Lanzamos el servidor de base de datos: +docker run --detach --name my-mariadb --publish 3306:3306 \ +--env MARIADB_USER=pyuser --env MARIADB_PASSWORD=secreto \ +--env MARIADB_ROOT_PASSWORD=secreto mariadb:10.7.3 + +# Instalamos el cliente de mariadb en nuestro linux +sudo apt install mariadb-client + +# Nos conectamos a la base de datos (para probar el acceso) +mariadb -h 127.0.0.1 -u pyuser -p +``` + +Ya tenemos un servidor de bases de datos _MariaDB_ accesible desde nuestro PC. Al estar dockerizada tenemos que hacer todas las conexiones con la dirección IP, como si fuera un servidor independiente en nuestra red, aunque usamos la IP local: `127.0.0.1` como dirección del servidor _MariaDB_. + +También tenemos que crear manualmente la base de datos que vamos a usar. Crearemos la base de datos `cornucopiadb` y daremos todos los privilegios de acceso sobre esta base de datos al usuario `pyuser`. El comando de conexion a la base de datos sería: + +```bash +mariadb -h 127.0.0.1 -u root -p +``` + +Y para crear la base de datos y dar privilegios: + +```sql +create database cornucopiadb; +grant all privileges on cornucopiadb.* to pyuser@'%'; +flush privileges; +quit +``` + +Es decir: + +- Creamos la base de datos `cornucopiadb` +- Concedemos todos los privilegios al usario `pyuser` conectado desde cualquier IP a todas las tablas de `cornucopiadb` +- Hacemos un `flush` para que los privilegios se activen de inmediato + + +El siguiente paso es instalar alguna biblioteca Python de conexión a la base de datos. Cualquiera de los conectores disponibles para _MySQL_ debería funcionar correctamente con _MariaDB_. En nuestro caso vamos a instalar `pymysql`. Nos aseguramos de tener activado el entorno virtual del proyecto e instalamos con `pip`: + +```bash +pyenv which pip +pip install pymysql +``` + +Sabiendo que biblioteca de conexión a MariaDB tenemos instalada ya podemos definir la conexión a la base de datos en nuestra aplicación ___py4web___. Tenemos que editar el parámetro `DB_URI` en el fichero `settings.py` de nuestra aplicación. + +El `DB_URI` que viene configurado por defecto es el de _sqlite3_, en la [documentación oficial](https://py4web.com/_documentation/static/en/chapter-07.html#connection-strings-the-uri-parameter) podemos comprobar que necesitamos algo como: `mysql://pyuser:secreto@127.0.0.1/cornucopiadb?set_encoding =utf8mb4`. + +Una vez editado el fichero `settings.py` y cambiado el `DB_URI` podemos arrancar nuestra aplicación con `./py4web run apps` + + +{{< admonition type=tip title="Otros motores de base de datos" open=true >}} + +Los pasos descritos deberían ser muy parecidos al margen del motor de base de datos que usemos. Solo tendremos que instalar la biblioteca python adecuada a la base de datos elegida y ajustar el `DB_URI` a ese motor de base de datos. + +{{< /admonition >}} + + +### Decidir el tipo de sesión y cambio del `SESSION_SECRET_KEY` + +En el video-curso de Luca de Alfaro, nos explican cuales son las funciones de una `session`, y por qué es imprescindible tener un mecanismo para gestionar sesiones de usuario en nuestra aplicación. Si no lo tienes claro mira los videos: + +- [Simple Form](https://www.youtube.com/watch?v=3nkdtnvFfdw&list=PLAVb3DQlAH4tIvdAsmese0_xRkvZYlox0&index=20) +- [Form Attacks](https://www.youtube.com/watch?v=qvWVFy8pRxY&list=PLAVb3DQlAH4tIvdAsmese0_xRkvZYlox0&index=21) +- [Py4web Form Processing](https://www.youtube.com/watch?v=_prMUT6EpUc&list=PLAVb3DQlAH4tIvdAsmese0_xRkvZYlox0&index=22) + +Editamos el fichero `settings.py` de nuestra nueva aplicación y fijamos el tipo de sesión (recomendable usar `database`) + +Cambiamos el parámetro `SESSION_SECRET_KEY` que viene por defecto en el template por uno nuevo. Podemos usar un generador de _uuid: como [este](https://www.uuidtools.com/generate/v5). + +### Definiendo nuestro modelo + +Una vez arrancado ___py4web___ podemos conectarnos a la base de datos (da igual que sea _sqlite3_ o _MariaDB_) y comprobar que ___py4web___ ha creado las tablas necesarias para la gestión de usuarios y sesiones. Podemos comprobarlo desde nuestro cliente de base de datos con el comando `.tables` si usamos _sqlite3_ o con el comando `show tables` si estamos usando _MariaDB_. También podemos comprobarlo desde el propio cuadro de mando del ___py4web___. + +Veremos que ___py4web___ ha creado las tablas: + +- `auth_user` +- `auth_user_tag_groups` +- `py4web_session` + +Todas las tablas estarán vacías, puesto que aun no hemos creado usuarios de la aplicación (lo haremos más adelante). Pero ya vemos que ___py4web___ es capaz de ir creando nuevas tablas en la base de datos que hayamos definido. Así, a medida que vayamos definiendo el __modelo__ de nuestra aplicación, veremos que automáticamente se crean (y/o modifican) las tablas correspondientes en nuestra base de datos. + + +#### Definiendo tablas + +El objetivo de nuestra aplicación es mantener un inventario de "cosas". Parece lógico que nuestra primera tabla valga para almacenar "cosas". Así que en el fichero `cornucopia/models.py` añadimos las siguientes lineas (en la sección indicada) y salvamos el fichero: + +~~~~python +### Define your table below +# +# db.define_table('thing', Field('name')) +# +## always commit your models to avoid problems later + +db.define_table('thing', + Field('id', 'integer'), + Field('name', 'string') + Field('description', 'string'), + migrate = True) +~~~~ + +Ya tenemos creada nuestra nueva tabla `thing`. La hemos definido de forma explícita con dos campos: `id` y `description` y un parámetro adicional: `migrate = True` + +Lo cierto es que se recomienda no crear explicitamente el campo `id`. ___py4web___ se va a encargar de crear siempre este campo para todas las tablas. Es un campo entero _autoincremental_ (generalmente empezando por 1); esto quiere decir que cada vez que se inserta un nuevo registro en la tabla, la base de datos va a asignar un entero en el campo `id` incrementando un contador interno de la tabla. + +El parámetro `migrate = True` hace que ___py4web___ intente mantener la definición de la base de datos real (en el motor de base de datos que estemos usando) alineada con el modelo que definamos en el fichero `models.py`. Si cambiamos la definición, se ejecutarán los comandos de base de datos necesarios para cambiar la definición de la tabla en la base de datos. + +En realidad se ha definido `migrate = True` por defecto para todas las tablas en el fichero `settings.py` así que la definición de nuestra tabla podria quedar commo: + +```python +Table('thing', + Field('name', 'string') + Field('descriptor', 'string')) +``` + +Si recargamos el fichero `models.py` (desde el _Dashboard_), podremos comprobar que se ha creado la correspondiente tabla en la base de datos y podríamos crear algunos registros (lineas de la tabla) en ella a través del propio _Dashboard_ de ___py4web___. + + +Laa tabla es demasiado simple, evidentemente tenemos que mejorar nuestro modelo. Pero antes de profundizar vamos a echar un vistazo a los __formularios__. + +### El primer formulario + +#### Un formulario simple + +Los formularios (_html forms_) son una parte importantísima de nuestra aplicación. Gran parte de las interacciones con los usuarios se harán via formularios html. + +Ya tenemos definida nuestra tabla `thing`, vamos a ver como crear un formulario (_html form_) para añadir nuevos objetos `thing` a nuestra base de datos. + +En la parte del template definimos: + +```yatl +[[extend 'layout.html']] + +

+ Add a new Thing + +
+
+
+ + +
+
+
+
+``` + +y en la parte del controller vamos a añadir una ruta `add`: + +```python3 +@action('add', method=['GET', 'POST']) +@action.uses('add.html', db, auth.user) +def add(): + if request.method == 'GET': + return dict() + else: + print(request.params.get("thing_name")) + db.thing.insert(name=request.params.get("thing_name")) + redirect(URL('add')) +``` + +El primer decorador de nuestro _controller_ (en la primera línea) define la ruta asociada, que será `//add`, en nuestro caso podría quedar como `http://127.0.0.1:8000/cornucopia/add`. Además especificamos que el controlador atiende peticiones (_html requests_) de tipo `GET` y `POST`. + +El segundo decorador del _controller_ (`@action.uses...` en la segunda línea) define los [_fixtures_](https://py4web.com/_documentation/static/en/chapter-06.html) asociados al _controller_: +* En primer lugar asocia el _template_ a la ruta, en nuestro caso `add.html`. Es importante que sea el primero por que los que vengan a continuación a menudo inyectarán funciones en el _template_ para que las podamos usar al generar el código _html_ +* Después un objeto `db` que encapsula la conexión a la base de datos. Esta conexión está definida en el fichero `common.py` y en nuestro caso nos permite acceder a una base de datos en el servidor _MariaDB_. +* Aunque no está declarado especificamente también se asigna el _session fixture_. +@ El _auth fixture_ nos permite gestionar el login del usuario, los permisos del usuario, etc. Hay varias opciones para configurar el comportamiento de `auth` en el fichero `common.py`. Al especificar `auth.user` será necesario ser un __usuario autenticado__ para acceder a esta ruta. + +{{< admonition type=tip title="Fixtures" open=true >}} + +Un objeto de clase `Fixture` en ___py4web___ implementa los siguientes métodos: +- `on_request` que se invoca al recibir un _html request_ +- `on_error` que se invoca si hay un error al procesar la _request_ +- `on_success` que se invoca una vez procesada con éxito la _request_ +- `transform` que se invoca tras procesar la _request_ para transformar la salida de la misma + +Por ejemplo el _DAL fixture_: +- `on_request`: hace una reconexión con la base de datos (es configurable) +- `on_error`: hace un _rollback_ de la transacción pendiente en la base de datos +- `on_success`: hace un _commit_ de la transacción pendiente en la base de datos +{{< /admonition >}} + + +Cuando visitamos la URL `/cornucopia/add` estamos haciendo un `GET` así que nuestro _controller_ devuelve un diccionario vacío, py4web renderiza el _template_ y lo envía como respuesta al navegador del usuario que verá en su pantalla el formulario html. + +Cuando el usuario hace un ___Submit___ con el botón correspondiente, lo que enviamos al servidor web es una `POST request`, así que nuestro _controller_ va a imprimir en la consola el nombre de nuestra _thing_ y la va a insertar en la base de datos. + +En el código podemos ver como consultar los parámetros del _payload_ de una `POST request`, ___py4web___ está basado en _Bottle.py_ así que podemos consultar [la documentación de _Bottle_](https://bottlepy.org/docs/dev/api.html) para cualquier duda. + +También podemos ver como se hace una inserción en la base de datos con ayuda del [DAL]^(Database Abstraction Layer) de ___py4web___. Vamos a hacer un uso intensivo del DAL si quieres puedes echar un ojo a la [documentación](https://py4web.com/_documentation/static/en/chapter-07.html) + +De todas formas esto no es más que un ejemplo para ver un formulario básico, en realidad jamás los vamos a implementar así por que por un lado es inseguro, y por otro lado ___py4web___ nos ofrece facilidades mucho más potentes para hacerlos. + +#### Un formulario usando las "facilidades" de ___py4web___ + +El formulario simple que hemos definido en el punto anterior, además de dar bastante trabajo es __inseguro__ cualquiera podría crear "cosas" en nuestra base de datos enviando _POST Requests_ a nuestro servidor. + +```python3 +@action('add', method=['GET', 'POST']) +@action.uses('add.html', db, auth.user) +def add(): + form = Form(db.thing, csrf_session=session, formstyle=FormStyleBulma) + if form.accepted: + # We simply redirect, the insertion already happened + redirect(URL('index')) + # This is a GET or a POST with errors + return(dict(form=form)) + +``` + +Este es nuestro formulario re-escrito. La parte importante es que ahora usamos `Form()` (es imprescindible hacer un `from py4web.utils.form import Form, FormStyleBulma` al principio de nuestro módulo `controllers.py`) + +`Form()` genera el formulario _html_ a partir de la definición de la tabla en la base de datos. A mayores le pasamos dos parámetros: uno para que genere un formulario con estilo "Bulma" y otro para que el formulario vaya protegido con una clave basada en la sesión del usuario. + +Además `Form()` nos ofrece un método para saber si el formulario ha sido recibido con datos válidos y aceptado. En ese caso simplemente dirigimos al usuario a la página principal (de momento). + +El fichero de _template_ quedaría tan simple como: + +```html +[[extend 'layout.html']] + +
+ Add a new Thing + +
+ [[=form]] +
+
+``` + +#### Refinar la base de datos + +Para comprobar como nuestro formulario se adapta automáticamente a la definición de la tabla en la base de datos vamos a añadir un par de campos a la definición. En el fichero `models.py` vamos a añadir también una _helper function_: + +```python3 +def get_user_username(): + """Return user username if we have an auth_user.""" + return auth.current_user.get('username') if auth.current_user else None +``` + +Esta función nos devuelve el _username_ del usuario logueado en el servidor (si es que se ha logueado claro) En general todo el template Bulma que nos propone Luca De Alfaro se orienta a usar el correo del usuario como identidad del mismo (y tiene sus ventajas), pero a mi me gusta usar el _login_. + +La nueva definición de la tabla queda: + +```python3 +db.define_table('thing', + Field('id', 'integer'), + Field('name', 'string', requires=IS_NOT_EMPTY()), + Field('description', 'string'), + Field('created_by', default=get_user_username), + Field('creation_date', 'datetime', default=get_time), + migrate=True) +``` + +Hemos añadido dos campos de tal manera que el propio ___py4web___ se va a encargar de poner el valor cuando creemos una nueva "cosa" usando las _helper functions_ `get_time` y `get_username` que tenemos en el fichero `models.py`. + +También hemos especificado el parámetro `migrate=True`, este es el valor por defecto así que no vamos a cambiar nada por especificarlo. El parámetro a `True` hace que _py4web_ cree o modifique las tablas en la base de datos cuando modifiquemos el fichero `models.py` (ver [documentación](https://py4web.com/_documentation/static/en/chapter-07.html#migrations) + +Si ahora comprobamos nuestra aplicación en el ___py4web___ veremos que: + +a) La estructura de la tabla en la base de datos se ha actualizado y ahora tenemos los dos campos nuevos +b) El formulario de la página `add` también se ha actualizado para mostrar los nuevos campos a la hora de crear una nueva "cosa" + +De todas formas los dos nuevos campos no deberían ser actualizables o iniciados por el usuario de la aplicación, es mejor reservarlos para que se inicien con los valores por defecto, para eso nos basta con cambiar el modelo y dejarlo así: + +```python3 +db.define_table('thing', + Field('id', 'integer'), + Field('name', 'string', requires=IS_NOT_EMPTY()), + Field('description', 'string'), + Field('created_by', default=get_user_username), + Field('creation_date', 'datetime', default=get_time), + migrate=True) + + +db.thing.id.readable = db.thing.id.writable = False +db.thing.created_by.readable = db.thing.created_by.writable = False +db.thing.creation_date.readable = db.thing.creation_date.writable = False +``` + +Con esto comprobaremos que al añadir una "cosa" ya no nos aparecen los campos en el formulario. + +### Listado de "cosas" + +Vamos a añadir un listado de "cosas" a nuestra aplicación, de momento lo añadimos en la página principal (una chapuza, pero lo corregiremos) + +Para empezar cambiamos el _controller_ que se ocupa de la página principal: + +```python3 +@action('index') +@action.uses('index.html', db, auth) +def index(): + rows = db(db.thing).select() + return dict(rows=rows) +``` + Con esto hemos usado por primera vez el [DAL]^(Database Abstraction Layer) de ___py4web___. En la línea 4 estamos haciendo un _select_ de todas las "cosas"" que hay en la tabla `things`. Y lo pasamos al _template_ a través de la variable `rows`. + + En el _template_ tenemos el siguiente código: + +```html +[[extend 'layout.html']] + +
+
+ + + + + + + + + [[for row in rows:]] + + + + + + + + [[pass]] +
IdNameDescriptionCreated byCreated on
[[=row.id]][[=row.name]][[=row.description]][[=row.created_by]][[=row.creation_date]]
+
+
+``` + +Las líneas 1 ~ 12 definen una página web con una tabla (vamos a presentar una "cosa" por cada linea de la tabla) +En las lineas 13 ~ 21 tenemos un bucle `for` que itera sobre todas las rows que hemos pasado al _template_ generando una linea de la tabla para cada `row`, es decir para cada "cosa" almacenada en la base de datos. + +Esta tabla es bastante chorras y no nos vale de mucho. Vamos a darle un poco más de funcionalidad + +#### Listado de "cosas" interactivo + +Vamos a cambiar el código _html_ para que en cada linea de la tabla (cada "cosa") tengamos un botón de edición y un botón de borrado. + +```html +[[extend 'layout.html']] + +
+
+ + + + + + + + + + + [[for row in rows:]] + + + + + + + + + + [[pass]] +
IdNameDescriptionCreated byCreated on
[[=row.id]][[=row.name]][[=row.description]][[=row.created_by]][[=row.creation_date]] + + Edit + + + + + +
+
+
+``` + +Hemos añadido un par de títulos de columna vacíos para que la tabla quede bonita, y en cada linea definimos los botones (lineas 22 ~ 32) + +Para el botón _Edit_ definimos un botón con un icono y un texto. + +Para el botón _Delete_ solo ponemos el icono de la papelera. + +Evidentemente tendremos que definir los correspondientes _controllers_ para las acciones de __Edición__ y __Borrado__ de los objetos "cosa" de nuestra base de datos. Pero hay que fijarse también en como generamos las URL asociadas a los botones: + +__Edición__ + +La url la generamos con `URL('edit', row.id)` eso nos va a generar una url de la forma: `http://://edit/` en nuestro caso sería algo como `http://127.0.0.1:8000/cornucopia/edit/83`. Y la tradución sería: _quiero editar la "cosa" con id=83_ + +Para que el _controller_ lea correctamente este URL tenemos que informar de las estructura del _path_ que añadimos a la url. En nuestro caso el _path_ es sencillamente `/` pero podría ser mucho más largo y con más parámetros. + +Nuestro _controller_ sería: + +```python3 +@action('edit/', method=['GET', 'POST']) +@action.uses('edit.html', url_signer, db, session, auth.user) +def edit(thing_id=None): + assert(thing_id is not None) + # my_thing = db(db.thing.id == thing.id).select().first() + my_thing = db.thing[thing_id] + if my_thing is None: + # Nothing found to edit + redirect(URL('index')) + form = Form(db.thing, record=my_thing, + csrf_session=session, formstyle=FormStyleBulma) + + if form.accepted: + # The update has been done + redirect(URL('index')) + return dict(form=form) + +``` + +* En la línea 1 el decorador `@action` define la interpretación del _path_, como `thing_id` que será un entero +* En la línea 3, el controller toma el `thing_id` como parámetro, además si no nos lo pasan (hay que ser siempre paranoico) lo ponemos a `None` y provocamos un fallo en la línea 4 +* Podríamos seleccionar nuestra "cosa" en la base de datos explicitamente como en la linea 5, pero esto se hace con tanta frecuencia que ___py4web___ nos ofrece una forma abreviada, que usamos en la linea 6 +* Por fin, si no encontramos la "cosa" en la base de datos (siempre paranoicos), nos vamos a la página principal sin hacer nada. Si la encontramos generamos un formulario para editarla especificando el parámetro `record`en la llamada a `Form()` +* Las lineas 13 ~ 15 se encargan de redirigir a la página principal si tenemos un _POST request_ y el formulario ha completado una edición +* En caso contrario, aun tenemos que preguntar al usuario que quiere editar así que pasamos el formulario al template y generamos la página de eición para el usuario. + + +__Borrado__ + +Para el botón de borrado la url generada es ligeramente diferente, usamos el comando: `URL('delete', row.id, signer=url_signer)`, donde especificamos que la _html request_ debe ir firmada. + +La acción de borrado se va a ejecutar directamente en el controller en cuando el botón lance la _request_ así que necesitamos asegurarnos de la autenticidad. La firma va a depender tanto de la sesión como del contenido de la propia _request_ para que un atacante no pueda falsificar peticiones de borrado. + +El _controller_ nos quedaría como especificamos a continuación: + +```python3 +@action('delete/') +@action.uses(db, session, auth.user, url_signer.verify()) +def delete(product_id=None): + assert product_id is not None + db(db.product.id == thing_id).delete() + redirect(URL('index')) +``` + +Vemos que simplemente procede al borrado de nuestra "cosa" en la base de datos y redirige de nuevo a la página principal. Ni siquiera necesitamos un _template_ ya que no tenemos una página web dedicada a la acción de _Borrar_. + + + + + +--- +--- + + +{{< admonition type=warning title="Apuntes de web2py" open=true >}} + +__Lo que sigue a continuación de este aviso son mis antiguos apuntes de web2py__ + +{{< /admonition >}} + +## web2py + +[web2py](http://www.web2py.com/) es un _framework_ para facilitar el desarrollo de aplicaciones web escrito en Python. + +___web2py___ funciona correctamente en Python 3. Su curva de aprendizaje no es tan empinada como la de [Django](https://www.djangoproject.com/) (que es el _framework_ de aplicaciones web de referencia en Python) y en muchos sentidos es más moderno que Django. + +___web2py___ tiene una [documentación](http://www.web2py.com/init/default/documentation) muy completa y actualizada (disponible también en castellano) y sobre todo una comunidad de usuarios y desarrolladores muy activa y que responden con rapidez a las dudas que puedas plantear. + +__web2py__ está basado en el modelo +[MVC](https://es.wikipedia.org/wiki/Modelo%E2%80%93vista%E2%80%93controlador) + +__web2py__ incorpora _Bootstrap 4_ + +{{< admonition type=info title="Referencias web2py" open=false >}} +* [Página de documentación y recursos de web2py, con enlaces a grupos de usuarios y + tutoriales](http://www.web2py.com/init/default/documentation) +* [Evolución del modelo MVC](https://martinfowler.com/eaaDev/uiArchs.html) +* [Fat models and thin controllers](https://nomadphp.com/blog/60/working-with-the-thin-controller-and-fat-model-concept-in-laravel) +* [Crítica del mantra](https://nomadphp.com/blog/60/working-with-the-thin-controller-and-fat-model-concept-in-laravel) +* [Video tutorial en Python Weekly](https://yewtu.be/playlist?list=PL5E2E223FE3777851) +* [Web2py Tutorial by Terry Toy](https://vid.puffyan.us/playlist?list=PLmavdTilTrxLJ-8vdx7iDvVtiyC0NjTy-) + +{{< /admonition >}} + +### Empezar rápido + +#### Instalación + +Vamos a ver el proceso de instalación de una instancia de ___web2py___ en modo _standalone_. ___web2py___ instalado de esta forma es ideal +para entornos de desarrollo. Para un entorno de producción puede ser más conveniente instalar ___web2py___ tras un servidor web como +[Apache](https://www.apache.org/) o [Nginx](https://www.nginx.com/), pero dependiendo de la carga de trabajo y de como administres tus +sistemas puede ser mejor opción usarlo _standalone_ también en producción. + +1. Creamos un entorno virtual + + Como ya hemos comentado ___web2py___ funciona ya en Python 3. Y en cualquier caso, con Python nunca está de mas encapsular nuestras + pruebas y desarrollos en un entorno virtual.^[Los siguientes comandos asumen que tienes instalado _virtualenvwrapper_ como + recomendamos en la guía de postinstalación de Linux Mint, si no lo tienes te recomendamos crear un virtualenv con los comandos + tradicionales] Así que creamos el virtualenv que llamaremos _web2py_: + + ~~~~ + mkvirtualenv -p `which python3` web2py + ~~~~ + +1. Bajamos el programa de la web de Web2py y descomprimimos el framework: + + ~~~~bash + # creamos un directorio (cambia el path a tu gusto) + mkdir web2py_test + cd web2py_test + + # bajamos el programa de la web y descomprimimos + wget https://mdipierro.pythonanywhere.com/examples/static/web2py_src.zip + + # opcionalmente borramos el zip, aunque sería mejor guardarlo + # por si queremos hacer nuevas instalaciones + rm web2py_src.zip + ~~~~ + +1. Generamos certificados para el protocolo _ssl_: + + Para usar con comodidad web2py conviene que nos generemos unos + certificados para gestionar el ssl: + + ~~~~bash + # nos movemos al directorio de web2py + cd web2py + + openssl genrsa -out server.key 2048 + openssl req -new -key server.key -out server.csr + + Country Name (2 letter code) [AU]:ES + State or Province Name (full name) [Some-State]:A Coruna + Locality Name (eg, city) []:A Coruna + Organization Name (eg, company) [Internet Widgits Pty Ltd]:BricoLabs + Organizational Unit Name (eg, section) []:Division de Hackeo + Common Name (e.g. server FQDN or YOUR name) []:testServer@bricolabs.cc + Email Address []:contacto@bricolabs.cc + + Please enter the following 'extra' attributes + to be sent with your certificate request + A challenge password []:secret1t05 + An optional company name[]:Asociacion BricoLabs + ~~~~ + + Y ahora ejecutamos: + + ~~~~ + openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt + ~~~~ + +1. Servidor de base de datos. + + Para usar ___web2py___ es imprescindible tener acceso a un servidor de base de datos. Podemos usar _MySQL_ o _MariaDB_ por ejemplo. Pero para empezar rápidamente vamos a tirar de [SQLite](https://www.sqlite.org/version3.html), un servidor fácil de instalar potente y versátil. Es importante usar la versión 3 que introduce grandes mejoras sobre el antiguo _SQLite_ + + ~~~~bash + sudo apt install sqlite3 + ~~~~ + +1. Arrancamos el servidor: + + Deberíamos tener los ficheros generados en el paso anterior: `server.key`, `server.csr` y `server.crt`, en el directorio raiz de web2py. Podemos arrancar el servidor con los siguientes parámetros (recuerda activar el entorno virtual si no lo tienes activo): + + ~~~~bash + python web2py.py -a 'admin_password' -c server.crt -k server.key -i 0.0.0.0 -p 8000 + ~~~~ + + Y ya podemos acceder nuestro server ___web2py___, con nuestro [navegador favorito](https://www.mozilla.org/en-US/firefox/developer/), visitando la dirección + + +Y ahora si que ya tenemos todo listo para empezar a usar ___web2py___. Ya podemos crear nuestra primera aplicación. + +##### Los detalles tenebrosos (del arranque) + +Si tienes mucha prisa por aprender web2py puedes saltarte esta sección e ir directamente a la sección [siguiente](#nuestra-primera-aplicación) + +Si por el contrario quieres entender exactamente que hemos hecho para poder arrancar el ___web2py___ continuar leyendo puede ser el primer +paso. + +¿Qué es un _virtualenv_? + +: Python nos permite definir _virtualenv_. Un _virtualenv_ es un entorno python aislado. Todos los _virtualenvs_ están aislados entre si y mejor todavía son independientes del python del sistema. Esto te permite tener multiples entornos de desarrollo (o producción) cada uno con distintas versiones de python y diferentes librerias python instaladas en cada uno de ellos, o quizás diferentes versiones de las mismas librerias. + +¿Que es _virtualenvwrapper_? + +: Es un frontend para usar _virtualenv_, la herramienta nativa de python para gestionar _virtualenvs_. Es completamente opcional, aunque a mi me parece muy cómoda. + +¿Qué es todo eso de los certificados? + +: ___web2py___ viene preparado para usar _https_ (estas siglas tienen varias interpretaciones: _HTTP over TLS_, _HTTP over SSL_ o _HTTP Secure_). _https_ usa comunicaciones cifradas entre tu navegador y el servidor web para garantizar dos cosas: que estás accediendo al auténtico servidor y que nadie este interceptando la comunicación entre navegador y servidor. En particular ___web2py___ exige que se use _https_ para conectarse a las páginas de administración. Así que si no generas los certificados podrás arrancar y conectar con ___web2py___ pero no podrás hacer demasiadas cosas. + +: Para usar _https_ hay que hacer varias cosas: + + * Generar un CSR (Certificate Signing Request) + * Obtener con ese CSR un certificado SSL de una autoridad certificadora (CA) + * O alternativamente generar nosotros un certificado a partir del CSR + +: Lo que hemos hecho con los comandos _openssl_ ha sido: + + * Generar un par de claves (privada y pública) para nuestro servidor (`server.key`) + * Generar con esa clave un CSR (el CSR lleva la información que le hemos metido de nuestro servidor y la clave pública) + * Generar un certificado firmándolo nosotros mismos con esa misma clave como si fueramos la autoridad certificadora. + +: Esto nos vale para arrancar ___web2py___ aunque nuestro navegador nos dará una alerta de riesgo de seguridad por que no reconoce a la + CA. + +[Más info de _openssl_](https://www.digitalocean.com/community/tutorials/openssl-essentials-working-with-ssl-certificates-private-keys-and-csrs) + +¿Qué es un motor de base de datos? + +: ___web2py___ usa un motor (o gestor) de [base de datos relacional](https://es.wikipedia.org/wiki/Base_de_datos_relacional). Puede usar muchos, incluyendo los más populares como por ejemplo MySQL, Postgres o MariaDB. + +: Las bases de datos relacionales se basan en relaciones. Las relaciones primarias son tablas que almacenan registros (filas) con atributos comunes (columnas). Las relaciones derivadas se establecen entre distintas tablas mediante consultas (queries) o vistas (views) + +: ___web2py___ te permite gestionar y utilizar las bases de datos a muy alto nivel, así que podras usarlo sin saber practicamente de bases de datos; pero no es demasiado difícil aprender los conceptos básicos y compensa ;-) Todo lo que puedas aprender de bases de datos te ayudará a hacer mejores aplicaciones web. + +#### Nuestra primera aplicación + +Vamos a crear nuestra primera aplicación en web2py. + +Si has seguido los pasos de la [sección anterior](#instalación) ya tienes el ___web2py___ funcionando y puedes seguir cualquiera de los +tutoriales que hay en la red para aprender. El [capítulo 3](http://web2py.com/books/default/chapter/29/03/overview) del libro +de ___web2py___ es muy recomendable, y está disponible [en castellano](http://web2py.com/books/default/chapter/41/03/resumen), +puedes ventilarte los ejemplos que trae explicados en una tarde y son muy ilustrativos. + +En esta guía vamos a ver la creación de una aplicación paso a paso. + +Crearemos una aplicación de inventario para el material de la Asociación BricoLabs, pero lo haremos de manera que también nos valga para uso particular y tener controladas todas nuestras cacharradas. + +Este no es un tutorial de diseño profesional de aplicaciones, sólo pretendemos demostrar lo fácil que es iniciarse con ___web2py___. + +De hecho, no seguiremos un orden lógico en el diseño de la aplicación, si no que intentaremos seguir un orden que facilite conocer el +framework. + +Sin más rollo, vamos a comenzar con nuestra aplicación: + +Crea una aplicación desde el interfaz de administración, en nuestro caso la llamaremos ___cornucopia___. + +Nuestro ___web2py___ "viene de serie" con algunas aplicaciones de ejemplo. La propia pantalla inicial es una de ellas la aplicación +"Welcome" o "Bienvenido" (dependerá del lenguaje por defecto de tu navegador). + +Para crear nuestra aplicación ___cornucopia___: + +* Vamos al botón __admin__ en la pantalla principal. +* Metemos la password de administración (con la que hemos arrancado el ___web2py___ en la linea de comandos). +* Desde la ventana de administración creamos nuestra nueva aplicación + +Inmediatamente nos encontraremos en la ventana de diseño de nuestra nueva aplicación. ___web2py___ nos permite diseñar completamente nuestra aplicación desde aquí, ni siquiera necesitaremos un editor de texto (aunque nada impide usar uno, desde luego). + +##### `private/appconfig.ini` + +El primer fichero que vamos a examinar es `private/appconfig.ini` La sección `private` debería estar abajo de todo en la ventana de diseño. + +En la sección `[app]` del fichero podemos configurar el nombre de la aplicación y los datos del desarrollador. + +En la sección `[db]` fichero configuramos el motor de base de datos que vamos a usar en nuestra aplicación. Por defecto viene configurado _sqlite_ así que no vamos a tener que cambiar nada en este sentido. + +En la seccion `[smtp]` podemos configurar el gateway de correo que usará la aplicación para enviar correos a los usuarios. Por defecto viene viene la configuración para usar una cuenta de gmail como gateway, solo tenemos que cubrir los valores de usuario y password y la dirección de correo.^[Es aconsejable crear una cuenta de gmail, o cualquier otro servicio de correo que nos guste, para pruebas. Usar tu cuenta de correo personal podría ser muy mala idea] + +##### El Modelo + +En la parte superior de la ventana de diseño (o edición) de nuestra aplicación tenemos la sección `Models` + +![Menú Modelos](src/img/models_menu.jpg) + +___web2py___ se encarga de crear las tablas necesarias en la base de datos que le hayamos indicado que use. + +Al crear la aplicación ___web2py__ ha creado en la base de datos todas las tablas relacionadas con la gestión de usuarios y sus privilegios. + +Si echamos un ojo al modelo gráfico (_Graphs Models_) veremos las tablas que ___web2py___ ha creado por defecto y las relaciones entre ellas. Estas tablas que ha creado el _framework_ son las que se encargan de la gestión de usuarios, sus privilegios y el acceso de los mismos al sistema, es decir la capa de seguridad. + +Si vemos el log de comandos de sql (_sql.log_) veremos los comandos que ___web2py___ ha ejecutado en el motor de base de datos. + +Y por último si vemos _database administration_ podremos ver las tablas creadas en la base de datos, e incluso crear nuevos registros en esas tablas (de momento no lo hagas) + +También podemos echar un ojo al contenido del fichero `db.py` o `menu.py` pero por el momento __no__ vamos a modificar nada en esos ficheros. + +Ahora tenemos que ampliar el modelo y añadir todo lo que consideremos necesario para nuestra aplicación. + +###### Diseñando el modelo + +_Build fat models and thin controllers_ es uno de los lemas del modelo MVC, no vamos a entrar en detalles de momento pero un modelo bien diseñado nos va a ahorrar muchísimo trabajo al construir la aplicación. + +El diseño de bases de datos es una rama de la ingeniería en si mismo, hay camiones de libros escritos sobre el tema y todo tipo de herramientas para ayudar al diseñador. Pero nosotros nos vamos a centrar en usar sólo lo que nos ofrece ___web2py___. + +Además como estamos aprendiendo vamos a ver algunas facilidades que nos da ___web2py___ sin proponer ningún proceso de diseño del modelo (recuerda, esto no es un curso de diseño de aplicaciones) + +Vamos a definir el modelo (concretamente las tablas) de nuestra aplicación en un nuevo fichero de la sección _Models_, que llamaremos `db_custom` así que pulsamos en el botón _Create_, y creamos el fichero `db_custom`. + +![Crear fichero](src/img/create_db_custom.png) + +___web2py___ parsea todos los ficheros de la sección _Models_ por +orden alfabético. Esto nos permite separar nuestro código del que +viene originalmente con la aplicación. Pero es importante que `db.py` +sea siempre el primero alfabeticamente para que se ejecute antes que +el resto. + +___web2py___ se encarga también de añadir la extensión `.py` al nuevo +fichero que estamos creando así que teclea sólo el nombre `db_custom`. + +El objetivo de nuestra aplicación es mantener un inventario de +"cosas". Parece lógico que nuestra primera tabla valga para almacenar +"cosas". Así que en el fichero `db_custom.py` añadimos las siguientes +lineas y salvamos el fichero: + +~~~~python +db.define_table('thing', + Field('id', 'integer'), + Field('desc', 'string'), + migrate = True); +~~~~ + +###### Tickets de error + + +Ya hemos salvado nuestro fichero, vamos a echar un ojo a nuestra base +de datos con el botón _Graph Model_. + +![Error interno](src/img/internal_error.jpg) + +¡Tenemos un horror! ¿Qué ha pasado?. Si pinchamos en el link del _Ticket_ +se abrirá una nueva pestaña en nuestro navegador: + +![Error palabra reservada SQL](src/img/error_reserved_sql.jpg) + +En el ticket tenemos mucha información acerca del error, +afortunadamente en este caso es facilito. El nombre del campo `desc` +que hemos añadido a nuestra tabla `thing` es una palabra reservada en +__todas__ las variedades de _SQL_ (es el comando para ver la +definición de una tabla: _desc tablename_) + +Editamos de nuevo nuestro fichero `db_custom.py` y corregimos el +contenido: + +~~~~python +db.define_table('thing', + Field('id', 'integer'), + Field('description', 'string'), + migrate = True); +~~~~ + +¡Ahora si! Si pulsamos en el botón de _Graph Model_ (después de salvar +el nuevo contenido) veremos que ___web2py___ ha creado la nueva tabla +en la base de datos. Incluso podríamos empezar a añadir filas (cosas) +a nuestra tabla desde el _database administration_ + +El campo `id` es _casi_ obligatorio en todas las tablas que definamos +en ___web2py___, siempre será un valor único para cada fila en una +tabla y se usará internamente como clave primaria. Podemos usar otros +campos como clave primaria pero de momento mantendremos las cosas +símples. + +Además el campo `id` se añade por defecto a la definición de una +tabla, aunque no lo especifiques en la definición. Si además tenemos +en cuenta que `string` es el tipo por defecto si no especificas un +tipo, podríamos haber escrito nuestra tabla como: + +~~~~python +db.define_table('thing', + Field('description'), + migrate = True); +~~~~ + +Pero de momento vamos a dejar todas las definiciones explícitas para +no liarnos. + +Si visitas ahora la sección de administración de la base de datos +puedes añadir algunas "cosas" a la nueva tabla. + +![Añadir destornillador](src/img/add_thing_a.jpg) + + +###### Mejorando la tabla + +Evidentemente nuestro modelo de "cosa" es demasiado simple, tenemos +que añadirle nuevos atributos de [distintos +tipos](http://web2py.com/books/default/chapter/29/06/the-database-abstraction-layer#Field-types) +para que sea funcional. Pero antes de ir a por todas vamos a ver +algunas funciones que nos ofrece ___web2py___ para construir los +Modelos. + +Vamos a añadir algunos campos más de distintos tipos a nuestro modelo +y verlos con un poco de calma. + +~~~~python +db.define_table('thing', + Field('id', 'integer'), + Field('name', 'string'), + Field('description', 'string'), + Field('picture', 'upload'), + Field('created_on, 'datetime'), + migrate = True); +~~~~ + +Hemos añadido a nuestra "cosa" un nombre (_name_), una foto +(_picture), que seguro que nos será muy útil, y una fecha de creación +(_created_on_) que será la fecha en que añadimos esta "cosa" concreta +a nuestro inventario. + +Si ahora volvemos al administrador de base de datos podemos comprobar que: + +* No hemos perdido las "cosas" que añadimos antes, ___web2py___ ha + añadido las nuevas columnas pero ha conservado los valores de las + antiguas. +* Podemos editar las "cosas" que habíamos añadido sin mas que hacer + click en el `id` +* Si queremos editar (o añadir) una "cosa", ___web2py___ nos ofrece un + diálogo para subir la foto de nuestro objeto. Sabe que los atributos + de tipo upload son fichero que subiremos al servidor. + + De la misma forma nos ofrece un menú inteligente para añadir el + campo `datetime` + +Este es el tipo de facilidades que ofrecen los _frameworks_ para +acelerar el trabajo de crear una aplicación. + +Sigamos refinando nuestra definición de "cosa" añadiendo +características más sofisticadas nuestra tabla `thing`: + +~~~~python +db.define_table('thing', + Field('id', 'integer'), + Field('name', 'string', + required = True, + requires = IS_NOT_EMPTY(error_message='cannot be empty')), + Field('description', 'string'), + Field('qty', 'integer', + default=1, + label=T('Quantity')), + Field('picture', 'upload'), + Field('created_on', 'datetime'), + format='%(name)s', + migrate = True); +~~~~ + +En la linea del `name` hemos añadido un `VALIDATOR`. Se trata de +[funciones +auxiliares](http://web2py.com/books/default/chapter/29/07/forms-and-validators) +que nos permiten comprobar multitud de condiciones y que son +extremadamente útiles (iremos viendo casos de uso). En este caso +exigimos que el campo `name` no puede estar vacío y además +especificamos el mensaje de error que debe aparecer si sucede. + +Hemos añadido un atributo `qty` (cantidad), hemos especificado que +tenga un valor por defecto de una unidad, y además hemos especificado +el `label`. + +El `label` se usará en los formularios en lugar del nombre del campo +en la base de datos. Si vamos a añadir una nueva "cosa" veremos que en +el formulario no aparece _qty_ sino que nos pregunta _Quantity_. +Además, y esto es muy importante, hemos asignado el valor de la +etiqueta con la función `T()`. + +___web2py___ incorpora un sistema completo de internacionalización. Al +usar la función `T()` la cadena _Quantity_ se ha añadido a todos los +diccionarios de traducción (si es que no estaba ya) y solo tenemos que +añadir la traducción en el diccionario correspondiente (p.ej. a +`es.py`) para que funcione la i18n. Una vez añadida si el idioma por +defecto de nuestro navegador es el castellano, en el formulario +aparecerá "Cantidad" en lugar de _Quantity_. + +Por último hemos añadido el `format` a la definición de la tabla, +`format` especifica que cuando nos refiramos a un objeto "cosa" se +represente por defecto con su atributo `name`. + +###### Relaciones entre tablas + +Supongamos ahora que queremos tener registrado en nuestro inventario +al proveedor de cada una de nuestras cosas. ¿cómo se hace eso? + +Vamos a añadir los proveedores a nuestro modelo: + +~~~~python +db.define_table('provider', + Field('id', 'integer'), + Field('name, 'string'), + Field('CIF', 'string'), + Field('email', 'string'), + Field('phone', 'string'), + migrate = True); +~~~~ + +Y ahora, a la tabla `thing`, le añadimos la referencia a proveedores: + +~~~~python + +db.define_table('thing', + Field('id', 'integer'), + Field('name', 'string', + required = True, + requires = IS_NOT_EMPTY(error_message='cannot be empty')), + Field('description', 'string'), + Field('qty', 'integer', default=1, label=T('Quantity')), + Field('picture', 'upload'), + Field('created_on', 'datetime'), + Field('provider_id', 'reference provider', + requires=IS_EMPTY_OR(IS_IN_DB(db, 'provider.id', '%(name)s'))), + format='%(name)s', + migrate = True); +~~~~ + +Si ahora creamos un proveedor (o varios): + +![Un proveedor](src/img/great_provider.jpg){width=75%} + +A la hora de crear una nueva "cosa" ___web2py___ se encargará de +ofrecernos un desplegable para escoger el proveedor. + +###### Detalles tenebrosos (del modelo inicial) + +Si ya has leido el [capítulo +3](http://web2py.com/books/default/chapter/29/03/overview) del libro +de ___web2py___, los detalles tenebrosos serán menos tenebrosos para +ti. + +Lo primero que tenemos que comentar es que mientras hemos estado +definiendo el modelo nos hemos pasado casi todo el tiempo usando el +_DAL_ que viene empaquetado con ___web2py___. + +El _DAL_ (_Database Abstraction Layer_) es una biblioteca de alto nivel +para tratar con bases de datos relacionales. Y podemos usarla por +separado en cualquier proyecto que queramos sin tener que usar +___web2py___. + +En segundo lugar, merece la pena subrayar que hay dos tipos de +restricciones que podemos aplicar a los atributos (o campos) de una +tabla. + +Cuando usamos `default=1`, o `required=True`, este tipo de directivas +se traducen directamente en la definición de la tabla en el motor de +bases de datos. + +Si marcásemos el campo `name` como `required=True` e intentásemos +crear un registro con el campo vacío, python nos daría una excepción +de base de datos. El motor de base de datos sería el que diera el +error, por que se violaría la estrutura de tabla que tiene definida. + +En cambio los _VALIDATORS_ funcionan de una forma totalmente distinta. +Se aplican a nivel de __formulario__, las comprobaciones y el error +(si procede) se harían en ___web2py___, no sería la base de datos la +que daría el error. + +Por último, quizás hayais notado que hay un fallo grave (deliberado) +en el modelo propuesto como ejemplo. Está claro que una cosa puede ser +comprada a varios proveedores. Y un proveedor puede vendernos muchas +cosas. Eso significa que entre las tablas `thing` y `provider` tenemos +una relación n:n (_many to many relationship_), varias cosas pueden +estar relacionadas con varios proveedores. Este tipo de relaciones +siempre son un problema en las bases de datos relacionales y más +adelante veremos como implementarlas correctamente. De momento nos +quedamos con el modelo simplificado. + + +### Checklist + +Hay que editar `private/appconfig.ini`: + +~~~~python +[app] +name = cornucopia +author = salvari +description = una aplicación de inventario +keywords = web2py, python, framework, bricolabs +generator = Web2py Web Framework +production = false +toolbar = false +~~~~ + + + +### Secciones en el futuro + +#### web2py y git + +#### Instalación con nginx + +#### Certificados let's encrypt + + +## Notas sueltas de Bases de Datos + +### Truncar tablas en MariaDB + +Los comandos de `TRUNCATE` se tratan internamente como un borrado y creado de la tabla. + +Cuando tenemos tablas con relaciones tenemos dos caminos posibles: + +Borrar toda la tabla y resetear el contador: + +```sql +DELETE FROM COUNTRY; +ALTER TABLE COUNTRY AUTO_INCREMENT = 1; +``` + +Desactivar los chequeos y volverlos a activar al final (ojito que no estoy seguro de que la desactivación sea por sesión) + +```sql +SET FOREIGN_KEY_CHECKS = 0; + +TRUNCATE TABLE COUNTRY; +TRUNCATE TABLE STATE; + +SET FOREIGN_KEY_CHECKS = 1; +```