<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Andrés Álvarez Iglesias</title>
    <description>The latest articles on Forem by Andrés Álvarez Iglesias (@doctorserone).</description>
    <link>https://forem.com/doctorserone</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F297198%2Fbdcbd0a7-1dcc-453c-b4a2-f0ba600f210f.jpg</url>
      <title>Forem: Andrés Álvarez Iglesias</title>
      <link>https://forem.com/doctorserone</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/doctorserone"/>
    <language>en</language>
    <item>
      <title>Using offline AI models for free in your Phyton scripts with Ollama</title>
      <dc:creator>Andrés Álvarez Iglesias</dc:creator>
      <pubDate>Wed, 05 Mar 2025 06:13:14 +0000</pubDate>
      <link>https://forem.com/doctorserone/using-offline-ai-models-for-free-in-your-phyton-scripts-with-ollama-man</link>
      <guid>https://forem.com/doctorserone/using-offline-ai-models-for-free-in-your-phyton-scripts-with-ollama-man</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;First published on Substack: &lt;a href="https://andresalvareziglesias.substack.com/p/using-offline-ai-models-for-free" rel="noopener noreferrer"&gt;https://andresalvareziglesias.substack.com/p/using-offline-ai-models-for-free&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The Ollama project allows us to donwload and use AI models for offline usage with our computer resources. This allows us to experiment with the AI in our Python projects without any cost, an testing a lot of models to find the ideal choice for our project. It's awesome.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiyh52rb3miq0n3ziw4ae.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiyh52rb3miq0n3ziw4ae.jpeg" alt="Using offline AI models for free in your Phyton scripts with Ollama" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation of Ollama
&lt;/h2&gt;

&lt;p&gt;The installation of Ollama in a Linux device (for MacOS and Windows, check &lt;a href="https://github.com/ollama/ollama" rel="noopener noreferrer"&gt;Ollama Github page&lt;/a&gt;) is very, very easy. Just write this command in a terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -fsSL https://ollama.com/install.sh | sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After a long wait, Ollama will be fully installed and configured.&lt;/p&gt;

&lt;h2&gt;
  
  
  Download a model
&lt;/h2&gt;

&lt;p&gt;Once installed, we can download any model to our computer for offline usage. In the Ollama library page we can read the full list of available models.&lt;/p&gt;

&lt;p&gt;For example, to download gemma2 with 2 billions of parameters, the command will be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ollama pull gemma2:2b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The model will be downloaded to &lt;code&gt;/usr/share/ollama/.ollama/models&lt;/code&gt; local folder, if you are curious (as I am).&lt;/p&gt;

&lt;h2&gt;
  
  
  Use the downloaded model in Python
&lt;/h2&gt;

&lt;p&gt;Now, we can use the downloaded Gemma model as any other cloud model, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from ollama import Client, ResponseError

try:
    client = Client(
        host='http://localhost:11434',
        headers={}
    )

    response = client.chat(
        model='gemma2:2b',
        messages=[{
            'role': 'user',
            'content': 'Describe why Ollama is useful',
        }]
    )

    print(response['message']['content'])

except ResponseError as e:
    print('Error:', e.error)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The program will output our requested answer. Wonderful!&lt;/p&gt;

&lt;h2&gt;
  
  
  A real example: check this article about Ollama... with Ollama
&lt;/h2&gt;

&lt;p&gt;We can program a very simple article checker with Ollama and Python, like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from ollama import Client, ResponseError

try:
    client = Client(
        host='http://localhost:11434',
        headers={}
    )

    prompt  = "I am an spanish writer that is learning how to "
    prompt += "write in english. Please, review if this article "
    prompt += "is well written. Thank you!\n\n"

    with open('article.md') as f:
        prompt += f.read()

    response = client.chat(
        model='gemma2:2b',
        messages=[{
            'role': 'user',
            'content': prompt,
        }]
    )

    print(response['message']['content'])

except ResponseError as e:
    print('Error:', e.error)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When executed, Gemma will give us a detailer analysis of this article, with advices for improvement.&lt;/p&gt;

&lt;p&gt;Awesome! The possibilities are limitless!&lt;/p&gt;

&lt;h2&gt;
  
  
  A lot to learn, a lot of fun
&lt;/h2&gt;

&lt;p&gt;Ollama allows us to test different models with our most precious data, without any privacy concern. Ollama allows to to save costs in the initial stages of development of an AI powered application.&lt;/p&gt;

&lt;p&gt;And you? What kind of projects will you develop witn the help of Ollama?&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

&lt;h2&gt;
  
  
  About the list
&lt;/h2&gt;

&lt;p&gt;Among the Python and Docker posts, I will also write about other related topics, like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Software architecture&lt;/li&gt;
&lt;li&gt;Programming environments&lt;/li&gt;
&lt;li&gt;Linux operating system&lt;/li&gt;
&lt;li&gt;Etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you found some interesting technology, programming language or whatever, please, let me know! I'm always open to learning something new!&lt;/p&gt;

&lt;h2&gt;
  
  
  About the author
&lt;/h2&gt;

&lt;p&gt;I'm Andrés, a full-stack software developer based in Palma, on a personal journey to improve my coding skills. I'm also a self-published fantasy writer with four published novels to my name. Feel free to ask me anything!&lt;/p&gt;

</description>
      <category>python</category>
      <category>ai</category>
      <category>development</category>
    </item>
    <item>
      <title>PWA and Django #4: Installing a PWA as a native application</title>
      <dc:creator>Andrés Álvarez Iglesias</dc:creator>
      <pubDate>Tue, 21 Jan 2025 05:38:00 +0000</pubDate>
      <link>https://forem.com/doctorserone/pwa-and-django-4-installing-a-pwa-as-a-native-application-3ljh</link>
      <guid>https://forem.com/doctorserone/pwa-and-django-4-installing-a-pwa-as-a-native-application-3ljh</guid>
      <description>&lt;p&gt;Welcome to the fourth entry on the Progressive Web Application with Django series. In this chapter we will learn how to install our webapp as a native application. Very useful and really easy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcocstmdh1q6dkhl788px.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcocstmdh1q6dkhl788px.png" alt="In this chapter we will learn how to install our webapp as a native application" width="512" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Allowing native installation
&lt;/h2&gt;

&lt;p&gt;With a small change to the source code, we can ask the user if they want to install our supercool webapp as a "native" app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let beforeInstallPromptEvent = null;
let installed = false;

async function installPWA() {
   if (beforeInstallPromptEvent === null || installed) {
       return;
   }

   try {
       beforeInstallPromptEvent.prompt();

       const { outcome } = await beforeInstallPromptEvent.userChoice;
       if (outcome === 'accepted') {
           console.log("App install dialog accepted!");
           beforeInstallPromptEvent = null;
           installed = true;
       }

   } catch(e) {
       console.error(e);
   }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can also listen to a couple of events to customize the responses and behavior of our webapp in every step of the process:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;window.addEventListener('beforeinstallprompt', (e) =&amp;gt; {
   beforeInstallPromptEvent = e;
});

window.addEventListener('appinstalled', () =&amp;gt; {
   installed = true;
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The user needs to fire the event, so an install button is a good place to call the new code:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqpc0m9eqseqpaxugintc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqpc0m9eqseqpaxugintc.png" alt="An install button is a good place to call the new code" width="302" height="390"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When clicked, the user will see a browser dialog asking for the installation like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flmhbj1i8v196575chfz4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flmhbj1i8v196575chfz4.png" alt="The user will see a browser dialog asking for the installation like this" width="470" height="204"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If accepted, the webapp will be registered on the operating system, with its own launcher icon:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnu88i2c30zusksk5x601.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnu88i2c30zusksk5x601.png" alt="The webapp will be registered on the operating system, with its own launcher icon" width="756" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Executing as a standalone app
&lt;/h2&gt;

&lt;p&gt;Once installed, the web app will launch in its own window, providing a more integrated experience with styling based on the manifest (see previous chapters). Like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fojv9jc2y3oggi9ln9u7j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fojv9jc2y3oggi9ln9u7j.png" alt="The web app will launch in its own window, providing a more integrated experience with styling based on the manifest" width="507" height="861"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note that you can customize the icon, the behavior of the webapp, colors, etc. in the PWA manifest. You can read more about this here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/Manifest" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Web/Manifest&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://web.dev/learn/pwa/web-app-manifest" rel="noopener noreferrer"&gt;https://web.dev/learn/pwa/web-app-manifest&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  About the list
&lt;/h2&gt;

&lt;p&gt;Among the Python and Docker posts, I will also write about other related topics, like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Software architecture&lt;/li&gt;
&lt;li&gt;Programming environments&lt;/li&gt;
&lt;li&gt;Linux operating system&lt;/li&gt;
&lt;li&gt;Etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you found some interesting technology, programming language or whatever, please, let me know! I'm always open to learning something new!&lt;/p&gt;

&lt;h2&gt;
  
  
  About the author
&lt;/h2&gt;

&lt;p&gt;I'm Andrés, a full-stack software developer based in Palma, on a personal journey to improve my coding skills. I'm also a self-published fantasy writer with four published novels to my name. Feel free to ask me anything!&lt;/p&gt;

</description>
      <category>python</category>
      <category>django</category>
      <category>pwa</category>
    </item>
    <item>
      <title>PWA and Django #3: Online and offline resources in a PWA - Developing Progressive Web Applications with Django</title>
      <dc:creator>Andrés Álvarez Iglesias</dc:creator>
      <pubDate>Wed, 27 Nov 2024 05:20:44 +0000</pubDate>
      <link>https://forem.com/doctorserone/pwa-and-django-3-online-and-offline-resources-in-a-pwa-developing-progressive-web-applications-38do</link>
      <guid>https://forem.com/doctorserone/pwa-and-django-3-online-and-offline-resources-in-a-pwa-developing-progressive-web-applications-38do</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;NOTE: First published in: &lt;a href="https://andresalvareziglesias.substack.com/p/pwa-and-django-3-online-and-offline" rel="noopener noreferrer"&gt;https://andresalvareziglesias.substack.com/p/pwa-and-django-3-online-and-offline&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Welcome to the third entry on the Progressive Web Application with Django series. In this chapter, we'll learn how to cache resources for our PWA to be able to use them offline, without an active internet connection.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2yp52ynoklk1yoxmxdv2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2yp52ynoklk1yoxmxdv2.png" alt="Online and offline resources in a PWA - Developing Progressive Web Applications with Django" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing Offline Functionality
&lt;/h2&gt;

&lt;p&gt;In the previous chapters we defined an small PWA application with every required part: the manifest and the ServiceWorker. We learned how to register the PWA and developed a very simple interface with some images:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7b39iorcle4gpb31zb7c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7b39iorcle4gpb31zb7c.png" alt="A very simple interface with some images for our demo PWA" width="367" height="302"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we will learn how to store data in the PWA cache and how to choose from where to load every image: from the internet or from the local cache.&lt;/p&gt;

&lt;p&gt;To store one or more resources on the PWA cache we use a function like this on the ServiceWorker:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const CACHE_NAME = "DJANGO_PWA_TEST"
const MAIN_URL = "https://laboratorio.alvarezperello.com/djangopwa/";

self.addEventListener("install", (event) =&amp;gt; {
   console.info("*** PWA event *** install", event);
   event.waitUntil(activateApp());
});

self.addEventListener("activate", (event) =&amp;gt; {
   console.info("*** PWA event *** activate", event);
   event.waitUntil(activateApp());
});

async function activateApp() {
   // When a service worker is initially registered, pages won't use it
   // until they next load. The claim() method causes those pages to be
   // controlled immediately.
   console.log('Claiming control...');
   clients.claim().then((ev) =&amp;gt; {
       console.log('...claimed!', ev);
   })

   manageCache();
}

self.addEventListener("sync", (event) =&amp;gt; {
   console.info("*** PWA event *** sync", event);
   manageCache();
});

async function manageCache() {
   const cache = await caches.open(CACHE_NAME);
   if (!cache) {
       console.error("Error storing resources in cache!");
       return;
   }

   storeResourceInCache(cache, MAIN_URL+"static/demo/img/snake1.jpg");
   //storeResourceInCache(cache, MAIN_URL+"static/demo/img/snake2.png");
   //storeResourceInCache(cache, MAIN_URL+"static/demo/img/snake3.png");
}

async function storeResourceInCache(cache, element) {
   console.log("Storing resource in cache: "+element);
   cache.add(element).then(event =&amp;gt; {
       console.info("Resource stored successfully! "+element);
   }).catch(event =&amp;gt; {
       console.error("Error storing resource! "+element, event);
   });
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, when we execute our PWA, we can read the cache messages in the developer console:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Registering service worker...
...register completed!
The service worker is active!

serviceworker.js: Claiming control...
serviceworker.js: Resource already in cache! static/demo/img/snake1.jpg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our PWA cache is working!&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing from where to load each resource
&lt;/h2&gt;

&lt;p&gt;When the PWA loads a resource, calls the fetch event, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;self.addEventListener("fetch", async (event) =&amp;gt; {
   console.info("*** PWA event *** fetch", event);

   let url = event.request.url.toString();
   console.info("The PWA is loading a resource from: "+url);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are in control of the request now, and can choose from where return the requested resource: from cache or from internet.&lt;/p&gt;

&lt;p&gt;Here is an example of how to check if we have a resource cached and return it from cache. And, if not cached, request it from the Internet instead.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;self.addEventListener("fetch", async (event) =&amp;gt; {
   let url = event.request.url.toString();
   if (!url.includes("static/demo/img/snake")) {
       return false;
   }

   const cache = await caches.open(CACHE_NAME);
   if (!cache) {
       console.error("Error loading resources from cache!");
       return false;
   }

   let fetchResponsePromise = await cache.match(url).then(async (cachedResponse) =&amp;gt; {
       if (cachedResponse &amp;amp;&amp;amp; cachedResponse.ok) {
           console.warn("Loading from cache: "+url);
           return cachedResponse;

       } else {
           console.error("Error! the cache does not have this url! "+url);
           console.error(cache.keys());

           remoteFetchResponsePromise = await fetch(event).then(async (networkResponse) =&amp;gt; {
               console.warn("Loading from internet: "+url);
               return networkResponse;
           });

           return remoteFetchResponsePromise;
       }
   });

   return (await fetchResponsePromise);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can read the developer console to know from where every image has been loaded, like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1md1kx90kesed15hb0ha.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1md1kx90kesed15hb0ha.png" alt="From where our PWA loads every image: cache or internet" width="708" height="71"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  In the next chapter
&lt;/h2&gt;

&lt;p&gt;We now have a PWA. Now we will learn how to make an installable PWA, that will show as a native application in the operating system. That's one of the greatest functionalities of the PWAs: we can use them to create "almost native" applications using Django.&lt;/p&gt;

&lt;p&gt;See you in the next chapter!&lt;/p&gt;

&lt;h2&gt;
  
  
  About the list
&lt;/h2&gt;

&lt;p&gt;Among the Python and Docker posts, I will also write about other related topics, like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Software architecture&lt;/li&gt;
&lt;li&gt;Programming environments&lt;/li&gt;
&lt;li&gt;Linux operating system&lt;/li&gt;
&lt;li&gt;Etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you found some interesting technology, programming language or whatever, please, let me know! I'm always open to learning something new!&lt;/p&gt;

&lt;h2&gt;
  
  
  About the author
&lt;/h2&gt;

&lt;p&gt;I'm Andrés, a full-stack software developer based in Palma, on a personal journey to improve my coding skills. I'm also a self-published fantasy writer with four published novels to my name. Feel free to ask me anything!&lt;/p&gt;

</description>
      <category>django</category>
      <category>python</category>
      <category>pwa</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Performance of Python with and without GIL</title>
      <dc:creator>Andrés Álvarez Iglesias</dc:creator>
      <pubDate>Wed, 23 Oct 2024 04:06:39 +0000</pubDate>
      <link>https://forem.com/doctorserone/performance-of-python-with-and-without-gil-4kaa</link>
      <guid>https://forem.com/doctorserone/performance-of-python-with-and-without-gil-4kaa</guid>
      <description>&lt;p&gt;Since Python 3.13, the famous Python GIL is optional. This is a long requested functionality but, is the performance gain of threaded code real? &lt;/p&gt;

&lt;p&gt;Let's test the performance of a threaded application with and without the GIL.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9nsxu1juf4y8pzyozr6u.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9nsxu1juf4y8pzyozr6u.jpeg" alt="Performance of Python with and without GIL" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is GIL?
&lt;/h2&gt;

&lt;p&gt;GIL stands for Global Interpreter Lock, and is a mechanism only present in the standard Python implementation (CPython) that ensures the coherence and safety of Python internal and runtime objects. The GIL makes sure that only a single thread is executed at the same time, losing the benefits of a multicore environment.&lt;/p&gt;

&lt;p&gt;The new versions make this security mechanism entirely optional, opening  whole word of possible optimizations in multicore environments.&lt;/p&gt;

&lt;p&gt;NOTE: this functionality is not yet available in the official releases of Python 3.14, but it will in the future.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing Python 3.14
&lt;/h2&gt;

&lt;p&gt;Use these commands to install Python 3.14 in Ubuntu:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;add-apt-repository ppa:deadsnakes/ppa
apt install python3.14-full python3.14-nogil
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the installation, we can test the installation with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3.14 --version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great, now we have a working Python 3.14 installation. Now, we can create a virtual environment with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3.14 -m venv ~/venv314
source ~/venv314/bin/activate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we are ready to execute our tests!&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing the same code with and without GIL
&lt;/h2&gt;

&lt;p&gt;We have coded this application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import time
import threading
import math

def test_function(num_thread):
    thread_start_time = time.time()
    print(F"Executing thread #{num_thread}...")
    math.factorial(250000)
    thread_execution_time = time.time() - thread_start_time
    print(F"...thread #{num_thread} finalized in {thread_execution_time} seconds")

print("Initializing thread test...")
start_time = time.time()

# Create multiple threads
threads = []
for num_thread in range(5):
    thread = threading.Thread(target=test_function, args=(num_thread,))
    thread.start()
    threads.append(thread)

# Wait for all threads to finish
for thread in threads:
    thread.join()

execution_time = time.time() - start_time
print(f"Finalized! Execution time: {execution_time} seconds")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Is a really simple application that spawns some threads and performs a CPU intensive task in each thread (a factorial). Now, we can execute the test code in each version, with and without GIL:&lt;/p&gt;

&lt;p&gt;With GIL enabled:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PYTHON_GIL=1 python3.14-nogil test.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Initializing thread test...

    Executing thread #0...
    Executing thread #1...
    Executing thread #2...
    ...thread #0 finalized in 1.6720194816589355 seconds
    ...thread #1 finalized in 1.6916308403015137 seconds
    Executing thread #3...
    ...thread #2 finalized in 1.8445136547088623 seconds
    Executing thread #4...
    ...thread #3 finalized in 0.9945917129516602 seconds
    ...thread #4 finalized in 1.0793228149414062 seconds

Finalized! Execution time: 4.599931955337524 seconds
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And without GIL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PYTHON_GIL=0 python3.14-nogil test.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Initializing thread test...

    Executing thread #0...
    Executing thread #1...
    Executing thread #2...
    Executing thread #3...
    Executing thread #4...
    ...thread #0 finalized in 0.8833539485931396 seconds
    ...thread #2 finalized in 0.8942356109619141 seconds
    ...thread #3 finalized in 0.934593677520752 seconds
    ...thread #4 finalized in 1.2945129871368408 seconds
    ...thread #1 finalized in 1.2981431484222412 seconds

Finalized! Execution time: 1.3003475666046143 seconds
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wow! The performance gain is notable!&lt;/p&gt;

&lt;h2&gt;
  
  
  A brilliant future
&lt;/h2&gt;

&lt;p&gt;The possibility of running Python code without GIL with the default Python interpreter opens a lot of optimization opportunities to the Python ecosystem. We can expect an improved Django, a faster FastAPI, more optimized ASGI or WSGI servers...&lt;/p&gt;

&lt;p&gt;Let's wait for this future together!&lt;/p&gt;

&lt;h2&gt;
  
  
  About the list
&lt;/h2&gt;

&lt;p&gt;Among the Python and Docker posts, I will also write about other related topics, like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Software architecture&lt;/li&gt;
&lt;li&gt;Programming environments&lt;/li&gt;
&lt;li&gt;Linux operating system&lt;/li&gt;
&lt;li&gt;Etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you found some interesting technology, programming language or whatever, please, let me know! I'm always open to learning something new!&lt;/p&gt;

&lt;h2&gt;
  
  
  About the author
&lt;/h2&gt;

&lt;p&gt;I'm Andrés, a full-stack software developer based in Palma, on a personal journey to improve my coding skills. I'm also a self-published fantasy writer with four published novels to my name. Feel free to ask me anything!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>PWA and Django #2: Components of a Progressive Web Application</title>
      <dc:creator>Andrés Álvarez Iglesias</dc:creator>
      <pubDate>Tue, 24 Sep 2024 04:44:10 +0000</pubDate>
      <link>https://forem.com/doctorserone/pwa-and-django-2-components-of-a-progressive-web-application-1b3k</link>
      <guid>https://forem.com/doctorserone/pwa-and-django-2-components-of-a-progressive-web-application-1b3k</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;NOTE: First published on Substack: &lt;a href="https://substack.com/@andresalvareziglesias" rel="noopener noreferrer"&gt;https://substack.com/@andresalvareziglesias&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Welcome to the second entry on the Progressive Web Application with Django series. In this chapter we will learn the basic structure of a PWA and how to implement it in Django. Let’s go!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frymlkg1h9qxex62hqhia.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frymlkg1h9qxex62hqhia.png" alt="PWA and Django #2: Components of a Progressive Web Application" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Components of a PWA
&lt;/h2&gt;

&lt;p&gt;A PWA is composed of two main elements, the Service Worker and the manifest.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The Service Worker: is the script that handles the logic of the PWA. It manages all the events of the PWA lifecycle, and the offline behavior.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The manifest: in the manifest resides the PWA description for the browser, like the name, colors and icons. This is used to show installation dialogs to the user, and to register the PWA in the browser registry,&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Scopes inside a PWA
&lt;/h2&gt;

&lt;p&gt;One of the settings configured in the manifest is the PWA scope. That is: what resources are available (and controllable) by this PWA.&lt;/p&gt;

&lt;p&gt;For example, if we register a PWA with the scope &lt;code&gt;/my/great/pwa/&lt;/code&gt;, then:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We will be able to add to the offline cache an image like &lt;code&gt;/my/great/pwa/images/one.png&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;…but not one like &lt;code&gt;/non/pwa/images/two.png&lt;/code&gt;, because is outside the configured scope.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Choosing the right scope is important because affects a lot of aspects of our PWA, like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Offline Functionality: By limiting the scope, you can ensure that only the necessary resources for your PWA are cached, optimizing offline performance.&lt;/li&gt;
&lt;li&gt;Security: A well-defined scope helps prevent unauthorized access to sensitive data or resources.&lt;/li&gt;
&lt;li&gt;Performance: A smaller scope can lead to faster load times, as the service worker doesn’t need to cache unnecessary files.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can also use some HTTP headers to control the scope at server level, like the Header Set Service-Worker-allowed "/" header, but we will discuss them in the next chapters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing the PWA in Django
&lt;/h2&gt;

&lt;p&gt;The basic implementation of a PWA does not require Django at all, because all the files are static javascript code and a JSON manifest. In the next chapters, we will use Django to add more power to our PWA, but le’ts start from the beginning.&lt;/p&gt;

&lt;p&gt;The manifest file is a JSON file with the descriptor of the app and the reference to the icons and colors. There are a lot of web apps to help us with the creation of the icons, like “Manifest icons generator” (&lt;a href="https://www.pwabuilder.com/imageGenerator" rel="noopener noreferrer"&gt;https://www.pwabuilder.com/imageGenerator&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;A basic manifest file is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
   "name": "PWA with Django",
   "short_name": "PWA with Django",

   "display": "standalone",
   "background_color": "#ffffff",
   "theme_color": "#1b5e20",
   "orientation": "any",

   "start_url": "/",
   "scope": "/",

   "icons": [{
       "src": "/static/demo/img/icons/icon-48x48.png",
       "sizes": "48x48",
       "type": "image/png"
   }, {
       "src": "/static/demo/img/icons/icon-72x72.png",
       "sizes": "72x72",
       "type": "image/png"
   }, {
       "src": "/static/demo/img/icons/icon-96x96.png",
       "sizes": "96x96",
       "type": "image/png"
   }, {
       "src": "/static/demo/img/icons/icon-144x144.png",
       "sizes": "144x144",
       "type": "image/png"
   }, {
       "src": "/static/demo/img/icons/icon-192x192.png",
       "sizes": "192x192",
       "type": "image/png"
   }, {
       "src": "/static/demo/img/icons/icon-512x512.png",
       "sizes": "512x512",
       "type": "image/png"
   }]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the manifest, we need to code the ServiceWorker, a javascript file responsible to handle the events of the PWA. The most basic events are “install” (when the user installs the PWA) and “activate” (when the PWA is loaded and executed).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;self.addEventListener("install", (event) =&amp;gt; {
   console.info("install", event);
});

self.addEventListener("activate", (event) =&amp;gt; {
   console.info("activate", event);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the man elements of the PWA are created (the manifest and the Service Worker), we need to instantiate then from the main view:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;document.addEventListener('DOMContentLoaded', function() {
   initializeServiceWorker();
});

function resetLog() {
   document.getElementById("log").innerHTML = "";
}

function log(message) {
   console.log(message);
   document.getElementById("log").innerHTML += "&amp;lt;p&amp;gt;"+message+"&amp;lt;/p&amp;gt;";
}

function error(message) {
   console.error(message);
   document.getElementById("log").innerHTML += "&amp;lt;p style='color: red;'&amp;gt;"+message+"&amp;lt;/p&amp;gt;";
}

function initializeServiceWorker() {
   try {
       resetLog();

       log("Registering service worker...");
       navigator.serviceWorker.register('/serviceworker.js', {
           scope: '/',
           type: 'classic',
           updateViaCache: 'all'

       }).then(function(registration) {
           log("...register completed!");

           if (registration.installing) {
               error("The service worker is installing, reloading...");
               document.location.reload();
               return;

           } else if (registration.waiting) {
               const sw = registration.waiting;
               error("The service worker is waiting, reloading...");
               document.location.reload();
               return;

           } else if (registration.active) {
               log("The service worker is active!");

               if(!navigator.serviceWorker.controller){
                   error("Webpage controller is still none, reloading...");
                   document.location.reload();
               }
           }
       });

   } catch (e) {
       error(e.message);
   }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The scripts try to register the PWA when the view is loaded. If you have followed all the steps, the screen will show something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyn8k7q6ryqd5xky417dw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyn8k7q6ryqd5xky417dw.png" alt="Service worker loaded screen" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can use Chrome Web Developer tools to check if the PWA has been registered successfully. Open the Developers Tools and click on the “Application” tab. Then, select “Service Workers” or “Manifest” in the left sidebar to display our shiny PWA:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhywjmgpqarl1zjttzyfn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhywjmgpqarl1zjttzyfn.png" alt="Chrome service worker inspection" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Great, isn’t it?&lt;/p&gt;

&lt;h2&gt;
  
  
  In the next chapter
&lt;/h2&gt;

&lt;p&gt;We now have a PWA. Now we will learn how to make an installable PWA, that will show as a native application in the operating system. That’s one of the greatest functionalities of the PWAs: we can use them to create “almost native” applications using Django.&lt;/p&gt;

&lt;p&gt;See you in the next chapter!&lt;/p&gt;

&lt;h2&gt;
  
  
  About the list
&lt;/h2&gt;

&lt;p&gt;Among the Python and Docker posts, I will also write about other related topics, like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Software architecture&lt;/li&gt;
&lt;li&gt;Programming environments&lt;/li&gt;
&lt;li&gt;Linux operating system&lt;/li&gt;
&lt;li&gt;Etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you found some interesting technology, programming language or whatever, please, let me know! I’m always open to learning something new!&lt;/p&gt;

&lt;h2&gt;
  
  
  About the author
&lt;/h2&gt;

&lt;p&gt;I’m Andrés, a full-stack software developer based in Palma, on a personal journey to improve my coding skills. I’m also a self-published fantasy writer with four published novels to my name. Feel free to ask me anything!&lt;/p&gt;

</description>
      <category>django</category>
      <category>python</category>
      <category>pwa</category>
      <category>webdev</category>
    </item>
    <item>
      <title>PWA and Django #1: What is a Progressive Web Application?</title>
      <dc:creator>Andrés Álvarez Iglesias</dc:creator>
      <pubDate>Tue, 10 Sep 2024 04:45:43 +0000</pubDate>
      <link>https://forem.com/doctorserone/pwa-and-django-1-what-is-a-progressive-web-application-1k3c</link>
      <guid>https://forem.com/doctorserone/pwa-and-django-1-what-is-a-progressive-web-application-1k3c</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Originally published on Substack:&lt;/strong&gt; &lt;a href="https://andresalvareziglesias.substack.com/p/pwa-and-django-1-what-is-a-web-application?r=1ymfiv" rel="noopener noreferrer"&gt;https://andresalvareziglesias.substack.com/p/pwa-and-django-1-what-is-a-web-application?r=1ymfiv&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The current web applications are much more than web pages that show interactive info. Sometimes, they behave almost like native apps. And what kind of magic do they use to do that? This series of posts will answer that question...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2pyq4xm53qov45njwws7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2pyq4xm53qov45njwws7.png" alt="PWA and Django #1: What is a Progressive Web Application?" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a Progressive Web Application
&lt;/h2&gt;

&lt;p&gt;I like the definition of PWA's at Mozilla Developer site (&lt;a href="https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps):" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps):&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A progressive web app (PWA) is an app that's built using web platform technologies, but that provides a user experience like that of a platform-specific app. Like a website, a PWA can run on multiple platforms and devices from a single codebase. Like a platform-specific app, it can be installed on the device, can operate while offline and in the background, and can integrate with the device and with other installed apps.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It's an hybrid between a native app and a webpage, thanks to the incredible capacities of the nowadays web browsers, like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Embedded database&lt;/li&gt;
&lt;li&gt;Offline workers&lt;/li&gt;
&lt;li&gt;Desktop and mobile operating system integration&lt;/li&gt;
&lt;li&gt;Etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this series of posts, we will develop an offline and installable Progressive Web Application using our beloved Django, with the help of Google Project IDX.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create the demo environment
&lt;/h2&gt;

&lt;p&gt;Create a github repo:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F80vptwskwosx5rfcrv0p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F80vptwskwosx5rfcrv0p.png" alt="Create a github repo" width="533" height="307"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Create a new app in IDX importing that repo:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ztdddx1zkbf631l4jo8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ztdddx1zkbf631l4jo8.png" alt="Create a new app in IDX importing a github repo" width="402" height="228"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Initialize the Django app from the IDX console:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python -m venv ~/.venv
source ~/.venv/bin/activate

mkdir src
cd src

echo "django" &amp;gt; requirements.txt
pip install --upgrade pip
pip install -r requirements.txt

django-admin startproject djangopwa
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do the initial migration and run the server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python manage.py migrate
python manage.py runserver
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create IDX files to enable embedded preview, with the help of the project &lt;a href="https://github.com/arifnd/nix-idx/" rel="noopener noreferrer"&gt;https://github.com/arifnd/nix-idx/&lt;/a&gt;, that compiles several IDX configurations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd ~/djangopwa 
wget https://raw.githubusercontent.com/arifnd/nix-idx/main/python/django/devserver.sh
cd ~/djangopwa/.idx
wget https://raw.githubusercontent.com/arifnd/nix-idx/main/python/django/dev.nix
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NOTE: Edit the default dev.nix and devserver.sh as needed and restart IDX environment&lt;/p&gt;

&lt;p&gt;Then, create demo app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python manage.py startapp demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add an empty view:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.shortcuts import render

def index(request):
    context = {}
    return render(request, "index.html", context)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create the routes to the new app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.contrib import admin
from django.urls import include, path

urlpatterns = [
    path("", include("demo.urls")),
    path('admin/', admin.site.urls),
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And wait a few days until the next chapter!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2f5bgh35f97jjbh3ngf4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2f5bgh35f97jjbh3ngf4.png" alt="Image description" width="393" height="492"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  About the list
&lt;/h2&gt;

&lt;p&gt;Among the Python and Docker posts, I will also write about other related topics, like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Software architecture&lt;/li&gt;
&lt;li&gt;Programming environments&lt;/li&gt;
&lt;li&gt;Linux operating system&lt;/li&gt;
&lt;li&gt;Etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you found some interesting technology, programming language or whatever, please, let me know! I'm always open to learning something new!&lt;/p&gt;

&lt;h2&gt;
  
  
  About the author
&lt;/h2&gt;

&lt;p&gt;I'm Andrés, a full-stack software developer based in Palma, on a personal journey to improve my coding skills. I'm also a self-published fantasy writer with four published novels to my name. Feel free to ask me anything!&lt;/p&gt;

</description>
      <category>python</category>
      <category>django</category>
      <category>pwa</category>
    </item>
    <item>
      <title>Speeding up Python code with C (and no extra libraries)</title>
      <dc:creator>Andrés Álvarez Iglesias</dc:creator>
      <pubDate>Wed, 21 Aug 2024 04:37:31 +0000</pubDate>
      <link>https://forem.com/doctorserone/speeding-up-python-code-with-c-and-no-extra-libraries-1k82</link>
      <guid>https://forem.com/doctorserone/speeding-up-python-code-with-c-and-no-extra-libraries-1k82</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; Originally posted in my Substack: &lt;a href="https://open.substack.com/pub/andresalvareziglesias/p/speeding-up-python-code-with-c-and" rel="noopener noreferrer"&gt;https://open.substack.com/pub/andresalvareziglesias/p/speeding-up-python-code-with-c-and&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Python is not the paradigm of speed, we all know this. But we can speed up some critical parts of our apps with the help of our good old friend C.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9u2ginheq22ezvffncph.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9u2ginheq22ezvffncph.jpeg" alt="Speeding up Python code with C (and no extra libraries)" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Fibonacci sequence in plain Python
&lt;/h2&gt;

&lt;p&gt;The Fibonacci sequence is a classic example used to teach software development. Is a series of numbers that starts with 0 and 1. Each subsequent number is the sum of the previous two. So, the sequence goes like this: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ...&lt;/p&gt;

&lt;p&gt;We can develop Fibonacci in python in this way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import time

# Configure iterations
iterations = 30

# Define fibonacci in native python
def fibonacci(n):
  if n &amp;lt;= 1:
    return n
  else:
    return fibonacci(n-1) + fibonacci(n-2)

# Calculate in pure python
start_time = time.perf_counter()
print(f"Calculating {iterations} iterations of fibonacci...")
print(fibonacci(iterations))
end_time = time.perf_counter()
execution_time_ms = (end_time - start_time) * 1000
print(f"Execution time: {execution_time_ms:.2f} milliseconds")
print()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we execute this pure Python (in a Google IDX virtual machine) version of Fibonacci we get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;10 iterations: 5.77 milliseconds&lt;/li&gt;
&lt;li&gt;30 iterations: 984.36 milliseconds&lt;/li&gt;
&lt;li&gt;50 iterations: (I have to cancel the process, too much time)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Fibonacci sequence in C
&lt;/h2&gt;

&lt;p&gt;We can develop the same sequence in plain C:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;

int fibonacci(int n) {
    if (n &amp;lt;= 1) {
        return n;
    } else {
        return fibonacci(n - 1) + fibonacci(n - 2);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compile the library with GCC:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gcc -o fibonacci.so -shared -fPIC -O2 fibonacci.c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we have a native binary library with the fibonacci sequence function inside. We can embed this library inside a Python app with ctypes (the Python C types library, because Python itself is developed in C):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import time
from ctypes import c_double, c_int, CDLL

# Configure iterations
iterations = 30

# Import the C library
library = CDLL('./fibonacci.so')
fibonacciAsLibrary = library.fibonacci
fibonacciAsLibrary.restype = c_int

# Calculate as C library
start_time = time.perf_counter()
print(f"Calculating {iterations} iterations of fibonacci as C library...")
print(fibonacciAsLibrary(iterations))
end_time = time.perf_counter()
execution_time_ms = (end_time - start_time) * 1000
print(f"Execution time: {execution_time_ms:.2f} milliseconds")
print()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, if we execute this version on Fibonacci, we get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;10 iterations: 0.54 milliseconds&lt;/li&gt;
&lt;li&gt;30 iterations: 6.92 millisecond&lt;/li&gt;
&lt;li&gt;50 iterations: 82324.90 milliseconds&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Better, isn’t?&lt;/p&gt;

&lt;h2&gt;
  
  
  Use cases for Python and C integration
&lt;/h2&gt;

&lt;p&gt;We can use this kind of integration in a lot of apps and scenarios, like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Speed up serializers and deserializers in our Django app&lt;/li&gt;
&lt;li&gt;Speed up critical parts on a workflow&lt;/li&gt;
&lt;li&gt;Low level interactions with the OS&lt;/li&gt;
&lt;li&gt;Etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And you? How will you use this litle trick in your project? I woult love to hear your comments!&lt;/p&gt;

&lt;h2&gt;
  
  
  About the list
&lt;/h2&gt;

&lt;p&gt;Among the Python and Docker posts, I will also write about other related topics (always tech and programming topics, I promise... with the fingers crossed), like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Software architecture&lt;/li&gt;
&lt;li&gt;Programming environments&lt;/li&gt;
&lt;li&gt;Linux operating system&lt;/li&gt;
&lt;li&gt;Etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you found some interesting technology, programming language or whatever, please, let me know! I'm always open to learning something new!&lt;/p&gt;

&lt;h2&gt;
  
  
  About the author
&lt;/h2&gt;

&lt;p&gt;I'm Andrés, a full-stack software developer based in Palma, on a personal journey to improve my coding skills. I'm also a self-published fantasy writer with four published novels to my name. Feel free to ask me anything!&lt;/p&gt;

</description>
      <category>python</category>
      <category>c</category>
      <category>programming</category>
    </item>
    <item>
      <title>Django AllAuth Chapter 5 - Extending Django AllAuth user model with custom fields</title>
      <dc:creator>Andrés Álvarez Iglesias</dc:creator>
      <pubDate>Tue, 13 Aug 2024 04:45:51 +0000</pubDate>
      <link>https://forem.com/doctorserone/django-allauth-chapter-5-extending-django-allauth-user-model-with-custom-fields-55ia</link>
      <guid>https://forem.com/doctorserone/django-allauth-chapter-5-extending-django-allauth-user-model-with-custom-fields-55ia</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;NOTE: This article was initially posted on my Substack, at &lt;a href="https://andresalvareziglesias.substack.com/" rel="noopener noreferrer"&gt;https://andresalvareziglesias.substack.com/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is the last chapter of this Django AllAuth series of posts. In these five chapters we have discovered a little piece of wonder, a really helpful Django component to handle all our authentication needs. In this chapter we are going to learn how to extend the basic Django user model to add custom fields.&lt;/p&gt;

&lt;h2&gt;
  
  
  List of chapters
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Chapter 1 - The All-in-one solution for Auth in Django &lt;/li&gt;
&lt;li&gt;Chapter 2 - How to install and configure Django AllAuth&lt;/li&gt;
&lt;li&gt;Chapter 3 - Social login with Django AllAuth&lt;/li&gt;
&lt;li&gt;Chapter 4 - Customizing Django AllAuth UI&lt;/li&gt;
&lt;li&gt;Chapter 5 - Extending Django AllAuth user model with custom fields ←This one!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fszrrweornqs03w19rswh.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fszrrweornqs03w19rswh.jpeg" alt="Django AllAuth Chapter 5 - Extending Django AllAuth user model with custom fields" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Django user model
&lt;/h2&gt;

&lt;p&gt;AllAuth uses the standard Django user model, plus some extra tables to handle social login and login tokens. In Django 5, the user model is located in the django.contrib.auth package, and has a bunch of predefined fields, as you can read in the official doc:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.djangoproject.com/en/5.0/ref/contrib/auth/" rel="noopener noreferrer"&gt;https://docs.djangoproject.com/en/5.0/ref/contrib/auth/&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sometimes, this is not enough for our project. Django allows you to create custom User tables and User managers, to handle the needs of every project.&lt;/p&gt;

&lt;p&gt;We are going to create a custom User table and a custom UserManager to handle our login and register processes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a custom User table
&lt;/h2&gt;

&lt;p&gt;Open models.py in our sample project an write a code like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class MyCustomUser(AbstractBaseUser):
   email = models.EmailField(unique=True)
   first_name = models.CharField(max_length=30, blank=True)
   last_name = models.CharField(max_length=30, blank=True)
   is_active = models.BooleanField(default=True)
   is_admin = models.BooleanField(default=False)
   timezone = models.CharField(max_length=30, default='UTC')
   is_custom = models.BooleanField(default=False)
   is_staff = models.BooleanField(default=False)
   created_at = models.DateTimeField(auto_now_add=True)
   updated_at = models.DateTimeField(auto_now=True)

   objects = MyCustomUserManager()
   USERNAME_FIELD = 'email'
   EMAIL_FIELD = 'email'

   def __str__(self):
       return self.email
   def has_perm(self, perm, obj=None):
       return True
   def has_module_perms(self, app_label):
       return True

   @property
   def is_utc(self):
       return self.timezone == 'UTC'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can define a new User model extending from Django's AbstractBaseUser model. In this new model we can add all fields or custom properties that we need.&lt;/p&gt;

&lt;p&gt;These lines are important:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   objects = MyCustomUserManager()
   USERNAME_FIELD = 'email'
   EMAIL_FIELD = 'email'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With these lines we are linking the user model with our custom UserManager, and we are also defining the field acting as a unique "username".&lt;/p&gt;

&lt;p&gt;Remember to register the new model in admin.py to manage it from the Django admin tool.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.contrib import admin
from .models import MyCustomUser

admin.site.register(MyCustomUser)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Creating a custom User manager
&lt;/h2&gt;

&lt;p&gt;Open again models.py in our sample project (or generate another file for the custom UserManager if you want) an write a code like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class MyCustomUserManager(BaseUserManager):

   def create_user(self, email, password=None):
       if not email:
           raise ValueError('Users must have an email address')

       user = self.model(
           email=self.normalize_email(email),
       )

       user.set_password(password)

       user.save(using=self._db)
       return user

   def create_superuser(self, email, password):
       user = self.create_user(
           email=email,
           password=password,
       )

       user.is_admin = True
       user.is_staff = True

       user.save(using=self._db)
       return user
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example we are extending BaseUserManager to create our custom UserManager. It creates our new users, and fills the custom fields as we expect.&lt;/p&gt;

&lt;p&gt;We defined before the UserManager for our custom User model, so Django knows what class to use during new user creation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using the custom User manager and model
&lt;/h2&gt;

&lt;p&gt;In the settings file of our project we can set the current user model for our project with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Set custom user model as the active one
AUTH_USER_MODEL = 'demo.MyCustomUser'

# Configure AllAuth username related management, because we are 
# using the e-mail as username. See:
# https://docs.allauth.org/en/latest/account/advanced.html
ACCOUNT_AUTHENTICATION_METHOD = 'email'
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_UNIQUE_EMAIL = True
ACCOUNT_USERNAME_REQUIRED = False
ACCOUNT_USER_MODEL_USERNAME_FIELD = None
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With just this small change (and the required DB migration, as usual), we can start to create users with AllAuth signup views to see our shiny custom UserManager and its model in action. Quick and easy.&lt;/p&gt;

&lt;p&gt;We are also disabling the AllAuth username related management, because we are using the e-mail as username in this example.&lt;/p&gt;

&lt;h2&gt;
  
  
  And that's the end... or not?
&lt;/h2&gt;

&lt;p&gt;We have reached the last chapter on this AllAuth series. AllAuth is a wonderful library to handle the authentication in our apps, and makes it especially easy to work with social logins, thanks to its large list of predefined integrations.&lt;/p&gt;

&lt;p&gt;This is the last chapter of the series, but I will revisit AllAuth in future posts. Thanks for reading and happy coding!&lt;/p&gt;

&lt;h2&gt;
  
  
  About the list
&lt;/h2&gt;

&lt;p&gt;Among the Python and Docker posts, I will also write about other related topics (always tech and programming topics, I promise... with the fingers crossed), like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Software architecture&lt;/li&gt;
&lt;li&gt;Programming environments&lt;/li&gt;
&lt;li&gt;Linux operating system&lt;/li&gt;
&lt;li&gt;Etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you found some interesting technology, programming language or whatever, please, let me know! I'm always open to learning something new!&lt;/p&gt;

&lt;h2&gt;
  
  
  About the author
&lt;/h2&gt;

&lt;p&gt;I'm Andrés, a full-stack software developer based in Palma, on a personal journey to improve my coding skills. I'm also a self-published fantasy writer with four published novels to my name. Feel free to ask me anything!&lt;/p&gt;

</description>
      <category>django</category>
      <category>python</category>
      <category>allauth</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Django AllAuth Chapter 4 - Customizing Django AllAuth UI</title>
      <dc:creator>Andrés Álvarez Iglesias</dc:creator>
      <pubDate>Tue, 30 Jul 2024 05:25:16 +0000</pubDate>
      <link>https://forem.com/doctorserone/django-allauth-chapter-4-customizing-django-allauth-ui-47nh</link>
      <guid>https://forem.com/doctorserone/django-allauth-chapter-4-customizing-django-allauth-ui-47nh</guid>
      <description>&lt;p&gt;In the previous chapters we have implemented a basic login and a social login with the help of AllAuth, using the default (and ugly) user interface. Now is the time of adding a touch of color to our little app.&lt;/p&gt;

&lt;h2&gt;
  
  
  List of chapters
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Chapter 1 - The All-in-one solution for Auth in Django &lt;/li&gt;
&lt;li&gt;Chapter 2 - How to install and configure Django AllAuth&lt;/li&gt;
&lt;li&gt;Chapter 3 - Social login with Django AllAuth&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chapter 4 - Customizing Django AllAuth UI&lt;/strong&gt; ←This one!&lt;/li&gt;
&lt;li&gt;Chapter 5 - Extending Django AllAuth user model with custom fields&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxs0144wprbtywjjc97z8.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxs0144wprbtywjjc97z8.jpeg" alt="Painting a login form" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Templates in AllAuth
&lt;/h2&gt;

&lt;p&gt;All default views in AllAuth are intentionally plain and unstyled. They are prepared to be customized on every app. In the AllAuth GIT page (&lt;a href="https://github.com/pennersr/django-allauth" rel="noopener noreferrer"&gt;https://github.com/pennersr/django-allauth&lt;/a&gt;) we can obtain a full list of the used templates.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe8bh6xz487bfbcnamqnz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe8bh6xz487bfbcnamqnz.png" alt="Templates in GIT" width="800" height="581"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are four groups:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Basic authentication templates: login, logout, registering, password recovery, etc&lt;/li&gt;
&lt;li&gt;Social authentication templates: social login workflow&lt;/li&gt;
&lt;li&gt;Account management: user profile, user actions, etc&lt;/li&gt;
&lt;li&gt;Other: mail templates, common snippets, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To start with our customization, we will download the GIT repo and copy some AllAuth templates to our template directory:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Allauth&lt;/li&gt;
&lt;li&gt;account&lt;/li&gt;
&lt;li&gt;socialaccount&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can copy all of them if you want to play a bit more, of course :)&lt;/p&gt;

&lt;h2&gt;
  
  
  Customizing base layout
&lt;/h2&gt;

&lt;p&gt;The file "allauth/layouts/base.html" contains the basic layout of all AllAuth pages, so we will start customizing it, using the fantastic MaterializeCSS library (&lt;a href="https://materializeweb.com/getting-started.html" rel="noopener noreferrer"&gt;https://materializeweb.com/getting-started.html&lt;/a&gt;). Simply, add the MaterializeCSS required inclusions, a topbar and a container card. Add other card for the messages and move the menu to the navbar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{% load i18n %}
&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;

&amp;lt;head&amp;gt;
   &amp;lt;meta http-equiv="X-UA-Compatible" content="IE=edge"&amp;gt;
   &amp;lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&amp;gt;

   &amp;lt;title&amp;gt;
       {% block head_title %}
       {% endblock head_title %}
   &amp;lt;/title&amp;gt;

   &amp;lt;!-- Compiled and minified CSS --&amp;gt;

   &amp;lt;link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@materializecss/materialize@2.1.0/dist/css/materialize.min.css"&amp;gt;

   {% block extra_head %}
   {% endblock extra_head %}
&amp;lt;/head&amp;gt;

&amp;lt;body&amp;gt;

   &amp;lt;header&amp;gt;
       &amp;lt;nav&amp;gt;
           &amp;lt;div class="nav-wrapper indigo darken-4 white-text"&amp;gt;

               &amp;lt;a href="#" class="brand-logo"&amp;gt;AllAuth test&amp;lt;/a&amp;gt;

               &amp;lt;ul id="nav-mobile" class="right hide-on-med-and-down"&amp;gt;
               {% if user.is_authenticated %}
                   {% url 'account_email' as email_url %}
                   {% if email_url %}
                       &amp;lt;li&amp;gt;
                           &amp;lt;a href="{{ email_url }}"&amp;gt;{% trans "Change Email" %}&amp;lt;/a&amp;gt;
                       &amp;lt;/li&amp;gt;
                   {% endif %}
                   {% url 'account_change_password' as change_password_url %}
                   {% if change_password_url %}
                       &amp;lt;li&amp;gt;
                           &amp;lt;a href="{{ change_password_url }}"&amp;gt;{% trans "Change Password" %}&amp;lt;/a&amp;gt;
                       &amp;lt;/li&amp;gt;
                   {% endif %}
                   {% url 'mfa_index' as mfa_url %}
                   {% if mfa_url %}
                       &amp;lt;li&amp;gt;
                           &amp;lt;a href="{{ mfa_url }}"&amp;gt;{% trans "Two-Factor Authentication" %}&amp;lt;/a&amp;gt;
                       &amp;lt;/li&amp;gt;
                   {% endif %}
                   {% url 'usersessions_list' as usersessions_list_url %}
                   {% if usersessions_list_url %}
                       &amp;lt;li&amp;gt;
                           &amp;lt;a href="{{ usersessions_list_url }}"&amp;gt;{% trans "Sessions" %}&amp;lt;/a&amp;gt;
                       &amp;lt;/li&amp;gt;
                   {% endif %}
                   {% url 'account_logout' as logout_url %}
                   {% if logout_url %}
                       &amp;lt;li&amp;gt;
                           &amp;lt;a href="{{ logout_url }}"&amp;gt;{% trans "Sign Out" %}&amp;lt;/a&amp;gt;
                       &amp;lt;/li&amp;gt;
                   {% endif %}
               {% else %}
                   {% url 'account_login' as login_url %}
                   {% if login_url %}
                       &amp;lt;li&amp;gt;
                           &amp;lt;a href="{{ login_url }}"&amp;gt;{% trans "Sign In" %}&amp;lt;/a&amp;gt;
                       &amp;lt;/li&amp;gt;
                   {% endif %}
                   {% url 'account_signup' as signup_url %}
                   {% if signup_url %}
                       &amp;lt;li&amp;gt;
                           &amp;lt;a href="{{ signup_url }}"&amp;gt;{% trans "Sign Up" %}&amp;lt;/a&amp;gt;
                       &amp;lt;/li&amp;gt;
                   {% endif %}
               {% endif %}

               &amp;lt;/ul&amp;gt;
           &amp;lt;/div&amp;gt;
       &amp;lt;/nav&amp;gt;
   &amp;lt;/header&amp;gt;

   &amp;lt;main&amp;gt;
       &amp;lt;div class="container"&amp;gt;

       {% block body %}

           {% if messages %}
               &amp;lt;div class="row"&amp;gt;&amp;lt;div class="col s12"&amp;gt;
                   &amp;lt;div class="card yellow black-text"&amp;gt;
                       &amp;lt;div class="card-content"&amp;gt;
                           &amp;lt;span class="card-title"&amp;gt;{% trans "Messages:" %}&amp;lt;/span&amp;gt;
                           &amp;lt;ul&amp;gt;
                               {% for message in messages %}&amp;lt;li&amp;gt;{{ message }}&amp;lt;/li&amp;gt;{% endfor %}
                           &amp;lt;/ul&amp;gt;
                       &amp;lt;/div&amp;gt;
                   &amp;lt;/div&amp;gt;
               &amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;
           {% endif %}

           &amp;lt;div class="row"&amp;gt;&amp;lt;div class="section col s12"&amp;gt;
               &amp;lt;div class="card white"&amp;gt;
                   &amp;lt;div class="card-content"&amp;gt;
                       {% block content %}
                       {% endblock content %}
                   &amp;lt;/div&amp;gt;
               &amp;lt;/div&amp;gt;
           &amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;

       {% endblock body %}

       &amp;lt;/div&amp;gt;
   &amp;lt;/main&amp;gt;

   &amp;lt;!-- Compiled and minified JavaScript --&amp;gt;

   &amp;lt;script src="https://cdn.jsdelivr.net/npm/@materializecss/materialize@2.1.0/dist/js/materialize.min.js"&amp;gt;&amp;lt;/script&amp;gt;

   {% block extra_body %}
   {% endblock extra_body %}

&amp;lt;/body&amp;gt;

&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before the UI update:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frcrqjpr8e5f83br3iwhv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frcrqjpr8e5f83br3iwhv.png" alt="Before the UI update" width="568" height="546"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After the UI update:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F01lfl9ttfyk8k5aat75f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F01lfl9ttfyk8k5aat75f.png" alt="After the UI update" width="800" height="524"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A wonderful look change with just a few lines!&lt;/p&gt;

&lt;h2&gt;
  
  
  Customizing the login form
&lt;/h2&gt;

&lt;p&gt;We still need to change individual components. The login form is located in the file "account/login.html". We will update the components to accommodate them to MaterializeCSS expected layout:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{% extends "account/base_entrance.html" %}
{% load i18n allauth account %}

{% block head_title %}
   {% trans "Sign In" %}
{% endblock head_title %}

{% block content %}

   &amp;lt;span class="card-title"&amp;gt;{% trans "Sign In" %}&amp;lt;/span&amp;gt;

   {% if not SOCIALACCOUNT_ONLY %}

       {% setvar link %}
           &amp;lt;a href="{{ signup_url }}"&amp;gt;
           {% endsetvar %}
           {% setvar end_link %}
           &amp;lt;/a&amp;gt;
       {% endsetvar %}

       &amp;lt;div class="row"&amp;gt;&amp;lt;div class="col s12"&amp;gt;
           {% blocktranslate %}
               If you have not created an account yet, then please {{ link }}sign up{{ end_link }} first.
           {% endblocktranslate %}
       &amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;br/&amp;gt;

       {% url 'account_login' as login_url %}
       {% element form form=form method="post" action=login_url tags="entrance,login" %}
           {% slot body %}
               {% csrf_token %}
               {% element fields form=form unlabeled=True %}
               {% endelement %}
               {{ redirect_field }}
           {% endslot %}

           {% slot actions %}
               &amp;lt;input class="btn indigo darken-2 white-text" type="submit" tags="prominent,login" value="{% trans "Sign In" %}" /&amp;gt;
               &amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;
           {% endslot %}

       {% endelement %}
       &amp;lt;br/&amp;gt;

   {% endif %}

   {% if LOGIN_BY_CODE_ENABLED %}
       {% element h2 %}
           {% element button href=request_login_code_url tags="prominent,login,secondary" %}
               {% trans "Mail me a sign-in code" %}
           {% endelement %}
       {% endelement %}
   {% endif %}

   {% if SOCIALACCOUNT_ENABLED %}
       {% include "socialaccount/snippets/login.html" with page_layout="entrance" %}
   {% endif %}

{% endblock content %}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To update the "social" part of the login form, we need to update also the "socialaccount/snippets/login.html" file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{% load i18n allauth  socialaccount %}
{% get_providers as socialaccount_providers %}

{% if socialaccount_providers %}

   {% if not SOCIALACCOUNT_ONLY %}
       &amp;lt;span class="card-title"&amp;gt;{% trans "Or use a third-party" %}&amp;lt;/span&amp;gt;
   {% endif %}

   {% include "socialaccount/snippets/provider_list.html" with process="login" %}
   {% include "socialaccount/snippets/login_extra.html" %}

{% endif %}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In AllAuth, each element has it's own template for easy customization, we can also add some classes to forms, fields and buttons to fully customize each shown element.&lt;/p&gt;

&lt;p&gt;The final result:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkvhr0poadjgb5967oihl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkvhr0poadjgb5967oihl.png" alt="The final result" width="800" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Better, isn’t?&lt;/p&gt;

&lt;h2&gt;
  
  
  Endless customization possibilities
&lt;/h2&gt;

&lt;p&gt;All internal views of AllAuth have their own customizable HTML. All individual HTML components have it's own template. With this clever system, it's easy to customize each tiny part of AllAuth user interface.&lt;/p&gt;

&lt;p&gt;The possibilities are endless!&lt;/p&gt;

&lt;h2&gt;
  
  
  About the list
&lt;/h2&gt;

&lt;p&gt;Among the Python and Docker posts, I will also write about other related topics (always tech and programming topics, I promise... with the fingers crossed), like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Software architecture&lt;/li&gt;
&lt;li&gt;Programming environments&lt;/li&gt;
&lt;li&gt;Linux operating system&lt;/li&gt;
&lt;li&gt;Etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you found some interesting technology, programming language or whatever, please, let me know! I'm always open to learning something new!&lt;/p&gt;

&lt;h2&gt;
  
  
  About the author
&lt;/h2&gt;

&lt;p&gt;I'm Andrés, a full-stack software developer based in Palma, on a personal journey to improve my coding skills. I'm also a self-published fantasy writer with four published novels to my name. Feel free to ask me anything!&lt;/p&gt;

</description>
      <category>python</category>
      <category>allauth</category>
      <category>django</category>
      <category>materializecss</category>
    </item>
    <item>
      <title>Django AllAuth Chapter 3 - Social login with Django AllAuth</title>
      <dc:creator>Andrés Álvarez Iglesias</dc:creator>
      <pubDate>Fri, 19 Jul 2024 04:22:08 +0000</pubDate>
      <link>https://forem.com/doctorserone/django-allauth-chapter-3-social-login-with-django-allauth-57b1</link>
      <guid>https://forem.com/doctorserone/django-allauth-chapter-3-social-login-with-django-allauth-57b1</guid>
      <description>&lt;p&gt;Django AllAuth also simplifies the integration with a lot -really, A LOT- of third party authentication platforms, like Google, Facebook, Microsoft, Github, etc. Let's see how to integrate Google login in our demo application.&lt;/p&gt;

&lt;h2&gt;
  
  
  List of chapters
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Chapter 1 - The All-in-one solution for Auth in Django &lt;/li&gt;
&lt;li&gt;Chapter 2 - How to install and configure Django AllAuth&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chapter 3 - Social login with Django AllAuth&lt;/strong&gt; ←This one!&lt;/li&gt;
&lt;li&gt;Chapter 4 - Customizing Django AllAuth UI&lt;/li&gt;
&lt;li&gt;Chapter 5 - Extending Django AllAuth user model with custom fields&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj0lh1szebyl8fl52e32j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj0lh1szebyl8fl52e32j.png" alt="The power of Python authentication" width="720" height="720"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring an OAuth application on Google
&lt;/h2&gt;

&lt;p&gt;First, we need to configure an OAuth (Open Authorization) application in Google cloud servers. All the process is explained in detail in &lt;a href="https://developers.google.com/identity/protocols/oauth2" rel="noopener noreferrer"&gt;https://developers.google.com/identity/protocols/oauth2&lt;/a&gt;, and involves the following steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Log into you Google Developer account at &lt;a href="https://console.cloud.google.com/apis/dashboard" rel="noopener noreferrer"&gt;https://console.cloud.google.com/apis/dashboard&lt;/a&gt; &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a new application or select an existent one&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select "credentials" on the sidebar and create a new "OAuth client ID" selecting "Web application" as it type. Fill with the correct URLs (the return url "/accounts/google/login/callback/" is an internal AllAuth managed URL) and annotate the client ID and secret.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu6zehhr9kx7zrakrwvt0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu6zehhr9kx7zrakrwvt0.png" alt="Select " id="" width="546" height="587"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Then, select "OAuth consent screen on the sidebar and configure the app name as shown to the users, and select a logo. Also, configure the e-mails allowed for testing in the development phase.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With these simple steps, after a while our OAuth Google Authentication will be ready to be integrated in our AllAuth application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrating the Google authentication with AllAuth
&lt;/h2&gt;

&lt;p&gt;Now, open the Django app main settings file (settings.py) and add a new block, writing the ClientID and secret obtained from Google before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Provider specific settings
SOCIALACCOUNT_PROVIDERS = {
   'google': {
       'APP': {
           'client_id': 'xxxxxxxxxxxx.apps.googleusercontent.com',
           'secret': 'GOCSPX-xxxxxxxxxxxxxxxxxxxxxxxx',
           'key': ''
       }
   }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, add the AllAuth social modules to active apps if not already configured:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INSTALLED_APPS = [
   (...)

   'allauth',
   'allauth.account',
   'allauth.socialaccount',
   'allauth.socialaccount.providers.google',

   'demo'
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And add a bunch of extra settings to configure the behavior of AllAuth at the end of the settings file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# AllAuth settings
SITE_ID = 1         

ACCOUNT_LOGIN_REDIRECT_URL ="/"
ACCOUNT_LOGOUT_REDIRECT_URL ="/"

ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_EMAIL_VERIFICATION = False
ACCOUNT_PASSWORD_MIN_LENGTH = 8
ACCOUNT_DEFAULT_HTTP_PROTOCOL='https'
ACCOUNT_LOGOUT_ON_GET = True

SOCIALACCOUNT_EMAIL_REQUIRED = True
SOCIALACCOUNT_EMAIL_VERIFICATION = False
SOCIALACCOUNT_EMAIL_AUTHENTICATION = True
SOCIALACCOUNT_LOGIN_ON_GET=True
SOCIALACCOUNT_AUTO_SIGNUP = True
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's all! Awesome!&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing the social login
&lt;/h2&gt;

&lt;p&gt;Open the preview of the app on IDX and navigate to /accounts/login/:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs2my6tdnwzjg7v1qjaiq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs2my6tdnwzjg7v1qjaiq.png" alt="Preview of the app on IDX" width="510" height="519"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on the "Google" social login, we will be redirected to the well known Google login page, yay! Select your google account and click on "login" button to finalize the social login.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv3sttn02dqzfvgdcrir5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv3sttn02dqzfvgdcrir5.png" alt="Google login page" width="720" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Google will redirect the user to the internal AllAuth login page that will finalize the process and redirect the user to the internal protected page. &lt;/p&gt;

&lt;p&gt;The process is simple and works great, but the default interface is intentionally simple and ugly. In the next chapter we will learn how to customize it.&lt;/p&gt;

&lt;h2&gt;
  
  
  About the list
&lt;/h2&gt;

&lt;p&gt;Among the Python and Docker posts, I will also write about other related topics (always tech and programming topics, I promise... with the fingers crossed), like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Software architecture&lt;/li&gt;
&lt;li&gt;Programming environments&lt;/li&gt;
&lt;li&gt;Linux operating system&lt;/li&gt;
&lt;li&gt;Etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you found some interesting technology, programming language or whatever, please, let me know! I'm always open to learning something new!&lt;/p&gt;

&lt;h2&gt;
  
  
  About the author
&lt;/h2&gt;

&lt;p&gt;I'm Andrés, a full-stack software developer based in Palma, on a personal journey to improve my coding skills. I'm also a self-published fantasy writer with four published novels to my name. Feel free to ask me anything!&lt;/p&gt;

</description>
      <category>django</category>
      <category>python</category>
      <category>allauth</category>
    </item>
    <item>
      <title>Django AllAuth Chapter 2 - How to install and configure Django AllAuth</title>
      <dc:creator>Andrés Álvarez Iglesias</dc:creator>
      <pubDate>Thu, 11 Jul 2024 04:38:03 +0000</pubDate>
      <link>https://forem.com/doctorserone/django-allauth-chapter-2-how-to-install-and-configure-django-allauth-513p</link>
      <guid>https://forem.com/doctorserone/django-allauth-chapter-2-how-to-install-and-configure-django-allauth-513p</guid>
      <description>&lt;p&gt;In this chapter we'll explore the basics of the AllAuth extension: from the installation to a basic usage for a login/password based access to our Django app. Let's go!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;(NOTE: First published in my Substack list: &lt;a href="https://andresalvareziglesias.substack.com/" rel="noopener noreferrer"&gt;https://andresalvareziglesias.substack.com/&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  List of chapters
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Chapter 1 - The All-in-one solution for Auth in Django&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chapter 2 - How to install and configure Django AllAuth&lt;/strong&gt; ←This one!&lt;/li&gt;
&lt;li&gt;Chapter 3 - Social login with Django AllAuth&lt;/li&gt;
&lt;li&gt;Chapter 4 - Customizing Django AllAuth UI&lt;/li&gt;
&lt;li&gt;Chapter 5 - Extending Django AllAuth user model with custom fields&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0uim5q2xi2wubf6fgv8x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0uim5q2xi2wubf6fgv8x.png" alt="Image description" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation of AllAuth
&lt;/h2&gt;

&lt;p&gt;As any other Django extension, AllAuth installation has two parts: install the python dependencies and configure the Django app settings file. To make things more fun, we will use (and learn) Google Project IDX, a wonderful cloud IDE and development platform.&lt;/p&gt;

&lt;p&gt;First, log into IDX and create a new Django based project:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgxfyc2t48kozhz41vr44.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgxfyc2t48kozhz41vr44.png" alt="Image description" width="485" height="541"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once created, we will have a fully working Django app, so move on!&lt;/p&gt;

&lt;p&gt;The installation of AllAuth itself is simple: just install the django-allauth python package. Project IDX (and ourselves, in case of manual project creation) creates a &lt;code&gt;requirements.txt&lt;/code&gt; file, so let's use it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add "&lt;strong&gt;django-allauth&lt;/strong&gt;" to &lt;code&gt;dependencies.txt&lt;/code&gt;. You can also add "&lt;strong&gt;django-allauth[socialaccount]&lt;/strong&gt;", used in the next chapter for social login&lt;/li&gt;
&lt;li&gt;Open the IDX terminal and navigate to &lt;code&gt;dependencies.txt&lt;/code&gt; parent folder&lt;/li&gt;
&lt;li&gt;Load the virtual environment created with out project by IDX: &lt;code&gt;source ~/allauth-test/.venv/bin/activate&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Execute: &lt;code&gt;pip install -r requirements.txt&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, we need to make some changes to the main Django app settings file. Open settings.py and locate the TEMPLATES setting. Add the AllAuth required processor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TEMPLATES = [
   {
       'BACKEND': 'django.template.backends.django.DjangoTemplates',
       'DIRS': [],
       'APP_DIRS': True,
       'OPTIONS': {
           'context_processors': [
               'django.template.context_processors.debug',
               'django.template.context_processors.request',
               'django.contrib.auth.context_processors.auth',
               'django.contrib.messages.context_processors.messages',

               # This one                
               'django.template.context_processors.request',
           ],
       },
   },
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, locate the &lt;code&gt;AUTHENTICATION_BACKENDS&lt;/code&gt; setting and add the AllAuth backend. If not present, add it now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AUTHENTICATION_BACKENDS = [
   # Needed to login by user in admin, regardless of `allauth`
   'django.contrib.auth.backends.ModelBackend',

   # This one
   'allauth.account.auth_backends.AuthenticationBackend',
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, add AllAuth to installed apps as any other Django extension. You can also add the social login extensions here, used in the next chapter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INSTALLED_APPS = [
   'django.contrib.admin',
   'django.contrib.auth',
   'django.contrib.contenttypes',
   'django.contrib.sessions',
   'django.contrib.messages',
   'django.contrib.staticfiles',

   # Add these
   'allauth',
   'allauth.account',
   'allauth.socialaccount',
   'allauth.socialaccount.providers.google',
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The last modification of the settings file is the required middleware. Locate the &lt;code&gt;MIDDLEWARE&lt;/code&gt; section and add the AllAuth middleware at the end:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MIDDLEWARE = [
   'django.middleware.security.SecurityMiddleware',
   'django.contrib.sessions.middleware.SessionMiddleware',
   'django.middleware.common.CommonMiddleware',
   'django.middleware.csrf.CsrfViewMiddleware',
   'django.contrib.auth.middleware.AuthenticationMiddleware',
   'django.contrib.messages.middleware.MessageMiddleware',
   'django.middleware.clickjacking.XFrameOptionsMiddleware',

   # This one
   "allauth.account.middleware.AccountMiddleware",
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;AllAuth has it own views, templates and databases, so we need to perform some extra actions. The first action is to define the URLs for AllAuth views. Open the main &lt;code&gt;urls.py&lt;/code&gt; and add them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.contrib import admin
from django.urls import path, include

urlpatterns = [
   path('admin/', admin.site.urls),
   path('accounts/', include('allauth.urls')),
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, the code modifications are completed, but we need to create AllAuth required tables. Use the Django migration tool from the IDX terminal, navigating to &lt;code&gt;manage.py&lt;/code&gt; location and executing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3 manage.py migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also need an administrator to test the login (and to create users). Create it now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3 manage.py createsuperuser
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Testing AllAuth installation
&lt;/h2&gt;

&lt;p&gt;Now, we have a fully working AllAuth installation. To test the authentication methods, create a demo app with &lt;code&gt;manage.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3 manage.py startapp demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Register it in the &lt;code&gt;INSTALLED_APPS&lt;/code&gt; section of the main settings page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INSTALLED_APPS = [
   (...)

   'allauth',
   'allauth.account',
   'allauth.socialaccount',
   'allauth.socialaccount.providers.google',

   # This one
   'demo'
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And map it to main &lt;code&gt;urls.py&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;urlpatterns = [
   path('', include('demo.urls')),
   path('admin/', admin.site.urls),
   path('accounts/', include('allauth.urls')),
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, create a simple view in our new demo app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.shortcuts import render
from django.http import HttpResponse

def indexView(request):
   if request.user.is_authenticated:
      return HttpResponse("""
         &amp;lt;span style='color: green;'&amp;gt;Logged in&amp;lt;/span&amp;gt;
         """)
   else:
      return HttpResponse("""
         &amp;lt;span style='color: red;'&amp;gt;Not logged in&amp;lt;/span&amp;gt;
         """)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And map it to demo's urls.py:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.contrib import admin
from django.urls import path, include
from demo.views import indexView

urlpatterns = [
   path('', indexView, name='indexView'),

   # Override default postlogin action with our view
   path('accounts/profile/', indexView, name='profileOverridenView'),
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now, load the page in IDX’s viewer:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F023ldb4i06w3axl9gdxc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F023ldb4i06w3axl9gdxc.png" alt="Image description" width="498" height="155"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can use now AllAuth views to perform authentication. For example, use /accounts/login endpoint to perform a login with the previously created user:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgtdqve6mqr63ucavab49.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgtdqve6mqr63ucavab49.png" alt="Image description" width="498" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And then, we will receive the expected login page:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4guybfar6zokarhz4xd5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4guybfar6zokarhz4xd5.png" alt="Image description" width="440" height="143"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also use other useful AllAuth views, like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Signup: &lt;code&gt;/accounts/signup/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Login: &lt;code&gt;/accounts/login/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Logout: &lt;code&gt;/accounts/logout/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Change password: &lt;code&gt;/accounts/password/change/&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Simple and easy!&lt;/p&gt;

&lt;h2&gt;
  
  
  About the list
&lt;/h2&gt;

&lt;p&gt;Among the Python and Docker posts, I will also write about other related topics (always tech and programming topics, I promise... with the fingers crossed), like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Software architecture&lt;/li&gt;
&lt;li&gt;Programming environments&lt;/li&gt;
&lt;li&gt;Linux operating system&lt;/li&gt;
&lt;li&gt;Etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you found some interesting technology, programming language or whatever, please, let me know! I'm always open to learning something new!&lt;/p&gt;

&lt;h2&gt;
  
  
  About the author
&lt;/h2&gt;

&lt;p&gt;I'm Andrés, a full-stack software developer based in Palma, on a personal journey to improve my coding skills. I'm also a self-published fantasy writer with four published novels to my name. Feel free to ask me anything!&lt;/p&gt;

</description>
      <category>django</category>
      <category>python</category>
      <category>allauth</category>
    </item>
    <item>
      <title>Django AllAuth Chapter 1 - The All-in-one solution for Auth in Django</title>
      <dc:creator>Andrés Álvarez Iglesias</dc:creator>
      <pubDate>Wed, 26 Jun 2024 04:52:53 +0000</pubDate>
      <link>https://forem.com/doctorserone/django-allauth-chapter-1-the-all-in-one-solution-for-auth-in-django-1dog</link>
      <guid>https://forem.com/doctorserone/django-allauth-chapter-1-the-all-in-one-solution-for-auth-in-django-1dog</guid>
      <description>&lt;p&gt;After some experimentation in previous articles, now we will build some useful apps with Django. And one of the most important aspects of any web app is the user authentication. Django has a pretty useful authentication mechanism, but in this series of articles we will explore a full authentication package: Django AllAuth.&lt;/p&gt;

&lt;h2&gt;
  
  
  List of chapters
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Chapter 1 - The All-in-one solution for Auth in Django ←This one!&lt;/li&gt;
&lt;li&gt;Chapter 2 - How to install and configure Django AllAuth&lt;/li&gt;
&lt;li&gt;Chapter 3 - Social login with Django AllAuth&lt;/li&gt;
&lt;li&gt;Chapter 4 - Customizing Django AllAuth UI&lt;/li&gt;
&lt;li&gt;Chapter 5 - Extending Django AllAuth user model with custom fields&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F71e8x1qchqmndjaihnv2.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F71e8x1qchqmndjaihnv2.jpeg" alt="Image description" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The All-in-one solution for Auth in Django
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://allauth.org/"&gt;Django AllAuth&lt;/a&gt; defines itself as a "Integrated set of Django applications addressing authentication, registration, account management as well as 3rd party (social) account authentication". And is a pretty good definition.&lt;/p&gt;

&lt;p&gt;You can read more about Django AllAuth on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://allauth.org/"&gt;It's home page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;In the &lt;a href="https://docs.allauth.org/en/latest/"&gt;official documentation&lt;/a&gt; (very well written and structured)&lt;/li&gt;
&lt;li&gt;In it's &lt;a href="https://github.com/pennersr/django-allauth"&gt;GitHub project page&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A very, very interesting project that we will unleash in the core of our Django app in the following chapters.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;In this series of articles we will learn how to install and configure AllAuth to have a fully working authentication in our Django App. And later, we will customize the default experience of AllAuth components.&lt;/p&gt;

&lt;p&gt;Django AllAuth includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Login&lt;/li&gt;
&lt;li&gt;Signup&lt;/li&gt;
&lt;li&gt;Logout&lt;/li&gt;
&lt;li&gt;Password Management&lt;/li&gt;
&lt;li&gt;Password Reset&lt;/li&gt;
&lt;li&gt;Emails Management&lt;/li&gt;
&lt;li&gt;Email Verification&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of these with a rate limit mechanism to prevent brute force attacks. Pretty good, isn't it?&lt;/p&gt;

&lt;p&gt;At the end of the series we will know how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Allow users to register in our site, through user/password/email and with social accounts&lt;/li&gt;
&lt;li&gt;Allow users to login in our site, through user/password/email and with social accounts&lt;/li&gt;
&lt;li&gt;Display user profile and allow change and recover it password&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do you want to come with us on this journey?&lt;/p&gt;

&lt;h2&gt;
  
  
  About the list
&lt;/h2&gt;

&lt;p&gt;Among the &lt;a href="https://andresalvareziglesias.substack.com/"&gt;Python and Docker posts&lt;/a&gt;, I will also write about other related topics (always tech and programming topics, I promise... with the fingers crossed), like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Software architecture&lt;/li&gt;
&lt;li&gt;Programming environments&lt;/li&gt;
&lt;li&gt;Linux operating system&lt;/li&gt;
&lt;li&gt;Etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you found some interesting technology, programming language or whatever, please, let me know! I'm always open to learning something new!&lt;/p&gt;

&lt;h2&gt;
  
  
  About the author
&lt;/h2&gt;

&lt;p&gt;I'm Andrés, a full-stack software developer based in Palma, on a personal journey to improve my coding skills. I'm also a self-published fantasy writer with four published novels to my name. Feel free to ask me anything!&lt;/p&gt;

</description>
      <category>django</category>
      <category>python</category>
      <category>allauth</category>
    </item>
  </channel>
</rss>
