<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Guguweb - django</title><link href="https://www.guguweb.com/" rel="alternate"></link><link href="https://www.guguweb.com/feeds/django.atom.xml" rel="self"></link><id>https://www.guguweb.com/</id><updated>2023-04-16T10:00:13+02:00</updated><subtitle>Freelance developer and sysadmin</subtitle><entry><title>Django Rest Framework authentication: the easy way</title><link href="https://www.guguweb.com/2022/01/23/django-rest-framework-authentication-the-easy-way/" rel="alternate"></link><published>2022-01-23T18:05:09+00:00</published><updated>2022-01-26T18:47:03+01:00</updated><author><name>Augusto Destrero</name></author><id>tag:www.guguweb.com,2022-01-23:/2022/01/23/django-rest-framework-authentication-the-easy-way/</id><summary type="html">&lt;p&gt;In this tutorial you'll learn how to implement Django Rest Framework authentication in your web application by leveraging the built-in Django session framework.&lt;/p&gt;
&lt;p&gt;This approach is way simpler (and secure) than other popular methods such as JWT, and has only one requirement: your frontend (think Vue.js, React, ...) and your …&lt;/p&gt;</summary><content type="html">&lt;p&gt;In this tutorial you'll learn how to implement Django Rest Framework authentication in your web application by leveraging the built-in Django session framework.&lt;/p&gt;
&lt;p&gt;This approach is way simpler (and secure) than other popular methods such as JWT, and has only one requirement: your frontend (think Vue.js, React, ...) and your backend should be served by the same domain.&lt;/p&gt;
&lt;p&gt;I created an &lt;a href="https://github.com/baxeico/drf-authentication"&gt;example project on GitHub&lt;/a&gt; you can use to follow along with this tutorial.&lt;/p&gt;
&lt;div class="toc"&gt;&lt;span class="toctitle"&gt;Table of Contents&lt;/span&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#why-you-should-avoid-jwt-for-django-rest-framework-authentication"&gt;Why you should avoid JWT for Django Rest Framework authentication&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#django-rest-framework-settings"&gt;Django Rest Framework settings&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#django-rest-framework-authentication-endpoint"&gt;Django Rest Framework authentication endpoint&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#test-authentication-using-httpie"&gt;Test authentication using HTTPie&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#a-new-endpoint-to-retrieve-the-user-profile"&gt;A new endpoint to retrieve the user profile&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#test-the-user-profile-endpoint-using-httpie"&gt;Test the user profile endpoint using HTTPie&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#conclusions"&gt;Conclusions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id="why-you-should-avoid-jwt-for-django-rest-framework-authentication"&gt;Why you should avoid JWT for Django Rest Framework authentication&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://auth0.com/learn/json-web-tokens/"&gt;JWT (Json Web Token)&lt;/a&gt; is a very popular method to provide authentication in APIs. If you are developing a modern web application with Vue.js or React as the frontend and Django Rest Framework as the backend, there is an high probability that you are considering JWT as the best method to implement authentication.&lt;/p&gt;
&lt;p&gt;The reality is that JWT is just one method, and unfortunately not the simpler, nor the most reliable. JWT is not supported out-of-the-box in Django Rest Framework and requires additional libraries and additional configuration for your project.&lt;/p&gt;
&lt;p&gt;Also, implementing JWT in a secure way is quite challenging, and this is due to its complex design. Quoting &lt;a href="https://groups.google.com/g/django-developers/c/6oS9R2GwO4k/m/Rep92xfsAwAJ"&gt;the words of James Bennet&lt;/a&gt;, a long time Django project contributor:&lt;/p&gt;
&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;"JWT is over-complex, puts too much power in the attacker's hands, has too many configuration knobs, and makes poor cryptographic choices. This is why we see vulnerabilities in JWT libraries and JWT-using systems again and again and again."&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Here is some examples of &lt;a href="https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/"&gt;JWT vulnerabilities&lt;/a&gt; found in the wild.&lt;/p&gt;
&lt;p&gt;The good news is that if you can control the domain of &lt;strong&gt;both your backend and your frontend&lt;/strong&gt;, you can use a much simpler method: Django sessions.&lt;/p&gt;
&lt;h2 id="django-rest-framework-settings"&gt;Django Rest Framework settings&lt;/h2&gt;
&lt;p&gt;Django Rest Framework comes with built-in &lt;a href="https://www.django-rest-framework.org/api-guide/authentication/#sessionauthentication"&gt;session based authentication&lt;/a&gt;. To use it you have to add this in your Django settings module:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;REST_FRAMEWORK&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s1"&gt;&amp;#39;DEFAULT_AUTHENTICATION_CLASSES&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s1"&gt;&amp;#39;rest_framework.authentication.SessionAuthentication&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="s1"&gt;&amp;#39;DEFAULT_PERMISSION_CLASSES&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s1"&gt;&amp;#39;rest_framework.permissions.IsAuthenticated&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Remember that &lt;em&gt;authentication&lt;/em&gt; deals with recognizing the users that are connecting to your API, while &lt;em&gt;permissions&lt;/em&gt; deals with giving access to some resources to the users.&lt;/p&gt;
&lt;p&gt;In the &lt;code&gt;DEFAULT_AUTHENTICATION_CLASSES&lt;/code&gt; list you are configuring only the good old Django sessions to authenticate users. In the &lt;code&gt;DEFAULT_PERMISSION_CLASSES&lt;/code&gt; list you are requiring that only authenticated users will access your endpoints.&lt;/p&gt;
&lt;div class="admonition note"&gt;
&lt;p class="admonition-title"&gt;Where is my token?&lt;/p&gt;
&lt;p&gt;Django sessions are based by default on a session cookie stored on the client. There's no need for a "Token", an "Authorization" header or something like that.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;If you can store that session cookie on the client and send it on every request to your API you will authenticate the user.&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;h2 id="django-rest-framework-authentication-endpoint"&gt;Django Rest Framework authentication endpoint&lt;/h2&gt;
&lt;p&gt;Now it's time to write a very simple view to let the users authenticate with a username/password.&lt;/p&gt;
&lt;p&gt;We'll need a serializer that will take the username and password from the request and will perform the actual authentication using Django authenication framework.&lt;/p&gt;
&lt;p&gt;Create a &lt;code&gt;serializers.py&lt;/code&gt; file in your app and add this code to it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.contrib.auth&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;authenticate&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;rest_framework&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;serializers&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LoginSerializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serializers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Serializer&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="sd"&gt;    This serializer defines two fields for authentication:&lt;/span&gt;
&lt;span class="sd"&gt;      * username&lt;/span&gt;
&lt;span class="sd"&gt;      * password.&lt;/span&gt;
&lt;span class="sd"&gt;    It will try to authenticate the user with when validated.&lt;/span&gt;
&lt;span class="sd"&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;serializers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Username&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;write_only&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;serializers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Password&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="c1"&gt;# This will be used when the DRF browsable API is enabled&lt;/span&gt;
        &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;input_type&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;password&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;trim_whitespace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;write_only&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attrs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Take username and password from request&lt;/span&gt;
        &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;attrs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;username&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;attrs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;password&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# Try to authenticate the user using Django auth framework.&lt;/span&gt;
            &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;request&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                                &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="c1"&gt;# If we don&amp;#39;t have a regular user, raise a ValidationError&lt;/span&gt;
                &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Access denied: wrong username or password.&amp;#39;&lt;/span&gt;
                &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;serializers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ValidationError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;authorization&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Both &amp;quot;username&amp;quot; and &amp;quot;password&amp;quot; are required.&amp;#39;&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;serializers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ValidationError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;authorization&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;# We have a valid user, put it in the serializer&amp;#39;s validated_data.&lt;/span&gt;
        &lt;span class="c1"&gt;# It will be used in the view.&lt;/span&gt;
        &lt;span class="n"&gt;attrs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;user&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;attrs&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then we can use this serializer in a login view. Add this to your &lt;code&gt;views.py&lt;/code&gt; file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;rest_framework&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;permissions&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;rest_framework&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;views&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;rest_framework.response&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;.&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;serializers&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LoginView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;views&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;APIView&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# This view should be accessible also for unauthenticated users.&lt;/span&gt;
    &lt;span class="n"&gt;permission_classes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;permissions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AllowAny&lt;/span&gt;&lt;span class="p"&gt;,)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;serializer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;serializers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LoginSerializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;request&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="n"&gt;serializer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_valid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raise_exception&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;serializer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;validated_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;user&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HTTP_202_ACCEPTED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Mount your view in the project &lt;code&gt;urls.py&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.contrib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;admin&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.urls&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;users&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;views&lt;/span&gt;

&lt;span class="n"&gt;urlpatterns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;admin/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;login/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;views&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LoginView&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;as_view&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Finally you can migrate the database, create a test user and launch the Django development server:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$ ./manage.py migrate
$ ./manage.py createsuperuser
&lt;span class="o"&gt;(&lt;/span&gt;... follow instructions ...&lt;span class="o"&gt;)&lt;/span&gt;
$ ./manage.py runserver
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="test-authentication-using-httpie"&gt;Test authentication using HTTPie&lt;/h3&gt;
&lt;p&gt;I really like &lt;a href="https://httpie.io/cli"&gt;HTTPie command line HTTP client&lt;/a&gt;. Maybe because it is written in Python and based on &lt;a href="https://docs.python-requests.org/en/latest/"&gt;Python requests&lt;/a&gt;. :)&lt;/p&gt;
&lt;p&gt;You can install it using&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$ pip install httpie
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It is one of the few packages that I like to install system wide.&lt;/p&gt;
&lt;p&gt;After installing HTTPie, let's test a wrong login:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$ http POST :8000/login/ &lt;span class="nv"&gt;username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;guguweb &lt;span class="nv"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;wrongpassword
HTTP/1.1 &lt;span class="m"&gt;400&lt;/span&gt; Bad Request
&lt;span class="o"&gt;(&lt;/span&gt; ... some other response headers ... &lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;non_field_errors&amp;quot;&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
        &lt;span class="s2"&gt;&amp;quot;Access denied: wrong username or password.&amp;quot;&lt;/span&gt;
    &lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As you can see the error message is returned and the user is not logged in.&lt;/p&gt;
&lt;p&gt;Now let's try with the right credentials:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$ http POST :8000/login/ &lt;span class="nv"&gt;username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;guguweb &lt;span class="nv"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;mysecret
HTTP/1.1 &lt;span class="m"&gt;202&lt;/span&gt; Accepted
&lt;span class="o"&gt;(&lt;/span&gt; ... some other response headers ... &lt;span class="o"&gt;)&lt;/span&gt;
Set-Cookie: &lt;span class="nv"&gt;csrftoken&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ALo4uq&lt;span class="o"&gt;(&lt;/span&gt;...&lt;span class="o"&gt;)&lt;/span&gt;lLoayts&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;expires&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Tue, &lt;span class="m"&gt;24&lt;/span&gt; Jan &lt;span class="m"&gt;2023&lt;/span&gt; &lt;span class="m"&gt;11&lt;/span&gt;:00:26 GMT&lt;span class="p"&gt;;&lt;/span&gt; Max-Age&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;31449600&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;Path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;SameSite&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Lax
Set-Cookie: &lt;span class="nv"&gt;sessionid&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;l5p5zqjkhuijhjdb84&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;expires&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Tue, &lt;span class="m"&gt;08&lt;/span&gt; Feb &lt;span class="m"&gt;2022&lt;/span&gt; &lt;span class="m"&gt;11&lt;/span&gt;:00:26 GMT&lt;span class="p"&gt;;&lt;/span&gt; HttpOnly&lt;span class="p"&gt;;&lt;/span&gt; Max-Age&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1209600&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;Path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The user is correctly logged in and a session cookie named &lt;code&gt;sessionid&lt;/code&gt; has been returned to our client.&lt;/p&gt;
&lt;p&gt;If we will persist that session cookie in each request, our user will be persistently authenticated.&lt;/p&gt;
&lt;h2 id="a-new-endpoint-to-retrieve-the-user-profile"&gt;A new endpoint to retrieve the user profile&lt;/h2&gt;
&lt;p&gt;Let's write a view that will let the user to retrieve his user profile. Of course this view will require an already authenticated user.&lt;/p&gt;
&lt;p&gt;First of all we need a new serializer that will be used to return the profile information. Add this to the &lt;code&gt;serializers.py&lt;/code&gt; file introduced earlier:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.contrib.auth.models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserSerializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serializers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ModelSerializer&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;
        &lt;span class="n"&gt;fields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="s1"&gt;&amp;#39;username&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;&amp;#39;email&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;&amp;#39;first_name&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;&amp;#39;last_name&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now you can add a view to retrieve the user profile. Remember that we added &lt;code&gt;rest_framework.permissions.IsAuthenticated&lt;/code&gt; in our &lt;code&gt;DEFAULT_PERMISSION_CLASSES&lt;/code&gt; setting, so each view will require that the user is authenticated, unless otherwise specified.&lt;/p&gt;
&lt;p&gt;Add this to your &lt;code&gt;views.py&lt;/code&gt; file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProfileView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;generics&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RetrieveAPIView&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;serializer_class&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;serializers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserSerializer&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And mount the view to an endpoint in your &lt;code&gt;urls.py&lt;/code&gt; file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;urlpatterns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;profile/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;views&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProfileView&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;as_view&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="test-the-user-profile-endpoint-using-httpie"&gt;Test the user profile endpoint using HTTPie&lt;/h3&gt;
&lt;p&gt;Let's test a unauthenticated call to our new endpoint:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$ http GET :8000/profile/
HTTP/1.1 &lt;span class="m"&gt;403&lt;/span&gt; Forbidden
&lt;span class="o"&gt;(&lt;/span&gt; ... some other response headers ... &lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;detail&amp;quot;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;quot;Authentication credentials were not provided.&amp;quot;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The endpoint is correctly protected from unauthenticated requests. Now let's try to add an header with our session cookie.&lt;/p&gt;
&lt;div class="admonition note"&gt;
&lt;p class="admonition-title"&gt;Where I can find the session cookie value?&lt;/p&gt;
&lt;p&gt;You can copy the sessionid value from the previous login request, it was something like this &lt;code&gt;Set-Cookie: sessionid=l5p5zqjkhuijhjdb84;&lt;/code&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$ http GET :8000/profile/ Cookie:sessionid&lt;span class="o"&gt;=&lt;/span&gt;l5p5zqjkhuijhjdb84
HTTP/1.1 &lt;span class="m"&gt;200&lt;/span&gt; OK
&lt;span class="o"&gt;(&lt;/span&gt; ... some other response headers ... &lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;email&amp;quot;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;quot;augusto@guguweb.com&amp;quot;&lt;/span&gt;,
    &lt;span class="s2"&gt;&amp;quot;first_name&amp;quot;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;quot;Augusto&amp;quot;&lt;/span&gt;,
    &lt;span class="s2"&gt;&amp;quot;last_name&amp;quot;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;quot;Destrero&amp;quot;&lt;/span&gt;,
    &lt;span class="s2"&gt;&amp;quot;username&amp;quot;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;quot;guguweb&amp;quot;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="conclusions"&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;In this tutorial you learned how to implement Django Rest Framework authentication in your web application by leveraging the built-in Django session framework.&lt;/p&gt;
&lt;p&gt;This approach assumes that you can control the domain of both your frontend and your backend, and the two layers of the web application can be served from the same top level domain. If this is not the case, you cannot rely on browser cookies to persist the user session between subsequent requests.&lt;/p&gt;
&lt;p&gt;In many cases this assumption is reasonable and this approach is way simper to configure and implement with respect to other token based approaches.&lt;/p&gt;
&lt;p&gt;Don't forget to clone/fork my &lt;a href="https://github.com/baxeico/drf-authentication"&gt;example project on GitHub&lt;/a&gt; to actually see this project running.&lt;/p&gt;
&lt;p&gt;In a follow up post I will show you how to implement a simple Vue.js based application that will connect to the REST API implemented in this tutorial.&lt;/p&gt;
&lt;p&gt;Have fun with Django Rest Framework!&lt;/p&gt;</content><category term="web"></category><category term="django"></category><category term="rest"></category><category term="authentication"></category><category term="cookies"></category></entry><entry><title>Integrate Axios with Django Rest Framework</title><link href="https://www.guguweb.com/2021/06/12/integrate-axios-with-django-rest-framework/" rel="alternate"></link><published>2021-06-12T12:34:09+00:00</published><updated>2022-01-14T21:06:19+01:00</updated><author><name>Augusto Destrero</name></author><id>tag:www.guguweb.com,2021-06-12:/2021/06/12/integrate-axios-with-django-rest-framework/</id><summary type="html">&lt;p&gt;Do you need to integrate the Axios HTTP client with Django Rest Framework? Then make sure to correctly configure the Django built-in Cross Site Request Forgery protection.&lt;/p&gt;
&lt;p&gt;TLDR: add these variables to your Django settings:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;CSRF_COOKIE_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;XSRF-TOKEN&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;CSRF_HEADER_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;HTTP_X_XSRF_TOKEN&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Axios has built-in support …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Do you need to integrate the Axios HTTP client with Django Rest Framework? Then make sure to correctly configure the Django built-in Cross Site Request Forgery protection.&lt;/p&gt;
&lt;p&gt;TLDR: add these variables to your Django settings:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;CSRF_COOKIE_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;XSRF-TOKEN&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;CSRF_HEADER_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;HTTP_X_XSRF_TOKEN&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Axios has built-in support for CSRF protection, and this is the default configuration:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;// name of the cookie to use as a value for xsrf token&lt;/span&gt;
&lt;span class="nx"&gt;xsrfCookieName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;XSRF-TOKEN&amp;#39;&lt;/span&gt;

&lt;span class="c1"&gt;// name of the http header that carries the xsrf token value&lt;/span&gt;
&lt;span class="nx"&gt;xsrfHeaderName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;X-XSRF-TOKEN&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;According to &lt;a href="https://docs.djangoproject.com/en/3.2/ref/settings/#csrf-header-name"&gt;Django documentation&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;"As with other HTTP headers in request.META, the header name received from the server is normalized by converting all characters to uppercase, replacing any hyphens with underscores, and adding an 'HTTP_' prefix to the name. For example, if your client sends a 'X-XSRF-TOKEN' header, the setting should be 'HTTP_X_XSRF_TOKEN'."&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;</content><category term="snippets"></category><category term="django"></category><category term="axios"></category><category term="rest"></category><category term="csrf"></category></entry><entry><title>How to accept Paypal payments on your Django application</title><link href="https://www.guguweb.com/2021/01/12/how-to-accept-paypal-payments-on-your-django-application/" rel="alternate"></link><published>2021-01-12T12:34:09+00:00</published><updated>2023-04-16T10:00:13+02:00</updated><author><name>Augusto Destrero</name></author><id>tag:www.guguweb.com,2021-01-12:/2021/01/12/how-to-accept-paypal-payments-on-your-django-application/</id><summary type="html">&lt;p&gt;In this tutorial you&amp;#8217;ll learn how to integrate Django and Paypal to accept payments in your Django web application.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.paypal.com/"&gt;Paypal&lt;/a&gt; is a popular solution for online payments. Even if nowadays there are &lt;a href="https://squareup.com/"&gt;many&lt;/a&gt; &lt;a href="https://stripe.com/"&gt;valid&lt;/a&gt; &lt;a href="https://www.skrill.com/"&gt;alternatives&lt;/a&gt;, Paypal is still a big player in the market with a solid reputation and …&lt;/p&gt;</summary><content type="html">&lt;p&gt;In this tutorial you&amp;#8217;ll learn how to integrate Django and Paypal to accept payments in your Django web application.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.paypal.com/"&gt;Paypal&lt;/a&gt; is a popular solution for online payments. Even if nowadays there are &lt;a href="https://squareup.com/"&gt;many&lt;/a&gt; &lt;a href="https://stripe.com/"&gt;valid&lt;/a&gt; &lt;a href="https://www.skrill.com/"&gt;alternatives&lt;/a&gt;, Paypal is still a big player in the market with a solid reputation and it&amp;#8217;s trusted by millions of users.&lt;/p&gt;
&lt;p&gt;Here is a simple step-by-step guide on how to integrate the &lt;a href="https://django-paypal.readthedocs.io/"&gt;django-paypal&lt;/a&gt; third party app on your website.&lt;/p&gt;
&lt;div class="toc"&gt;&lt;span class="toctitle"&gt;Table of Contents&lt;/span&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#1-install-the-django-paypal-app"&gt;1. Install the django-paypal app&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#2-insert-the-app-in-your-django-settings"&gt;2. Insert the app in your Django settings&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#3-insert-a-paypal-form-on-a-view"&gt;3. Insert a Paypal form on a view&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#4-provide-an-url-for-paypal-ipn"&gt;4. Provide an URL for Paypal IPN&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#5-create-views-for-success-and-failure-of-paypal-checkout"&gt;5. Create views for success and failure of Paypal checkout&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#6-setup-a-listener-to-detect-successful-paypal-payments"&gt;6. Setup a listener to detect successful Paypal payments&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id="1-install-the-django-paypal-app"&gt;1. Install the django-paypal app&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;pip install django-paypal
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="2-insert-the-app-in-your-django-settings"&gt;2. Insert the app in your Django settings&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;INSTALLED_APPS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="o"&gt;...&lt;/span&gt;
  &lt;span class="s1"&gt;&amp;#39;paypal.standard.ipn&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="3-insert-a-paypal-form-on-a-view"&gt;3. Insert a Paypal form on a view&lt;/h2&gt;
&lt;p&gt;Assuming you are using Django &lt;a href="https://docs.djangoproject.com/en/3.1/topics/class-based-views/"&gt;class-based views&lt;/a&gt;, you can use a FormView like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.views.generic&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FormView&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.urls&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;reverse&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;paypal.standard.forms&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;PayPalPaymentsForm&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PaypalFormView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FormView&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;template_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;paypal_form.html&amp;#39;&lt;/span&gt;
    &lt;span class="n"&gt;form_class&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PayPalPaymentsForm&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_initial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="s1"&gt;&amp;#39;business&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;your-paypal-business-address@example.com&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;&amp;#39;amount&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;&amp;#39;currency_code&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;EUR&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;&amp;#39;item_name&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Example item&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;&amp;#39;invoice&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1234&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;&amp;#39;notify_url&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;build_absolute_uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reverse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;paypal-ipn&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
            &lt;span class="s1"&gt;&amp;#39;return_url&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;build_absolute_uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reverse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;paypal-return&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
            &lt;span class="s1"&gt;&amp;#39;cancel_return&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;build_absolute_uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reverse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;paypal-cancel&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
            &lt;span class="s1"&gt;&amp;#39;lc&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;EN&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;&amp;#39;no_shipping&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is a regular &lt;em&gt;FormView&lt;/em&gt; and the template &lt;em&gt;paypal_form.html&lt;/em&gt; is a standard Django template like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    {{ form.render }}
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Notice how we are settings some initial values for the Paypal form. Let us see all the parameters used here:&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;&lt;strong&gt;business&lt;/strong&gt;&lt;/dt&gt;
&lt;dd&gt;this is your Paypal account email. Payments will be sent to this account, so choose it carefully.&lt;/dd&gt;
&lt;dt&gt;&lt;strong&gt;amount&lt;/strong&gt;&lt;/dt&gt;
&lt;dd&gt;the payment amount.&lt;/dd&gt;
&lt;dt&gt;&lt;strong&gt;currency_code&lt;/strong&gt;&lt;/dt&gt;
&lt;dd&gt;the currency used in the previous amount parameter. Here is a list of &lt;a href="https://developer.paypal.com/docs/api/reference/currency-codes/"&gt;accepted currency codes&lt;/a&gt;.&lt;/dd&gt;
&lt;dt&gt;&lt;strong&gt;item_name&lt;/strong&gt;&lt;/dt&gt;
&lt;dd&gt;the name of the item that the customer is paying. Choose it carefully, because Paypal will show this name to the user in the payment confirmation page.&lt;/dd&gt;
&lt;dt&gt;&lt;strong&gt;invoice&lt;/strong&gt;&lt;/dt&gt;
&lt;dd&gt;this is an &amp;#8220;invoice code&amp;#8221; that you can use to match the payment with an object on your database. I suggest to use some sort of primary key for your transaction here.&lt;/dd&gt;
&lt;dt&gt;&lt;strong&gt;notify_url&lt;/strong&gt;&lt;/dt&gt;
&lt;dd&gt;a complete URI where Paypal will send an IPN (Instant Payment Notification). This is a Django endpoint you&amp;#8217;ll have to provide and that we&amp;#8217;ll see in a moment. Here you&amp;#8217;ll receive an HTTP request by the Paypal servers, when the payment will be correctly registered by Paypal.&lt;/dd&gt;
&lt;dt&gt;&lt;strong&gt;return_url&lt;/strong&gt;&lt;/dt&gt;
&lt;dd&gt;a complete URI where the customer will be redirected upon a successful payment.&lt;/dd&gt;
&lt;dt&gt;&lt;strong&gt;cancel_return&lt;/strong&gt;&lt;/dt&gt;
&lt;dd&gt;a complete URI where the customer will be redirected when the payment is cancelled.&lt;/dd&gt;
&lt;dt&gt;&lt;strong&gt;lc&lt;/strong&gt;&lt;/dt&gt;
&lt;dd&gt;The locale code to use in the checkout page. Here is a list of &lt;a href="https://developer.paypal.com/docs/api/reference/locale-codes/"&gt;supported locale codes&lt;/a&gt;.&lt;/dd&gt;
&lt;dt&gt;&lt;strong&gt;no_shipping&lt;/strong&gt;&lt;/dt&gt;
&lt;dd&gt;Can be set to 1 if you are selling digital goods, that doesn&amp;#8217;t require shipping.&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;Some of this data will likely be dynamic, because it depends on the object you are selling.&lt;/p&gt;
&lt;h2 id="4-provide-an-url-for-paypal-ipn"&gt;4. Provide an URL for Paypal IPN&lt;/h2&gt;
&lt;p&gt;In your Django &lt;em&gt;urls.py&lt;/em&gt; file, add an urlconf like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;paypal/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;paypal.standard.ipn.urls&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="5-create-views-for-success-and-failure-of-paypal-checkout"&gt;5. Create views for success and failure of Paypal checkout&lt;/h2&gt;
&lt;p&gt;You can add two &lt;em&gt;TemplateView&lt;/em&gt; to show your user a message upon success or failure of the Paypal checkout.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.views.generic&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TemplateView&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PaypalReturnView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TemplateView&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;template_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;paypal_success.html&amp;#39;&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PaypalCancelView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TemplateView&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;template_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;paypal_cancel.html&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then you can mount these views in your &lt;em&gt;urls.py&lt;/em&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;.&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;views&lt;/span&gt;
&lt;span class="n"&gt;urlpatterns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/paypal-return/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;views&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PaypalReturnView&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;as_view&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;paypal-return&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/paypal-cancel/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;views&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PaypalCancelView&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;as_view&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;paypal-cancel&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The names of the urls should match with those defined in the form initial data, as shown at step 3.&lt;/p&gt;
&lt;h2 id="6-setup-a-listener-to-detect-successful-paypal-payments"&gt;6. Setup a listener to detect successful Paypal payments&lt;/h2&gt;
&lt;p&gt;When a successful payment if performed on Paypal, you&amp;#8217;ll receive a so-called IPN: &amp;#8220;Instant Payment Notification&amp;#8221; from Paypal.&lt;/p&gt;
&lt;p&gt;django-paypal uses the &lt;a href="https://docs.djangoproject.com/en/3.1/topics/signals/"&gt;Django signal dispatcher&lt;/a&gt; to let you hook your code when a successful payment arrives. You can define a listener like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;paypal.standard.models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ST_PP_COMPLETED&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;paypal.standard.ipn.signals&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;valid_ipn_received&lt;/span&gt;

&lt;span class="nd"&gt;@receiver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;valid_ipn_received&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;paypal_payment_received&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;ipn_obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sender&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ipn_obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payment_status&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;ST_PP_COMPLETED&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# WARNING !&lt;/span&gt;
        &lt;span class="c1"&gt;# Check that the receiver email is the same we previously&lt;/span&gt;
        &lt;span class="c1"&gt;# set on the `business` field. (The user could tamper with&lt;/span&gt;
        &lt;span class="c1"&gt;# that fields on the payment form before it goes to PayPal)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ipn_obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;receiver_email&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;your-paypal-business-address@example.com&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# Not a valid payment&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;

        &lt;span class="c1"&gt;# ALSO: for the same reason, you need to check the amount&lt;/span&gt;
        &lt;span class="c1"&gt;# received, `custom` etc. are all what you expect or what&lt;/span&gt;
        &lt;span class="c1"&gt;# is allowed.&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;my_pk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ipn_obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;invoice&lt;/span&gt;
            &lt;span class="n"&gt;mytransaction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MyTransaction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pk&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;my_pk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;ipn_obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mc_gross&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;mytransaction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;ipn_obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mc_currency&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;EUR&amp;#39;&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Paypal ipn_obj data not valid!&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;mytransaction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;paid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
            &lt;span class="n"&gt;mytransaction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Paypal payment status not completed: &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;ipn_obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payment_status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here we assumed that you had a model &lt;em&gt;MyTransaction&lt;/em&gt; on your Django application, and that you want to set the transaction as paid when the Paypal payment is confirmed.&lt;/p&gt;
&lt;p&gt;That&amp;#8217;s it! Following these steps you should have a working Paypal integration in your Django project. Please let me know if you have questions or comments.&lt;/p&gt;</content><category term="web"></category><category term="django"></category><category term="paypal"></category></entry><entry><title>Django on a production server</title><link href="https://www.guguweb.com/2020/05/08/django-on-a-production-server/" rel="alternate"></link><published>2020-05-08T10:34:43+00:00</published><updated>2022-03-02T15:47:12+01:00</updated><author><name>augusto</name></author><id>tag:www.guguweb.com,2020-05-08:/2020/05/08/django-on-a-production-server/</id><summary type="html">&lt;p&gt;Is your Django project ready for production? Follow these guides to bring your Django project on a production server!&lt;/p&gt;
&lt;p&gt;There are many good tutorials out there for learning Django and developing projects locally. But I think that simple tutorials for production deployment is somewhat lacking. In this guide I'll try …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Is your Django project ready for production? Follow these guides to bring your Django project on a production server!&lt;/p&gt;
&lt;p&gt;There are many good tutorials out there for learning Django and developing projects locally. But I think that simple tutorials for production deployment is somewhat lacking. In this guide I'll try to fill this gap a little bit. 😉&lt;/p&gt;
&lt;p&gt;In the last months I wrote some tutorials that will show you how to bring your Django project on production. Here is a summary of each tutorial.&lt;/p&gt;
&lt;h2 id="1-django-nginx-deploy-your-django-project-on-a-production-server"&gt;1. &lt;a href="/2019/11/13/django-nginx-deploy-your-django-project-on-a-production-server/"&gt;Django NGINX: deploy your Django project on a production server&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This tutorial will give you the basics on deployment using the &lt;a href="https://www.nginx.com/"&gt;NGINX webserver&lt;/a&gt; and &lt;a href="https://uwsgi-docs.readthedocs.io/en/latest/"&gt;uWSGI application server&lt;/a&gt;.&lt;/p&gt;
&lt;div class="row"&gt;
    &lt;div class="col-12 col-sm-8 col-md-6 mx-auto"&gt;
        &lt;div class="card my-5"&gt;
    &lt;img src="/images/2019/11/thumbnails/400x_/django_nginx.png" class="card-img-top" alt="Django NGINX: deploy your Django project on a production server"&gt;
    &lt;div class="card-body"&gt;
      &lt;h5 class="card-title"&gt;Django NGINX: deploy your Django project on a production server&lt;/h5&gt;
      &lt;a href="/2019/11/13/django-nginx-deploy-your-django-project-on-a-production-server/" class="btn btn-link stretched-link"&gt;Read more...&lt;/a&gt;
    &lt;/div&gt;
&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="2-how-to-deploy-a-django-project-in-15-minutes-with-ansible"&gt;2. &lt;a href="/2017/05/02/how-to-deploy-a-django-project-in-15-minutes-with-ansible/"&gt;How to deploy a Django project in 15 minutes with Ansible&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This tutorial will make a step further and will show you how to leverage the power of &lt;a href="https://www.ansible.com/"&gt;Ansible&lt;/a&gt; to automate all the steps needed for a production deployment.&lt;/p&gt;
&lt;div class="row"&gt;
    &lt;div class="col-12 col-sm-8 col-md-6 mx-auto"&gt;
        &lt;div class="card my-5"&gt;
    &lt;img src="/images/2017/05/thumbnails/400x_/ansible_django.png" class="card-img-top" alt="How to deploy a Django project in 15 minutes with Ansible"&gt;
    &lt;div class="card-body"&gt;
      &lt;h5 class="card-title"&gt;How to deploy a Django project in 15 minutes with Ansible&lt;/h5&gt;
      &lt;a href="/2017/05/02/how-to-deploy-a-django-project-in-15-minutes-with-ansible/" class="btn btn-link stretched-link"&gt;Read more...&lt;/a&gt;
    &lt;/div&gt;
&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="3-bitbucket-pipelines-and-ansible-continuous-delivery-for-your-django-project"&gt;3. &lt;a href="/2020/01/03/bitbucket-pipelines-and-ansible-continuous-delivery-for-your-django-project/"&gt;Bitbucket Pipelines and Ansible: Continuous delivery for your Django project&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you are using &lt;a href="https://bitbucket.org/"&gt;Bitbucket&lt;/a&gt; you can automate the deployment when you push some code on your repository.&lt;/p&gt;
&lt;div class="row"&gt;
    &lt;div class="col-12 col-sm-8 col-md-6 mx-auto"&gt;
        &lt;div class="card my-5"&gt;
    &lt;img src="/images/2019/05/thumbnails/400x_/devops-3148393_1280.png" class="card-img-top" alt="Bitbucket Pipelines and Ansible: Continuous delivery for your Django project"&gt;
    &lt;div class="card-body"&gt;
      &lt;h5 class="card-title"&gt;Bitbucket Pipelines and Ansible: Continuous delivery for your Django project&lt;/h5&gt;
      &lt;a href="/2020/01/03/bitbucket-pipelines-and-ansible-continuous-delivery-for-your-django-project/" class="btn btn-link stretched-link"&gt;Read more...&lt;/a&gt;
    &lt;/div&gt;
&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="4-django-asynchronous-tasks-without-celery"&gt;4. &lt;a href="/2019/11/21/django-asynchronous-tasks-without-celery/"&gt;Django asynchronous tasks without Celery&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Did you know that &lt;a href="https://uwsgi-docs.readthedocs.io/en/latest/"&gt;uWSGI&lt;/a&gt; provides a production ready task queue? In this tutorial I explain how to configure and use it for your Django asyncronous tasks.&lt;/p&gt;
&lt;div class="row"&gt;
    &lt;div class="col-12 col-sm-8 col-md-6 mx-auto"&gt;
        &lt;div class="card my-5"&gt;
    &lt;img src="/images/2019/11/thumbnails/400x_/logistics-852936_1920.jpg" class="card-img-top" alt="Django asynchronous tasks without Celery"&gt;
    &lt;div class="card-body"&gt;
      &lt;h5 class="card-title"&gt;Django asynchronous tasks without Celery&lt;/h5&gt;
      &lt;a href="/2019/11/21/django-asynchronous-tasks-without-celery/" class="btn btn-link stretched-link"&gt;Read more...&lt;/a&gt;
    &lt;/div&gt;
&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;</content><category term="web"></category><category term="django"></category><category term="guide"></category><category term="production"></category></entry><entry><title>Remote debugging a Django project in VS Code</title><link href="https://www.guguweb.com/2020/04/20/remote-debugging-a-django-project-in-vs-code/" rel="alternate"></link><published>2020-04-20T08:02:16+00:00</published><updated>2022-01-14T20:56:31+01:00</updated><author><name>Augusto Destrero</name></author><id>tag:www.guguweb.com,2020-04-20:/2020/04/20/remote-debugging-a-django-project-in-vs-code/</id><summary type="html">&lt;p&gt;In this tutorial you will learn how to use VS Code for remote debugging. I&amp;#8217;ll show you how to debug a Django application running on a remote server over SSH or in a Docker container.&lt;/p&gt;
&lt;p&gt;Imagine the following scenario: You developed a Django application on your laptop. You did …&lt;/p&gt;</summary><content type="html">&lt;p&gt;In this tutorial you will learn how to use VS Code for remote debugging. I&amp;#8217;ll show you how to debug a Django application running on a remote server over SSH or in a Docker container.&lt;/p&gt;
&lt;p&gt;Imagine the following scenario: You developed a Django application on your laptop. You did your tests and made some debug. The application worked fine. Finally you deploy the application on a production server. Something goes wrong. There is a bug to hunt down and you cannot reproduce it locally.&lt;/p&gt;
&lt;p&gt;You could connect to the remote server using SSH, then use a remote editor like &lt;code&gt;vim&lt;/code&gt; on &lt;code&gt;nano&lt;/code&gt; to tweak the code. You could put some &lt;code&gt;print("I'm here!")&lt;/code&gt; here and there, trying to find the bug.&lt;/p&gt;
&lt;p&gt;But wait, aren&amp;#8217;t you a VS Code user? Why you have to debug in an editor you don&amp;#8217;t know? Wouldn&amp;#8217;t be great if you could connect to the remote environment from VS Code and debug your application inside the IDE you love?&lt;/p&gt;
&lt;p&gt;It turns out that VS Code has some extensions made exactly for that purpose, and you&amp;#8217;ll learn how to use them.&lt;/p&gt;
&lt;p&gt;At the end of this tutorial you will be able to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Connect with VS Code to a remote server using SSH and remotely debug a web project.&lt;/li&gt;
&lt;li&gt;Run a Docker container within VS Code and debug a project inside the container.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Before starting the tutorial let me say that I assume you are actively using Visual Studio Code for development and you already know how to install VS Code extensions and how to manage a Python project in the IDE. If you need a refresh you can check this &lt;a href="https://code.visualstudio.com/docs/languages/python"&gt;introductory tutorial&lt;/a&gt;.&lt;/p&gt;
&lt;div class="toc"&gt;&lt;span class="toctitle"&gt;Table of Contents&lt;/span&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#1-remote-debugging-over-ssh"&gt;1. Remote Debugging Over SSH&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#what-if-you-do-not-have-a-remote-ssh-server"&gt;What if You Do Not Have a Remote SSH Server?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#install-the-vs-code-extension"&gt;Install the VS Code Extension&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#generate-an-ssh-key-pair-and-configure-server-for-remote-access"&gt;Generate an SSH Key Pair and Configure Server for Remote Access&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#connect-to-remote-server-in-vs-code"&gt;Connect to Remote Server in VS Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#create-a-simple-django-project-on-remote-server"&gt;Create a Simple Django Project on Remote Server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#mapping-ports-to-test-the-project"&gt;Mapping Ports to Test the Project&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#a-buggy-django-app"&gt;A buggy Django app&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#debugging-in-vs-code"&gt;Debugging in VS Code&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#2-remote-debugging-on-a-docker-container"&gt;2. Remote Debugging on a Docker Container&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#install-docker"&gt;Install Docker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#install-the-vs-code-extension_1"&gt;Install the VS Code Extension&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#an-example-container-for-your-project"&gt;An Example Container for Your Project&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#understanding-devcontainerjson"&gt;Understanding devcontainer.json&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#debugging-in-vs-code_1"&gt;Debugging in VS Code&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#3-other-remote-debugging-scenarios"&gt;3. Other Remote Debugging Scenarios&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#wsl"&gt;WSL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#liveshare"&gt;LiveShare&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#4-conclusion"&gt;4. Conclusion&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id="1-remote-debugging-over-ssh"&gt;1. Remote Debugging Over SSH&lt;/h2&gt;
&lt;p&gt;The first scenario I will present is remote debugging on a server that is accessible via SSH. I assume that you already know how to connect to a remote server using SSH. You can find &lt;a href="https://www.digitalocean.com/community/tutorials/ssh-essentials-working-with-ssh-servers-clients-and-keys"&gt;good resources&lt;/a&gt; on the internet if you need more information.&lt;/p&gt;
&lt;h3 id="what-if-you-do-not-have-a-remote-ssh-server"&gt;What if You Do Not Have a Remote SSH Server?&lt;/h3&gt;
&lt;p&gt;Of course to follow along with this part of the tutorial you&amp;#8217;ll need an SSH remote server to connect to. If you don&amp;#8217;t have one readily available you can spin up a local virtual machine using &lt;a href="https://www.vagrantup.com/intro/getting-started/index.html"&gt;Vagrant&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After installing Vagrant and VirtualBox, creating a virtual machine is as simple as:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$ vagrant init hashicorp/bionic64
$ vagrant up
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You&amp;#8217;ll find an Ubuntu Server listening for SSH connections on &lt;code&gt;localhost:2222&lt;/code&gt;. Username is &lt;code&gt;vagrant&lt;/code&gt;, password is &lt;code&gt;vagrant&lt;/code&gt;. Easy enough!&lt;/p&gt;
&lt;p&gt;If you prefer to test on a real remote environment, you can create a virtual machine on &lt;a href="https://code.visualstudio.com/remote-tutorials/ssh/create-vm"&gt;Azure&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In this tutorial I&amp;#8217;ll use the Vagrant method to spin up a test SSH “remote” server on localhost, port 2222.&lt;/p&gt;
&lt;h3 id="install-the-vs-code-extension"&gt;Install the VS Code Extension&lt;/h3&gt;
&lt;p&gt;First of all you have to install the &lt;em&gt;Remote &amp;#8211; SSH&lt;/em&gt; extension from the VS Code marketplace. Go to the &lt;em&gt;Extensions&lt;/em&gt; section in VS Code and install the extension from there:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Install VS Code SSH extension" class="img-fluid d-block mx-auto" src="https://www.guguweb.com/images/2020/04/vscode_remote_ssh_install.png"&gt;&lt;/p&gt;
&lt;p&gt;If the extension has been installed correctly you will see a new green icon in the bottom left corner of the VS Code window.&lt;/p&gt;
&lt;h3 id="generate-an-ssh-key-pair-and-configure-server-for-remote-access"&gt;Generate an SSH Key Pair and Configure Server for Remote Access&lt;/h3&gt;
&lt;p&gt;You&amp;#8217;ll need to access the SSH server without entering the passphrase every time. For this you&amp;#8217;ll need an SSH keypair to connect to the server. If you don&amp;#8217;t already have one you can generate one by typing:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ssh-keygen -t rsa -b &lt;span class="m"&gt;2048&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can leave the SSH key passphrase empty, when prompted. In this way the public key will be saved in the &lt;code&gt;.ssh/id_rsa.pub&lt;/code&gt; file under your home directory.&lt;/p&gt;
&lt;p&gt;The last step is copying the public key on the remote server and appending it to the &lt;code&gt;.ssh/authorized_keys&lt;/code&gt; file, inside the home directory of the remote user you&amp;#8217;ll use to connect.&lt;/p&gt;
&lt;p&gt;If you are using the test SSH server created with Vagrant, as shown previously, the commands to copy the SSH public key in the right place are:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;localhost:~$ scp -P &lt;span class="m"&gt;2222&lt;/span&gt; ~/.ssh/id_rsa.pub vagrant@localhost:
localhost:~$ ssh -p &lt;span class="m"&gt;2222&lt;/span&gt; vagrant@localhost
vagrant@vagrant:~$ cat id_rsa.pub &lt;span class="p"&gt;&amp;amp;&lt;/span&gt;gt&lt;span class="p"&gt;;&amp;amp;&lt;/span&gt;gt&lt;span class="p"&gt;;&lt;/span&gt; ~/.ssh/authorized_keys
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;When prompted for a password remember that both the username and the password are &lt;code&gt;vagrant&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The last command is ran on the remote SSH server. You should now be able to login to SSH server without the need to write your passphrase.&lt;/p&gt;
&lt;h3 id="connect-to-remote-server-in-vs-code"&gt;Connect to Remote Server in VS Code&lt;/h3&gt;
&lt;p&gt;It&amp;#8217;s time to connect to the remote server in VS Code. Click on the green icon on the bottom left corner:&lt;/p&gt;
&lt;p&gt;&lt;img alt="VS Code Remote Window" class="img-fluid d-block mx-auto" src="https://www.guguweb.com/images/2020/04/vscode_remote_window_icon.png"&gt;&lt;/p&gt;
&lt;p&gt;A command prompt will appear at the top of the windows, click on &lt;strong&gt;Remote-SSH: Connect to Host…&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="VS Code Remote SSH" class="img-fluid d-block mx-auto" src="https://www.guguweb.com/images/2020/04/vscode_remote_ssh_connect.png"&gt;&lt;/p&gt;
&lt;p&gt;If you already have some SSH servers configured in your &lt;em&gt;.ssh/config&lt;/em&gt; file you&amp;#8217;ll see them listed here. In our example we will connect to a new SSH server, by writing the connection parameters in the &lt;em&gt;user@host:port&lt;/em&gt; form.&lt;/p&gt;
&lt;p&gt;&lt;img alt="VS Code Remote SSH Connection Details" class="img-fluid d-block mx-auto" src="https://www.guguweb.com/images/2020/04/vscode_remote_ssh_connect_details.png"&gt;&lt;/p&gt;
&lt;p&gt;Press Enter and a new VS Code windows will appear. That&amp;#8217;s literally your window to the remote system.&lt;/p&gt;
&lt;p&gt;The file explorer will let you to add remote directories in your workspace. You&amp;#8217;ll be able to edit files as if they were local.&lt;/p&gt;
&lt;p&gt;You can even open a terminal inside VS Code and it will act as a remote terminal. You&amp;#8217;ll make use of the remote terminal in the following section.&lt;/p&gt;
&lt;h3 id="create-a-simple-django-project-on-remote-server"&gt;Create a Simple Django Project on Remote Server&lt;/h3&gt;
&lt;p&gt;A Django project will serve just as an example of what you can do with VS Code SSH extension to debug your remote application. Even if you&amp;#8217;re not familiar with Django you&amp;#8217;ll be able to follow along with the tutorial. If otherwise you&amp;#8217;d like to better understand what you are doing here you can read this &lt;a href="https://docs.djangoproject.com/en/2.2/intro/tutorial01/"&gt;introductory Django tutorial&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In the VS Code remote window, open a terminal using the &lt;em&gt;“Terminal &amp;gt; New terminal”&lt;/em&gt; menu. Notice how this terminal is running on the remote server, and not locally on your machine.&lt;/p&gt;
&lt;p&gt;First you&amp;#8217;ll need to install a package on the remote server. This is needed to create a virtualenv for the project:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;vagrant@vagrant:~$ sudo apt update
vagrant@vagrant:~$ sudo apt install python3-venv
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then you can create a virtualenv and activate it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;vagrant@vagrant:~$ python3 -mvenv vscode-example-env
vagrant@vagrant:~$ . vscode-example-env/bin/activate
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now install Django on the virtualenv and create a new project:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;(&lt;/span&gt;vscode-example-env&lt;span class="o"&gt;)&lt;/span&gt; vagrant@vagrant:~$ pip install &lt;span class="nv"&gt;django&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;.2.12
&lt;span class="o"&gt;(&lt;/span&gt;vscode-example-env&lt;span class="o"&gt;)&lt;/span&gt; vagrant@vagrant:~$ django-admin startproject vscode_example
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="mapping-ports-to-test-the-project"&gt;Mapping Ports to Test the Project&lt;/h3&gt;
&lt;p&gt;Now that you&amp;#8217;ve created the example Django project, go into the project directory, create/migrate the Django database and run the Django development server:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;(&lt;/span&gt;vscode-example-env&lt;span class="o"&gt;)&lt;/span&gt; vagrant@vagrant:~$ &lt;span class="nb"&gt;cd&lt;/span&gt; vscode_example
&lt;span class="o"&gt;(&lt;/span&gt;vscode-example-env&lt;span class="o"&gt;)&lt;/span&gt; vagrant@vagrant:~$ ./manage.py migrate
&lt;span class="o"&gt;(&lt;/span&gt;vscode-example-env&lt;span class="o"&gt;)&lt;/span&gt; vagrant@vagrant:~$ ./manage.py runserver
Watching &lt;span class="k"&gt;for&lt;/span&gt; file changes with StatReloader
Performing system checks...

System check identified no issues &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt; silenced&lt;span class="o"&gt;)&lt;/span&gt;.
April &lt;span class="m"&gt;01&lt;/span&gt;, &lt;span class="m"&gt;2020&lt;/span&gt; - &lt;span class="m"&gt;17&lt;/span&gt;:35:01
Django version &lt;span class="m"&gt;2&lt;/span&gt;.2.12, using settings &lt;span class="s1"&gt;&amp;#39;vscode_example.settings&amp;#39;&lt;/span&gt;
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As you can see from the command output the Django development server is listening on &lt;em&gt;&lt;a href="http://127.0.0.1:8000/"&gt;http://127.0.0.1:8000/&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Don&amp;#8217;t confuse the &lt;em&gt;&lt;a href="http://127.0.0.1:8000/"&gt;http://127.0.0.1:8000/&lt;/a&gt;&lt;/em&gt; you see here. That is the localhost &lt;strong&gt;of the server&lt;/strong&gt; and not the local address of your PC.&lt;/p&gt;
&lt;p&gt;That address will not be accessible from your PC because it&amp;#8217;s local to the server. Fortunately VS Code lets you map ports of remote server to ports of your PC. This will let you access server ports as if they were local.&lt;/p&gt;
&lt;p&gt;Click on VS Code “Remote explorer” left pane:&lt;/p&gt;
&lt;p&gt;&lt;img alt="VS Code Remote explorer" class="img-fluid d-block mx-auto" src="https://www.guguweb.com/images/2020/04/vscode_remote_explorer.png"&gt;&lt;/p&gt;
&lt;p&gt;You&amp;#8217;ll see that in the “Forwarded ports” section there is a port on the server that is “&amp;#8221;Not Forwarded”. Hover with your mouse on the port and click on the “+” icon:&lt;/p&gt;
&lt;p&gt;&lt;img alt="VS Code Remote explorer add port" class="img-fluid d-block mx-auto" src="https://www.guguweb.com/images/2020/04/vscode_remote_explorer_add_port.png"&gt;&lt;/p&gt;
&lt;p&gt;Now that the server 8000 port is mapped on your PC 8000 port, you&amp;#8217;ll be able to access your Django project on &lt;em&gt;http://localhost:8000/&lt;/em&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Django default page" class="img-fluid d-block mx-auto" src="https://www.guguweb.com/images/2020/04/django_default_page.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Don&amp;#8217;t forget to forward the 8000 port every time you restart the Django development server.&lt;/p&gt;
&lt;h3 id="a-buggy-django-app"&gt;A buggy Django app&lt;/h3&gt;
&lt;p&gt;Now that you have a Django project running remotely why don&amp;#8217;t you create a Django app to test some remote debugging? Let&amp;#8217;s do it!&lt;/p&gt;
&lt;p&gt;Back to the VS Code terminal and stop the Django development server with CTRL-C. Then create a Django app:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;(&lt;/span&gt;vscode-example-env&lt;span class="o"&gt;)&lt;/span&gt; vagrant@vagrant:~$ ./manage.py startapp todo
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Every example project has a todo app, isn&amp;#8217;t it?&lt;/p&gt;
&lt;p&gt;Now it&amp;#8217;s time to edit some files remotely using VS Code. As promised you won&amp;#8217;t use vim or nano over SSH!&lt;/p&gt;
&lt;p&gt;Click on the VS Code file explorer pane, then on Open Folder button:&lt;/p&gt;
&lt;p&gt;&lt;img alt="VS Code Open Folder button" class="img-fluid d-block mx-auto" src="https://www.guguweb.com/images/2020/04/vscode_fileexplorer_openfolder_button.png"&gt;&lt;/p&gt;
&lt;p&gt;From the menu choose the directory you want to add to VS Code workspace, that is &lt;em&gt;vscode_example&lt;/em&gt; in our case:&lt;/p&gt;
&lt;p&gt;&lt;img alt="VS Code Open Folder menu" class="img-fluid d-block mx-auto" src="https://www.guguweb.com/images/2020/04/vscode_fileexplorer_openfolder_menu.png"&gt;&lt;/p&gt;
&lt;p&gt;Select the directory and click on “OK”. Now you can browse the remote files in the VS Code file explorer!&lt;/p&gt;
&lt;p&gt;Open the &lt;em&gt;todo/view.py&lt;/em&gt; file and add the following code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.http&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;HttpResponse&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;random&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;choice&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;random_todo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;todo_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s1"&gt;&amp;#39;Buy milk&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;&amp;#39;Clean the room&amp;#39;&lt;/span&gt;
        &lt;span class="s1"&gt;&amp;#39;Write tutorial&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;&amp;#39;Read books&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;choice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;todo_list&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then open the &lt;em&gt;vscode_example/urls.py&lt;/em&gt; file and edit like this to add a route to the view:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.contrib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;admin&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.urls&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;todo.views&lt;/span&gt;

&lt;span class="n"&gt;urlpatterns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;admin/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;todo/random/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;todo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;views&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;random_todo&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now you can return to the terminal and restart the Django development server:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;(&lt;/span&gt;vscode-example-env&lt;span class="o"&gt;)&lt;/span&gt; vagrant@vagrant:~$ ./manage.py runserver
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Check that the virtualenv is active before running the server. Also check that the port 8000 is mapped in the VS Code “Remote explorer” left pane, as seen previously.&lt;/p&gt;
&lt;p&gt;Open your web browser and go to the newly created url at &lt;em&gt;http://localhost:8000/todo/random/&lt;/em&gt;. You should see a randomly chosen todo item. Try to refresh the page a couple of times, and then a bug will show up:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Django buggy view" class="img-fluid d-block mx-auto" src="https://www.guguweb.com/images/2020/04/django_buggy_view.png"&gt;&lt;/p&gt;
&lt;p&gt;There is something wrong in our todo list! Of course you can spot the bug quite easily in our toy project, but why don&amp;#8217;t leverage a full featured debugger in VS Code to check what&amp;#8217;s going on?&lt;/p&gt;
&lt;h3 id="debugging-in-vs-code"&gt;Debugging in VS Code&lt;/h3&gt;
&lt;p&gt;Stop the Django development server with CTRL-C and click on the VS Code “&amp;#8221;Run” left pane. There you&amp;#8217;ll see a &lt;em&gt;create a launch.json file&lt;/em&gt; link.&lt;/p&gt;
&lt;p&gt;&lt;img alt="VS Code create launch.json file" class="img-fluid d-block mx-auto" src="https://www.guguweb.com/images/2020/04/vscode_run_create_launch.png"&gt;&lt;/p&gt;
&lt;p&gt;Click on the link and select &lt;em&gt;More…&lt;/em&gt; from the menu. You can then install the Python extension on remote server by clicking on &lt;strong&gt;Install in SSH: localhost&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="VS Code install Python remote extension" class="img-fluid d-block mx-auto" src="https://www.guguweb.com/images/2020/04/vscode_install_python_remote_extension.png"&gt;&lt;/p&gt;
&lt;p&gt;The remote extension will install and you&amp;#8217;ll have to reload the VS Code window to activate it.&lt;/p&gt;
&lt;p&gt;Go back to the Run left pane and click on &lt;em&gt;create a launch.json file&lt;/em&gt; link again. This time you&amp;#8217;ll see a Django item in the menu. Click on it.&lt;/p&gt;
&lt;p&gt;&lt;img alt="VS Code run Django debug" class="img-fluid d-block mx-auto" src="https://www.guguweb.com/images/2020/04/vscode_run_django_debug.png"&gt;&lt;/p&gt;
&lt;p&gt;A &lt;em&gt;launch.json&lt;/em&gt; file will open in VS Code. You&amp;#8217;ll only have to add the path to your virtualenv, by adding a &lt;code&gt;pythonPath&lt;/code&gt; entry in the configuration.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Use IntelliSense to learn about possible attributes.&lt;/span&gt;
    &lt;span class="c1"&gt;// Hover to view descriptions of existing attributes.&lt;/span&gt;
    &lt;span class="c1"&gt;// For more info, visit: https://go.microsoft.com/fwlink/?linkid=830387&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;version&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;0.2.0&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;configurations&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Python: Django&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s2"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;python&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s2"&gt;&amp;quot;request&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;launch&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s2"&gt;&amp;quot;pythonPath&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/home/vagrant/vscode-example-env/bin/python&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s2"&gt;&amp;quot;program&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${workspaceFolder}/manage.py&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s2"&gt;&amp;quot;args&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="s2"&gt;&amp;quot;runserver&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s2"&gt;&amp;quot;--noreload&amp;quot;&lt;/span&gt;
            &lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="s2"&gt;&amp;quot;django&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now you can run the project for remote debugging in VS Code by hitting F5. Go to the &lt;em&gt;todo/views.py&lt;/em&gt; file and add a breakpoint on line 13:&lt;/p&gt;
&lt;p&gt;&lt;img alt="VS Code add breakpoint" class="img-fluid d-block mx-auto" src="https://www.guguweb.com/images/2020/04/vscode_breakpoint.png"&gt;&lt;/p&gt;
&lt;p&gt;Then try to reload the &lt;code&gt;http://localhost:8000/todo/random/&lt;/code&gt; page. You&amp;#8217;ll see that execution will block and you&amp;#8217;ll be able to inspect variables in VS Code:&lt;/p&gt;
&lt;p&gt;&lt;img alt="VS Code inspect variables" class="img-fluid d-block mx-auto" src="https://www.guguweb.com/images/2020/04/vscode_debug_variables.png"&gt;&lt;/p&gt;
&lt;p&gt;In this simple case the bug was a missing comma in the &lt;code&gt;todo_list&lt;/code&gt; definition.&lt;/p&gt;
&lt;p&gt;That was a trivial bug in a simple project, but imagine to leverage the power of VS Code debugger in a real project running remotely. Now you learned all the tools needed to accomplish this task and make your remote debugging easier.&lt;/p&gt;
&lt;h2 id="2-remote-debugging-on-a-docker-container"&gt;2. Remote Debugging on a Docker Container&lt;/h2&gt;
&lt;p&gt;Remote debugging can be useful also on another common scenario: debugging a project while running in a Docker container.&lt;/p&gt;
&lt;p&gt;Suppose that your team uses a Docker container to have a common and established development environment. You can leverage VS Code &lt;em&gt;Remote &amp;#8211; Containers&lt;/em&gt; extension to build and run the container and attach to it for remote debugging.&lt;/p&gt;
&lt;p&gt;I assume that you have some basic knowledge on how to obtain a Docker image and run it either by using Docker command line or VS Code Docker extension. If you need more information you can refer to &lt;a href="https://code.visualstudio.com/docs/containers/overview"&gt;this tutorial&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="install-docker"&gt;Install Docker&lt;/h3&gt;
&lt;p&gt;You have to install Docker to follow this tutorial. If you are on Windows or Mac you can install &lt;a href="https://www.docker.com/products/docker-desktop"&gt;Docker Desktop&lt;/a&gt;. If you are on Linux you can install Docker using your distribution package manager.&lt;/p&gt;
&lt;h3 id="install-the-vs-code-extension_1"&gt;Install the VS Code Extension&lt;/h3&gt;
&lt;p&gt;The next step is to install the &lt;em&gt;Remote &amp;#8211; Containers&lt;/em&gt; extension from the VS Code marketplace. Go to the &lt;em&gt;Extensions&lt;/em&gt; section in VS Code and install the extension from there:&lt;/p&gt;
&lt;p&gt;&lt;img alt="VS Code remote containers extension" class="img-fluid d-block mx-auto" src="https://www.guguweb.com/images/2020/04/vscode_remote_containers_install.png"&gt;&lt;/p&gt;
&lt;p&gt;If the extension has been installed correctly you will see a new green icon in the bottom left corner of the VS Code window.&lt;/p&gt;
&lt;p&gt;Clicking on the green icon will bring up the &lt;code&gt;Remote - Containers&lt;/code&gt; commands.&lt;/p&gt;
&lt;h3 id="an-example-container-for-your-project"&gt;An Example Container for Your Project&lt;/h3&gt;
&lt;p&gt;In this tutorial you&amp;#8217;ll clone an example project container from a Git repository. That container uses the same example Django application seen in previous section of this tutorial. It will serve as a starting point to see how you can build, run and perform remote debugging on a Python project running in a Docker container.&lt;/p&gt;
&lt;p&gt;Clone the repository using Git:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git clone https://github.com/baxeico/vscode_django_container.git
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Go into the &lt;em&gt;vscodedjangocontainer&lt;/em&gt; directory and launch VS Code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$ &lt;span class="nb"&gt;cd&lt;/span&gt; vscode_django_container/
$ code .
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;VS Code will notice that this directory contains a configuration for remote containers and it will prompt you to reopen the project in a container:&lt;/p&gt;
&lt;p&gt;&lt;img alt="VS Code reopen in container" class="img-fluid d-block mx-auto" src="https://www.guguweb.com/images/2020/04/vscode_reopen_in_container.png"&gt;&lt;/p&gt;
&lt;p&gt;Click on the &lt;em&gt;Reopen in Container&lt;/em&gt; button and VS Code will build the container and configure the project for remote debugging.&lt;/p&gt;
&lt;h3 id="understanding-devcontainerjson"&gt;Understanding devcontainer.json&lt;/h3&gt;
&lt;p&gt;The &lt;em&gt;Remote Containers&lt;/em&gt; extension will look for a file called &lt;em&gt;devcontainer.json&lt;/em&gt; in the &lt;em&gt;.devcontainer&lt;/em&gt; directory.&lt;/p&gt;
&lt;p&gt;The content of the file will look like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Django container example&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;build&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s2"&gt;&amp;quot;dockerfile&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Dockerfile&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;&amp;quot;context&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;..&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;

    &lt;span class="c1"&gt;// Set *default* container specific settings.json values.&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;settings&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s2"&gt;&amp;quot;terminal.integrated.shell.linux&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/bin/bash&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;&amp;quot;python.pythonPath&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/usr/local/bin/python3&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;

    &lt;span class="c1"&gt;// IDs of extensions you want installed when the container is created.&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;extensions&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s2"&gt;&amp;quot;ms-python.python&amp;quot;&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;

    &lt;span class="c1"&gt;// make a list of ports inside the container available locally.&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;forwardPorts&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;8000&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;

    &lt;span class="c1"&gt;// run commands after the container is created.&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;postCreateCommand&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;pip3 install -r requirements.txt; cd vscode_example; ./manage.py migrate&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In the &lt;code&gt;build&lt;/code&gt; section you can define the parameters used to build the container. In this case you are using a Dockerfile contained in the same directory. The Dockerfile uses the Python3 official image from Docker Hub, without modifications.&lt;/p&gt;
&lt;p&gt;In the &lt;code&gt;settings&lt;/code&gt; section you can define some specific settings for VS Code, when running in the container. Notice how the &lt;em&gt;pythonPath&lt;/em&gt; option is set to the python3 executable path in the Docker image.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;extensions&lt;/code&gt; section will let you define the VS Code extensions you want to install in the container. The &lt;em&gt;ms-python.python&lt;/em&gt; is required to let you debug Python applications.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;forwardPorts&lt;/code&gt; is useful to let you access your application as if it was local, by exposing container ports on the local host. Here you are mapping the 8000 port of the container to the same port of your local host.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;postCreateCommand&lt;/code&gt; is used to install the requirements of the Python application using &lt;em&gt;pip&lt;/em&gt; and to migrate the Django database after the container has been created.&lt;/p&gt;
&lt;p&gt;Here you can find a complete &lt;a href="https://code.visualstudio.com/docs/remote/containers#_devcontainerjson-reference"&gt;devcontainer.json reference&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="debugging-in-vs-code_1"&gt;Debugging in VS Code&lt;/h3&gt;
&lt;p&gt;Clicking on F5 will start the Django application. You can open the browser and point it to &lt;a href="http://localhost:8000/"&gt;&lt;em&gt;http://localhost:8000/&lt;/em&gt;&lt;/a&gt; to see the app running.&lt;/p&gt;
&lt;p&gt;VS Code will let you debug the code, set breakpoints, inspect variables as if the project is running locally.&lt;/p&gt;
&lt;p&gt;As usual, the launch configuration is made in the &lt;em&gt;launch.json&lt;/em&gt; file, inside the &lt;em&gt;.vscode&lt;/em&gt; directory. If you look at the example inside the container it will launch the Django application on port 8000.&lt;/p&gt;
&lt;p&gt;This tutorial used a very simple Django app in a minimal Docker container. Imagine to use your own container and have your team working and remote debugging on it using VS Code.&lt;/p&gt;
&lt;p&gt;All you have to do is to define a proper &lt;em&gt;devcontainer.json&lt;/em&gt; for your environment and use the Docker image of your choice with your configuration.&lt;/p&gt;
&lt;h2 id="3-other-remote-debugging-scenarios"&gt;3. Other Remote Debugging Scenarios&lt;/h2&gt;
&lt;p&gt;There are also other use cases for remote debugging that are covered by other VS Code extensions.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ll not go into much details here, but I think that it&amp;#8217;s useful to know that these extensions exist.&lt;/p&gt;
&lt;h3 id="wsl"&gt;WSL&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://docs.microsoft.com/windows/wsl/install-win10"&gt;Windows Subsystem for Linux&lt;/a&gt; is a feature in Windows 10 that will let you to install a complete Linux distribution (e.g. Ubuntu 18.04) in your local Windows 10 installation. The Linux and Windows installations will be isolated, so you cannot run and debug an application running in WSL directly from VS Code, if running on Windows.&lt;/p&gt;
&lt;p&gt;You need the &lt;a href="https://code.visualstudio.com/remote-tutorials/wsl/getting-started"&gt;Remote WSL&lt;/a&gt; extension to remotely debug your application running in WSL, as it was local.&lt;/p&gt;
&lt;h3 id="liveshare"&gt;LiveShare&lt;/h3&gt;
&lt;p&gt;While technically this feature cannot be considered “remote debugging”, it is worth knowing that VS Code has a &lt;a href="https://docs.microsoft.com/en-us/visualstudio/liveshare/use/vscode"&gt;LiveShare&lt;/a&gt; feature that will let you share a debugging session with one or more colleagues.&lt;/p&gt;
&lt;p&gt;You can think of it as a sort of “video conference” session where one developer is the host and he can share his VS Code window with other people.&lt;/p&gt;
&lt;p&gt;Actually this feature is more powerful than a simple video conference session because for instance you&amp;#8217;ll be able to debug the code concurrently, by inspecting different variables or files independently without having to negotiate control.&lt;/p&gt;
&lt;h2 id="4-conclusion"&gt;4. Conclusion&lt;/h2&gt;
&lt;p&gt;In this tutorial you learned how to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Connect with VS Code to a remote server using SSH and remotely debug a web project.&lt;/li&gt;
&lt;li&gt;Run a Docker container within VS Code and debug a project inside the container.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Using the correct tools you&amp;#8217;ll never resort to wild debugging sessions over SSH using vim or nano. No more &lt;code&gt;print("I'm here")&lt;/code&gt; to catch those nasty bugs! Now you learned how to use a full featured IDE for remote debugging.&lt;/p&gt;
&lt;p&gt;I want to publicly thank &lt;a href="https://twitter.com/gahjelle"&gt;Geir Arne Hjelle&lt;/a&gt; who helped me in shaping up the outline of this tutorial.&lt;/p&gt;</content><category term="web"></category><category term="debug"></category><category term="django"></category><category term="docker"></category><category term="ssh"></category><category term="vscode"></category></entry><entry><title>Optimize Django memory usage</title><link href="https://www.guguweb.com/2020/03/27/optimize-django-memory-usage/" rel="alternate"></link><published>2020-03-27T16:55:31+00:00</published><updated>2022-01-14T20:57:05+01:00</updated><author><name>Augusto Destrero</name></author><id>tag:www.guguweb.com,2020-03-27:/2020/03/27/optimize-django-memory-usage/</id><summary type="html">&lt;p&gt;Django memory usage is usually quote good, but sometimes &amp;#8211; if you use the Django ORM without really knowing what is doing behind the scenes &amp;#8211; you can see a huge spike in RAM usage. Fortunately there exist some simple methods to optimize Django memory usage.&lt;/p&gt;
&lt;div class="toc"&gt;&lt;span class="toctitle"&gt;Table of Contents&lt;/span&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#1-the-problem"&gt;1. The problem …&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;Django memory usage is usually quote good, but sometimes &amp;#8211; if you use the Django ORM without really knowing what is doing behind the scenes &amp;#8211; you can see a huge spike in RAM usage. Fortunately there exist some simple methods to optimize Django memory usage.&lt;/p&gt;
&lt;div class="toc"&gt;&lt;span class="toctitle"&gt;Table of Contents&lt;/span&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#1-the-problem"&gt;1. The problem&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#2-a-bit-of-django-memory-profiling"&gt;2. A bit of Django memory profiling&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#3-optimize-django-memory-usage-using-iterator-method"&gt;3. Optimize Django memory usage: using iterator() method&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#4-optimize-django-memory-usage-using-pagination"&gt;4. Optimize Django memory usage: using pagination&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#5-conclusion"&gt;5. Conclusion&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id="1-the-problem"&gt;1. The problem&lt;/h2&gt;
&lt;p&gt;Consider this is the apparently innocent view&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.http&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;HttpResponse&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;.models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FirstModel&lt;/span&gt;

&lt;span class="c1"&gt;# this view will make crazy use of the RAM ;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# this queryset contains about 100k records&lt;/span&gt;
    &lt;span class="c1"&gt;# each of them has many ForeignKeys to other models&lt;/span&gt;
    &lt;span class="n"&gt;huge_queryset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FirstModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;dumb.dump&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;w&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;huge_queryset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;

    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Dumb dump completed!&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;as you can see it&amp;#8217;s very simple, the peculiarity here is the dimension of the queryset, because the table contains about 100k records, and each record has several ForeignKey fields to other models.&lt;/p&gt;
&lt;p&gt;An experienced Django developer should immediately see the problem, but it can be interesting to analyze the problem a little bit more.&lt;/p&gt;
&lt;p&gt;If you are impatient, &lt;a href="#solution"&gt;go directly to my solution.&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="2-a-bit-of-django-memory-profiling"&gt;2. A bit of Django memory profiling&lt;/h2&gt;
&lt;p&gt;When you want to profile memory usage in Python you&amp;#8217;ll find &lt;a href="https://pypi.python.org/pypi/guppy/" target="_blank" rel="noopener noreferrer"&gt;some&lt;/a&gt; &lt;a href="https://pypi.python.org/pypi/Pympler" target="_blank" rel="noopener noreferrer"&gt;useful&lt;/a&gt; &lt;a href="https://pypi.python.org/pypi/meliae" target="_blank" rel="noopener noreferrer"&gt;tools.&lt;/a&gt; I choose to use &lt;a title="Objgraph tool" href="http://mg.pov.lt/objgraph/#memory-leak-example" target="_blank" rel="noopener noreferrer"&gt;objgraph&lt;/a&gt;. The only drawback is that objgraph is designed to work in a python console, while my code is running in a Django powered website.&lt;/p&gt;
&lt;p&gt;So I put together some code to redirect the standard output used by objgraph to my beloved Django logging system, and here is the result.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;objgraph&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;logging&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.http&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;HttpResponse&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;.models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FirstModel&lt;/span&gt;

&lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vm"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LoggerWriter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;LoggerWriter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;huge_queryset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FirstModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;dumb.dump&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;w&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;huge_queryset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;
        &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;objgraph&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;show_growth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Dumb dump completed!&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In the Django log I saw something like this (I cut from the log some internal objects not so interesting in this example):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;[24/09/2014 10:35:31] DEBUG [leaky_app.views:31] dict 106524 +106524
[24/09/2014 10:35:31] DEBUG [leaky_app.views:31] ModelState 101328 +101328
[24/09/2014 10:35:31] DEBUG [leaky_app.views:31] FirstModel 98327 +98327

[24/09/2014 10:36:23] DEBUG [leaky_app.views:31] dict 109526 +3002
[24/09/2014 10:36:23] DEBUG [leaky_app.views:31] ModelState 104329 +3001
[24/09/2014 10:36:23] DEBUG [leaky_app.views:31] SecondModel 1999 +1000
[24/09/2014 10:36:23] DEBUG [leaky_app.views:31] ThirdModel 1999 +1000
[24/09/2014 10:36:23] DEBUG [leaky_app.views:31] FourthModel 2000 +1000

[24/09/2014 10:37:17] DEBUG [leaky_app.views:31] dict 112874 +3348
[24/09/2014 10:37:17] DEBUG [leaky_app.views:31] ModelState 107330 +3001
[24/09/2014 10:37:17] DEBUG [leaky_app.views:31] FourthModel 3000 +1000
[24/09/2014 10:37:17] DEBUG [leaky_app.views:31] SecondModel 2999 +1000
[24/09/2014 10:37:17] DEBUG [leaky_app.views:31] ThirdModel 2999 +1000
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;FirstModel has some ForeignKey fields to SecondModel, ThirdModel and so on. That means that every 1000 row three different objects are loaded in memory. But why Django is putting all those objects in memory? After all I want only to write a record in my dumb.dump file.&lt;/p&gt;
&lt;p id="solution"&gt;
  It turns out that Django caches the results of each queryset, when you iterate over it. Each and every object in the queryset will be saved in memory. This lets the ORM to access the queryset again very efficiently, without the need to hit the database again.
&lt;/p&gt;

&lt;h2 id="3-optimize-django-memory-usage-using-iterator-method"&gt;3. Optimize Django memory usage: using iterator() method&lt;/h2&gt;
&lt;p&gt;You can avoid caching and simply iterate over a queryset using the &lt;a href="https://docs.djangoproject.com/en/3.2/ref/models/querysets/#iterator" target="_blank" rel="noopener noreferrer"&gt;iterator&lt;/a&gt; method on the queryset. The Django documentation clearly states:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;#8220;For a QuerySet which returns a large number of objects that you only need to access once, this can result in better performance and a significant reduction in memory.&amp;#8221;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So the first solution to the problem is simply adding &lt;code&gt;.iterator()&lt;/code&gt; to the iterated queryset, like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.http&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;HttpResponse&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;.models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FirstModel&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# this queryset contains about 100k records&lt;/span&gt;
    &lt;span class="c1"&gt;# each of them has many ForeignKeys to other models&lt;/span&gt;
    &lt;span class="n"&gt;huge_queryset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FirstModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iterator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;dumb.dump&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;w&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;huge_queryset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;

    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Dumb dump completed!&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="4-optimize-django-memory-usage-using-pagination"&gt;4. Optimize Django memory usage: using pagination&lt;/h2&gt;
&lt;p&gt;Even using &lt;code&gt;iterator()&lt;/code&gt; the data is first fetched on the client side by the database driver, occupying a lot of memory. This happens because Django doesn&amp;#8217;t yet support &lt;a href="https://code.djangoproject.com/ticket/16614" target="_blank" rel="noopener noreferrer"&gt;server side cursors&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A workaround for this issue is using an utility function like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;gc&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;queryset_iterator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;batchsize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gc_collect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;iterator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;qs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;values_list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;pk&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flat&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;order_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;pk&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;distinct&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iterator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;eof&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;eof&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;primary_key_buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;primary_key_buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;batchsize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;primary_key_buffer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iterator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;StopIteration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;eof&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;qs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pk__in&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;primary_key_buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;order_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;pk&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iterator&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;gc_collect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;gc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;collect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can use simply by passing a normal Django queryset as the single parameter, like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;queryset_iterator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HugeQueryset&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;()):&lt;/span&gt;
   &lt;span class="c1"&gt;# do something with obj&lt;/span&gt;
   &lt;span class="k"&gt;pass&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is useful when you want to delete an high number of objects that have a ForeignKey pointing to them. In that case using the Queryset &lt;code&gt;.delete()&lt;/code&gt; method doesn&amp;#8217;t help because Django has to fetch each object in memory to handle the &lt;a href="https://docs.djangoproject.com/en/3.2/ref/models/fields/#django.db.models.ForeignKey.on_delete" target="_blank" rel="noopener noreferrer"&gt;deletion cascade policy&lt;/a&gt; given for the objects being deleted. You can do something like this to mitigate that effect:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;queryset_iterator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HugeQueryset&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;()):&lt;/span&gt;
   &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="5-conclusion"&gt;5. Conclusion&lt;/h2&gt;
&lt;p&gt;In this tutorial you learned how to optimize Django memory usage, especially when dealing with large querysets. Django ORM is really powerful and the abstraction it provides will let you write complex queries easily. But you have to be careful when using the ORM with large querysets because the effects on memory and CPU usage can be large as well.&lt;/p&gt;</content><category term="web"></category><category term="django"></category><category term="memleak"></category></entry><entry><title>Bitbucket Pipelines and Ansible: Continuous delivery for your Django project</title><link href="https://www.guguweb.com/2020/01/03/bitbucket-pipelines-and-ansible-continuous-delivery-for-your-django-project/" rel="alternate"></link><published>2020-01-03T08:33:41+00:00</published><updated>2022-01-14T21:08:18+01:00</updated><author><name>Augusto Destrero</name></author><id>tag:www.guguweb.com,2020-01-03:/2020/01/03/bitbucket-pipelines-and-ansible-continuous-delivery-for-your-django-project/</id><summary type="html">&lt;p class="lead"&gt;
  &amp;#8220;Bitbucket Pipelines and Ansible: Continuous delivery for your Django project&amp;#8221; was originally published as a guest post on &lt;a href="https://bitbucket.org/blog/continuous-delivery-for-django-projects-with-bitbucket-pipelines-and-ansible"&gt;Bitbucket Blog&lt;/a&gt;.
&lt;/p&gt;

&lt;div class="toc"&gt;&lt;span class="toctitle"&gt;Table of Contents&lt;/span&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#introduction"&gt;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#let-the-automation-begin"&gt;Let the automation begin!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#setup-your-pipelines"&gt;Setup your pipelines&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#conclusion"&gt;Conclusion&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id="introduction"&gt;Introduction&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.ansible.com/"&gt;Ansible&lt;/a&gt; is a powerful tool for the automation of your server administration. It can be used both …&lt;/p&gt;</summary><content type="html">&lt;p class="lead"&gt;
  &amp;#8220;Bitbucket Pipelines and Ansible: Continuous delivery for your Django project&amp;#8221; was originally published as a guest post on &lt;a href="https://bitbucket.org/blog/continuous-delivery-for-django-projects-with-bitbucket-pipelines-and-ansible"&gt;Bitbucket Blog&lt;/a&gt;.
&lt;/p&gt;

&lt;div class="toc"&gt;&lt;span class="toctitle"&gt;Table of Contents&lt;/span&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#introduction"&gt;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#let-the-automation-begin"&gt;Let the automation begin!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#setup-your-pipelines"&gt;Setup your pipelines&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#conclusion"&gt;Conclusion&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id="introduction"&gt;Introduction&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.ansible.com/"&gt;Ansible&lt;/a&gt; is a powerful tool for the automation of your server administration. It can be used both to install and configure the software needed for your application and to deploy a new version of your application.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://bitbucket.org/product/features/pipelines"&gt;Bitbucket Pipelines&lt;/a&gt; are basically Docker containers, hosted in the Bitbucket infrastructure, that you can launch automatically to build or deploy your code. They can be attached to “events” happening in your repository, usually a push on one branch.&lt;/p&gt;
&lt;p&gt;These tools are complementary to each other, because on Ansible you can define exactly what you want to do on your target server to deploy your application, while on Bitbucket Pipelines you can configure and launch a container to perform the actual deploy.&lt;/p&gt;
&lt;p&gt;In a previous post I described &lt;a href="https://www.guguweb.com/2017/05/02/how-to-deploy-a-django-project-in-15-minutes-with-ansible/"&gt;how to deploy a Django project using Ansible&lt;/a&gt;. Here I explain how to make a step further and deploy a Django project using &lt;a href="https://bitbucket.org/product/features/pipelines"&gt;Bitbucket Pipelines&lt;/a&gt; and &lt;a href="https://www.ansible.com/"&gt;Ansible&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The use-cases for deploying a Django project automatically are many. Even if your Django project has a simple architecture, there are many steps you have to perform in the right order to complete a successful deploy in the general case. As a bare minimum you&amp;#8217;ll have to: update the application code, install or update project dependencies, migrate the database, collect static files, restart the application server.&lt;/p&gt;
&lt;p&gt;Automating all these steps in a reproducible and formal way will save you a lot of time in the long run and will help you to avoid human errors. Think about how many times you&amp;#8217;ll deploy a new version of your application in the future.&lt;/p&gt;
&lt;p&gt;If your architecture is more complex, the number of steps to perform will be larger and the deploy process will be more error-prone, so the benefits of an automated deploy will be even greater.&lt;/p&gt;
&lt;h2 id="let-the-automation-begin"&gt;Let the automation begin!&lt;/h2&gt;
&lt;p&gt;You can clone or fork &lt;a href="https://bitbucket.org/baxeico/django_ansible"&gt;this Bitbucket repository&lt;/a&gt; to follow along with this tutorial.&lt;/p&gt;
&lt;p&gt;First thing first, add a file named &lt;strong&gt;bitbucket-pipelines.yml&lt;/strong&gt; to the root of your repository. The content of the file should be similar to this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# use the official Python 2.7.16 docker image&lt;/span&gt;
&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="l l-Scalar l-Scalar-Plain"&gt;python:2.7.16&lt;/span&gt;

&lt;span class="nt"&gt;pipelines&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="nt"&gt;branches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# deploy only when pushing to the master branch&lt;/span&gt;
    &lt;span class="nt"&gt;master&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="p p-Indicator"&gt;-&lt;/span&gt; &lt;span class="nt"&gt;step&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
          &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="l l-Scalar l-Scalar-Plain"&gt;Deploy to prod&lt;/span&gt;
          &lt;span class="c1"&gt;# this is the name of the Bitbucket Deployment&lt;/span&gt;
          &lt;span class="nt"&gt;deployment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="l l-Scalar l-Scalar-Plain"&gt;Production&lt;/span&gt;
          &lt;span class="nt"&gt;caches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# cache the Ansible installation&lt;/span&gt;
            &lt;span class="p p-Indicator"&gt;-&lt;/span&gt; &lt;span class="l l-Scalar l-Scalar-Plain"&gt;pip&lt;/span&gt;
          &lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# install Ansible&lt;/span&gt;
            &lt;span class="p p-Indicator"&gt;-&lt;/span&gt; &lt;span class="l l-Scalar l-Scalar-Plain"&gt;pip install ansible==2.8.0&lt;/span&gt;
            &lt;span class="c1"&gt;# go into the ansible directory&lt;/span&gt;
            &lt;span class="c1"&gt;# in this same repository&lt;/span&gt;
            &lt;span class="p p-Indicator"&gt;-&lt;/span&gt; &lt;span class="l l-Scalar l-Scalar-Plain"&gt;cd ansible&lt;/span&gt;
            &lt;span class="c1"&gt;# perform the actual deploy&lt;/span&gt;
            &lt;span class="p p-Indicator"&gt;-&lt;/span&gt; &lt;span class="l l-Scalar l-Scalar-Plain"&gt;ansible-playbook -i ./hosts deploy.yaml&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Let&amp;#8217;s examine the configuration line by line:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;On line &lt;strong&gt;2&lt;/strong&gt; you define the docker image you want to use;&lt;/li&gt;
&lt;li&gt;On line &lt;strong&gt;7&lt;/strong&gt; you define the branch that will trigger the deploy (&lt;em&gt;master&lt;/em&gt; in this example);&lt;/li&gt;
&lt;li&gt;On line &lt;strong&gt;11&lt;/strong&gt; you define the deployment, that is basically an environment (managed by Bitbucket) where you can define some variables. In this way you can have different deployments (staging, production, &amp;#8230;) with different variables that you can use in your build/deploy steps. In this example I do not use this feature, and I merely use one of the default Bitbucket deployments (named &lt;em&gt;Production&lt;/em&gt;) without configuring any variable in this environment;&lt;/li&gt;
&lt;li&gt;On line &lt;strong&gt;14&lt;/strong&gt; you are asking Bitbucket to cache the installation of packages installed by pip. This is useful to avoid to reinstall every time the Python libraries you need for your deployment (Ansible 2.8.0 in this example) from scratch. The build time for Bitbucket Pipelines is limited to &lt;strong&gt;50 minutes/month in the free plan&lt;/strong&gt;, so it&amp;#8217;s important to have the libraries already installed to save some build/deploy time.&lt;/li&gt;
&lt;li&gt;From line &lt;strong&gt;16&lt;/strong&gt; to line &lt;strong&gt;22&lt;/strong&gt; you define the actual steps for deployment: install Ansible (if not already cached), go into the &lt;em&gt;ansible&lt;/em&gt; directory, make the deploy. Please check the playbook &lt;em&gt;ansible/deploy.yaml&lt;/em&gt; to see what it will actually do on the target server.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ansible will perform the actual deploy by:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;pulling the &lt;em&gt;master&lt;/em&gt; branch from your Git repository;&lt;/li&gt;
&lt;li&gt;installing all needed production requirements;&lt;/li&gt;
&lt;li&gt;running Django migrate and collectstatic commands;&lt;/li&gt;
&lt;li&gt;restarting the application server uwsgi.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Please check the Ansible playbook &lt;em&gt;ansible/deploy.yaml&lt;/em&gt; to see what it will actually do on the target server in details.&lt;/p&gt;
&lt;p&gt;Commit and push the &lt;strong&gt;bitbucket-pipelines.yml&lt;/strong&gt; file on the root of your Bitbucket repository.&lt;/p&gt;
&lt;h2 id="setup-your-pipelines"&gt;Setup your pipelines&lt;/h2&gt;
&lt;p&gt;Now go on your repository settings and click &lt;em&gt;Settings&lt;/em&gt; under the section &lt;em&gt;PIPELINES&lt;/em&gt;:&lt;/p&gt;
&lt;div class="d-flex"&gt;
    &lt;figure class="figure mx-auto"&gt;
        &lt;img src="/images/2019/05/thumbnails/800x_/pipelines_settings2.png" class="figure-img img-fluid rounded" alt="Pipelines settings"&gt;
        &lt;figcaption class="figure-caption text-center"&gt;Pipelines settings&lt;/figcaption&gt;
    &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;Now click on &lt;em&gt;Enable Pipelines&lt;/em&gt;:&lt;/p&gt;
&lt;div class="d-flex"&gt;
    &lt;figure class="figure mx-auto"&gt;
        &lt;img src="/images/2019/05/thumbnails/800x_/pipelines_settings3.png" class="figure-img img-fluid rounded" alt="Pipelines settings"&gt;
        &lt;figcaption class="figure-caption text-center"&gt;Pipelines settings&lt;/figcaption&gt;
    &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;If you have read my previous post on &lt;a href="https://www.guguweb.com/2017/05/02/how-to-deploy-a-django-project-in-15-minutes-with-ansible/"&gt;how to deploy a Django project using Ansible&lt;/a&gt;, you should know that Ansible work through an SSH connection made between the client host (the Bitbucket Pipeline docker container in this case) and the server where you want to deploy your code.&lt;/p&gt;
&lt;p&gt;For this SSH connection to work you have to setup an SSH public/private keypair on the Bitbucket Pipeline, and allow the public key on your server authorized_keys.&lt;/p&gt;
&lt;p&gt;Go on the settings of your repository, under PIPELINES navigate to SSH keys:&lt;/p&gt;
&lt;div class="d-flex"&gt;
    &lt;figure class="figure mx-auto"&gt;
        &lt;img src="/images/2019/05/thumbnails/800x_/pipelines_settings.png" class="figure-img img-fluid rounded" alt="Pipelines settings"&gt;
        &lt;figcaption class="figure-caption text-center"&gt;Pipelines settings&lt;/figcaption&gt;
    &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;Now click on &amp;#8220;Generate keys&amp;#8221; to let Bitbucket generate a new SSH keypair for you.&lt;/p&gt;
&lt;div class="d-flex"&gt;
    &lt;figure class="figure mx-auto"&gt;
        &lt;img src="/images/2019/05/thumbnails/800x_/pipelines_settings4.png" class="figure-img img-fluid rounded" alt="Pipelines settings"&gt;
        &lt;figcaption class="figure-caption text-center"&gt;Pipelines settings&lt;/figcaption&gt;
    &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;Now you can copy the generated public key and paste it in the &lt;em&gt;.ssh/authorized_keys&lt;/em&gt; file of your deploy target.&lt;/p&gt;
&lt;div class="d-flex"&gt;
    &lt;figure class="figure mx-auto"&gt;
        &lt;img src="/images/2019/05/thumbnails/800x_/pipelines_settings5.png" class="figure-img img-fluid rounded" alt="Pipelines settings"&gt;
        &lt;figcaption class="figure-caption text-center"&gt;Pipelines settings&lt;/figcaption&gt;
    &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;You&amp;#8217;ll also have to add your server fingerprint to the Known hosts section in the same page. Insert your target server hostname in the &amp;#8220;Host address&amp;#8221; field, press the &amp;#8220;Fetch&amp;#8221; button and finally the &amp;#8220;Add host&amp;#8221; button.&lt;/p&gt;
&lt;div class="d-flex"&gt;
    &lt;figure class="figure mx-auto"&gt;
        &lt;img src="/images/2019/09/thumbnails/800x_/bitbucket_known_hosts.png" class="figure-img img-fluid rounded" alt="Known hosts settings"&gt;
        &lt;figcaption class="figure-caption text-center"&gt;Known hosts settings&lt;/figcaption&gt;
    &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;You can refer to the &lt;a href="https://confluence.atlassian.com/bitbucket/use-ssh-keys-in-bitbucket-pipelines-847452940.html"&gt;Bitbucket documentation about SSH keys&lt;/a&gt;, if you need more details.&lt;/p&gt;
&lt;p&gt;You can test that the deploy is working simply by pushing some changes to the &lt;em&gt;master&lt;/em&gt; branch of the repository&lt;/p&gt;
&lt;p&gt;If you want to push some changes on &lt;em&gt;master&lt;/em&gt;, but you &lt;strong&gt;do not want&lt;/strong&gt; to deploy the change automatically on the server, you can put the string &lt;em&gt;[skip-ci]&lt;/em&gt; in your commit message.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this tutorial I explained a simple yet powerful setup for the continuous delivery of a Django project. This is only a little example of what you can do with Bitbucket Pipelines and Ansible, but I hope that this  helped you to understand the great potential of these technologies.&lt;/p&gt;
&lt;p&gt;I think that learning and implementing this kind of automation in your projects is always worth the effort. Time saved and less human errors in the deploy process will make a big difference in the long run.&lt;/p&gt;</content><category term="sysadmin"></category><category term="ansible"></category><category term="bitbucket"></category><category term="continuous delivery"></category><category term="devops"></category><category term="django"></category><category term="docker"></category><category term="git"></category></entry><entry><title>Automate your Telegram channel with a Django Telegram Bot</title><link href="https://www.guguweb.com/2019/12/09/automate-your-telegram-channel-with-a-django-telegram-bot/" rel="alternate"></link><published>2019-12-09T17:45:14+00:00</published><updated>2022-01-26T14:53:25+01:00</updated><author><name>Augusto Destrero</name></author><id>tag:www.guguweb.com,2019-12-09:/2019/12/09/automate-your-telegram-channel-with-a-django-telegram-bot/</id><summary type="html">&lt;p&gt;In this post I will guide you in a very interesting and funny development task: automate your Telegram channel with a Django Telegram Bot.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://telegram.org/"&gt;Telegram&lt;/a&gt; is a popular instant messaging application. It&amp;#8217;s not as widespread as Whatsapp, but its user base is constantly growing and according to &lt;a href="https://en.wikipedia.org/wiki/Telegram_(software)"&gt;Wikipedia&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The …&lt;/p&gt;&lt;/blockquote&gt;</summary><content type="html">&lt;p&gt;In this post I will guide you in a very interesting and funny development task: automate your Telegram channel with a Django Telegram Bot.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://telegram.org/"&gt;Telegram&lt;/a&gt; is a popular instant messaging application. It&amp;#8217;s not as widespread as Whatsapp, but its user base is constantly growing and according to &lt;a href="https://en.wikipedia.org/wiki/Telegram_(software)"&gt;Wikipedia&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The number of monthly Telegram users as of October 2019 is 300 million people worldwide&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A very interesting aspect of the Telegram platform is the ability to create &lt;a href="https://telegram.org/faq_channels"&gt;channels&lt;/a&gt; and &lt;a href="https://core.telegram.org/bots"&gt;bots&lt;/a&gt; to automate the broadcasting of messages to large audiences. These features open the possibility to better engage your users using Telegram, for example by sending them news, offers, etc. all from your existing Django web project! Let&amp;#8217;s see how to do it.&lt;/p&gt;
&lt;div class="toc"&gt;&lt;span class="toctitle"&gt;Table of Contents&lt;/span&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#1-create-a-telegram-channel"&gt;1. Create a Telegram channel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#2-create-a-telegram-bot"&gt;2. Create a Telegram Bot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#3-make-the-bot-an-admin-for-your-telegram-channel"&gt;3. Make the bot an Admin for your Telegram channel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#4-install-python-telegram-bot"&gt;4. Install python-telegram-bot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#5-edit-your-django-settings-to-add-telegram-parameters"&gt;5. Edit your Django settings to add Telegram parameters&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#6-send-a-message-to-the-channel-from-your-django-code"&gt;6. Send a message to the channel from your Django code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#7-conclusions"&gt;7. Conclusions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#8-do-you-want-more-power-for-your-django-telegram-bot"&gt;8. Do you want more power for your Django Telegram bot?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id="1-create-a-telegram-channel"&gt;1. Create a Telegram channel&lt;/h2&gt;
&lt;p&gt;Nothing special here: you can do this from the Telegram app on your phone. Just tap &amp;#8220;New Channel&amp;#8221; on the Telegram main menu. Choose a nice name and a clear description.&lt;/p&gt;
&lt;div class="d-flex"&gt;
    &lt;figure class="figure mx-auto"&gt;
        &lt;img src="/images/2019/12/thumbnails/400x_/channel_create.png" class="figure-img img-fluid rounded" alt="Create the Telegram channel"&gt;
        &lt;figcaption class="figure-caption text-center"&gt;Create the Telegram channel&lt;/figcaption&gt;
    &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;Then setup the channel as Public and choose a nice &amp;#8220;permalink&amp;#8221; for your channel:&lt;/p&gt;
&lt;div class="d-flex"&gt;
    &lt;figure class="figure mx-auto"&gt;
        &lt;img src="/images/2019/12/thumbnails/400x_/channel_settings.png" class="figure-img img-fluid rounded" alt="Setup the Telegram channel"&gt;
        &lt;figcaption class="figure-caption text-center"&gt;Setup the Telegram channel&lt;/figcaption&gt;
    &lt;/figure&gt;
&lt;/div&gt;

&lt;h2 id="2-create-a-telegram-bot"&gt;2. Create a Telegram Bot&lt;/h2&gt;
&lt;p&gt;Now the funny part begins: search for a contact named &amp;#8220;BotFather&amp;#8221; on Telegram&lt;/p&gt;
&lt;div class="d-flex"&gt;
    &lt;figure class="figure mx-auto"&gt;
        &lt;img src="/images/2019/12/thumbnails/400x_/botfather_search.png" class="figure-img img-fluid rounded" alt="Search for BotFather"&gt;
        &lt;figcaption class="figure-caption text-center"&gt;Search for BotFather&lt;/figcaption&gt;
    &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;This is a bot to manage bots, a sort of meta-bot. 🙂 Start a chat with him and write &lt;strong&gt;/help&lt;/strong&gt; to know what are the available commands. To create a new bot you have to write the command &lt;strong&gt;/newbot&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The BotFather will ask you a couple of questions to setup your bot. Basically you&amp;#8217;ll have to choose a &amp;#8220;display name&amp;#8221; and a username for your bot.&lt;/p&gt;
&lt;div class="d-flex"&gt;
    &lt;figure class="figure mx-auto"&gt;
        &lt;img src="/images/2019/12/thumbnails/400x_/bot_create.png" class="figure-img img-fluid rounded" alt="Create the Telegram bot"&gt;
        &lt;figcaption class="figure-caption text-center"&gt;Create the Telegram bot&lt;/figcaption&gt;
    &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;As you can see in the screenshot above, the BotFather will write you a token that you should save and &lt;strong&gt;keep secret&lt;/strong&gt;. This token will be used to interact with your bot using the &lt;a href="https://core.telegram.org/bots/api"&gt;Telegram Bot API&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can also set a description, an about text and even a nice profile picture for your bot; for example &lt;a href="https://pixabay.com/it/illustrations/bot-icona-robot-automatizzato-2883144/"&gt;something like this&lt;/a&gt;. &lt;strong&gt;/help&lt;/strong&gt; command is your friend to find out how you can do these things.&lt;/p&gt;
&lt;h2 id="3-make-the-bot-an-admin-for-your-telegram-channel"&gt;3. Make the bot an Admin for your Telegram channel&lt;/h2&gt;
&lt;p&gt;Your bot will be used to automatically post messages on your channel, so you have to add the bot to the group of channel&amp;#8217;s administrators. Tap on the channel&amp;#8217;s name and then on &lt;strong&gt;Administrators&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="d-flex"&gt;
    &lt;figure class="figure mx-auto"&gt;
        &lt;img src="/images/2019/12/thumbnails/400x_/edit_channel.png" class="figure-img img-fluid rounded" alt="Edit the Telegram channel"&gt;
        &lt;figcaption class="figure-caption text-center"&gt;Edit the Telegram channel&lt;/figcaption&gt;
    &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;Then on &lt;strong&gt;Add Admin&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="d-flex"&gt;
    &lt;figure class="figure mx-auto"&gt;
        &lt;img src="/images/2019/12/thumbnails/400x_/administrators.png" class="figure-img img-fluid rounded" alt="Edit the Telegram channel administrators"&gt;
        &lt;figcaption class="figure-caption text-center"&gt;Edit the Telegram channel administrators&lt;/figcaption&gt;
    &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;Now search for the bot you created at step 2:&lt;/p&gt;
&lt;div class="d-flex"&gt;
    &lt;figure class="figure mx-auto"&gt;
        &lt;img src="/images/2019/12/thumbnails/400x_/add_bot_admin.png" class="figure-img img-fluid rounded" alt="Add the bot as the channel admin"&gt;
        &lt;figcaption class="figure-caption text-center"&gt;Add the bot as the channel admin&lt;/figcaption&gt;
    &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;And add it to the channel with the minimum required permission, that is only &lt;strong&gt;Post Messages&lt;/strong&gt; for the scope of this tutorial:&lt;/p&gt;
&lt;div class="d-flex"&gt;
    &lt;figure class="figure mx-auto"&gt;
        &lt;img src="/images/2019/12/thumbnails/400x_/bot_admin_permissions.png" class="figure-img img-fluid rounded" alt="Setup the bot permissions"&gt;
        &lt;figcaption class="figure-caption text-center"&gt;Setup the bot permissions&lt;/figcaption&gt;
    &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;Ok, you have completed all the steps needed on the Telegram app, and from now on you&amp;#8217;ll work only on the Python/Django side.&lt;/p&gt;
&lt;h2 id="4-install-python-telegram-bot"&gt;4. Install python-telegram-bot&lt;/h2&gt;
&lt;p&gt;To interact with the Telegram bot API I strongly recommend to use a wrapper, so you don&amp;#8217;t have to deal with low level details. There are &lt;a href="https://github.com/python-telegram-bot/python-telegram-bot"&gt;three&lt;/a&gt; &lt;a href="https://github.com/eternnoir/pyTelegramBotAPI"&gt;different&lt;/a&gt; &lt;a href="https://github.com/aiogram/aiogram"&gt;projects&lt;/a&gt; for Python, but I chose &lt;a href="https://github.com/python-telegram-bot/python-telegram-bot"&gt;python-telegram-bot&lt;/a&gt; because it looks quite simple to integrate and use.&lt;/p&gt;
&lt;p&gt;Install with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;pip install python-telegram-bot
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Or add the project to your requirements:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;tornado==5.1.1 # dependency of python-telegram-bot
python-telegram-bot==12.2.0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I also had to fix the version of &lt;strong&gt;tornado&lt;/strong&gt; in my requirements, because the requirement made by python-telegram-bot is &lt;strong&gt;tornado&amp;gt;=5.1&lt;/strong&gt; and this installed tornado 6 in my case, which is not compatibile with my version on Python.&lt;/p&gt;
&lt;h2 id="5-edit-your-django-settings-to-add-telegram-parameters"&gt;5. Edit your Django settings to add Telegram parameters&lt;/h2&gt;
&lt;p&gt;This is not strictly required, but I strongly suggest you to keep all the Telegram related parameters in your Django settings. Add a dictionary called &lt;strong&gt;TELEGRAM&lt;/strong&gt; like this in your Django settings module:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;TELEGRAM&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s1"&gt;&amp;#39;bot_token&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;123456789:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;&amp;#39;channel_name&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;guguweb&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Of course you have to customize the &lt;strong&gt;bot_token&lt;/strong&gt; parameter using the token you received from the BotFather at step 2, and the &lt;strong&gt;channel_name&lt;/strong&gt; parameter with the actual name of your channel.&lt;/p&gt;
&lt;h2 id="6-send-a-message-to-the-channel-from-your-django-code"&gt;6. Send a message to the channel from your Django code&lt;/h2&gt;
&lt;p&gt;Suppose you have a Django powered website where you publish events for your community. An &lt;strong&gt;Event&lt;/strong&gt; model could be something like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TextField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;blank&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;start_date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now suppose that you want to send a message on your Telegram channel when you post a new event. To do this create a Django template that will be used to define the HTML for the Telegram message, with a content similar to this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;{{ event.url }}&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;{{ event.title }}&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
{{ event.description|truncatewords:30 }}
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;strong&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Date:&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;strong&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;{{ event.start_date|date:&amp;#39;SHORT_DATE_FORMAT&amp;#39; }}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Consider that only a &lt;a href="https://core.telegram.org/bots/api#html-style"&gt;subset of HTML tags&lt;/a&gt; are supported by Telegram and that &lt;strong&gt;you cannot nest&lt;/strong&gt; HTML tags. Save the template with the name &lt;strong&gt;telegram_message.html&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;You can then define a function to actually create the message and send it to the Telegram bot:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;telegram&lt;/span&gt; &lt;span class="c1"&gt;# this is from python-telegram-bot package&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.conf&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.template.loader&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;render_to_string&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;post_event_on_telegram&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;message_html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;render_to_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;telegram_message.html&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s1"&gt;&amp;#39;event&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="n"&gt;telegram_settings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TELEGRAM&lt;/span&gt;
    &lt;span class="n"&gt;bot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;telegram&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;telegram_settings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;bot_token&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chat_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;@&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;telegram_settings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;channel_name&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                     &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;message_html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parse_mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;telegram&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ParseMode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HTML&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The function takes an Event instance as the only argument, uses the Django template system to render the HTML, and then uses an instance of telegram.Bot to actually send the message. So simple, isn&amp;#8217;t it?&lt;/p&gt;
&lt;p&gt;If you plan to call the function from one of your views in a request-response cycle, I strongly suggest you to configure an asynchronous task to send the message, like I explained in my post &lt;a href="https://www.guguweb.com/2019/11/21/django-asynchronous-tasks-without-celery/"&gt;Django asynchronous tasks without Celery&lt;/a&gt;:&lt;/p&gt;
&lt;div class="row"&gt;
    &lt;div class="col-12 col-sm-8 col-md-6 mx-auto"&gt;
        &lt;div class="card my-5"&gt;
    &lt;img src="/images/2019/11/thumbnails/400x_/logistics-852936_1920.jpg" class="card-img-top" alt="Django asynchronous tasks without Celery"&gt;
    &lt;div class="card-body"&gt;
      &lt;h5 class="card-title"&gt;Django asynchronous tasks without Celery&lt;/h5&gt;
      &lt;a href="/2019/11/21/django-asynchronous-tasks-without-celery/" class="btn btn-link stretched-link"&gt;Read more...&lt;/a&gt;
    &lt;/div&gt;
&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="7-conclusions"&gt;7. Conclusions&lt;/h2&gt;
&lt;p&gt;In this post I&amp;#8217;ve shown you how to automate your Telegram channel with a Django Telegram Bot. I think that this approach opens many interesting possibilities for better engaging the users of your Django web application.&lt;/p&gt;
&lt;p&gt;Please don&amp;#8217;t hesitate to ask questions or make comments in the form below or by &lt;a class="post-contact-link" href="/#home-contact"&gt;contacting me&lt;/a&gt;. Of course you can also join my &lt;a href="https://t.me/guguweb"&gt;Telegram channel&lt;/a&gt;, the one that I created when writing this tutorial: &lt;a href="https://t.me/guguweb"&gt;https://t.me/guguweb&lt;/a&gt;. I&amp;#8217;ll use the channel to post updates from this blog, so if you find this post useful please join the channel. 😉&lt;/p&gt;
&lt;h2 id="8-do-you-want-more-power-for-your-django-telegram-bot"&gt;8. Do you want more power for your Django Telegram bot?&lt;/h2&gt;
&lt;p&gt;Of course you can! In a following post I will explain how to make a step further and make your Telegram bot more useful, by giving it the power to answer inquiries coming from Telegram users.&lt;/p&gt;
&lt;p&gt;The bot (you guessed it) will use Django as the backend to receive messages from Telegram and send replies to the users. Stay tuned!&lt;/p&gt;</content><category term="web"></category><category term="api"></category><category term="django"></category><category term="telegram"></category></entry><entry><title>Django asynchronous tasks without Celery</title><link href="https://www.guguweb.com/2019/11/21/django-asynchronous-tasks-without-celery/" rel="alternate"></link><published>2019-11-21T10:18:45+00:00</published><updated>2022-01-14T21:10:47+01:00</updated><author><name>Augusto Destrero</name></author><id>tag:www.guguweb.com,2019-11-21:/2019/11/21/django-asynchronous-tasks-without-celery/</id><summary type="html">&lt;p&gt;In this blog post I will guide you to implement Django asynchronous tasks without Celery. First of all I will define what I mean with the term &amp;#8220;asynchronous task&amp;#8221;.&lt;/p&gt;
&lt;div class="toc"&gt;&lt;span class="toctitle"&gt;Table of Contents&lt;/span&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#what-are-django-asynchronous-tasks"&gt;What are Django asynchronous tasks?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#enter-the-uwsgi-spooler"&gt;Enter the uWSGI spooler&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#install-uwsgidecorators-package"&gt;Install uwsgidecorators package&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#create-the-directory-for-the-spool-files"&gt;Create the directory for the &amp;#8220;spool …&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;In this blog post I will guide you to implement Django asynchronous tasks without Celery. First of all I will define what I mean with the term &amp;#8220;asynchronous task&amp;#8221;.&lt;/p&gt;
&lt;div class="toc"&gt;&lt;span class="toctitle"&gt;Table of Contents&lt;/span&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#what-are-django-asynchronous-tasks"&gt;What are Django asynchronous tasks?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#enter-the-uwsgi-spooler"&gt;Enter the uWSGI spooler&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#install-uwsgidecorators-package"&gt;Install uwsgidecorators package&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#create-the-directory-for-the-spool-files"&gt;Create the directory for the &amp;#8220;spool files&amp;#8221;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#create-a-tasks-module-in-your-django-application"&gt;Create a tasks module in your Django application&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#call-the-asynchronous-task-from-your-django-view"&gt;Call the asynchronous task from your Django view&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#configure-uwsgi-to-use-the-spooler"&gt;Configure uWSGI to use the spooler&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#conclusion"&gt;Conclusion&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id="what-are-django-asynchronous-tasks"&gt;What are Django asynchronous tasks?&lt;/h2&gt;
&lt;p&gt;Suppose that you want to perform a long running task in your Django web app, but you want to give an immediate response to the user without waiting for the task to finish. The task could be: sending an email, building a report, making a request to an external web service, etc. The response given to the user usually is a confirmation message that the task has started.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Every task that &lt;strong&gt;could&lt;/strong&gt; take some time to complete should not block the request-response cycle between the user and your application.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you Google for &amp;#8220;Django asynchronous tasks&amp;#8221; probably you&amp;#8217;ll be directed to &lt;a href="http://www.celeryproject.org/"&gt;Celery&lt;/a&gt; as &lt;strong&gt;the way&lt;/strong&gt; to implement asynchronous tasks with Django. Please don&amp;#8217;t get me wrong: there is nothing wrong in Celery. Many successful projects use Celery in production with success. I also used Celery in a couple of projects, and it works well. What I find annoying is the additional effort.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Celery is yet another service to configure, launch and maintain.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="enter-the-uwsgi-spooler"&gt;Enter the uWSGI spooler&lt;/h2&gt;
&lt;p&gt;As I wrote in my other post &lt;a href="https://www.guguweb.com/2019/11/13/django-nginx-deploy-your-django-project-on-a-production-server/"&gt;Django &amp;#8211; NGINX: deploy your Django project on a production server&lt;/a&gt;, I like to use the &lt;a href="https://uwsgi-docs.readthedocs.io/en/latest/"&gt;uWSGI&lt;/a&gt; application server. Well, it turns out that uWSGI provides a full featured, production ready, system to implement asynchronous tasks. They call it the &lt;a href="https://uwsgi-docs.readthedocs.io/en/latest/Spooler.html"&gt;uWSGI Spooler&lt;/a&gt;. Citing the uWSGI documentation:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The Spooler is a queue manager built into uWSGI that works like a printing/mail system.&lt;/p&gt;
&lt;p&gt;You can enqueue massive sending of emails, image processing, video encoding, etc. and let the spooler do the hard work in background while your users get their requests served by normal workers.&lt;/p&gt;
&lt;p&gt;A spooler works by defining a directory in which “spool files” will be written, every time the spooler find a file in its directory it will parse it and will run a specific function.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The uWSGI Spooler is very easy to configure!&lt;/p&gt;
&lt;h2 id="install-uwsgidecorators-package"&gt;Install uwsgidecorators package&lt;/h2&gt;
&lt;p&gt;To interact with uWSGI spooler from your Python code it is really convenient to install the &lt;strong&gt;uwsgidecorators&lt;/strong&gt; package. Unfortunately there isn&amp;#8217;t a recent version of uwsgidecorators on PyPI, but you can install it using apt:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo apt install python3-uwsgidecorators
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you use a virtualenv for your Django project (as you should) you can link the uwsgidecorator module in your virtualenv:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ln -s /usr/lib/python3/dist-packages/uwsgidecorators.py /path/to/your/virtualenv/lib/python3.6/site-packages
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="create-the-directory-for-the-spool-files"&gt;Create the directory for the &amp;#8220;spool files&amp;#8221;&lt;/h2&gt;
&lt;p&gt;First of all you have to create the directory where uWSGI will save the &amp;#8220;spool files&amp;#8221; used by the spooler:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;mkdir -p /home/ubuntu/tasks
sudo chown www-data.www-data /home/ubuntu/tasks
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Please make sure that the directory is writable by the user running uWSGI, that is &lt;strong&gt;www-data&lt;/strong&gt; in the example.&lt;/p&gt;
&lt;h2 id="create-a-tasks-module-in-your-django-application"&gt;Create a tasks module in your Django application&lt;/h2&gt;
&lt;p&gt;Assuming that you have a Django app named &lt;strong&gt;app1&lt;/strong&gt; you should create a module named &lt;strong&gt;tasks.py&lt;/strong&gt; in the app directory. The content of the module should be something like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;logging&lt;/span&gt;
&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;uwsgidecorators&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;spool&lt;/span&gt;
&lt;span class="k"&gt;except&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;spool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;func_wrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;func_wrapper&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;django&lt;/span&gt;
&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;.models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Model1&lt;/span&gt;

&lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vm"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nd"&gt;@spool&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;long_running_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;obj1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Model1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pk&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;obj1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;long_running_model_method&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The try/except construct will let you test the code even when not running in a uWSGI application server, for instance when running locally using &lt;code&gt;./manage.py runserver&lt;/code&gt;. In that case the task will be executed synchronously, as it was a regular python function call.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;long_running_task&lt;/strong&gt; function is the task you will invoke using the uWSGI Spooler. As you can see you have to decorate it with the &lt;strong&gt;@spool&lt;/strong&gt; decorator, and the parameters for the task are passed in a dictionary called &lt;strong&gt;arguments&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;In this example I&amp;#8217;m using the Django ORM to get an instance of a model and to call a model method that will take a long time to complete.&lt;/p&gt;
&lt;h2 id="call-the-asynchronous-task-from-your-django-view"&gt;Call the asynchronous task from your Django view&lt;/h2&gt;
&lt;p&gt;Here you can find how to call the asynchronous task from an example view:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.shortcuts&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;redirect&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.contrib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;messages&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;.tasks&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;long_running_task&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;async_view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;long_running_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SUCCESS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;&amp;#39;Task started correctly&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;some_other_view&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here I call the task, then I use the &lt;a href="https://docs.djangoproject.com/en/2.2/ref/contrib/messages/"&gt;Django messages framework&lt;/a&gt; to show the user a confirmation message on the next page view, and finally I redirect the user to another view.&lt;/p&gt;
&lt;h2 id="configure-uwsgi-to-use-the-spooler"&gt;Configure uWSGI to use the spooler&lt;/h2&gt;
&lt;p&gt;To configure the uWSGI Spooler you should edit the uWSGI configuration file I presented in the post &lt;a href="https://www.guguweb.com/2019/11/13/django-nginx-deploy-your-django-project-on-a-production-server/"&gt;Django &amp;#8211; NGINX: deploy your Django project on a production server&lt;/a&gt;. The file is located here: &lt;code&gt;/etc/uwsgi/apps-enabled/django.ini&lt;/code&gt;. The content of the file should be something like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;[uwsgi]&lt;/span&gt;
&lt;span class="na"&gt;chdir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;/home/ubuntu/django_project # customize with your django installation directory&lt;/span&gt;
&lt;span class="na"&gt;env&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;DJANGO_SETTINGS_MODULE=project.settings.production # customize with your settings module&lt;/span&gt;
&lt;span class="na"&gt;wsgi-file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;project/wsgi.py # customize with the relative path to your wsgi.py file&lt;/span&gt;
&lt;span class="na"&gt;workers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;1&lt;/span&gt;
&lt;span class="na"&gt;spooler-chdir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;/home/ubuntu/django_project # customize with your django installation directory&lt;/span&gt;
&lt;span class="na"&gt;spooler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;/home/ubuntu/tasks/&lt;/span&gt;
&lt;span class="na"&gt;import&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;app1.tasks&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Restart uWSGI with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;service uwsgi restart
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You will find the uWSGI logs in &lt;strong&gt;/var/log/uwsgi/apps/django.log&lt;/strong&gt;. Therefore you can check them to see if the Python process started correctly or there are issues.&lt;/p&gt;
&lt;p&gt;In the log file you&amp;#8217;ll also find messages about the Spooler, something like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Mon Nov 18 14:50:45 2019 - [spooler /home/ubuntu/tasks pid: 8646] managing request uwsgi_spoolfile_on_www.example.com_8647_3_1383635828_1574067630_419736 ...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this post I&amp;#8217;ve shown how to setup Django asynchronous tasks using uWSGI Spooler. That is a simple and convenient way to perform long running tasks outside the request-response cycle. Especially if you already use uWSGI application server.&lt;/p&gt;
&lt;p&gt;I used this technique in many different projects, for example an &amp;#8220;Instagram like&amp;#8221; &lt;a href="https://media.mtb-mag.com/en/pv/"&gt;photo and video sharing platform&lt;/a&gt; I built from scratch for the popular online magazine &lt;a href="https://www.mtb-mag.com/"&gt;mtb-mag.com&lt;/a&gt;. In that case videos are processed asynchronously to make two versions suitable for all devices, in standard and high definition.&lt;/p&gt;
&lt;p&gt;Please let me know if you have comments or question by leaving a reply below. Happy coding!&lt;/p&gt;</content><category term="web"></category><category term="async"></category><category term="django"></category><category term="uwsgi"></category></entry><entry><title>Django NGINX: deploy your Django project on a production server</title><link href="https://www.guguweb.com/2019/11/13/django-nginx-deploy-your-django-project-on-a-production-server/" rel="alternate"></link><published>2019-11-13T09:46:56+00:00</published><updated>2022-03-30T14:50:56+02:00</updated><author><name>Augusto Destrero</name></author><id>tag:www.guguweb.com,2019-11-13:/2019/11/13/django-nginx-deploy-your-django-project-on-a-production-server/</id><summary type="html">&lt;p&gt;&lt;a href="https://www.djangoproject.com/"&gt;Django&lt;/a&gt; &lt;a href="https://www.nginx.com/"&gt;NGINX&lt;/a&gt; is a popular and well tested combination used to deploy web applications in production. In this post I will explain the steps needed to have your Django project deployed on a production server using Ubuntu 18.04.&lt;/p&gt;
&lt;p&gt;To have Django NGINX deployed on your production server follow these …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="https://www.djangoproject.com/"&gt;Django&lt;/a&gt; &lt;a href="https://www.nginx.com/"&gt;NGINX&lt;/a&gt; is a popular and well tested combination used to deploy web applications in production. In this post I will explain the steps needed to have your Django project deployed on a production server using Ubuntu 18.04.&lt;/p&gt;
&lt;p&gt;To have Django NGINX deployed on your production server follow these simple steps.&lt;/p&gt;
&lt;div class="toc"&gt;&lt;span class="toctitle"&gt;Table of Contents&lt;/span&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#django-nginx-its-better-together"&gt;Django Nginx: it's better together!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#install-required-packages-using-apt"&gt;Install required packages using apt&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#create-directories-for-your-static-and-media-files"&gt;Create directories for your static and media files&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#setup-your-django-project-and-install-requirements"&gt;Setup your Django project and install requirements&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#collect-static-files"&gt;Collect static files&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#configure-uwsgi-to-host-your-django-project"&gt;Configure uWSGI to host your Django project&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#configure-nginx-to-serve-your-application"&gt;Configure NGINX to serve your application&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#enjoy-your-django-nginx-application"&gt;Enjoy your Django NGINX application&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#extra-step-automate-all-these-steps-with-ansible"&gt;Extra step: automate all these steps with Ansible!&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id="django-nginx-its-better-together"&gt;Django Nginx: it's better together!&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.djangoproject.com/"&gt;Django&lt;/a&gt; is a web framework written in Python. It lets you develop and prototype web applications with little effort. It comes with many built-in features that are often useful in a web application, such as: session management, user authentication, an object relational mapper, a template language.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.nginx.com/"&gt;NGINX&lt;/a&gt; is a very fast and configurable web server that is very well suited to serve static files and act as a reverse proxy for other applications. In this tutorial I'll explain how to configure NGINX to serve static files (images, javascript, css, ...) and to proxy requests to your Django application.&lt;/p&gt;
&lt;h2 id="install-required-packages-using-apt"&gt;Install required packages using apt&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo apt install nginx uwsgi uwsgi-plugin-python3
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Why do you need &lt;a href="https://uwsgi-docs.readthedocs.io/en/latest/"&gt;uWSGI&lt;/a&gt;? In very simple terms NGINX on its own cannot run a Python process to host your application, for this you&amp;#8217;ll need a so called &lt;em&gt;application server&lt;/em&gt; that will host a Python process running your Django project. NGINX and uWSGI will &amp;#8220;talk&amp;#8221; each other using the uwsgi protocol.&lt;/p&gt;
&lt;h2 id="create-directories-for-your-static-and-media-files"&gt;Create directories for your static and media files&lt;/h2&gt;
&lt;p&gt;Static files are &amp;#8220;not-python&amp;#8221; files needed by your Django project, for example Javascript, CSS and images. Media files will be the files uploaded by the users of your application. Not every application will let users upload files, but it&amp;#8217;s a very common scenario. Django will not serve static and media files by itself. We&amp;#8217;ll leverage NGINX to serve them.&lt;/p&gt;
&lt;p&gt;First of all you have to create the directories. Here I assume that you are currently using the user &lt;strong&gt;ubuntu&lt;/strong&gt; with the default home directory &lt;strong&gt;/home/ubuntu&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;mkdir -p /home/ubuntu/static /home/ubuntu/media
sudo chown www-data.www-data /home/ubuntu/media
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The second command will make the user named &lt;strong&gt;www-data&lt;/strong&gt; the owner of the &lt;strong&gt;/home/ubuntu/media&lt;/strong&gt; directory. &lt;strong&gt;www-data&lt;/strong&gt; will be the user running your Python process in uWSGI, and that user should be able to write in the media directory to correctly save user uploaded files.&lt;/p&gt;
&lt;h2 id="setup-your-django-project-and-install-requirements"&gt;Setup your Django project and install requirements&lt;/h2&gt;
&lt;p&gt;This step really depends on your particular Django application, for the purpose of this tutorial I will assume that your Django project is installed in the directory &lt;code&gt;/home/ubuntu/django_project/&lt;/code&gt; with the following structure:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;/home/ubuntu/django_project/
├── app1
│   ├── admin.py
│   ├── __init__.py
│   ├── migrations
│   │   └── __init__.py
│   ├── models.py
│   ├── tests.py
│   ├── views.py
├── manage.py
└── project
   ├── __init__.py
   ├── settings
  │   └── __init__.py
  │   └── base.py
  │   └── production.py
   ├── urls.py
   ├── wsgi.py
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Also I will assume that you installed all your Python requirements, for example using apt or pip.&lt;/p&gt;
&lt;p&gt;I always follow a best practice when starting a new Django project, by splitting the monolithic &lt;strong&gt;settings.py&lt;/strong&gt; file in different files, one for each deploy environment (local, test, production, &amp;#8230;). You can read a more &lt;a href="https://www.coderedcorp.com/blog/django-settings-for-multiple-environments/"&gt;in depth explanation&lt;/a&gt; of this approach if you aren&amp;#8217;t used to it.&lt;/p&gt;
&lt;p&gt;In our case Django will use the module &lt;strong&gt;project/settings/production.py&lt;/strong&gt; for his settings. Here we set the &lt;strong&gt;STATIC_ROOT&lt;/strong&gt; and &lt;strong&gt;MEDIA_ROOT&lt;/strong&gt; variables to the directories we created at step 2:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;.base&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;

&lt;span class="n"&gt;ALLOWED_HOSTS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;www.example.com&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# customize with your domain name&lt;/span&gt;

&lt;span class="n"&gt;DATABASES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s1"&gt;&amp;#39;default&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;# here the configuration for your database&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;STATIC_ROOT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;/home/ubuntu/static&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;MEDIA_ROOT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;/home/ubuntu/media&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="collect-static-files"&gt;Collect static files&lt;/h2&gt;
&lt;p&gt;Run the following command to collect all static files for your Django project:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;./manage.py collectstatic
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This command will copy all static files (Javascript, CSS, images) for all your Django apps in the &lt;strong&gt;STATIC_ROOT&lt;/strong&gt; directory configured in &lt;strong&gt;production.py&lt;/strong&gt;. For instance &lt;strong&gt;/home/ubuntu/static&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id="configure-uwsgi-to-host-your-django-project"&gt;Configure uWSGI to host your Django project&lt;/h2&gt;
&lt;p&gt;Create a file named &lt;strong&gt;django.ini&lt;/strong&gt; in the &lt;strong&gt;/etc/uwsgi/apps-enabled/&lt;/strong&gt; directory. The content of the file should be something like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;[uwsgi]&lt;/span&gt;
&lt;span class="na"&gt;chdir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;/home/ubuntu/django_project # customize with your django installation directory&lt;/span&gt;
&lt;span class="na"&gt;env&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;DJANGO_SETTINGS_MODULE=project.settings.production # customize with your settings module&lt;/span&gt;
&lt;span class="na"&gt;wsgi-file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;project/wsgi.py # customize with the relative path to your wsgi.py file&lt;/span&gt;
&lt;span class="na"&gt;workers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Restart uWSGI with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;service uwsgi restart
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You should find the uWSGI logs in &lt;strong&gt;/var/log/uwsgi/apps/django.log&lt;/strong&gt;. Therefore you can check them to see if the Python process started correctly or there are issues.&lt;/p&gt;
&lt;h2 id="configure-nginx-to-serve-your-application"&gt;Configure NGINX to serve your application&lt;/h2&gt;
&lt;p&gt;Create a file named &lt;strong&gt;django&lt;/strong&gt; in the &lt;strong&gt;/etc/nginx/sites-enabled/&lt;/strong&gt; directory. The content of the file should be something like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;www.example.com&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;# customize with your domain name&lt;/span&gt;

    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="s"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;# django running in uWSGI&lt;/span&gt;
        &lt;span class="kn"&gt;uwsgi_pass&lt;/span&gt; &lt;span class="s"&gt;unix:///run/uwsgi/app/django/socket&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;include&lt;/span&gt; &lt;span class="s"&gt;uwsgi_params&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;uwsgi_read_timeout&lt;/span&gt; &lt;span class="s"&gt;300s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;client_max_body_size&lt;/span&gt; &lt;span class="mi"&gt;32m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="s"&gt;/static/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="c1"&gt;# static files&lt;/span&gt;
       &lt;span class="kn"&gt;alias&lt;/span&gt; &lt;span class="s"&gt;/home/ubuntu/static/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;# ending slash is required&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="s"&gt;/media/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;# media files, uploaded by users&lt;/span&gt;
        &lt;span class="kn"&gt;alias&lt;/span&gt; &lt;span class="s"&gt;/home/ubuntu/media/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;# ending slash is required&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Restart NGINX with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;service nginx restart
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="enjoy-your-django-nginx-application"&gt;Enjoy your Django NGINX application&lt;/h2&gt;
&lt;p&gt;Point the browser to your domain, and you should see your Django application in all of its glory!&lt;/p&gt;
&lt;h2 id="extra-step-automate-all-these-steps-with-ansible"&gt;Extra step: automate all these steps with Ansible!&lt;/h2&gt;
&lt;p&gt;If you have to manage many different Django projects on many different servers, certainly you&amp;#8217;ll find that automating stuff is always a good idea.&lt;/p&gt;
&lt;p&gt;Read my post on &lt;a href="https://www.guguweb.com/2017/05/02/how-to-deploy-a-django-project-in-15-minutes-with-ansible/"&gt;How to deploy a Django project in 15 minutes with Ansible&lt;/a&gt; to automate all the steps described here.&lt;/p&gt;
&lt;p&gt;In conclusion, I hope that this post helped you with configuring Django NGINX to deploy your Django project on a production server. Please let me know if you have questions leaving a comment in the area below or contacting me by email or social account.&lt;/p&gt;</content><category term="web"></category><category term="django"></category><category term="nginx"></category><category term="python"></category><category term="uwsgi"></category></entry><entry><title>A Django custom command to write model fields on an Excel file</title><link href="https://www.guguweb.com/2017/11/09/a-django-custom-command-to-write-model-fields-on-an-excel-file/" rel="alternate"></link><published>2017-11-09T17:36:15+00:00</published><updated>2022-01-04T17:57:06+01:00</updated><author><name>Augusto Destrero</name></author><id>tag:www.guguweb.com,2017-11-09:/2017/11/09/a-django-custom-command-to-write-model-fields-on-an-excel-file/</id><summary type="html">&lt;hr&gt;
&lt;p&gt;Suppose you need to write down your model fields on an Excel file, for example to complement the documentation of your code.&lt;/p&gt;
&lt;p&gt;Django has built in functions to introspect models and fields of an app, and you can leverage this API to have the information you need.&lt;/p&gt;
&lt;p&gt;You can use …&lt;/p&gt;</summary><content type="html">&lt;hr&gt;
&lt;p&gt;Suppose you need to write down your model fields on an Excel file, for example to complement the documentation of your code.&lt;/p&gt;
&lt;p&gt;Django has built in functions to introspect models and fields of an app, and you can leverage this API to have the information you need.&lt;/p&gt;
&lt;p&gt;You can use the following Django custom command:&lt;/p&gt;
&lt;div class="gist"&gt;
    &lt;script src='https://gist.github.com/1a06f5491f175510356359421b22cdec.js'&gt;&lt;/script&gt;
    &lt;noscript&gt;
        &lt;pre&gt;&lt;code&gt;# coding=utf-8
from __future__ import unicode_literals
import logging

from django.core.management.base import BaseCommand, CommandError
from django.apps import apps

from xlsxwriter.workbook import Workbook

logger = logging.getLogger(__name__)

class Command(BaseCommand):
    help = 'Export all models of a given app to Excel file'

    def add_arguments(self, parser):
        parser.add_argument('app_labels', nargs='+', type=str)
        parser.add_argument('output', type=str)
        parser.add_argument('--exclude-models', dest="exclude_models_file",
                            type=file)
        parser.add_argument('--include-reverse-relations', action='store_true',
                            dest="include_reverse_relations", default=False)

    def handle(self, *args, **options):
        workbook = Workbook(options['output'], {'constant_memory': True})
        bold = workbook.add_format({'bold': True})
        headers = ['Field', 'Type']

        exclude_models = []
        if options['exclude_models_file']:
            exclude_models = options['exclude_models_file'].read().splitlines()

        for app_label in options['app_labels']:
            app_config = apps.get_app_config(app_label)
            app_models = app_config.get_models(include_auto_created=False)
            
            for model in app_models:
                model_name = model.__name__
                if model_name in exclude_models:
                    continue
                worksheet_name = '%s - %s' % (app_label, model_name)
                if len(worksheet_name) &gt; 31:
                    worksheet_name = '%s - %s' % (app_label[:3], model_name)
                worksheet = workbook.add_worksheet(worksheet_name)
                worksheet.write_row(0, 0, headers, bold)
                worksheet.set_column(0, len(headers), 30)
                fields = model._meta.get_fields()
                row = 1
                for f in fields:
                    try:
                        fieldname = f.verbose_name
                    except:
                        fieldname = f.name
                    fieldtype = f.__class__.__name__
                    if (options['include_reverse_relations'] or
                        fieldtype not in ('ManyToOneRel', 'ManyToManyRel',
                                          'OneToOneRel')):
                        worksheet.write(row, 0, fieldname.strip())
                        worksheet.write(row, 1, fieldtype)
                        row += 1

        workbook.close()
&lt;/code&gt;&lt;/pre&gt;
    &lt;/noscript&gt;
&lt;/div&gt;
&lt;p&gt;You can run the command like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;./manage.py excel_models app1 app2 models.xlsx
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And it will write all the models of &lt;em&gt;app1&lt;/em&gt; and &lt;em&gt;app2&lt;/em&gt; on the &lt;em&gt;models.xlsx&lt;/em&gt; file. Every model will be written on a different sheet.&lt;/p&gt;
&lt;p&gt;The option _&amp;#8211;exclude-models_can be used to specify a text file with models to exclude from Excel file (one per line).&lt;/p&gt;
&lt;p&gt;The option &lt;em&gt;&amp;#8211;include-reverse-relations&lt;/em&gt; (default false) can be used to include also reverse relations of your models, that are fields that are not part of the models itself, but are reverse fields from other models that have for instance a &lt;em&gt;ForeignKey&lt;/em&gt; to the model.&lt;/p&gt;
&lt;p&gt;The command depends on the &lt;a href="https://pypi.python.org/pypi/XlsxWriter"&gt;XlsxWriter package&lt;/a&gt; to create the Excel file.&lt;/p&gt;</content><category term="snippets"></category><category term="django"></category><category term="python"></category></entry><entry><title>A simple Python email gateway</title><link href="https://www.guguweb.com/2017/05/10/a-simple-python-email-gateway/" rel="alternate"></link><published>2017-05-10T13:23:11+00:00</published><updated>2022-01-07T15:50:01+01:00</updated><author><name>Augusto Destrero</name></author><id>tag:www.guguweb.com,2017-05-10:/2017/05/10/a-simple-python-email-gateway/</id><summary type="html">&lt;p&gt;Say you have a Django web application that you want to integrate with emails to make it possibile to send data and files to your web application over SMTP.&lt;/p&gt;
&lt;p&gt;The good news is that Python has a simple SMTP daemon in the standard library, together with modules to parse emails …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Say you have a Django web application that you want to integrate with emails to make it possibile to send data and files to your web application over SMTP.&lt;/p&gt;
&lt;p&gt;The good news is that Python has a simple SMTP daemon in the standard library, together with modules to parse emails. Let&amp;#8217;s see how to create a simple email gateway on top of these tools.&lt;/p&gt;
&lt;p&gt;Using the following Python module you can setup a simple pure Python email server on port 25, parse the incoming emails and make a &lt;em&gt;multipart/form-data&lt;/em&gt; POST HTTP request to your web application. You&amp;#8217;ll need the awesome &lt;a href="http://docs.python-requests.org/en/master/"&gt;Requests&lt;/a&gt; library for the HTTP request to work.&lt;/p&gt;
&lt;div class="gist"&gt;
    &lt;script src='https://gist.github.com/d5d6f855774ba9f72e11909648a46cae.js'&gt;&lt;/script&gt;
    &lt;noscript&gt;
        &lt;pre&gt;&lt;code&gt;import smtpd
import asyncore
import logging
import email
from email.header import decode_header
import requests

logger = logging.getLogger(__name__)

class CustomSMTPServer(smtpd.SMTPServer):

    def process_message(self, peer, mailfrom, rcpttos, data):
        try:
            logger.debug('Receiving message from: %s:%d' % peer)
            logger.debug('Message addressed from: %s' % mailfrom)
            logger.debug('Message addressed to: %s' % str(rcpttos))

            msg = email.message_from_string(data)
            subject = ''
            for encoded_string, charset in decode_header(msg.get('Subject')):
                try:
                    if charset is not None:
                        subject += encoded_string.decode(charset)
                    else:
                        subject += encoded_string
                except:
                    logger.exception('Error reading part of subject: %s charset %s' %
                                     (encoded_string, charset))

            logger.debug('Subject: %s' % subject)

            text_parts = []
            attachments = {}

            logger.debug('Headers: %s' % msg.items())

            # YOU CAN DO SOME SECURITY CONTROLS HERE
            if (not mailfrom.endswith("@example.com") or
                not msg.get('Mail-Header') == 'expected value'):
                raise Exception("Email not trusted")

            # loop on the email parts
            for part in msg.walk():
                if part.get_content_maintype() == 'multipart':
                    continue

                c_type = part.get_content_type()
                c_disp = part.get('Content-Disposition')

                # text parts will be appended to text_parts
                if c_type == 'text/plain' and c_disp == None:
                    text_parts.append(part.get_payload(decode=True).strip())
                # ignore html part
                elif c_type == 'text/html':
                    continue
                # attachments will be sent as files in the POST request
                else:
                    filename = part.get_filename()
                    filecontent = part.get_payload(decode=True)
                    if filecontent is not None:
                        if filename is None:
                            filename = 'untitled'
                        attachments['file%d' % len(attachments)] = (filename,
                                                                    filecontent)

            body = '\n'.join(text_parts)
        except:
            logger.exception('Error reading incoming email')
        else:
            # this data will be sent as POST data
            data = {
                'subject': subject,
                'body': body,
                'from': mailfrom,
            }
            url = 'http://yourserver.example.com/email-receive/'
            logger.debug('Sending data and files to %s' % url)
            try:
                r = requests.post(url, data=data, files=attachments)
                r.raise_for_status()
            except:
                logger.exception('Error in server request')
                logger.debug(data)
                logger.debug(attachments)
            else:
                logger.debug('Response from server: %s %s' % (r.status_code, r.text))

        return

if __name__ == '__main__':
    ch = logging.StreamHandler()
    ch.setLevel(logging.DEBUG)
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    ch.setFormatter(formatter)
    logger.setLevel(logging.DEBUG)
    logger.addHandler(ch)

    server = CustomSMTPServer(('111.111.111.111', 25), None) # use your public IP here
    asyncore.loop()&lt;/code&gt;&lt;/pre&gt;
    &lt;/noscript&gt;
&lt;/div&gt;
&lt;p&gt;In a production environment you can setup &lt;a href="http://supervisord.org/"&gt;supervisor&lt;/a&gt; to launch your simple SMTP server. With a simple configuration like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;[program:smtp_server]&lt;/span&gt;
&lt;span class="na"&gt;command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;/home/ubuntu/.virtualenvs/venv/bin/python /home/ubuntu/mail_gateway/smtp_server.py&lt;/span&gt;
&lt;span class="na"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;root&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then try to send an email to your server, if the server public IP has been associated to a DNS record &lt;em&gt;yourserver.example.com&lt;/em&gt; you can use something like &lt;em&gt;test@yourserver.example.com&lt;/em&gt; as a recipient, and you should see the incoming email in the logs.&lt;/p&gt;
&lt;p&gt;Have fun with emails!&lt;/p&gt;</content><category term="sysadmin"></category><category term="django"></category><category term="email"></category><category term="python"></category></entry><entry><title>How to deploy a Django project in 15 minutes with Ansible</title><link href="https://www.guguweb.com/2017/05/02/how-to-deploy-a-django-project-in-15-minutes-with-ansible/" rel="alternate"></link><published>2017-05-02T11:01:47+00:00</published><updated>2022-03-30T14:50:52+02:00</updated><author><name>Augusto Destrero</name></author><id>tag:www.guguweb.com,2017-05-02:/2017/05/02/how-to-deploy-a-django-project-in-15-minutes-with-ansible/</id><summary type="html">&lt;p&gt;In this tutorial I will explain how to deploy a Django project in 15 minutes with Ansible. I will assume that you are a &lt;a href="https://www.djangoproject.com/"&gt;Django&lt;/a&gt; developer and you have built and tested a project locally. It&amp;#8217;s time to deploy the project on a public server to let users access …&lt;/p&gt;</summary><content type="html">&lt;p&gt;In this tutorial I will explain how to deploy a Django project in 15 minutes with Ansible. I will assume that you are a &lt;a href="https://www.djangoproject.com/"&gt;Django&lt;/a&gt; developer and you have built and tested a project locally. It&amp;#8217;s time to deploy the project on a public server to let users access your awesome application.&lt;/p&gt;
&lt;p&gt;If you are new in deploying Django on a production server you can read my post &lt;a href="https://www.guguweb.com/2019/11/13/django-nginx-deploy-your-django-project-on-a-production-server/"&gt;Django – NGINX: deploy your Django project on a production server&lt;/a&gt; to have a basic introduction on the steps needed.&lt;/p&gt;
&lt;p&gt;So you need a VPS with an SSH access, then you will access the server, install and configure all necessary software (web server, application server, database server), create a database user, configure Django to use it, copy your Django project on the server, migrate the database, collect static files, trial and error, fix, trial and error, &amp;#8230;&lt;/p&gt;
&lt;p&gt;All this boring stuff will take some good hours that you should definitely spend in a more profitable way, don&amp;#8217;t you think? The good news is that you can automate almost all the work needed to go from a vanilla VPS to a fully deployed server hosting your Django project.&lt;/p&gt;
&lt;p&gt;Follow this tutorial and I&amp;#8217;ll show you how to leverage the power of &lt;a href="https://www.ansible.com/"&gt;Ansible&lt;/a&gt; to automate all the needed steps in 15 minutes. Are you ready? Check the time on your clock and follow me!&lt;/p&gt;
&lt;div class="toc"&gt;&lt;span class="toctitle"&gt;Table of Contents&lt;/span&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#1-setup-the-ssh-access-to-your-vps"&gt;1. Setup the SSH access to your VPS&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#add-the-vps-address-to-your-ssh-configuration"&gt;Add the VPS address to your SSH configuration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#configure-ssh-access-without-using-a-password"&gt;Configure SSH access without using a password&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#2-deploy-your-django-project-with-ansible"&gt;2. Deploy your Django project with Ansible&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#clone-the-template-repository"&gt;Clone the template repository&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#django"&gt;django&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#requirements"&gt;requirements&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#ansible"&gt;ansible&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#push-your-django-project-in-a-publicly-accessible-git-repository"&gt;Push your Django project in a publicly accessible GIT repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#let-the-ansible-automation-begins"&gt;Let the Ansible automation begins!&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#3-update-your-django-project"&gt;3. Update your Django project&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#4-continuous-delivery-using-bitbucket-pipelines"&gt;4. Continuous delivery using Bitbucket Pipelines&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#5-conclusions"&gt;5. Conclusions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id="1-setup-the-ssh-access-to-your-vps"&gt;1. Setup the SSH access to your VPS&lt;/h2&gt;
&lt;p&gt;There are plenty of good VPS providers out there, and the choice of the VPS is out of scope of this tutorial.&lt;/p&gt;
&lt;p&gt;If you are looking for a cheap and powerful cloud provider to host your project I highly suggest &lt;a class="aff" href="/r/do"&gt;DigitalOcean.&lt;/a&gt; It is very flexible and powerful, the price is very good for what they offer and you&amp;#8217;ll get no surprises on your billing at the end of the month! Join by using &lt;a class="aff" href="/r/do"&gt;this link&lt;/a&gt; and you&amp;#8217;ll get a &lt;strong&gt;100$ free credit&lt;/strong&gt; to use in 60 days.&lt;/p&gt;
&lt;p&gt;Here I assume that you already bought a Debian/Ubuntu based VPS with a public IP/hostname and root SSH access. I tested the procedure described in this tutorial using Ubuntu server 18.04.&lt;/p&gt;
&lt;h3 id="add-the-vps-address-to-your-ssh-configuration"&gt;Add the VPS address to your SSH configuration&lt;/h3&gt;
&lt;p&gt;If you use OpenSSH client on Linux/UNIX, you can add an entry like this in &lt;em&gt;~/.ssh/config&lt;/em&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Host yourserver
User root
Port 22
HostName yourserver.example.com
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Pay attention to what you use on &lt;em&gt;Host&lt;/em&gt; value, &lt;em&gt;yourserver&lt;/em&gt; in this example, because this is the label you&amp;#8217;ll use in the following steps to refer to this particular server.&lt;/p&gt;
&lt;p&gt;In &lt;em&gt;HostName&lt;/em&gt; you&amp;#8217;ll configure the actual IP address or hostname of your VPS, according to the access data received by your provider.&lt;/p&gt;
&lt;h3 id="configure-ssh-access-without-using-a-password"&gt;Configure SSH access without using a password&lt;/h3&gt;
&lt;p&gt;To be able to connect to your VPS without using a password, you have to setup a public/private SSH key on your workstation (if you don&amp;#8217;t already have one), this is very simple and can be done with the following command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ssh-keygen
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then you can configure a password-less access to your VPS using the command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ssh-copy-id yourserver
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That&amp;#8217;s it. You should now be able to connect to your VPS using SSH without entering your password every time.&lt;/p&gt;
&lt;h2 id="2-deploy-your-django-project-with-ansible"&gt;2. Deploy your Django project with Ansible&lt;/h2&gt;
&lt;h3 id="clone-the-template-repository"&gt;Clone the template repository&lt;/h3&gt;
&lt;p&gt;I prepared a &lt;a href="https://github.com/baxeico/django_ansible"&gt;template repository&lt;/a&gt; of a Django project, you can clone it at the following address before proceeding:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git clone https://github.com/baxeico/django_ansible.git
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In the repository you&amp;#8217;ll find three directories:&lt;/p&gt;
&lt;h4 id="django"&gt;django&lt;/h4&gt;
&lt;p&gt;This directory is a sample Django project created with the usual:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;django-admin.py startproject yourproject
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I renamed the root directory created by the command to be simply &lt;em&gt;django&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;It is just a bare template not meant to be used as is, but it should give you an idea on how the Django settings are supposed to be structured in this tutorial.&lt;/p&gt;
&lt;p&gt;I always follow a best practice when starting a new Django project, by splitting the monolithic &lt;em&gt;settings.py&lt;/em&gt; file in different files, one for each deploy environment (local, test, production, &amp;#8230;). You can read a more &lt;a href="https://www.coderedcorp.com/blog/django-settings-for-multiple-environments/"&gt;in depth explanation&lt;/a&gt; of this approach if you aren&amp;#8217;t used to it.&lt;/p&gt;
&lt;p&gt;So inside &lt;em&gt;yourproject&lt;/em&gt; sub-directory you&amp;#8217;ll find a &lt;em&gt;settings&lt;/em&gt; package containing different modules for different deploy environments:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;base.py&lt;/em&gt; &amp;#8211; This is the common settings which will be inherited (and possibly overridden) from all deploy environments;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;local.py&lt;/em&gt; &amp;#8211; This will be the &lt;em&gt;DJANGO_SETTINGS_MODULE&lt;/em&gt; used in your local development environment. Nothing special here, it only makes Django to use sqlite as DB for local development;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;production.py&lt;/em&gt; &amp;#8211; This will be the &lt;em&gt;DJANGO_SETTINGS_MODULE&lt;/em&gt; used in production. Here you&amp;#8217;ll find that the database used by Django is defined using &lt;a href="https://github.com/kennethreitz/dj-database-url"&gt;dj-database-url&lt;/a&gt; package, by means of an environment variable. Also the &lt;em&gt;STATIC_ROOT&lt;/em&gt; settings variable is defined by means of an environment variable.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="requirements"&gt;requirements&lt;/h4&gt;
&lt;p&gt;This directory contains the minimum Python requirements of your project, you&amp;#8217;ll find three files there:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;base.txt&lt;/em&gt; &amp;#8211; contains the basic requirements for all deploy environment (only Django in the example, it&amp;#8217;s a Django project after all, isn&amp;#8217;t it?);&lt;/li&gt;
&lt;li&gt;&lt;em&gt;local.txt&lt;/em&gt; &amp;#8211; it inherits from &lt;em&gt;base.txt&lt;/em&gt; and adds Ansible as a requirement for your local development environment. Version 2.3.0 is the latest Ansible version at the time of writing;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;production.txt&lt;/em&gt; &amp;#8211; it also inherits from &lt;em&gt;base.txt&lt;/em&gt; and adds &lt;a href="https://github.com/kennethreitz/dj-database-url"&gt;dj-database-url&lt;/a&gt; as a requirement for your production environment. It will be used to configure the database used by Django by means of the environment variable &lt;em&gt;DATABASE_URL&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Notice how this structure mimics the different Django settings modules described above. You can install the local requirements using this command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;pip install -r requirements/local.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I strongly suggest to use &lt;a href="https://virtualenv.pypa.io/en/stable/"&gt;Virtualenv&lt;/a&gt;, together with &lt;a href="https://virtualenvwrapper.readthedocs.io/en/latest/"&gt;virtualenvwrapper&lt;/a&gt; to create and manage an isolated environment for your project.&lt;/p&gt;
&lt;h4 id="ansible"&gt;ansible&lt;/h4&gt;
&lt;p&gt;In this directory you&amp;#8217;ll find the most interesting part, that is a set of Ansible playbooks to automate the installation and configuration of the server and the deployment of your project.&lt;/p&gt;
&lt;p&gt;I suggest to copy the &lt;em&gt;ansible&lt;/em&gt; directory in your project root, and eventually adapt the playbooks to your needs.&lt;/p&gt;
&lt;p&gt;The first thing to customize is the &lt;em&gt;hosts&lt;/em&gt; file. This is the file where you could list all the hosts controlled by Ansible. In this example you should have only one entry, corresponding to the &lt;em&gt;Host&lt;/em&gt; value you entered in SSH client configuration.&lt;/p&gt;
&lt;p&gt;Then you can proceed to rename the file &lt;em&gt;host_vars/yourserver&lt;/em&gt;, using the label you gave to your server in the &lt;em&gt;hosts&lt;/em&gt; file. Here you&amp;#8217;ll also find some variables used in the playbooks.&lt;/p&gt;
&lt;p&gt;Here is a brief description of each playbook you&amp;#8217;ll find:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;config_files.yaml&lt;/em&gt; &amp;#8211; Copy nginx and uwsgi configuration files on remote server.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;deploy.yaml&lt;/em&gt; &amp;#8211; Deploy your Django project on the server, pulling the master branch from your GIT repository, installing all needed production requirements, running migrate and collectstatic and restarting uwsgi.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;packages.yaml&lt;/em&gt; &amp;#8211; Install needed software packages on remote server using &lt;em&gt;apt&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;postgresql.yaml&lt;/em&gt; &amp;#8211; Create and configure the access to a &lt;a href="https://www.postgresql.org/"&gt;Postgresql&lt;/a&gt; database used by your Django project on remote server. Notice how the database password is randomly generated and stored in the local file &lt;em&gt;postgresqlpasswd&lt;/em&gt;. The password will be automatically inserted in the &lt;em&gt;DATABASE_URL&lt;/em&gt; environment variable, to be used in Django production settings.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;system.yaml&lt;/em&gt; &amp;#8211; Create an user &lt;em&gt;ubuntu&lt;/em&gt; on remote server, together with a private/public SSH key pair. The public key is returned as output when you run the playbook, to be used as a &amp;#8220;deploy key&amp;#8221; on the server. More details later on this step.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;upgrade.yaml&lt;/em&gt; &amp;#8211; Upgrade all &lt;em&gt;apt&lt;/em&gt; packages on remote server.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="push-your-django-project-in-a-publicly-accessible-git-repository"&gt;Push your Django project in a publicly accessible GIT repository&lt;/h3&gt;
&lt;p&gt;Probably you already have your project sources hosted on a public GIT repository like &lt;a href="https://github.com/"&gt;Github&lt;/a&gt; or &lt;a href="https://bitbucket.org/"&gt;Bitbucket&lt;/a&gt;. If you don&amp;#8217;t, this is a perfect time to do it! I personally use Bitbucket, because it offers an unlimited number of private repositories.&lt;/p&gt;
&lt;p&gt;In the following steps I assume that you have your Django project hosted on Bitbucket, under this path:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;ssh&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="nv"&gt;@bitbucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;youruser&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;yourproject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="let-the-ansible-automation-begins"&gt;Let the Ansible automation begins!&lt;/h3&gt;
&lt;p&gt;Inside the &lt;em&gt;ansible&lt;/em&gt; directory, run the following command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;./ansible.sh system.yaml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You should see an output similar to this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ok: &lt;span class="o"&gt;[&lt;/span&gt;yourserver&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&amp;gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;changed&amp;quot;&lt;/span&gt;: false,
    &lt;span class="s2"&gt;&amp;quot;msg&amp;quot;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;quot;ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC1kvkW9... ansible-generated on yourserver.example.com\n&amp;quot;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;What you find in the &lt;em&gt;msg&lt;/em&gt; variable is the public SSH key generated for the &lt;em&gt;ubuntu&lt;/em&gt; user on remote server. You should copy the public key and add it as a &amp;#8220;deploy key&amp;#8221; in the settings of your GIT repository.&lt;/p&gt;
&lt;p&gt;A deploy key is a read-only SSH key that will be used to clone your repository from the remote server. You can find more details in the &lt;a href="https://confluence.atlassian.com/bitbucket/use-access-keys-294486051.html"&gt;Bitbucket&lt;/a&gt; and &lt;a href="https://developer.github.com/guides/managing-deploy-keys/#deploy-keys"&gt;Github&lt;/a&gt; documentation.&lt;/p&gt;
&lt;p&gt;Now you are ready to complete the deploy of your Django project! Run the following commands inside the &lt;em&gt;ansible&lt;/em&gt; directory:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;./ansible.sh packages.yaml
./ansible.sh postgresql.yaml
./ansible.sh config_files.yaml
./ansible.sh deploy.yaml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If all goes well you should be able to reach your Django project on your remote server public address, on port 80.&lt;/p&gt;
&lt;h2 id="3-update-your-django-project"&gt;3. Update your Django project&lt;/h2&gt;
&lt;p&gt;Keeping your Django project updated on the remote server is very easy in this setup. You only need to push your changes to your GIT repository (on the &lt;em&gt;master&lt;/em&gt; branch) and then you can run the following command inside the &lt;em&gt;ansible&lt;/em&gt; directory:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;./ansible.sh deploy.yaml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This playbook will perform the following tasks for you:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;pull the updated master branch from your GIT repository;&lt;/li&gt;
&lt;li&gt;eventually install new Python production requirements, and update the existing ones;&lt;/li&gt;
&lt;li&gt;migrate the database to the latest version;&lt;/li&gt;
&lt;li&gt;update your static files with collectstatic;&lt;/li&gt;
&lt;li&gt;restart uwsgi.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="4-continuous-delivery-using-bitbucket-pipelines"&gt;4. Continuous delivery using Bitbucket Pipelines&lt;/h2&gt;
&lt;p&gt;In the follow up article &lt;a href="https://www.guguweb.com/2020/01/03/bitbucket-pipelines-and-ansible-continuous-delivery-for-your-django-project/"&gt;Bitbucket Pipelines and Ansible: Continuous delivery for your Django project&lt;/a&gt; I explained how you can use Ansible together with Bitbucket Pipelines to implement a simple yet powerful continuous delivery setup for your Django project.&lt;/p&gt;
&lt;h2 id="5-conclusions"&gt;5. Conclusions&lt;/h2&gt;
&lt;p&gt;In this article I explained how to deploy a Django project in 15 minutes with Ansible. The key here is in following some Django best practices and leveraging the power on Ansible to quickly deploy a Django project on a remote server. I think that the time spent to learn and master those technologies is worth the effort for the time you&amp;#8217;ll save in the future and all the human errors you&amp;#8217;ll avoid by automating and standardizing your processes.&lt;/p&gt;
&lt;p&gt;Of course this is only the tip of the iceberg of what you could do and automate with Ansible, but I found this simple approach to be already a big time saver in my daily work.&lt;/p&gt;
&lt;p&gt;Have fun with Ansible!&lt;/p&gt;</content><category term="sysadmin"></category><category term="ansible"></category><category term="devops"></category><category term="django"></category><category term="ubuntu"></category></entry><entry><title>How to add CORS headers to a Django view for use with a Cordova app</title><link href="https://www.guguweb.com/2016/05/27/how-to-add-cors-headers-to-a-django-view-for-use-with-a-cordova-app/" rel="alternate"></link><published>2016-05-27T16:42:17+00:00</published><updated>2022-01-07T15:52:01+01:00</updated><author><name>Augusto Destrero</name></author><id>tag:www.guguweb.com,2016-05-27:/2016/05/27/how-to-add-cors-headers-to-a-django-view-for-use-with-a-cordova-app/</id><summary type="html">&lt;p&gt;Suppose you want to access some JSON data from a mobile app using &lt;a href="https://cordova.apache.org/" target="_blank" rel="noopener noreferrer"&gt;Cordova&lt;/a&gt;. You have to bypass &lt;a href="https://en.wikipedia.org/wiki/Cross-origin_resource_sharing" target="_blank" rel="noopener noreferrer"&gt;CORS restrictions&lt;/a&gt;&amp;nbsp;in the&amp;nbsp;web view, and to do that you have to provide some HTTP headers in your Django views.&lt;/p&gt;
&lt;!--more--&gt;

&lt;p&gt;You can do this pretty easily by using this mixin in …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Suppose you want to access some JSON data from a mobile app using &lt;a href="https://cordova.apache.org/" target="_blank" rel="noopener noreferrer"&gt;Cordova&lt;/a&gt;. You have to bypass &lt;a href="https://en.wikipedia.org/wiki/Cross-origin_resource_sharing" target="_blank" rel="noopener noreferrer"&gt;CORS restrictions&lt;/a&gt;&amp;nbsp;in the&amp;nbsp;web view, and to do that you have to provide some HTTP headers in your Django views.&lt;/p&gt;
&lt;!--more--&gt;

&lt;p&gt;You can do this pretty easily by using this mixin in your Class Based Views:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.http&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;HttpResponse&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AllowCORSMixin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add_access_control_headers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Access-Control-Allow-Origin&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;*&amp;quot;&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Access-Control-Allow-Methods&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;GET, OPTIONS&amp;quot;&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Access-Control-Max-Age&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;1000&amp;quot;&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Access-Control-Allow-Headers&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;X-Requested-With, Content-Type&amp;quot;&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;options&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_access_control_headers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Use it like in the example below. Here used together with &lt;a href="https://github.com/brack3t/django-braces" target="_blank" rel="noopener noreferrer"&gt;Django Braces&lt;/a&gt; app:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.views.generic&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;View&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;braces.views&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AjaxResponseMixin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;JSONResponseMixin&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;JsonView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;JSONResponseMixin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AjaxResponseMixin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AllowCORSMixin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;View&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_ajax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

        &lt;span class="c1"&gt;# ... get some data ...&lt;/span&gt;

        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;render_json_response&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;data&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_access_control_headers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="web"></category><category term="cordova"></category><category term="django"></category></entry><entry><title>How to migrate your existing Django project to Heroku</title><link href="https://www.guguweb.com/2016/05/18/how-to-migrate-your-existing-django-project-to-heroku/" rel="alternate"></link><published>2016-05-18T14:15:45+00:00</published><updated>2022-01-07T15:56:58+01:00</updated><author><name>Augusto Destrero</name></author><id>tag:www.guguweb.com,2016-05-18:/2016/05/18/how-to-migrate-your-existing-django-project-to-heroku/</id><summary type="html">&lt;hr&gt;
&lt;p&gt;Recently I had some fun with &lt;a href="https://www.heroku.com/" target="_blank" rel="noopener noreferrer"&gt;Heroku&lt;/a&gt;, the well known PaaS provider. I had a small personal Django project I use for invoicing that I ran locally with ./manage.py runserver when needed. That was a perfect candidate for the &lt;a href="https://www.heroku.com/pricing" target="_blank" rel="noopener noreferrer"&gt;Heroku free plan&lt;/a&gt; because I need to access the app …&lt;/p&gt;</summary><content type="html">&lt;hr&gt;
&lt;p&gt;Recently I had some fun with &lt;a href="https://www.heroku.com/" target="_blank" rel="noopener noreferrer"&gt;Heroku&lt;/a&gt;, the well known PaaS provider. I had a small personal Django project I use for invoicing that I ran locally with ./manage.py runserver when needed. That was a perfect candidate for the &lt;a href="https://www.heroku.com/pricing" target="_blank" rel="noopener noreferrer"&gt;Heroku free plan&lt;/a&gt; because I need to access the app only occasionally.&lt;/p&gt;
&lt;p&gt;In this tutorial I assume you have a basic knowledge of what Heroku is, and that you already know how to create and deploy a Python project on Heroku. In case you miss some basic information you can refer to the good &lt;a href="https://devcenter.heroku.com/articles/getting-started-with-python" target="_blank" rel="noopener noreferrer"&gt;Getting started tutorial on Heroku with Python&lt;/a&gt;.&lt;/p&gt;
&lt;div class="toc"&gt;&lt;span class="toctitle"&gt;Table of Contents&lt;/span&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#how-to-structure-your-django-project-for-heroku"&gt;How to structure your Django project for Heroku&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#how-to-configure-your-django-project-for-heroku"&gt;How to configure your Django project for Heroku&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#create-an-heroku-application-for-your-django-project"&gt;Create an Heroku application for your Django project&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#migrating-data"&gt;Migrating data&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#media-files-on-aws-s3"&gt;Media files on AWS S3&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id="how-to-structure-your-django-project-for-heroku"&gt;How to structure your Django project for Heroku&lt;/h2&gt;
&lt;p&gt;Here I focus on my use case, which was to migrate an existing Django project on Heroku platform. My existing Django project was structured in accordance to the best practices I read in the wonderful &lt;a href="http://twoscoopspress.com/products/two-scoops-of-django-1-8" target="_blank" rel="noopener noreferrer"&gt;Two Scoops of Django&lt;/a&gt; book, so my project structure was similar to this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;django/
├── project
│   ├── __init__.py
│   ├── settings
│   │   ├── __init__.py
│   │   ├── base.py
│   │   ├── local.py
│   │   └── production.py
│   ├── urls.py
│   ├── wsgi.py
├── app
│   ├── __init__.py
│   ├── admin.py
│   ├── models.py
│   ├── tests.py
│   ├── urls.py
│   ├── views.py
└── manage.py
requirements
├── base.txt
├── local.txt
└── production.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;See how I have different settings for each deploy environment: one for local development, one for production. All common settings go in base.py.&lt;/p&gt;
&lt;p&gt;See also how I have a different requirements file for each environment, for example I have django-debug-toolbar in local.txt, while I have psycopg2 in production.txt. All common requirements are in base.txt.&lt;/p&gt;
&lt;p&gt;For Heroku I created a file &lt;em&gt;heroku.txt&lt;/em&gt; under &lt;em&gt;requirements/&lt;/em&gt; directory with the following content:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;-r base.txt

dj-database-url==0.3.0
psycopg2==2.6.1
whitenoise==2.0.2
django-storages==1.4.1
boto==2.38.0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="how-to-configure-your-django-project-for-heroku"&gt;How to configure your Django project for Heroku&lt;/h2&gt;
&lt;p&gt;On Heroku I will use Postgres as database backend (which is free , and &lt;a href="https://github.com/kennethreitz/dj-database-url" target="_blank" rel="noopener noreferrer"&gt;dj-database-url&lt;/a&gt; to configure the database parameters using an environment variable, which is already set by Heroku.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ll also use &lt;a href="http://whitenoise.evans.io/en/stable/django.html" target="_blank" rel="noopener noreferrer"&gt;whitenoise&lt;/a&gt; to handle static files directly from django and &lt;a href="https://github.com/jschneier/django-storages" target="_blank" rel="noopener noreferrer"&gt;django-storages&lt;/a&gt; to handle media files on Amazon S3.&lt;/p&gt;
&lt;p&gt;The first thing you have to do to tell Heroku you are deploying a python project is to put a &lt;code&gt;requirements.txt&lt;/code&gt; file in the root of your git project. You can create a file with this content to include the requirements specific to Heroku:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;-r requirements/heroku.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then you have to do some modification to your settings, for deploy on Heroku platform:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# Parse database configuration from $DATABASE_URL&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;dj_database_url&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;environ&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;.base&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;

&lt;span class="n"&gt;ALLOWED_HOSTS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;yourappname.herokuapp.com&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;DATABASES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="s1"&gt;&amp;#39;default&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;dj_database_url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;WSGI_APPLICATION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;yourproject.wsgi_heroku.application&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;STATICFILES_STORAGE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;whitenoise.django.GzipManifestStaticFilesStorage&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;STATIC_ROOT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;static_root&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;INSTALLED_APPS&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;storages&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,)&lt;/span&gt;
&lt;span class="n"&gt;DEFAULT_FILE_STORAGE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;storages.backends.s3boto.S3BotoStorage&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;AWS_ACCESS_KEY_ID&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;AWS_SECRET_ACCESS_KEY&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;AWS_STORAGE_BUCKET_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;yourbucketname&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then you have to edit your wsgi.py file to make use of whitenoise for static files, the file whould look something like this. Save it in a different wsgi_heroku.py file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.core.wsgi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;get_wsgi_application&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;whitenoise.django&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DjangoWhiteNoise&lt;/span&gt;

&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setdefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;DJANGO_SETTINGS_MODULE&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;yourproject.settings.heroku&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;application&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_wsgi_application&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;application&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DjangoWhiteNoise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;application&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="create-an-heroku-application-for-your-django-project"&gt;Create an Heroku application for your Django project&lt;/h2&gt;
&lt;p&gt;Now you can create you Heroku application:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;heroku&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;region&lt;/span&gt; &lt;span class="n"&gt;eu&lt;/span&gt; &lt;span class="n"&gt;yourappname&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In the root directory of your project you should have a Procfile, used by Heroku to know how to launch the web worker, in our case the Procfile should contain just one line like the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;web&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;gunicorn&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;pythonpath&lt;/span&gt; &lt;span class="n"&gt;django&lt;/span&gt; &lt;span class="n"&gt;yourproject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;wsgi_heroku&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now push the code on Heroku:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git push heroku master
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then you can create the database schema with the usual migrate command, run on the Heroku instance:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;heroku run python django/manage.py migrate
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="migrating-data"&gt;Migrating data&lt;/h2&gt;
&lt;p&gt;If you have some data to migrate you can use a couple of command from core Django&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;./manage.py dumpdata yourapp &amp;gt; yourapp/fixtures/app_data.json
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then you can import the data on Heroku instance:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;heroku&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;loaddata&lt;/span&gt; &lt;span class="n"&gt;app_data&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="media-files-on-aws-s3"&gt;Media files on AWS S3&lt;/h2&gt;
&lt;p&gt;If your application needs some user uploaded data, you can use Amazon S3 to store the files, by using django-storages app to configure the correct Storage for you media files.&lt;/p&gt;
&lt;p&gt;The configuration of django-storages is out of scope for this tutorial, but you can find some &lt;a href="https://www.caktusgroup.com/blog/2014/11/10/Using-Amazon-S3-to-store-your-Django-sites-static-and-media-files/" target="_blank" rel="noopener noreferrer"&gt;good tutorials&lt;/a&gt; on the web.&lt;/p&gt;</content><category term="web"></category><category term="django"></category><category term="git"></category><category term="heroku"></category><category term="python"></category></entry><entry><title>A simple script to update a DB migration in Django 1.7+</title><link href="https://www.guguweb.com/2015/10/22/a-simple-script-to-update-a-db-migration-in-django-1-7/" rel="alternate"></link><published>2015-10-22T10:41:37+00:00</published><updated>2022-01-04T17:58:44+01:00</updated><author><name>augusto</name></author><id>tag:www.guguweb.com,2015-10-22:/2015/10/22/a-simple-script-to-update-a-db-migration-in-django-1-7/</id><summary type="html">&lt;hr&gt;
&lt;p&gt;During the development of a Django model on your local machine is it often necessary to refine the most recent migration to cope with updates to the model, without polluting the migrations of the app with a new migration for each local update.&lt;/p&gt;
&lt;p&gt;South had the &lt;em&gt;update&lt;/em&gt; flag for the …&lt;/p&gt;</summary><content type="html">&lt;hr&gt;
&lt;p&gt;During the development of a Django model on your local machine is it often necessary to refine the most recent migration to cope with updates to the model, without polluting the migrations of the app with a new migration for each local update.&lt;/p&gt;
&lt;p&gt;South had the &lt;em&gt;update&lt;/em&gt; flag for the &lt;a href="http://south.readthedocs.org/en/latest/commands.html#schemamigration" target="_blank" rel="noopener noreferrer"&gt;schemamigration&lt;/a&gt; command, but I didn&amp;#8217;t find a similar functionality in the Django builtin &lt;a href="https://docs.djangoproject.com/en/1.8/ref/django-admin/#django-admin-makemigrations" target="_blank" rel="noopener noreferrer"&gt;makemigrations&lt;/a&gt; command introduced in Django 1.7.&lt;/p&gt;
&lt;p&gt;So I put togheter a simple bash script to automate the process.&lt;/p&gt;
&lt;!--more--&gt;

&lt;div class="gist"&gt;
    &lt;script src='https://gist.github.com/4b5ceb2eee14fe776c34.js'&gt;&lt;/script&gt;
    &lt;noscript&gt;
        &lt;pre&gt;&lt;code&gt;#!/bin/bash

if [ -z $1 ]; then
    echo "Usage:  $0  app_label"
    exit 1
fi

app=$1 # this is the name of the app where we want to update the last migration

# get the list of known migrations for the app
migrations=(`./manage.py showmigrations $app | awk '{print $2}' | tail -2`)

if [ ${#migrations[@]} == 1 ]; then
    # there is just one migration in the list
    # here we are updating the initial migration
    previous_migration=zero
    current_migration=${migrations[0]} # should be 0001_initial
else
    # there is more than one migration in the list
    # get the previous one to go back to
    # and the current one to update
    previous_migration=${migrations[0]}
    current_migration=${migrations[1]}
fi

# go back to the previous migration
./manage.py migrate $app $previous_migration
# remove the current, outdated migration
rm $app/migrations/${current_migration}.*
# create a new migration
./manage.py makemigrations $app
# migrate the DB to the new migration
./manage.py migrate $app
&lt;/code&gt;&lt;/pre&gt;
    &lt;/noscript&gt;
&lt;/div&gt;
&lt;p&gt;Basically the script unapplies the last migration for a given app, update the migration and reapplies it. I find it a little time saver and it feels good to know that the script is doing the right things in the right order.&lt;/p&gt;</content><category term="snippets"></category><category term="bash"></category><category term="django"></category></entry><entry><title>How to add a group choice combo box in a Django user profile form</title><link href="https://www.guguweb.com/2014/09/10/group-combo-box-django-user-profile-form/" rel="alternate"></link><published>2014-09-10T11:38:30+00:00</published><updated>2022-01-04T18:33:56+01:00</updated><author><name>augusto</name></author><id>tag:www.guguweb.com,2014-09-10:/2014/09/10/group-combo-box-django-user-profile-form/</id><summary type="html">&lt;p&gt;Assume that you have a Django project where each user belongs to just one group, say &lt;em&gt;Registered&lt;/em&gt; or &lt;em&gt;Admin&lt;/em&gt;, but &lt;strong&gt;not both&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;You want to show a form in your front-end to let Admin users edit the user profiles, where each user profile is made with First name, Last name …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Assume that you have a Django project where each user belongs to just one group, say &lt;em&gt;Registered&lt;/em&gt; or &lt;em&gt;Admin&lt;/em&gt;, but &lt;strong&gt;not both&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;You want to show a form in your front-end to let Admin users edit the user profiles, where each user profile is made with First name, Last name, Email &lt;strong&gt;and&lt;/strong&gt; the user group.&lt;/p&gt;
&lt;p&gt;This task can be accomplished very easily! What you need is a customized &lt;a title="ModelForm official documentation" href="https://docs.djangoproject.com/en/1.6/topics/forms/modelforms/" target="_blank" rel="noopener noreferrer"&gt;ModelForm&lt;/a&gt; to add the possibility to edit the user group together with the other fields, and a customized &lt;a title="UpdateView documentation from the &amp;quot;Classy Class-Based Views&amp;quot; website" href="http://ccbv.co.uk/projects/Django/1.6/django.views.generic.edit/UpdateView/" target="_blank" rel="noopener noreferrer"&gt;UpdateView&lt;/a&gt; to let you set the form initial data for the group field, and to save the changes correctly.&lt;/p&gt;
&lt;p&gt;Here is the ModelForm:&lt;/p&gt;
&lt;div class="gist"&gt;
    &lt;script src='https://gist.github.com/e5083af4fef6a968dc0d.js'&gt;&lt;/script&gt;
    &lt;noscript&gt;
        &lt;pre&gt;&lt;code&gt;from django import forms
from django.contrib.auth.models import User, Group

class UserProfileForm(forms.ModelForm):
    group = forms.ModelChoiceField(queryset=Group.objects.all(),
                                   required=True)
    
    class Meta:
        model = User
        fields = ['first_name', 'last_name', 'email', 'group']&lt;/code&gt;&lt;/pre&gt;
    &lt;/noscript&gt;
&lt;/div&gt;
&lt;p&gt;That is a standard ModelForm for the User model, we have just added a &lt;em&gt;group&lt;/em&gt; field that is a &lt;a title="ModelChoiceField documentation" href="https://docs.djangoproject.com/en/3.2/ref/forms/fields/#modelchoicefield" target="_blank" rel="noopener noreferrer"&gt;ModelChoiceField&lt;/a&gt;, that is a combo box with all available groups in our project as choices, if you want you can filter the queryset according to your needs. We have also restricted the fields shown in the user profile form to First name, Last name, Email and Group.&lt;/p&gt;
&lt;div class="gist"&gt;
    &lt;script src='https://gist.github.com/f641eaf9663f0f4122ea.js'&gt;&lt;/script&gt;
    &lt;noscript&gt;
        &lt;pre&gt;&lt;code&gt;from django.contrib.auth.models import User
from django.views.generic import UpdateView

from .forms import UserProfileForm

class UserProfileUpdateView(UpdateView):
    model = User
    
    def get_initial(self):
        initial = super(UserProfileUpdateView, self).get_initial()
        try:
            current_group = self.object.groups.get()
        except:
            # exception can occur if the edited user has no groups
            # or has more than one group
            pass
        else:
            initial['group'] = current_group.pk
        return initial
    
    def get_form_class(self):
        return UserProfileForm
    
    def form_valid(self, form):
        self.object.groups.clear()
        self.object.groups.add(form.cleaned_data['group'])
        return super(UserProfileUpdateView, self).form_valid(form)&lt;/code&gt;&lt;/pre&gt;
    &lt;/noscript&gt;
&lt;/div&gt;
&lt;p&gt;This is the view we&amp;#8217;ll use to update the user profile. We have overridden some methods of UpdateView:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;get_initial&lt;/strong&gt; is used to set the initial value for the custom group field with the current group the user belongs to. Note that when the user profile is edited for the first time the user will not belong to any group, but this is taken into account and no initial value will be provided to the field;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;get_form_class&lt;/strong&gt; is used to set the class used by the UpdateView to show and validate the form. We have set it to the one we created before;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;form_valid&lt;/strong&gt; is called by the UpdateView when the form submitted is valid. Here we remove the old group the user belonged to, and we add the new group selected in the form to the user. Remember that the &lt;em&gt;groups&lt;/em&gt; field of the User model is a &lt;a title="ManyToManyField official documentation" href="https://docs.djangoproject.com/en/3.2/ref/models/fields/#ref-manytomany" target="_blank" rel="noopener noreferrer"&gt;ManyToManyField&lt;/a&gt;, so we are simply using the Django ORM here.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That&amp;#8217;s it, I hope that this how-to helps you with your Django project! Please let me know if you found my approach useful in the comments.&lt;/p&gt;</content><category term="web"></category><category term="django"></category></entry><entry><title>PUT and DELETE HTTP requests with Django and jQuery</title><link href="https://www.guguweb.com/2014/06/25/put-and-delete-http-requests-with-django-and-jquery/" rel="alternate"></link><published>2014-06-25T11:42:13+00:00</published><updated>2022-01-14T21:18:29+01:00</updated><author><name>augusto</name></author><id>tag:www.guguweb.com,2014-06-25:/2014/06/25/put-and-delete-http-requests-with-django-and-jquery/</id><summary type="html">&lt;p&gt;Sometimes it could be useful and elegant to have a Django view responding to more that GET and POST requests, implementing a simple REST interface. In this post I&amp;#8217;ll show how you can support PUT and DELETE HTTP requests in Django.&lt;/p&gt;
&lt;div class="toc"&gt;&lt;span class="toctitle"&gt;Table of Contents&lt;/span&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#your-goal"&gt;Your goal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#the-problems"&gt;The problems&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#the-solution"&gt;The …&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;Sometimes it could be useful and elegant to have a Django view responding to more that GET and POST requests, implementing a simple REST interface. In this post I&amp;#8217;ll show how you can support PUT and DELETE HTTP requests in Django.&lt;/p&gt;
&lt;div class="toc"&gt;&lt;span class="toctitle"&gt;Table of Contents&lt;/span&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#your-goal"&gt;Your goal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#the-problems"&gt;The problems&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#the-solution"&gt;The solution&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#what-about-the-function-based-views"&gt;What about the function based views?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#conclusion"&gt;Conclusion&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id="your-goal"&gt;Your goal&lt;/h2&gt;
&lt;p&gt;To put it in examples your goal is to have a View like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.views.generic&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;View&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.shortcuts&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.forms.models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;modelform_factory&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.http&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;HttpResponse&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;.models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MyModel&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RestView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;View&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# retrieve some object and render in template&lt;/span&gt;
    &lt;span class="nb"&gt;object&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MyModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pk&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;pk&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;object_detail.html&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;object&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# create an object and redirect to detail page&lt;/span&gt;
    &lt;span class="n"&gt;modelform&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;modelform_factory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyModel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;form&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;modelform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PUT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;form&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_valid&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;form&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;restview&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# delete an object and send a confirmation response&lt;/span&gt;
    &lt;span class="n"&gt;MyModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pk&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DELETE&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;pk&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And accessing the view by jQuery Ajax methods like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ajax&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;DELETE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;/restview&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;pk&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pk&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;success&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Object deleted!&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="the-problems"&gt;The problems&lt;/h2&gt;
&lt;p&gt;Unfortunately there are two problems that restrict you to implement the view and the javascript like described above:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Not all browsers support HTTP requests different from GET and POST. In some browsers the &lt;em&gt;type: &amp;#8216;DELETE&amp;#8217;&lt;/em&gt; in your ajax method will not work;&lt;/li&gt;
&lt;li&gt;Django does not put data sent with a PUT or DELETE request in a request.PUT or request.DELETE dictionary, like it does with GET or POST data. This is for a &lt;a title="Why Django doesn't create a request.PUT or request.DELETE dictionary." href="https://groups.google.com/forum/#!msg/django-developers/dxI4qVzrBY4/m_9IiNk_p7UJ" target="_blank" rel="noopener noreferrer"&gt;good reason&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="the-solution"&gt;The solution&lt;/h2&gt;
&lt;p&gt;What you can do to solve these problems? You can use the so called &lt;em&gt;POST TUNNELLING&lt;/em&gt; method, that is using a POST request, putting the HTTP header &lt;code&gt;X_METHODOVERRIDE&lt;/code&gt; in the request.&lt;/p&gt;
&lt;p&gt;In jQuery you can accomplish this by modifyng the ajax method a little bit:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ajax&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;POST&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;/restview&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;pk&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pk&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;success&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Object deleted!&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;X_METHODOVERRIDE&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;DELETE&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So now you have a &amp;#8220;standard&amp;#8221; &lt;em&gt;type: &amp;#8216;POST&amp;#8217;&lt;/em&gt; and you&amp;#8217;ve added the &lt;em&gt;X_METHODOVERRIDE=DELETE&lt;/em&gt; HTTP header to the request.&lt;/p&gt;
&lt;p&gt;To support this in the Django side you can write a &lt;a title="Django documentation about middlewares." href="https://docs.djangoproject.com/en/1.6/topics/http/middleware/" target="_blank" rel="noopener noreferrer"&gt;middleware&lt;/a&gt;, like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.http&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;QueryDict&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HttpPostTunnelingMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;process_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;META&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;has_key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;HTTP_X_METHODOVERRIDE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;http_method&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;META&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;HTTP_X_METHODOVERRIDE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;http_method&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;put&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;PUT&amp;#39;&lt;/span&gt;
                &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;META&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;REQUEST_METHOD&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;PUT&amp;#39;&lt;/span&gt;
                &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PUT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;QueryDict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;http_method&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;delete&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;DELETE&amp;#39;&lt;/span&gt;
                &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;META&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;REQUEST_METHOD&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;DELETE&amp;#39;&lt;/span&gt;
                &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DELETE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;QueryDict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The middleware intercepts the &lt;em&gt;HTTP_X_METHODOVERRIDE&lt;/em&gt; header, and act accordingly by forcing the HTTP method in the Django side and creating the &lt;em&gt;request.PUT&lt;/em&gt; and &lt;em&gt;request.DELETE&lt;/em&gt; QueryDict.&lt;/p&gt;
&lt;p&gt;Assuming that you saved the above middleware in a file called middleware.py in your myapp Django app, you can add the middleware to your settings.py like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;MIDDLEWARE_CLASSES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s1"&gt;&amp;#39;django.contrib.sessions.middleware.SessionMiddleware&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;&amp;#39;django.middleware.common.CommonMiddleware&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;&amp;#39;django.middleware.csrf.CsrfViewMiddleware&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;&amp;#39;django.contrib.auth.middleware.AuthenticationMiddleware&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;&amp;#39;django.contrib.messages.middleware.MessageMiddleware&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;&amp;#39;django.middleware.clickjacking.XFrameOptionsMiddleware&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;&amp;#39;myapp.middleware.HttpPostTunnelingMiddleware&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now your coding dream will come true, enjoy your simple REST View in Django, consuming it with jQuery!&lt;/p&gt;
&lt;h2 id="what-about-the-function-based-views"&gt;What about the function based views?&lt;/h2&gt;
&lt;p&gt;You are not limited to a class-based view, but you can also use a function based view, by writing a view function similar to this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;rest_view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;GET&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# retrieve some object and render in template&lt;/span&gt;
    &lt;span class="nb"&gt;object&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MyModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pk&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;pk&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;object_detail.html&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;object&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;PUT&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# create an object and redirect to detail page&lt;/span&gt;
    &lt;span class="n"&gt;modelform&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;modelform_factory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyModel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;form&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;modelform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PUT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;form&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_valid&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;form&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;restview&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;DELETE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# delete an object and send a confirmation response&lt;/span&gt;
    &lt;span class="n"&gt;MyModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pk&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DELETE&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;pk&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ok&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I hope that this post helped you to implement put and delete requests in Django. If you want you can read other interesting Django related posts &lt;a href="/tag/django"&gt;here on my blog&lt;/a&gt;.&lt;/p&gt;</content><category term="web"></category><category term="django"></category><category term="jquery"></category><category term="rest"></category></entry><entry><title>Django on windows: how to make Django run in CherryPy as a Windows service</title><link href="https://www.guguweb.com/2013/10/13/django-on-windows/" rel="alternate"></link><published>2013-10-13T20:23:11+00:00</published><updated>2022-01-26T17:19:44+01:00</updated><author><name>Augusto Destrero</name></author><id>tag:www.guguweb.com,2013-10-13:/2013/10/13/django-on-windows/</id><summary type="html">&lt;p&gt;Recently a client asked me to investigate the possibility to have a Django application hosted in a Windows environment. I looked around a bit and there are &lt;a href="https://code.djangoproject.com/wiki/WindowsInstall"&gt;many ways&lt;/a&gt; to achieve this goal. I found the &amp;#8220;pure Python&amp;#8221; approach described here simpler to deploy and configure, yet very powerful and …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Recently a client asked me to investigate the possibility to have a Django application hosted in a Windows environment. I looked around a bit and there are &lt;a href="https://code.djangoproject.com/wiki/WindowsInstall"&gt;many ways&lt;/a&gt; to achieve this goal. I found the &amp;#8220;pure Python&amp;#8221; approach described here simpler to deploy and configure, yet very powerful and production ready for my needs.&lt;/p&gt;
&lt;p&gt;I will explain how to install Python, CherryPy and Django on Windows, and how to configure them to serve a Django application from the CherryPy WSGI server, running as a Windows service.&lt;/p&gt;
&lt;div class="toc"&gt;&lt;span class="toctitle"&gt;Table of Contents&lt;/span&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#install-python-27"&gt;Install Python 2.7&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#install-cherrypy"&gt;Install CherryPy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#cherrypy-server-started-as-a-windows-service"&gt;CherryPy server started as a Windows Service&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#install-django"&gt;Install Django&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#_1"&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#give-a-powerful-db-engine-to-your-django-app-install-mysql"&gt;Give a powerful DB engine to your Django app: install MySQL!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#make-your-django-project-an-installable-python-package"&gt;Make your Django project an installable python package&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#django-running-in-cherrypy-as-a-windows-service"&gt;Django running in CherryPy as a Windows service&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#conclusions"&gt;Conclusions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id="install-python-27"&gt;Install Python 2.7&lt;/h2&gt;
&lt;p&gt;First of all you have to install the &lt;a href="http://www.python.org/getit/"&gt;Python programming language&lt;/a&gt; support for Windows. I used Python 2.7.5 Windows Installer.&lt;/p&gt;
&lt;p&gt;Then to be able to invoke the &lt;em&gt;python&lt;/em&gt; command from the command line &amp;#8211; no matter what the current work directory is &amp;#8211; add Python to system path. Go to&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Control panel &amp;gt; System &amp;gt; Advanced &amp;gt; Environment variables&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;look for &lt;em&gt;path&lt;/em&gt; variable, click on &lt;em&gt;Edit&lt;/em&gt; and add this at the end:&lt;/p&gt;
&lt;pre&gt;C:\Python27\;C:\Python27\Scripts;&lt;/pre&gt;

&lt;p&gt;You have to close the Command prompt and then reopen it to have the &lt;em&gt;path&lt;/em&gt; variable updated.&lt;/p&gt;
&lt;h2 id="install-cherrypy"&gt;Install CherryPy&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://www.cherrypy.org/" title="CherryPy"&gt;CherryPy&lt;/a&gt; is a popular WSGI framework written in Python. Sometimes it is used &lt;strong&gt;instead of&lt;/strong&gt; Django to develop full fledged web applications. Here we will use the powerful &lt;a href="http://docs.cherrypy.org/stable/deployguide/index.html"&gt;WSGI and HTTP server&lt;/a&gt; implementation in CherryPy to host our Django application. Install latest version of CherryPy using a convenient &lt;a href="http://download.cherrypy.org/cherrypy/3.2.2/CherryPy-3.2.2.win32.exe"&gt;Windows installer&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;CherryPy will be installed in the standard path &lt;em&gt;C:\Python27\Lib\site-packages&lt;/em&gt;. To check your installation you can try the first tutorial by writing the following commands in the Command Prompt:&lt;/p&gt;
&lt;pre&gt;cd C:\Python27\Lib\site-packages\cherrypy\tutorial
python tut01_helloworld.py&lt;/pre&gt;

&lt;p&gt;Then open a web browser and go to &lt;em&gt;http://127.0.0.1:8080&lt;/em&gt; , if you see &lt;em&gt;Hello World&lt;/em&gt; your CherryPy installation was successful.&lt;/p&gt;
&lt;h2 id="cherrypy-server-started-as-a-windows-service"&gt;CherryPy server started as a Windows Service&lt;/h2&gt;
&lt;p&gt;It is very convenient to have your CherryPy based WSGI server launched as a Windows Service. In this way you can control your WSGI server using the standard management tools of Windows. You have to install the &lt;a href="http://sourceforge.net/projects/pywin32/files/pywin32/"&gt;pywin32 package&lt;/a&gt; to have Windows Service integration in Python.&lt;/p&gt;
&lt;p&gt;You can find a simple &lt;a href="http://tools.cherrypy.org/wiki/WindowsService"&gt;example script&lt;/a&gt; in the CherryPy wiki for launching a CherryPy based app as a Windows Service:&lt;/p&gt;
&lt;p&gt;Save the script with the name &lt;em&gt;cherrypy_service.py&lt;/em&gt;, then you can use the following commands to install the service in Windows and control the service afterwards:&lt;/p&gt;
&lt;p&gt;Install service with:&lt;/p&gt;
&lt;pre&gt;python cherrypy_service.py install&lt;/pre&gt;

&lt;p&gt;and start it with&lt;/p&gt;
&lt;pre&gt;python cherrypy_service.py start&lt;/pre&gt;

&lt;p&gt;If you do modifications to the script, use&lt;/p&gt;
&lt;pre&gt;python cherrypy_service.py update&lt;/pre&gt;

&lt;p&gt;to update the service, then&lt;/p&gt;
&lt;p&gt;python cherrypy_service.py restart&lt;/p&gt;
&lt;p&gt;to restart the modified service. You can also configure the service to start automatically from:&lt;/p&gt;
&lt;pre&gt;Control panel &amp;gt; Administration tools &amp;gt; Services&lt;/pre&gt;

&lt;h2 id="install-django"&gt;Install Django&lt;/h2&gt;
&lt;p&gt;Django is a popular web framework written in Python. A complete description of Django and how to use it is beyond the scope of this how-to, but I suggest you to look at the wonderful tutorials in the &lt;a href="https://docs.djangoproject.com/en/1.5/"&gt;Django documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Download the &lt;a href="https://www.djangoproject.com/download/"&gt;latest version of Django&lt;/a&gt;, extract the tar.gz using &lt;a href="http://www.winzip.com/"&gt;WinZip&lt;/a&gt; (unfortunately tar.gz is not supported in my version of Windows), then install Django with the usual:&lt;/p&gt;
&lt;pre&gt;python setup.py install&lt;/pre&gt;

&lt;p&gt;Try your Django installation with the following command in the Command Prompt&lt;/p&gt;
&lt;pre&gt;python -c "import django; print(django.get_version())"&lt;/pre&gt;

&lt;p&gt;if Django is installed correctly it will print the version number of Django, for instance &lt;em&gt;1.5.4&lt;/em&gt;. Now you can create your Django project and apps as described in the &lt;a href="https://docs.djangoproject.com/en/1.5/intro/tutorial01/"&gt;first tutorial&lt;/a&gt; in the Django documentation.&lt;/p&gt;
&lt;h2 id="_1"&gt;&lt;/h2&gt;
&lt;h2 id="give-a-powerful-db-engine-to-your-django-app-install-mysql"&gt;Give a powerful DB engine to your Django app: install MySQL!&lt;/h2&gt;
&lt;p&gt;Download the &lt;a href="http://dev.mysql.com/downloads/mysql/5.5.html#downloads"&gt;MySQL 5.5 windows installer&lt;/a&gt; and launch it; the installer will ask you some configuration preferences, the most important is the root password for the DB administration&lt;/p&gt;
&lt;p&gt;Enter mysql shell with your MySQL root account (assuming you chose &lt;em&gt;mysecret&lt;/em&gt; as your root password):&lt;/p&gt;
&lt;pre&gt;mysql -uroot -pmysecret&lt;/pre&gt;

&lt;p&gt;In the mysql shell create a test database and a test user with all privileges for the test DB:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;CREATE DATABASE test_django;&amp;lt;br /&amp;gt;
CREATE USER django@localhost IDENTIFIED BY 'django';&amp;lt;br /&amp;gt;
GRANT ALL PRIVILEGES ON test_django.* TO django@localhost;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;To be able to use MySQL as a DB backend in Django you have to install a last package: &lt;a href="https://pypi.python.org/pypi/MySQL-python"&gt;MySQL-python&lt;/a&gt;, by downloading and launching a convenient Windows installer.&lt;/p&gt;
&lt;p&gt;Then you can configure Django to use the newly created DB, by modifyng the DATABASES setting in the settings.py module of your Django project:&lt;/p&gt;
&lt;pre&gt;DATABASES = {
  'default': {
    'ENGINE': 'django.db.backends.mysql',
    'NAME': 'test_django',
    'USER': 'django',
    'PASSWORD': 'django',
    'HOST': '', # Empty for localhost through domain sockets
    'PORT': '', # Set to empty string for default.
  }
}&lt;/pre&gt;

&lt;p&gt;Now you can try syncdb to check the correct installation and configuration of Django and MySQL:&lt;/p&gt;
&lt;pre&gt;python manage.py syncdb&lt;/pre&gt;

&lt;p&gt;if all goes well it will create some &amp;#8220;internal&amp;#8221; Django tables in the MySQL database and it will ask you to create a Superuser account for your Django project.&lt;/p&gt;
&lt;h2 id="make-your-django-project-an-installable-python-package"&gt;Make your Django project an installable python package&lt;/h2&gt;
&lt;p&gt;That&amp;#8217;s simple! Just download &lt;a href="https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py"&gt;ez_setup.py&lt;/a&gt; save it in the Django project folder (where manage.py resides). Then in the same folder create a new file &lt;em&gt;setup.py&lt;/em&gt; with this content:&lt;/p&gt;
&lt;pre&gt;from ez_setup import use_setuptools
use_setuptools()
from setuptools import setup, find_packages
setup(
  name = "django_site",
  version = "0.1",
  packages = find_packages(),
  author = "John Doe",
  author_email = "john@example.com",
  description = "Test Django",
  include_package_data = True
)&lt;/pre&gt;

&lt;p&gt;Now you can install your Django project by doing:&lt;/p&gt;
&lt;pre&gt;python setup.py install&lt;/pre&gt;

&lt;h2 id="django-running-in-cherrypy-as-a-windows-service"&gt;Django running in CherryPy as a Windows service&lt;/h2&gt;
&lt;p&gt;This &lt;a href="http://www.defuze.org/archives/262-hosting-a-django-application-on-a-cherrypy-server.html"&gt;great article&lt;/a&gt; explains how to serve a Django application from the CherryPy WSGI server, I borrowed the code given in their &lt;a href="https://bitbucket.org/Lawouach/cherrypy-recipes/src/c8290261eefb/frameworks/django_"&gt;Bitbucket repo&lt;/a&gt; and I modified it a little to better fit my needs. I also added a script to make our CherryPy server launched as a Windows service, as described before. You can download a &lt;a href="https://docs.google.com/file/d/0B_nvs3fbLCaySDVHdW9ONUo1QW8/edit?usp=sharing"&gt;zip package&lt;/a&gt; from Google Drive with all the code.&lt;/p&gt;
&lt;p&gt;You can use the following command to install the Windows service:&lt;/p&gt;
&lt;pre&gt;python cherrypy_django_service.py install&lt;/pre&gt;

&lt;p&gt;Then you can start the service with:&lt;/p&gt;
&lt;pre&gt;python cherrypy_django_service.py start&lt;/pre&gt;

&lt;p&gt;The script &lt;em&gt;cherrypy_django_service.py&lt;/em&gt; assumes your Django project is installed in a standard Python path; this is guaranteed if you installed your Django project as a Python package as described before.&lt;/p&gt;
&lt;p&gt;Also, the script assumes that your Django project is called &lt;em&gt;django_site.&lt;/em&gt; If your Django project has a different name (likely) you have to edit &lt;em&gt;cherrypy_django_service.py&lt;/em&gt; accordingly.&lt;/p&gt;
&lt;p&gt;If everything works you should see your Django site at the address:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;http://127.0.0.1:8090&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;You can change the port in the &lt;em&gt;cherrypy_django_service.py&lt;/em&gt; script, together with other CherryPy options, which are however beyond the scope of this how-to.&lt;/p&gt;
&lt;h2 id="conclusions"&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;The method described here is IMHO a quite simple and straightforward way to deploy Django on Windows. I&amp;#8217;m particularly interested in your feedback about this approach and the results you obtained. Also the scalability and the performance of this solution is a very interesting discussion topic for me. Please leave a comment below if you have something to share.&lt;/p&gt;</content><category term="sysadmin"></category><category term="cherrypy"></category><category term="django"></category><category term="windows"></category></entry></feed>