<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Pedro Gomez</title><link href="https://pedrogomez.blog/" rel="alternate"/><link href="https://pedrogomez.blog/feeds/all.atom.xml" rel="self"/><id>https://pedrogomez.blog/</id><updated>2026-09-02T00:00:00+02:00</updated><subtitle>Cosas y más cosas</subtitle><entry><title>PKM_definitivo_v20_final_2</title><link href="https://pedrogomez.blog/pkm_definitivo_v20_final_2.html" rel="alternate"/><published>2026-09-02T00:00:00+02:00</published><updated>2026-04-01T18:13:53+02:00</updated><author><name>Pedro Gomez</name></author><id>tag:pedrogomez.blog,2026-09-02:/pkm_definitivo_v20_final_2.html</id><summary type="html">&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;*Disclaimer
Estamos trabajando ello...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;span class="caps"&gt;TLDR&lt;/span&gt;: Obsidian + Git +&amp;nbsp;Quilden&lt;/p&gt;
&lt;h1&gt;Desktop: La Aplicación de notas&amp;nbsp;definitiva&lt;/h1&gt;
&lt;p&gt;Se han escrito ríos de tinta sobre el tema del &lt;span class="caps"&gt;PKM …&lt;/span&gt;&lt;/p&gt;</summary><content type="html">&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;*Disclaimer
Estamos trabajando ello...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;span class="caps"&gt;TLDR&lt;/span&gt;: Obsidian + Git +&amp;nbsp;Quilden&lt;/p&gt;
&lt;h1&gt;Desktop: La Aplicación de notas&amp;nbsp;definitiva&lt;/h1&gt;
&lt;p&gt;Se han escrito ríos de tinta sobre el tema del &lt;span class="caps"&gt;PKM&lt;/span&gt; (Personal Knowledge Manager). Vaya por delante que no soy ningún experto en la materia. Soy el cuñado en el bar diciendo &amp;#8220;tienen que jugar más por la&amp;nbsp;banda&amp;#8221;.&lt;/p&gt;
&lt;h2&gt;Qué es un &lt;span class="caps"&gt;PKM&lt;/span&gt;?&lt;/h2&gt;
&lt;p&gt;Se supone que es el &amp;#8220;Jardín de tu conocimiento&amp;#8221;, dónde lo vas a apuntar todo. Cosas que has aprendido, cosas que quieres aprender, reflexiones profundas que no le importan a nadie y son demasiado largas para una taza&amp;#8230;
    - Pero Pedro, yo lo que no sé, lo busco en Google (update: le pregunto a una &lt;span class="caps"&gt;IA&lt;/span&gt; random)
    - Perfecto, toma, un Sugus.
Yo primero lo busco en mis apuntes, si no lo encuentro, lo busco y lo apunto para la siguiente. ¿Por que? No sé, se me hace más rápido de buscar, está escrito a mi manera, me hace ilusión tenerlo, mientras lo escribo aprendo. Pero que si a ti no te funciona, no lo hagas eh! Es más, te diría que es una pérdida de&amp;nbsp;tiempo.&lt;/p&gt;
&lt;h2&gt;Aplicaciones&lt;/h2&gt;
&lt;p&gt;Recuerdo los inicios con &lt;em&gt;Evernote&lt;/em&gt; y el método de organización &lt;em&gt;&lt;span class="caps"&gt;GTD&lt;/span&gt;&lt;/em&gt; (Getting Things Done). Cambié de sistema en el momento en que &lt;em&gt;Evernote&lt;/em&gt; empezó a ponerse pesado con el sistema de pago. Aquí salté a &lt;a href="https://orgmode.org/"&gt;Org-mode&lt;/a&gt; y Emacs, más adelante incorporé org-roam. El sistema tenía básicamente 2 problemas; la complejidad de la configuración, y su uso des del móvil. Cansado, decidí buscar alternativas, pasé por Joplin, Logseq, y Obsidian. De momento he decidido quedarme con Obsidian por 2 motivos; la facilidad de la configuración y el ecosistema de plugins. ¿Se acabó el viaje?. Obviamente, no. Obsidian &lt;strong&gt;&lt;span class="caps"&gt;NO&lt;/span&gt;&lt;/strong&gt; es &lt;em&gt;open-source&lt;/em&gt;. En cualquier momento puede volver a pasar lo de Evernote. La verdad es que voy mirando de reojo a &lt;a href="https://logseq.com/"&gt;Logseq&lt;/a&gt;, es probable que en algún momento acabe&amp;nbsp;allí.&lt;/p&gt;
&lt;h2&gt;Plugins&lt;/h2&gt;
&lt;p&gt;Por el momento hay un montón de plugins que me hacen quedarme en Obsidian. Alguno de ellos son:
- &lt;a href="https://github.com/makebit/obsidian-readeck-importer"&gt;Readeck&lt;/a&gt;: Tengo una instancia de Readeck donde guardo artículos que me han gustado o que me interesan. 
- &lt;a href="https://github.com/hadynz/obsidian-kindle-plugin"&gt;Highlights&lt;/a&gt;: Cuando leo en mi Kindle Paperwhite me gusta ir subrayando todo lo que me parezca interesante. Cuando conecto el kindle al &lt;span class="caps"&gt;PC&lt;/span&gt; puedo importar todo lo que he subrayado.
- &lt;a href="https://github.com/Vinzent03/obsidian-git"&gt;Git&lt;/a&gt;: Pieza esencial para configuración. Las notas se suben a un repositorio &amp;#8220;privado&amp;#8221; de&amp;nbsp;Github.&lt;/p&gt;
&lt;h2&gt;Sync&lt;/h2&gt;
&lt;p&gt;Las notas se encuentran en una carpeta en mi instancia de Nextcloud. Sincronizo la carpeta entre mis ordenadores, y eso me permite acceder a mis notas des de diferentes&amp;nbsp;ordenadores.&lt;/p&gt;
&lt;p&gt;Cada cliente de obsidian tiene una configuración separada. Al tener diferentes sistemas operativos, no quiero que la configuración sea la misma en todos. Esto es muy útil para tener todas las configuraciones sincronizadas sin que interfieran entre&amp;nbsp;ellas.&lt;/p&gt;
&lt;h1&gt;&lt;span class="caps"&gt;OK&lt;/span&gt; y el&amp;nbsp;móvil?&lt;/h1&gt;
&lt;p&gt;Obsidian dispone de aplicación oficial para Android. Estaría muy bien si la aplicación pudiera conectarse a un servidor Webdav, como no es posible, utilizo Github para sincronizar las notas. &lt;a href="https://github.com/ViscousPot/GitSync"&gt;GitSync&lt;/a&gt; sincroniza un repositorio de Github con una carpeta local de Android. Esto me permite tener las notas en local y acceder con Obsidian.
Todavía tengo que investigar el manual, pero parece que esto podria hacerse de manera automáitca cada vez que se abra la aplicación de Obsidian. Acutalmente lo hago manualmente antes de abrir la&amp;nbsp;aplicación.&lt;/p&gt;
&lt;h1&gt;Aja&amp;#8230; yo quiero una &lt;span class="caps"&gt;PWA&lt;/span&gt;&lt;/h1&gt;
&lt;p&gt;Escribir notas des del móbil es una auténtica pérdida de tiempo (humilde opinión). Cuando quiero escribir una nota y no tengo ninguno de mis portátiles a mano, puedo acceder a &lt;a href="https://quilden.com/"&gt;Quilden.com&lt;/a&gt;. Es un frontend muy simplificado de Obsidian que te permite acceder a tu repositorio de&amp;nbsp;Github.&lt;/p&gt;
&lt;h1&gt;Conclusión&lt;/h1&gt;
&lt;p&gt;¿Me gusta la configuración actual?. &lt;span class="caps"&gt;NO&lt;/span&gt;. ¿La voy a utilizar hasta que me canse, hasta que Github u Obsidian pertuben mi paz? &lt;span class="caps"&gt;AFIRMATIVO&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;En algún momento se romperá todo, y no me procupa. No me va la vida en esto. Cuando se rompa, me preocuparé. Ahora, no. Enjoy the&amp;nbsp;process.&lt;/p&gt;
&lt;p&gt;&lt;span class="caps"&gt;GL&lt;/span&gt;&amp;amp;&lt;span class="caps"&gt;HF&lt;/span&gt;&lt;/p&gt;</content><category term="Notes"/><category term="notes"/><category term="PKM"/><category term="obsidian"/></entry><entry><title>Usando zsh en la terminal</title><link href="https://pedrogomez.blog/usando-zsh-en-la-terminal.html" rel="alternate"/><published>2023-03-26T00:00:00+01:00</published><updated>2023-03-26T18:36:48+02:00</updated><author><name>Pedro Gomez</name></author><id>tag:pedrogomez.blog,2023-03-26:/usando-zsh-en-la-terminal.html</id><summary type="html">&lt;p&gt;*Disclaimer: No te fies de este&amp;nbsp;blog&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;span class="caps"&gt;TLDR&lt;/span&gt;&lt;/strong&gt;: Utilizando el shell de zsh. Plugins que he&amp;nbsp;añadido.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Intro&lt;/h2&gt;
&lt;p&gt;Necesitaba facilitarme la vida en la terminal …&lt;/p&gt;</summary><content type="html">&lt;p&gt;*Disclaimer: No te fies de este&amp;nbsp;blog&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;span class="caps"&gt;TLDR&lt;/span&gt;&lt;/strong&gt;: Utilizando el shell de zsh. Plugins que he&amp;nbsp;añadido.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Intro&lt;/h2&gt;
&lt;p&gt;Necesitaba facilitarme la vida en la terminal, sobretodo algún auto completar y seleccionado con el tabulador. He decidido utilizar el shell de &lt;a href="https://zsh.sourceforge.io/"&gt;zsh&lt;/a&gt;, y &lt;a href="https://ohmyz.sh/"&gt;ohmyzsh&lt;/a&gt; para la instalación de&amp;nbsp;plugins.&lt;/p&gt;
&lt;h2&gt;Plugins&amp;nbsp;utilizados&lt;/h2&gt;
&lt;h3&gt;&lt;a href="https://github.com/marlonrichert/zsh-autocomplete#manual-installation"&gt;zsh-autocomplete&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Según su repositorio debería de tener múltiples funciones. En mi caso, la única función que me permite es el auto-complete. Pulsando la flecha derecha auto completa el comando&amp;nbsp;sugerido. &lt;/p&gt;
&lt;h3&gt;&lt;a href="https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/copypath"&gt;Copypath&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;El&amp;nbsp;comando &lt;code&gt;copypath&lt;/code&gt; copia la ruta del directorio&amp;nbsp;actual, &lt;code&gt;copypath &amp;lt;file_or_directory&amp;gt;&lt;/code&gt; copia la ruta del directorio del archivo &lt;file_or_directory&gt;.&lt;/p&gt;
&lt;h3&gt;&lt;a href="https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/copybuffer"&gt;Copybuffer&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ctrl-o&lt;/code&gt; copia el texto actual de la linea de&amp;nbsp;comando.&lt;/p&gt;
&lt;h3&gt;&lt;a href="https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/ag"&gt;The Silver&amp;nbsp;Searcher&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ag&lt;/code&gt; busca recursivamente en el directorio actual y en todos los&amp;nbsp;subdirectorios.&lt;/p&gt;
&lt;h2&gt;Tema&lt;/h2&gt;
&lt;h3&gt;&lt;a href="https://github.com/ohmyzsh/ohmyzsh/blob/master/themes/gallois.zsh-theme"&gt;Gallois&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;img alt="Gallois" src="https://user-images.githubusercontent.com/49100982/108254828-86636680-716c-11eb-8d3a-146431df149f.jpg"&gt; &lt;/p&gt;
&lt;h2&gt;Extra&lt;/h2&gt;
&lt;p&gt;Si alguien necesita información extra, a mi ha ido muy bien este blog de &lt;a href="https://timjames.dev/blog/overhaul-your-terminal-with-zsh-plugins-more-3oag"&gt;Tim&amp;nbsp;James&lt;/a&gt; &lt;/p&gt;</content><category term="Linux"/><category term="zsh"/><category term="linux"/><category term="terminal"/></entry><entry><title>Muchos dockers, poca diversión</title><link href="https://pedrogomez.blog/muchos-dockers-poca-diversion.html" rel="alternate"/><published>2023-02-14T00:00:00+01:00</published><updated>2023-02-03T09:53:51+01:00</updated><author><name>Pedro Gomez</name></author><id>tag:pedrogomez.blog,2023-02-14:/muchos-dockers-poca-diversion.html</id><summary type="html">&lt;p&gt;*Disclaimer: Esto me funciona a mí, puede que a tí&amp;nbsp;no.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;span class="caps"&gt;TLDR&lt;/span&gt;&lt;/strong&gt;: &lt;span class="caps"&gt;LOOPS&lt;/span&gt; &lt;span class="caps"&gt;EN&lt;/span&gt; &lt;span class="caps"&gt;BASH&lt;/span&gt;!!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Estructura&lt;/h2&gt;
&lt;p&gt;La estructura de las carpetas, dónde se encuentran los …&lt;/p&gt;</summary><content type="html">&lt;p&gt;*Disclaimer: Esto me funciona a mí, puede que a tí&amp;nbsp;no.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;span class="caps"&gt;TLDR&lt;/span&gt;&lt;/strong&gt;: &lt;span class="caps"&gt;LOOPS&lt;/span&gt; &lt;span class="caps"&gt;EN&lt;/span&gt; &lt;span class="caps"&gt;BASH&lt;/span&gt;!!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Estructura&lt;/h2&gt;
&lt;p&gt;La estructura de las carpetas, dónde se encuentran los dockers-compose.yaml es la&amp;nbsp;siguiente:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;DockerFolder&lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;|-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;AplicaciónLegal_1&lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="err"&gt;|-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;docker-compose.yaml&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="err"&gt;|-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;folders&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;files&lt;/span&gt;
&lt;span class="err"&gt;|-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;AplicaciónLegal_2&lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="err"&gt;|-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;docker-compose.yaml&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="err"&gt;|-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;folders&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;files&lt;/span&gt;
&lt;span class="na"&gt;.env&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;La carpeta DockerFolder solo contiene otras carpetas y un&amp;nbsp;archivo &lt;code&gt;.env&lt;/code&gt;. Las  carpetas interiores contienen el docker-compose.yaml y otras carpetas de configuración para la cada aplicación. El&amp;nbsp;arhcivo &lt;code&gt;.env&lt;/code&gt; contiene variables necesarias para ejecutar los docker-compose.
Por&amp;nbsp;ejemplo:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;SECURE_PASSWORD=123456
MOVIES_DIR=/srv/dev-externalfiles/Movies
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;En los archivos docker-compose nos podemos referir a estas variables de la siguiente&amp;nbsp;manera:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;volumes:
&lt;span class="w"&gt;      &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;./config:/config
&lt;span class="w"&gt;      &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;${&lt;/span&gt;&lt;span class="n"&gt;MOVIES_DIR&lt;/span&gt;&lt;span class="cp"&gt;}&lt;/span&gt;:/movies
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Magia&lt;/h2&gt;
&lt;p&gt;Si queremos parar todos los dockers nos situamos dentro de la carpeta &lt;em&gt;DockerFolder/&lt;/em&gt; y&amp;nbsp;ejecutamos;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;for dir in */; do docker-compose --env-file .env -f &amp;quot;$dir&amp;quot;/docker-compose.yaml down; done
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Si queremos iniciar todos los dockers nos situamos dentro de la carpeta &lt;em&gt;DockerFolder/&lt;/em&gt; y&amp;nbsp;ejecutamos;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;for dir in */; do docker-compose --env-file .env -f &amp;quot;$dir&amp;quot;/docker-compose.yaml up -d; done
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;También podríamos&amp;nbsp;incluir &lt;code&gt;up -d --force-recreate&lt;/code&gt; si fuera&amp;nbsp;necesario.&lt;/p&gt;
&lt;h2&gt;Tmux; un pasito&amp;nbsp;más&lt;/h2&gt;
&lt;p&gt;En mi caso los dockers están en un servidor al cual me conecto por ssh. Cuando hay muchos dockers estas operaciones pueden tardar un poco, por eso utilizo &lt;a href="https://github.com/tmux/tmux"&gt;Tmux&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Una vez tenemos instalado Tmux, abrimos la terminal y&amp;nbsp;ejecutamos &lt;code&gt;Tmux&lt;/code&gt;. Des de Tmux accedemos al servidor por ssh y ejecutamos el comando que queramos. Mientras se ejecuta,&amp;nbsp;presionamos &lt;code&gt;Ctrl+b d&lt;/code&gt;. Esto deja la sesión en un segundo plano (deattach). En este punto ya podemos cerrar la terminal y esperar tranquilamente a que pase el&amp;nbsp;tiempo.&lt;/p&gt;
&lt;p&gt;Cuando queramos comprobar el estado del comando, abrimos la terminal y&amp;nbsp;ejecutamos &lt;code&gt;tmux attach&lt;/code&gt;, esto nos llevarà a la sesión anterior y podremos ver si ha&amp;nbsp;finalizado.&lt;/p&gt;
&lt;p&gt;Esto se puede aplicar a muchas otras tareas, copias de seguridad,&amp;nbsp;aplicaciones..&lt;/p&gt;</content><category term="Linux"/><category term="docker"/><category term="linux"/><category term="docker-compose"/></entry><entry><title>Nextcloud background cronjob</title><link href="https://pedrogomez.blog/nextcloud-background-cronjob.html" rel="alternate"/><published>2022-01-30T00:00:00+01:00</published><updated>2023-03-25T08:43:57+01:00</updated><author><name>Pedro Gomez</name></author><id>tag:pedrogomez.blog,2022-01-30:/nextcloud-background-cronjob.html</id><summary type="html">&lt;h1&gt;Nextcloud&amp;nbsp;cronjob&lt;/h1&gt;
&lt;p&gt;Determinadas tareas se realizan automáticamente en segundo plano. 
Según la &lt;a href="!https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/background_jobs_configuration.html"&gt;documentación&lt;/a&gt; de Nextcloud hay 3 formas de realizar estas&amp;nbsp;tareas:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class="caps"&gt;AJAX&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="caps"&gt;WEBCRON&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="caps"&gt;CRON …&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;</summary><content type="html">&lt;h1&gt;Nextcloud&amp;nbsp;cronjob&lt;/h1&gt;
&lt;p&gt;Determinadas tareas se realizan automáticamente en segundo plano. 
Según la &lt;a href="!https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/background_jobs_configuration.html"&gt;documentación&lt;/a&gt; de Nextcloud hay 3 formas de realizar estas&amp;nbsp;tareas:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class="caps"&gt;AJAX&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="caps"&gt;WEBCRON&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="caps"&gt;CRON&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="Nextcloud cron" src="https://pedrogomez.blog/images/nextcloud_cron.png"&gt;&lt;/p&gt;
&lt;p&gt;En la documentación ofical, la forma recomendada es&amp;nbsp;&amp;#8220;Cron&amp;#8221;.&lt;/p&gt;
&lt;p&gt;Cron hace referencia a crontab. Un archivo que ejecuta las tareas indicadas en él, en el intervalo de tiempo indicado. El script a ejecutar es &amp;#8220;cron.php&amp;#8221; y debería ejecutarlo el usuario www-data cada 5&amp;nbsp;min.&lt;/p&gt;
&lt;p&gt;En mi caso uso Nextcloud en un docker denominado (&lt;em&gt;container_name&lt;/em&gt;) &amp;#8220;nextcloud&amp;#8221;, por lo tanto tengo que hacer lo&amp;nbsp;siguiente:&lt;/p&gt;
&lt;p&gt;Editamos crontab usando el siguiente&amp;nbsp;comando:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;crontab&lt;span class="w"&gt; &lt;/span&gt;-e
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Añadimos la siguiente linea al&amp;nbsp;documento:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;*/&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;docker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nextcloud&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;php&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;cron&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ph&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Dentro del docker nextcloud ejecuta el script cron.php como el usuario www-data cada 5&amp;nbsp;minutos.&lt;/p&gt;</content><category term="Server"/><category term="self-hosted"/><category term="nextcloud"/><category term="crontab"/></entry><entry><title>SqlAlchemy Intro (1): Engine.</title><link href="https://pedrogomez.blog/sqlalchemy-intro-1-engine.html" rel="alternate"/><published>2021-11-03T00:00:00+01:00</published><updated>2022-08-23T17:06:53+02:00</updated><author><name>Pedro Gomez</name></author><id>tag:pedrogomez.blog,2021-11-03:/sqlalchemy-intro-1-engine.html</id><summary type="html">&lt;p&gt;*Disclaimer: No tengo la carrera de ingeniería informática, soy un&amp;nbsp;aficionado!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;span class="caps"&gt;TLDR&lt;/span&gt;&lt;/strong&gt;: Para trabajar con SQLAlchemy necesitamos crear el objeto&amp;nbsp;Engine.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;¿Qué es&amp;nbsp;esto?&lt;/h2&gt;
&lt;p&gt;En …&lt;/p&gt;</summary><content type="html">&lt;p&gt;*Disclaimer: No tengo la carrera de ingeniería informática, soy un&amp;nbsp;aficionado!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;span class="caps"&gt;TLDR&lt;/span&gt;&lt;/strong&gt;: Para trabajar con SQLAlchemy necesitamos crear el objeto&amp;nbsp;Engine.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;¿Qué es&amp;nbsp;esto?&lt;/h2&gt;
&lt;p&gt;En algún momento necesitaré interactuar con bases de datos. Quizá aprender SQLAlchemy haga el trabajo un poco menos pesado, así que esto van a ser un poco mis apuntes y&amp;nbsp;notas.&lt;/p&gt;
&lt;h2&gt;Pasamos a&amp;nbsp;2.0.&lt;/h2&gt;
&lt;p&gt;Parece que en la versión 1.4 hay un cambio de paradigma y se convertirá en la&amp;nbsp;2.0.&lt;/p&gt;
&lt;p&gt;Utilizaremos la guía &lt;a href="https://docs.sqlalchemy.org/en/14/tutorial/index.html#unified-tutorial"&gt;oficial&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Como síntesis parece que la gran diferencia entre la 1.3 y la 1.4&amp;nbsp;es:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The &lt;span class="caps"&gt;ORM&lt;/span&gt; now uses Core-style querying with&amp;nbsp;the &lt;code&gt;select()&lt;/code&gt; construct, and transactional semantics between Core connections and &lt;span class="caps"&gt;ORM&lt;/span&gt; sessions are&amp;nbsp;equivalent.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;En cuanto al resto nos vamos a olvidar de las diferencias entre 1.3 y 1.4 ya que no sabíamos nada de la 1.3. &lt;span class="caps"&gt;XD&lt;/span&gt;. Vamos directamente a la&amp;nbsp;2.0.&lt;/p&gt;
&lt;h2&gt;&lt;span class="caps"&gt;API&lt;/span&gt;&amp;#8217;s.&lt;/h2&gt;
&lt;p&gt;SQLAlchemy Tiene dos &lt;span class="caps"&gt;API&lt;/span&gt;&amp;#8217;s para interactuar con las bases de datos: &lt;span class="caps"&gt;CORE&lt;/span&gt; y &lt;span class="caps"&gt;ORM&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span class="caps"&gt;ORM&lt;/span&gt;:&lt;/strong&gt; The &lt;span class="caps"&gt;ORM&lt;/span&gt; provides an additional configuration layer allowing user-defined Python classes to be &lt;strong&gt;mapped&lt;/strong&gt; to database tables and other constructs, as well as an object persistence mechanism known as the &lt;strong&gt;Session&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span class="caps"&gt;CORE&lt;/span&gt;&lt;/strong&gt;: The library provides tools for managing connectivity to a database, interacting with database queries and results, and programmatic construction of &lt;span class="caps"&gt;SQL&lt;/span&gt;&amp;nbsp;statements.&lt;/p&gt;
&lt;h2&gt;Estableciendo conexión - &lt;em&gt;The Engine&lt;/em&gt;:&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Engine&lt;/em&gt; és el objeto que actúa como fuente central de todas las conexiones a la base de datos. Es lo primero que hay que&amp;nbsp;definir.&lt;/p&gt;
&lt;p&gt;Se crea con la función &lt;a href="https://docs.sqlalchemy.org/en/14/core/engines.html#sqlalchemy.create_engine"&gt;create_engine(url, **kwargs)&lt;/a&gt;. El argumento principal es un &lt;em&gt;string&lt;/em&gt; que contiene la dirección de la base de datos además de otros argumentos necesarios para la conexión. Profundizaré más adelante acerca de este&amp;nbsp;string.&lt;/p&gt;
&lt;p&gt;Es importante que uno de los argumentos&amp;nbsp;sea &lt;code&gt;future=True&lt;/code&gt;, esto nos permitirá hacer uso del estilo de la versión&amp;nbsp;2.0.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;sqlalchemy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;create_engine&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;create_engine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;sqlite+pysqlite:///:memory:&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;echo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;future&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="Python"/><category term="python"/><category term="sql"/><category term="programacion"/></entry><entry><title>SqlAlchemy Intro (3): Metadata.</title><link href="https://pedrogomez.blog/sqlalchemy-intro-3-metadata.html" rel="alternate"/><published>2021-07-27T00:00:00+02:00</published><updated>2022-08-23T17:07:03+02:00</updated><author><name>Pedro Gomez</name></author><id>tag:pedrogomez.blog,2021-07-27:/sqlalchemy-intro-3-metadata.html</id><summary type="html">&lt;p&gt;*Disclaimer: Hoy es lunes, y mañana será martes. &amp;#8220;Deal with&amp;nbsp;it!&amp;#8221;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;span class="caps"&gt;TLDR&lt;/span&gt;&lt;/strong&gt;: Diferentes maneras de crear tablas en una base de datos. Mi intención es …&lt;/p&gt;&lt;/blockquote&gt;</summary><content type="html">&lt;p&gt;*Disclaimer: Hoy es lunes, y mañana será martes. &amp;#8220;Deal with&amp;nbsp;it!&amp;#8221;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;span class="caps"&gt;TLDR&lt;/span&gt;&lt;/strong&gt;: Diferentes maneras de crear tablas en una base de datos. Mi intención es utilizar la metodologia &lt;span class="caps"&gt;ORM&lt;/span&gt;. Las tablas se crean extendiendo una clase&amp;nbsp;Base.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Siguiendo con la guía de introducción a &lt;a href="https://docs.sqlalchemy.org/en/14/tutorial/dbapi_transactions.html"&gt;SQLAlchemy&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Componentes de la base de datos:&amp;nbsp;Metadata&lt;/h2&gt;
&lt;p&gt;Los cimientos de las interacciones de SQLAlchemy con la base de datos son un conjuto de objetos Python que representan conceptos de la base de datos, el conjunto de estos objetos se denomina &amp;#8220;&lt;a href="https://docs.sqlalchemy.org/en/14/glossary.html#term-database-metadata"&gt;database metadata&lt;/a&gt;&amp;#8221;. Algunos de estos objetos son; tablas,&amp;nbsp;columnas&amp;#8230;&lt;/p&gt;
&lt;p&gt;Una base de datos puede tener diferentes conjutos de metadatos, pero habitualmente si usamos tablas relacionadas entre ellas es mejor usar un solo objeto de&amp;nbsp;metadatos.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;sqlalchemy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MetaData&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MetaData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Estructura básica:&amp;nbsp;&amp;#8220;Table&amp;#8221;.&lt;/h3&gt;
&lt;p&gt;Las tablas (&amp;#8220;&lt;a href="https://docs.sqlalchemy.org/en/14/core/metadata.html#sqlalchemy.schema.Table"&gt;Table&lt;/a&gt;&amp;#8221;), son la unidad básica del conjunto de metadatos. Hay dos formas de crear una tabla &lt;strong&gt;reflejarla&lt;/strong&gt; o &lt;strong&gt;declararla&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;Declarar&amp;nbsp;tablas.&lt;/h3&gt;
&lt;p&gt;Declarar una tabla significa definir una tabla para añadirla al conjunto de metadatos. Hay tres formas de&amp;nbsp;declarar:&lt;/p&gt;
&lt;h4&gt;Usando&amp;nbsp;Core.&lt;/h4&gt;
&lt;p&gt;Creamos la tabla como una instancia de la clase&amp;nbsp;&amp;#8220;Table&amp;#8221;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;sqlalchemy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;sqlalchemy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ForeignKey&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user_table&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;user_account&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="n"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;primary_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="n"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;name&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="n"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;fullname&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;address_table&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;address&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="n"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;primary_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="n"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;user_id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ForeignKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;user_account.id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nullable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="n"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;email_address&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nullable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;De esta forma las tabla se agregan a la metadata. &amp;#8220;&lt;a href="https://docs.sqlalchemy.org/en/14/core/metadata.html#sqlalchemy.schema.Column"&gt;Column&lt;/a&gt;&amp;#8221; es una clase que representa una columna de la tabla. &amp;#8220;Integer&amp;#8221; o &amp;#8220;String&amp;#8221; los tipos de datos que contendrá la columna (&amp;#8220;&lt;a href="https://docs.sqlalchemy.org/en/14/core/types.html"&gt;Column and Data Types&lt;/a&gt;&amp;#8221;).&lt;/p&gt;
&lt;p&gt;También se puden crear relaciones y restricciones entre tablas. En la tabla denominada &amp;#8220;user_account&amp;#8221; se crea una clave primaria con el atributo de la&amp;nbsp;columna &lt;code&gt;primary_key=True&lt;/code&gt;. Como contraparte, en la tabla &amp;#8220;address&amp;#8221; se crea una columna denominada &amp;#8220;user_id&amp;#8221; que mediante la&amp;nbsp;función &lt;code&gt;ForeignKey()&lt;/code&gt;hace referencia a la clave primaria antes mencionada. Al&amp;nbsp;utilizar &lt;code&gt;ForeignKey()&lt;/code&gt; no es necesario definir el tipo de dato de la columna, ya que heredará el tipo de dato de la clave&amp;nbsp;primaria. &lt;/p&gt;
&lt;p&gt;Además del tipo de dato y de la restricción de clave externa, también se pueden crear restricciones de obligatoriedad. Al&amp;nbsp;indicar &lt;code&gt;nullable=False&lt;/code&gt; restingimos la columna a &lt;span class="caps"&gt;NO&lt;/span&gt; estar&amp;nbsp;vacía. &lt;/p&gt;
&lt;p&gt;Para crear las tablas en la base de datos utilizaremos la función &amp;#8220;&lt;a href="https://docs.sqlalchemy.org/en/14/core/metadata.html#sqlalchemy.schema.MetaData.create_all"&gt;MetaData.create_all()&lt;/a&gt;&amp;#8221;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;metadata.create_all(engine)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;Usando &lt;span class="caps"&gt;ORM&lt;/span&gt;.&lt;/h4&gt;
&lt;p&gt;Para crear tablas usando la metodología &lt;span class="caps"&gt;ORM&lt;/span&gt; utilizaremos una clase base, y a partir de esa clase crearemos otras clases que representarán las diferentes&amp;nbsp;tablas. &lt;/p&gt;
&lt;p&gt;Para crear la clase base utilizaremos la función &amp;#8220;&lt;a href="https://docs.sqlalchemy.org/en/14/orm/mapping_api.html#sqlalchemy.orm.declarative_base"&gt;declarative_base()&lt;/a&gt;&amp;#8221;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;sqlalchemy.orm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;declarative_base&lt;/span&gt;
&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;declarative_base&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Esta función además de crear una clase base, también crea un registro (&amp;#8220;&lt;a href="https://docs.sqlalchemy.org/en/14/orm/mapping_api.html#sqlalchemy.orm.registry"&gt;registry&lt;/a&gt;&amp;#8221;), y éste crea la&amp;nbsp;metadata.&lt;/p&gt;
&lt;p&gt;Una vez definida la clae Base, podemos definir las&amp;nbsp;tablas.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;sqlalchemy.orm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;relationship&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="n"&gt;__tablename__&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;user_account&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;primary_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="n"&gt;fullname&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="n"&gt;addresses&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;relationship&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Address&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;back_populates&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;user&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;__repr__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;User(id=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="si"&gt;!r}&lt;/span&gt;&lt;span class="s2"&gt;, name=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;!r}&lt;/span&gt;&lt;span class="s2"&gt;, fullname=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fullname&lt;/span&gt;&lt;span class="si"&gt;!r}&lt;/span&gt;&lt;span class="s2"&gt;)&amp;quot;&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Address&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="n"&gt;__tablename__&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;address&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;primary_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="n"&gt;email_address&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nullable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ForeignKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;user_account.id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;relationship&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;User&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;back_populates&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;addresses&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;__repr__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Address(id=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="si"&gt;!r}&lt;/span&gt;&lt;span class="s2"&gt;, email_address=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;email_address&lt;/span&gt;&lt;span class="si"&gt;!r}&lt;/span&gt;&lt;span class="s2"&gt;)&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Estas clases creadas también incluyen objetos tipo tabla como los creados en la sección del uso de la metodologia &amp;#8220;Core&amp;#8221;. Se puede acceder a éstos objetos con el&amp;nbsp;atributo &lt;code&gt;.__table__&lt;/code&gt;. Este objeto se crea graicas al atributo de la clase Base&amp;nbsp;denominado &lt;code&gt;.__tablename__&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;En este ejemplo también se ha utilizado la restricción de clave primaria y clave externa. Para crear esta relación se utiliza la función &amp;#8220;&lt;a href="https://docs.sqlalchemy.org/en/14/orm/relationship_api.html#sqlalchemy.orm.relationship"&gt;relationship()&lt;/a&gt;&amp;#8221;.&lt;/p&gt;
&lt;p&gt;Para crear las tablas en la base de datos utilizaremos &amp;#8220;&lt;a href="https://docs.sqlalchemy.org/en/14/core/metadata.html#sqlalchemy.schema.MetaData.create_all"&gt;Metadata.create_all()&lt;/a&gt;&amp;#8221;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Base.metadata.create_all(engine)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;Usando un método&amp;nbsp;híbrido.&lt;/h4&gt;
&lt;p&gt;En el método híbrido crearemos la tabla como si utilizaramos el método &amp;#8220;Core&amp;#8221;, y posteriormente la integraremos en la clase &amp;#8220;Base&amp;#8221; del método &amp;#8220;&lt;span class="caps"&gt;ORM&lt;/span&gt;&amp;#8221;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;__table__&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;user_table&lt;/span&gt;

&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nx"&gt;addresses&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;relationship&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Address&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;back_populates&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;user&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nx"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;__repr__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;User({self.name!r}, {self.fullname!r})&amp;quot;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Address&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;__table__&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;address_table&lt;/span&gt;

&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;relationship&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;User&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;back_populates&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;addresses&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nx"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;__repr__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Address({self.email_address!r})&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;En este caso en vez de utilizar el&amp;nbsp;atributo &lt;code&gt;.__tablename__&lt;/code&gt; para crear el objeto &amp;#8220;table&amp;#8221;, directamente usamos el&amp;nbsp;atributo &lt;code&gt;.__table__&lt;/code&gt; y le asignamos el objeto creador mediate el método&amp;nbsp;&amp;#8220;Core&amp;#8221;.&lt;/p&gt;
&lt;h3&gt;Reflejar&amp;nbsp;tablas.&lt;/h3&gt;
&lt;p&gt;Este método de creación de tablas no me acaba de quedar del todo claro. Parece que en vez de crear una tabla en la metadata, lo que hace es copiar la estructura de una tabla creada previamente. No creo que vaya a usar este sistema, para más información &lt;a href="https://docs.sqlalchemy.org/en/14/tutorial/metadata.html#table-reflection"&gt;aquí&lt;/a&gt; y &lt;a href="https://docs.sqlalchemy.org/en/14/core/reflection.html"&gt;aquí&lt;/a&gt;.&lt;/p&gt;</content><category term="Python"/><category term="python"/><category term="sql"/><category term="programacion"/></entry><entry><title>SqlAlchemy Intro (2): Conectando.</title><link href="https://pedrogomez.blog/sqlalchemy-intro-2-conectando.html" rel="alternate"/><published>2021-07-26T00:00:00+02:00</published><updated>2022-08-23T17:07:03+02:00</updated><author><name>Pedro Gomez</name></author><id>tag:pedrogomez.blog,2021-07-26:/sqlalchemy-intro-2-conectando.html</id><summary type="html">&lt;p&gt;*Disclaimer: Si quieres aprender, no leas,&amp;nbsp;escribe.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;span class="caps"&gt;TLDR&lt;/span&gt;&lt;/strong&gt;: Creamos el objeto de conexion al engine con engine.connect() o con Session(engine), dependiendo si trabajamos …&lt;/p&gt;&lt;/blockquote&gt;</summary><content type="html">&lt;p&gt;*Disclaimer: Si quieres aprender, no leas,&amp;nbsp;escribe.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;span class="caps"&gt;TLDR&lt;/span&gt;&lt;/strong&gt;: Creamos el objeto de conexion al engine con engine.connect() o con Session(engine), dependiendo si trabajamos con Core o con &lt;span class="caps"&gt;ORM&lt;/span&gt;. Si realizamos consultas se nos retornará el objeto&amp;nbsp;Result.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Siguiendo con la guía de introducción a &lt;a href="https://docs.sqlalchemy.org/en/14/tutorial/dbapi_transactions.html"&gt;SQLAlchemy&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Transacciones: trabajando con el &lt;em&gt;engine&lt;/em&gt;.&lt;/h2&gt;
&lt;h3&gt;&lt;a href="https://docs.sqlalchemy.org/en/14/core/future.html#sqlalchemy.future.Connection"&gt;Conexiones&lt;/a&gt; &lt;code&gt;engine.connect()&lt;/code&gt;:&lt;/h3&gt;
&lt;p&gt;Esta función se usa para crear un objeto que permite interactuar con la base de datos. Habitualmente se usa dentro de un “context manager”. De esta manera que podríamos ejecutar una consulta a la base de datos de la siguiente&amp;nbsp;forma:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;sqlalchemy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;select &amp;#39;hello world&amp;#39;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Los cambios ejecutados no se efectúan hasta no hacer un “commit” al&amp;nbsp;objeto.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Hay un modo “autocommit”, que explicaremos más&amp;nbsp;adelante.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Cambios&amp;nbsp;persistentes:&lt;/h3&gt;
&lt;p&gt;Para que los cambios realizados en una consulta sean persistentes utilizaremos la función &lt;a href="https://docs.sqlalchemy.org/en/14/core/future.html#sqlalchemy.future.Connection.commit"&gt;commit()&lt;/a&gt; del objeto de&amp;nbsp;conexión.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;with engine.connect() as conn:
    conn.execute(text(&amp;quot;CREATE TABLE some_table (x int, y int)&amp;quot;))
    conn.execute(
        text(&amp;quot;INSERT INTO some_table (x, y) VALUES (:x, :y)&amp;quot;),
        [{&amp;quot;x&amp;quot;: 1, &amp;quot;y&amp;quot;: 1}, {&amp;quot;x&amp;quot;: 2, &amp;quot;y&amp;quot;: 4}]
    )
    conn.commit()
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;De esta manera cuando queremos realizar un cambio permanente simplemente ejecutamos la&amp;nbsp;función &lt;code&gt;Commit()&lt;/code&gt; para hacerlo permanente. A esto se le llama “&lt;em&gt;commit as you go&lt;/em&gt;”.&lt;/p&gt;
&lt;p&gt;El otro sistema para hacer cambios permanentes se denomina “&lt;em&gt;begin once&lt;/em&gt;”. Con este sistema en vez de&amp;nbsp;utilizar &lt;code&gt;engine.connect()&lt;/code&gt;, utilizaremos &amp;#8220;&lt;a href="https://docs.sqlalchemy.org/en/14/core/future.html#sqlalchemy.future.Engine.begin"&gt;engine.begin()&lt;/a&gt;&amp;#8221;. Este método creará la conexión y hará “commit” una vez finalizado el&amp;nbsp;bucle.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;with engine.begin() as conn:
    conn.execute(
        text(&amp;quot;INSERT INTO some_table (x, y) VALUES (:x, :y)&amp;quot;),
        [{&amp;quot;x&amp;quot;: 6, &amp;quot;y&amp;quot;: 10}, {&amp;quot;x&amp;quot;: 9, &amp;quot;y&amp;quot;: 10}]
    )
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Instrucciones&amp;nbsp;básicas.&lt;/h3&gt;
&lt;p&gt;El objeto que retorna una consulta, tanto las&amp;nbsp;consultas &lt;code&gt;Conection.execute()&lt;/code&gt; como las&amp;nbsp;consultas &lt;code&gt;Session.execute()&lt;/code&gt; (de las que hablaremos más adelante), se denomina &lt;a href="https://docs.sqlalchemy.org/en/14/core/connections.html#sqlalchemy.engine.Result"&gt;Result&lt;/a&gt;. Éste es un objeto iterable compuesto por filas de resultados (&lt;a href="https://docs.sqlalchemy.org/en/14/core/connections.html#sqlalchemy.engine.Row"&gt;Row&lt;/a&gt;). Las filas se componen de &amp;#8220;&lt;a href="https://docs.python.org/3/library/collections.html#collections.namedtuple"&gt;named tuples&lt;/a&gt;&amp;#8221;,&lt;/p&gt;
&lt;h4&gt;Obtención de valores de las&amp;nbsp;filas.&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Tuple&amp;nbsp;Assignment:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;result = conn.execute(text(&amp;quot;select x, y from some_table&amp;quot;))

for x, y in result:
    # ...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Integer&amp;nbsp;Index:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;result = conn.execute(text(&amp;quot;select x, y from some_table&amp;quot;))

  for row in result:
      x = row[0]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Attribute&amp;nbsp;Name:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;result = conn.execute(text(&amp;quot;select x, y from some_table&amp;quot;))

for row in result:
    y = row.y

    # illustrate use with Python f-strings
    print(f&amp;quot;Row: {row.x} {row.y}&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Mapping&amp;nbsp;Access:&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Mediante la función &amp;#8220;&lt;a href="https://docs.sqlalchemy.org/en/14/core/connections.html#sqlalchemy.engine.MappingResult"&gt;Result.mappings()&lt;/a&gt;&amp;#8221;, transformamos el resultado en un generador de diccionarios. De esta manera cada fila es un diccionario compuesto del nombre de la columna y su&amp;nbsp;valor.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;result = conn.execute(text(&amp;quot;select x, y from some_table&amp;quot;))

for dict_row in result.mappings():
    x = dict_row[&amp;#39;x&amp;#39;]
    y = dict_row[&amp;#39;y&amp;#39;]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;Envío de&amp;nbsp;parámetros.&lt;/h4&gt;
&lt;p&gt;Hasta el momento hemos ejecutado declaración &lt;span class="caps"&gt;SQL&lt;/span&gt; utilizando la&amp;nbsp;funicón &lt;code&gt;Connection.execute()&lt;/code&gt;, ésta también permite incluir parámetros en ella llamados &amp;#8220;&lt;a href="https://docs.sqlalchemy.org/en/14/glossary.html#term-bound-parameters"&gt;bound parameters&lt;/a&gt;&amp;#8221;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; with engine.connect() as conn:
&lt;span class="k"&gt;...&lt;/span&gt;     result = conn.execute(
&lt;span class="k"&gt;...&lt;/span&gt;         text(&amp;quot;SELECT x, y FROM some_table WHERE y &amp;gt; :y&amp;quot;),
&lt;span class="k"&gt;...&lt;/span&gt;         {&amp;quot;y&amp;quot;: 2}
&lt;span class="k"&gt;...&lt;/span&gt;     )
&lt;span class="k"&gt;...&lt;/span&gt;     for row in result:
&lt;span class="k"&gt;...&lt;/span&gt;        print(f&amp;quot;x: {row.x}  y: {row.y}&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;El parámetro se presenta dentro de la&amp;nbsp;función &lt;code&gt;text()&lt;/code&gt; como &amp;#8220;&lt;strong&gt;:y&lt;/strong&gt;&amp;#8221;. En el siguiente argumento de la&amp;nbsp;función &lt;code&gt;Conection.execute()&lt;/code&gt; incluimos los &amp;#8220;bound parameters&amp;#8221;, en este caso un diccionario que contiene el nombre del parámetro presentado anteriormente &amp;#8220;&lt;strong&gt;:y&lt;/strong&gt;&amp;#8221; y su&amp;nbsp;valor.&lt;/p&gt;
&lt;p&gt;Cuando se trata de enviar un único parámetro se puede integrar en la declración &lt;span class="caps"&gt;SQL&lt;/span&gt; mediente el método &amp;#8220;&lt;a href="https://docs.sqlalchemy.org/en/14/core/sqlelement.html#sqlalchemy.sql.expression.TextClause.bindparams"&gt;TextClause.bindparams()&lt;/a&gt;&amp;#8221;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; stmt = text(&amp;quot;SELECT x, y FROM some_table WHERE y &amp;gt; :y ORDER BY x, y&amp;quot;).bindparams(y=6)
&amp;gt;&amp;gt;&amp;gt; with engine.connect() as conn:
&lt;span class="k"&gt;...&lt;/span&gt;     result = conn.execute(stmt)
&lt;span class="k"&gt;...&lt;/span&gt;     for row in result:
&lt;span class="k"&gt;...&lt;/span&gt;        print(f&amp;quot;x: {row.x}  y: {row.y}&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Envío de múltiples&amp;nbsp;parámetros:&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;En el caso de declaraciones &lt;span class="caps"&gt;SQL&lt;/span&gt; que no retornan un resultado (p.ej. &amp;#8220;&lt;span class="caps"&gt;INSERT&lt;/span&gt;&amp;#8221;), podemos enviar múltiples parámetros de la misma manera que en el ejemplo anterior, pero en vez de incluir un diccionario como &amp;#8220;bound parameters&amp;#8221; incluimos una lista de&amp;nbsp;diccionarios.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; with engine.connect() as conn:
&lt;span class="k"&gt;...&lt;/span&gt;     conn.execute(
&lt;span class="k"&gt;...&lt;/span&gt;         text(&amp;quot;INSERT INTO some_table (x, y) VALUES (:x, :y)&amp;quot;),
&lt;span class="k"&gt;...&lt;/span&gt;         [{&amp;quot;x&amp;quot;: 11, &amp;quot;y&amp;quot;: 12}, {&amp;quot;x&amp;quot;: 13, &amp;quot;y&amp;quot;: 14}]
&lt;span class="k"&gt;...&lt;/span&gt;     )
&lt;span class="k"&gt;...&lt;/span&gt;     conn.commit()
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Ejecutando con &lt;span class="caps"&gt;ORM&lt;/span&gt;:&amp;nbsp;&amp;#8220;Session&amp;#8221;.&lt;/h3&gt;
&lt;p&gt;Podríamos decir que el equivalente &lt;span class="caps"&gt;ORM&lt;/span&gt; de la &amp;#8220;Connection&amp;#8221; usada en &amp;#8220;Core&amp;#8221; es &amp;#8220;&lt;a href="https://docs.sqlalchemy.org/en/14/orm/session_api.html#sqlalchemy.orm.Session"&gt;Session&lt;/a&gt;&amp;#8221;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;sqlalchemy.orm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Session&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;SELECT x, y FROM some_table WHERE y &amp;gt; :y ORDER BY x, y&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bindparams&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;with&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Session&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;x: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;  y: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;El objeto &amp;#8220;Session&amp;#8221; también permite el uso de &amp;#8220;Commit as you go&amp;#8221; y el envío de múltiples parámetros con &amp;#8220;bound&amp;nbsp;parmeters&amp;#8221;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; with Session(engine) as session:
&lt;span class="k"&gt;...&lt;/span&gt;     result = session.execute(
&lt;span class="k"&gt;...&lt;/span&gt;         text(&amp;quot;UPDATE some_table SET y=:y WHERE x=:x&amp;quot;),
&lt;span class="k"&gt;...&lt;/span&gt;         [{&amp;quot;x&amp;quot;: 9, &amp;quot;y&amp;quot;:11}, {&amp;quot;x&amp;quot;: 13, &amp;quot;y&amp;quot;: 15}]
&lt;span class="k"&gt;...&lt;/span&gt;     )
&lt;span class="k"&gt;...&lt;/span&gt;     session.commit()
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="Python"/><category term="python"/><category term="sql"/><category term="programacion"/></entry><entry><title>Atajos de teclado Doom-Emacs.</title><link href="https://pedrogomez.blog/atajos-de-teclado-doom-emacs.html" rel="alternate"/><published>2021-07-13T00:00:00+02:00</published><updated>2025-05-28T21:05:53+02:00</updated><author><name>Pedro Gomez</name></author><id>tag:pedrogomez.blog,2021-07-13:/atajos-de-teclado-doom-emacs.html</id><summary type="html">&lt;p&gt;Creo que lo mejor para adaptarse a una aplicación es escribir sobre ella. Voy a ir poniendo, poco a poco los atajos que voy usando …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Creo que lo mejor para adaptarse a una aplicación es escribir sobre ella. Voy a ir poniendo, poco a poco los atajos que voy usando en la aplicación. No me apetecía mucho ponerme a configurar Emacs desde cero, así que utilizaré&amp;nbsp;Doom-Emacs.&lt;/p&gt;
&lt;h4&gt;Emacs&amp;nbsp;functions:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;(org-narrow-to-subtree)&lt;/code&gt; &lt;em&gt;&lt;span class="caps"&gt;SPC&lt;/span&gt;-m-s-n&lt;/em&gt;: Cuando estas trabajando en un archivo muy grande y quieres centrarte solo en un &amp;#8220;subtree&amp;#8221;, utilizamos (org-narrow-to-subtree) para restringir la información a esa&amp;nbsp;rama.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;(widen)&lt;/code&gt; &lt;em&gt;&lt;span class="caps"&gt;SPC&lt;/span&gt;-m-s-N&lt;/em&gt;: Para remover la&amp;nbsp;restricción.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;(doom/toggle-line-numbers)&lt;/code&gt; &lt;em&gt;&lt;span class="caps"&gt;SPC&lt;/span&gt;-t-l&lt;/em&gt;: Recorre la secuencia de opciones para mostrar los números de&amp;nbsp;línea.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;(query-replace)&lt;/code&gt; &lt;em&gt;M-%&lt;/em&gt;: Entrar en el modo reemplazar texto. Indicar la palabra a reemplazar y la palabra con la que se quiere reemplazar. Después apretar &amp;#8220;!&amp;#8221;, para reemplazarlas todas o &amp;#8220;y&amp;#8221; para reemplazar de una a&amp;nbsp;una.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;(link-hint-open-link&lt;/code&gt; &lt;em&gt;&lt;span class="caps"&gt;SPC&lt;/span&gt;-s-l&lt;/em&gt;: Resalta todos los enlaces visibles, puedes abrir cualquiera seleccionando las&amp;nbsp;letras.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;(ffap-menu &amp;amp;optional RESCAN)&lt;/code&gt;&lt;em&gt;&lt;span class="caps"&gt;SPC&lt;/span&gt;-s-L&lt;/em&gt;: Abre un buffer con todos los enlaces del&amp;nbsp;buffer.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;(org-next-link)&lt;/code&gt; &lt;em&gt;]-l&lt;/em&gt;: Se dirige al siguiente enlace del documento. Se puede presionar &lt;em&gt;enter&lt;/em&gt; para abrir el&amp;nbsp;enlace.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;(org-previous-link)&lt;/code&gt; &lt;em&gt;[-l&lt;/em&gt;: Se dirige al enlace previo a la posición del cursor. Se puede presionar &lt;em&gt;enter&lt;/em&gt; para abrir el&amp;nbsp;enlace.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;(counsel-grep-or-swiper)&lt;/code&gt; &lt;em&gt;&lt;span class="caps"&gt;SPC&lt;/span&gt;-s-b&lt;/em&gt;: Realiza una búsqueda en el buffer actual del término que le indiques. Es muy visual y bastante&amp;nbsp;rápido.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Help&amp;nbsp;functions:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;(describe-function)&lt;/code&gt; &lt;em&gt;&lt;span class="caps"&gt;SPC&lt;/span&gt;-h-f&lt;/em&gt;: Al ejecutar esta función puedes introducir el nombre de otra función y te indicará la documentación de la&amp;nbsp;misma.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;(describe-key)&lt;/code&gt; &lt;em&gt;&lt;span class="caps"&gt;SPC&lt;/span&gt;-h-k&lt;/em&gt;: Al ejecutar esta función puedes introducir otra combinación de teclas y te indicará que función corresponde a esa&amp;nbsp;combinación.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Vim text&amp;nbsp;movement.&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;i&lt;/code&gt;: Insert mode. Tan solo para&amp;nbsp;escribir.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ESC&lt;/code&gt;: Volver al modo&amp;nbsp;normal.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;t&lt;/code&gt;: Moverte hacia adelante hasta un espacio antes del caràcter indicado a&amp;nbsp;posteriori. &lt;code&gt;,&lt;/code&gt;: Moverte a la siguiente&amp;nbsp;coincidencia. &lt;code&gt;;&lt;/code&gt;: Moverte a la coincidencia&amp;nbsp;anterior.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;T&lt;/code&gt;: Moverte hacia atrás hasta un espacio antes del caràcter indicado a&amp;nbsp;posteriori. &lt;code&gt;,&lt;/code&gt;: Moverte a la siguiente&amp;nbsp;coincidencia. &lt;code&gt;;&lt;/code&gt;: Moverte a la coincidencia&amp;nbsp;anterior.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;f&lt;/code&gt;: Moverte hacia adelante hasta el caràcter indicado a&amp;nbsp;posteriori. &lt;code&gt;,&lt;/code&gt;: Moverte a la siguiente&amp;nbsp;coincidencia. &lt;code&gt;;&lt;/code&gt;: Moverte a la coincidencia&amp;nbsp;anterior.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;F&lt;/code&gt;: Moverte hacia atrás hasta el caràcter indicado a&amp;nbsp;posteriori. &lt;code&gt;,&lt;/code&gt;: Moverte a la siguiente&amp;nbsp;coincidencia. &lt;code&gt;;&lt;/code&gt;: Moverte a la coincidencia&amp;nbsp;anterior.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Ctrl+d&lt;/code&gt;: Scroll media pantalla hacia&amp;nbsp;abajo.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Ctrl+u&lt;/code&gt;: Scroll media pantalla hacia&amp;nbsp;arriba.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Ctrl+f&lt;/code&gt;: Scroll pantalla completa hacia&amp;nbsp;abajo.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Ctrl+b&lt;/code&gt;: Scroll pantalla completa hacia&amp;nbsp;arriba.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Keybindings Insert&amp;nbsp;Mode:&lt;/h4&gt;
&lt;p&gt;Cuando se utiliza el modo &amp;#8220;insert mode&amp;#8221; las combinaciones de teclas&amp;nbsp;cambian.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Para pegar texto podemos utilizar las siguientes combinaciones: &lt;a href="https://github.com/hlissner/doom-emacs/issues/3127#issuecomment-628852408"&gt;info&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="emacs"/><category term="emacs"/><category term="doom"/></entry><entry><title>Distrohopping! Me voy a Manjaro.</title><link href="https://pedrogomez.blog/distrohopping-me-voy-a-manjaro.html" rel="alternate"/><published>2021-02-28T00:00:00+01:00</published><updated>2026-03-02T21:38:37+01:00</updated><author><name>Pedro Gomez</name></author><id>tag:pedrogomez.blog,2021-02-28:/distrohopping-me-voy-a-manjaro.html</id><summary type="html">&lt;h1&gt;De Ubuntu a&amp;nbsp;Manjaro.&lt;/h1&gt;
&lt;p&gt;He decido cambiar de distro por 2&amp;nbsp;motivos:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;En Ubuntu me resultaba más complicado mantener todos los paquetes actualizados &amp;#8220;a la …&lt;/li&gt;&lt;/ul&gt;</summary><content type="html">&lt;h1&gt;De Ubuntu a&amp;nbsp;Manjaro.&lt;/h1&gt;
&lt;p&gt;He decido cambiar de distro por 2&amp;nbsp;motivos:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;En Ubuntu me resultaba más complicado mantener todos los paquetes actualizados &amp;#8220;a la&amp;nbsp;última&amp;#8221;. &lt;/li&gt;
&lt;li&gt;Habían ciertas cosas que no acaban de funcionar como el Bluetooth de mi&amp;nbsp;portátil.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Primeros problemas: El Trackpad no funciona como me&amp;nbsp;gustaría.&lt;/h1&gt;
&lt;p&gt;Linux cada vez es más sencillo de configurar y dejarlo todo a tu gusto. Por defecto el desplazamiento del trackpad estaba invertido y el click táctil no&amp;nbsp;funcionaba.&lt;/p&gt;
&lt;p&gt;La solución la encontré rápidamente en este &lt;a href="!https://www.rockyourcode.com/get-your-touchpad-working-on-manjaro-i3/"&gt;blog&lt;/a&gt;. También hay bastantes referencias en el manual de arch&amp;nbsp;Linux.&lt;/p&gt;
&lt;h1&gt;Programas a&amp;nbsp;instalar:&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Gestor de ventanas: &lt;a href="!https://github.com/Airblader/i3"&gt;i3-gaps&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Barra de información: &lt;a href="!https://github.com/polybar/polybar"&gt;polybar&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Cambiar fondo: &lt;a href="!https://github.com/derf/feh"&gt;feh&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Gestión de opacidad: &lt;a href="!https://github.com/yshui/picom"&gt;picom&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Lanzador de aplicaciones: &lt;a href="!https://github.com/davatorium/rofi"&gt;rofi&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Gestor de archivos: &lt;a href="!https://github.com/ranger/ranger"&gt;ranger&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Editor: &lt;a href="!https://neovim.io/"&gt;neovim&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Gestor de notas: &lt;a href="!https://www.gnu.org/software/emacs/"&gt;emacs&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Terminal: &lt;a href="!https://sw.kovidgoyal.net/kitty/"&gt;kitty&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Nube personal: &lt;a href="!https://nextcloud.com/install/#"&gt;nextcloud&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Mensajería: &lt;a href="!https://desktop.telegram.org/"&gt;telegram&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ahora a la parte divertida! A configurar todas las&amp;nbsp;aplicaciones!&lt;/p&gt;</content><category term="Linux"/><category term="distrohopping"/><category term="manjaro"/><category term="linux"/></entry><entry><title>Docker-compse en crontab.</title><link href="https://pedrogomez.blog/docker-compse-en-crontab.html" rel="alternate"/><published>2021-01-20T00:00:00+01:00</published><updated>2021-01-20T00:00:00+01:00</updated><author><name>Pedro Gomez</name></author><id>tag:pedrogomez.blog,2021-01-20:/docker-compse-en-crontab.html</id><summary type="html">&lt;p&gt;Este blog funciona gracias a &lt;a href="https://blog.getpelican.com/"&gt;Pelican&lt;/a&gt;, un generador de páginas web, y se reconstruye cada 30 minutos gracias a Docker (docker-compose) y&amp;nbsp;crontab.&lt;/p&gt;
&lt;p&gt;En mi …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Este blog funciona gracias a &lt;a href="https://blog.getpelican.com/"&gt;Pelican&lt;/a&gt;, un generador de páginas web, y se reconstruye cada 30 minutos gracias a Docker (docker-compose) y&amp;nbsp;crontab.&lt;/p&gt;
&lt;p&gt;En mi caso el docker-compose levanta un Dockerfile de python que regenera el&amp;nbsp;blog.&lt;/p&gt;
&lt;p&gt;Para reconstruir el blog cada 30 min. deberemos añadir lo siguiente a crontab. Editamos crontab&amp;nbsp;con:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;crontab -e
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Para reconstruir el blog cada 30 min añadimos la siguiente linea a&amp;nbsp;crontab:&lt;/p&gt;
&lt;p&gt;*/30 * * * * $(which docker-compose) -f $PATH_DOCKER_COMPOSE_YAML_FILE up&amp;nbsp;-d&lt;/p&gt;
&lt;p&gt;Donde &amp;#8220;$PATH_DOCKER_COMPOSE_YAML_FILE&amp;#8221; es la ruta absoluta donde se encuentra el archivo &lt;em&gt;docker-compose.yaml&lt;/em&gt;. Importante que sea la ruta &lt;strong&gt;absoluta&lt;/strong&gt; no la&amp;nbsp;relativa.&lt;/p&gt;
&lt;p&gt;No sé si es necesario, pero reiniciamos crontab con el siguiente&amp;nbsp;comando:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cron&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;reload&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="Linux"/><category term="cron"/><category term="docker"/><category term="linux"/><category term="pelican"/></entry><entry><title>Nextcloud desde el terminal</title><link href="https://pedrogomez.blog/nextcloud-desde-el-terminal.html" rel="alternate"/><published>2020-05-25T00:00:00+02:00</published><updated>2022-08-23T17:06:53+02:00</updated><author><name>Pedro Gomez</name></author><id>tag:pedrogomez.blog,2020-05-25:/nextcloud-desde-el-terminal.html</id><summary type="html">&lt;h2&gt;NextCloud en el&amp;nbsp;Terminal.&lt;/h2&gt;
&lt;p&gt;Debido al uso que le doy a Linux (cacharrear), necesito un cliente que pueda quedar configurado en el primer arranque del …&lt;/p&gt;</summary><content type="html">&lt;h2&gt;NextCloud en el&amp;nbsp;Terminal.&lt;/h2&gt;
&lt;p&gt;Debido al uso que le doy a Linux (cacharrear), necesito un cliente que pueda quedar configurado en el primer arranque del sistema o utilizando dotfiles (&lt;a href="https://github.com/deadc0de6/dotdrop"&gt;dotdrop&lt;/a&gt;).&lt;/p&gt;
&lt;h2&gt;Veo dos&amp;nbsp;alternativas:&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.nextcloud.com/desktop/2.6/advancedusage.html#nextcloud-command-line-client"&gt;Nextcloudcmd&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://rclone.org/webdav/#nextcloud"&gt;RClone&lt;/a&gt;: Sincronizar con&amp;nbsp;webdav. &lt;/li&gt;
&lt;/ul&gt;</content><category term="misc"/></entry><entry><title>Cambios en la configuración de Regolith.</title><link href="https://pedrogomez.blog/cambios-en-la-configuracion-de-regolith.html" rel="alternate"/><published>2020-05-21T00:00:00+02:00</published><updated>2025-05-28T21:07:11+02:00</updated><author><name>Pedro Gomez</name></author><id>tag:pedrogomez.blog,2020-05-21:/cambios-en-la-configuracion-de-regolith.html</id><summary type="html">&lt;h2&gt;i3&amp;nbsp;Config.&lt;/h2&gt;
&lt;p&gt;Para guardar la configuración a nivel de usuario, es recomendable seguir los pasos que indican en su &lt;a href="https://regolith-linux.org/docs/interface/system/#i3-wm"&gt;documentación&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Una vez copiado el archivo …&lt;/p&gt;</summary><content type="html">&lt;h2&gt;i3&amp;nbsp;Config.&lt;/h2&gt;
&lt;p&gt;Para guardar la configuración a nivel de usuario, es recomendable seguir los pasos que indican en su &lt;a href="https://regolith-linux.org/docs/interface/system/#i3-wm"&gt;documentación&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Una vez copiado el archivo en el directorio de usuario ya podemos realizar las modificaciones que&amp;nbsp;queramos.&lt;/p&gt;
&lt;h3&gt;Focused&amp;nbsp;window.&lt;/h3&gt;
&lt;p&gt;Lo primero que quería personalizar es la indicación de la pantalla activa, tal y como también comentan es su &lt;a href="https://github.com/regolith-linux/regolith-desktop/issues/210"&gt;github&lt;/a&gt;, no se aprecia mucho el cambio de una ventana a&amp;nbsp;otra.&lt;/p&gt;
&lt;p&gt;La solución la encontré en el mismo hilo un poco más &lt;a href="https://github.com/regolith-linux/regolith-desktop/issues/210#issuecomment-585724557"&gt;abajo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Otra opción es jugar con la opacidad de las ventanas inactivas y la aplicación &lt;a href="https://github.com/chjj/compton"&gt;compon&lt;/a&gt;. &lt;a href="https://www.reddit.com/r/i3wm/comments/63krm9/whats_the_common_way_to_indicate_focus_on_a_window/dfv4caj/?context=8&amp;amp;depth=9"&gt;Visto en&amp;nbsp;Reddit&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Config &lt;span class="caps"&gt;ST&lt;/span&gt;&amp;nbsp;(terminal)&lt;/h3&gt;
&lt;p&gt;En el &lt;a href="https://github.com/regolith-linux/regolith-desktop/wiki/Customize"&gt;github&lt;/a&gt; de Regolith encontraremos información para personalizar &lt;span class="caps"&gt;ST&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;En principio el archivo de configuración debería encontrarse en el siguiente&amp;nbsp;directorio.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;!&lt;span class="w"&gt; &lt;/span&gt;--&lt;span class="w"&gt; &lt;/span&gt;Applications
!&lt;span class="w"&gt; &lt;/span&gt;These&lt;span class="w"&gt; &lt;/span&gt;files&lt;span class="w"&gt; &lt;/span&gt;map&lt;span class="w"&gt; &lt;/span&gt;values&lt;span class="w"&gt; &lt;/span&gt;defined&lt;span class="w"&gt; &lt;/span&gt;above&lt;span class="w"&gt; &lt;/span&gt;into&lt;span class="w"&gt; &lt;/span&gt;specific&lt;span class="w"&gt; &lt;/span&gt;app&lt;span class="w"&gt; &lt;/span&gt;settings.
&lt;span class="c1"&gt;#include &amp;quot;/etc/regolith/styles/st-term&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Aquí dejo una configuración de &lt;span class="caps"&gt;ST&lt;/span&gt; de &lt;a href="https://github.com/ctjhoa/st/blob/master/config.h"&gt;ejemplo&lt;/a&gt;, sacada del usuario de github &lt;a href="https://github.com/ctjhoa"&gt;ctjhoa&lt;/a&gt;, y otro ejemplo de la configuración oficial del &lt;a href="https://wiki.archlinux.org/index.php/St#Configuration"&gt;ArchWiki&lt;/a&gt;.w&lt;/p&gt;</content><category term="Linux"/></entry><entry><title>Configuraciones de emacs</title><link href="https://pedrogomez.blog/configuraciones-de-emacs.html" rel="alternate"/><published>2020-02-26T00:00:00+01:00</published><updated>2022-08-23T17:06:53+02:00</updated><author><name>Pedro Gomez</name></author><id>tag:pedrogomez.blog,2020-02-26:/configuraciones-de-emacs.html</id><summary type="html">&lt;h2&gt;Emacs:&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.gnu.org/software/emacs/" title="emacs"&gt;Emacs&lt;/a&gt; es un editor de texto. No seré yo quien describa su funcionamiento y sus bondades. Pero aseguro que es muy rápido, muy eficiente …&lt;/p&gt;</summary><content type="html">&lt;h2&gt;Emacs:&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.gnu.org/software/emacs/" title="emacs"&gt;Emacs&lt;/a&gt; es un editor de texto. No seré yo quien describa su funcionamiento y sus bondades. Pero aseguro que es muy rápido, muy eficiente, y &lt;strong&gt;extremadamente adaptable&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;Diferentes configuraciones de&amp;nbsp;Emacs.&lt;/h2&gt;
&lt;p&gt;Algunos ejemplos de configuraciones son las&amp;nbsp;siguientes:&lt;/p&gt;
&lt;p&gt;En&amp;nbsp;castellano:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://notxor.nueva-actitud.org/blog/"&gt;Notxor&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://ugeek.github.io/"&gt;UGeek&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="http://elblog.deshackra.com/"&gt;Sackra&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://elblogdelazaro.gitlab.io/"&gt;Lázaro&lt;/a&gt; y su configuración de &lt;a href="https://gitlab.com/hefistion/emacs.d"&gt;emacs&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;En&amp;nbsp;inglés:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://sachachua.com/blog/category/emacs/"&gt;Sacha&amp;nbsp;Chua&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://www.reddit.com/r/emacs/comments/2edbau/what_are_some_great_emacsd_examples/"&gt;Otros ejemplos en&amp;nbsp;reddit&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://github.com/emacs-tw/awesome-emacs#starter-kit"&gt;Awesome&amp;nbsp;emacs&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Para buscar otros ejemplos de configuraciones podemos buscarlos en GitHub. Para buscar muchas configuraciones de Emacs, podemos buscar en&amp;nbsp;google: &lt;code&gt;site:github.com emacs.d&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;Doom&amp;nbsp;emacs.&lt;/h2&gt;
&lt;p&gt;Después de mucho tiempo con Emacs, he decidido probar &lt;a href="https://github.com/hlissner/doom-emacs/blob/master/core/core-keybinds.el" title="GitHub Doom Emacs"&gt;doom emacs&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;Doom Emacs tiene una forma de configuración diferente respecto a emacs, y
diferentes atajos de&amp;nbsp;teclado. &lt;/p&gt;
&lt;p&gt;Más adelante iré añadiendo configuración y problemas que me he ido&amp;nbsp;encontrando.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="!https://github.com/hlissner/doom-emacs/blob/master/core/core-keybinds.el"&gt;Core-Keybindings&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="!https://github.com/hlissner/doom-emacs/blob/develop/docs/getting_started.org"&gt;Getting-Started&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;</content><category term="emacs"/><category term="emacs"/></entry></feed>