<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>django on Arunrocks</title>
    <link>https://arunrocks.com/tags/django/</link>
    <description>Recent articles in django on Arunrocks</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <lastBuildDate>Tue, 13 Apr 2021 13:01:13 +0530</lastBuildDate><atom:link href="https://arunrocks.com/tags/django/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Home pages that morph</title>
      <link>https://arunrocks.com/home-pages-that-morph/</link>
      <pubDate>Tue, 13 Apr 2021 13:01:13 +0530</pubDate>
      
      <guid>https://arunrocks.com/home-pages-that-morph/</guid>
      <description>

&lt;div class=&#34;series-box&#34;&gt;
  &lt;p&gt;You are reading a post from a multi-part series of articles&lt;/p&gt;
  &lt;ol&gt;
    
    &lt;li&gt;
      &lt;a href=&#34;https://arunrocks.com/bleeding-edge-django/&#34;&gt;Staying on the bleeding edge&lt;/a&gt;
      &lt;/li&gt;
    
    &lt;li&gt;Home pages that morph&lt;/li&gt;
    &lt;/ol&gt;
&lt;/div&gt;

&lt;p&gt;Have you ever struggled to create a beautiful landing page for your Django site?&lt;/p&gt;
&lt;p&gt;A common ask by users of the &lt;a href=&#34;https://github.com/arocks/edge&#34;&gt;Edge project template&lt;/a&gt; was the support for home pages that had a completely different layout than the inner pages. For example, a first time visitor opening &lt;a href=&#34;https://example.com&#34;&gt;https://example.com&lt;/a&gt; should see a landing page that shows the benefits of signing up. But once signed-in the same url &lt;a href=&#34;https://example.com&#34;&gt;https://example.com&lt;/a&gt; should show the user interface of the web application.&lt;/p&gt;
&lt;p&gt;This is a common pattern today. For example this is how different github.com looks to a first time visitor and a logged in user:&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
    &lt;img loading=&#34;lazy&#34; src=&#34;https://arunrocks.com/static/images/blog/dimorphic-github.gif&#34; alt=&#34;Github-width50&#34;  title=&#34;Github homepage before signing in and after signing in (two-frame animation)&#34;  width=1125 height=&#34;2436&#34;  /&gt;
    &lt;figcaption&gt;Github homepage before signing in and after signing in (two-frame animation)&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;h3 id=&#34;whats-a-landing-page&#34;&gt;What’s a Landing Page&lt;/h3&gt;
&lt;p&gt;A landing page is a standalone page created for a specific marketing conversion goal, like subscribing to a newsletter or ebook downloads. For the purpose of this article, we will focus on the conversion goal of signing up users to your website or online product.&lt;/p&gt;
&lt;p&gt;A good landing page must be convincing enough for a visitor to share their personal details like their name and email. Even then, ask as few details as possible in the sign up form. If it is not relevant like the Company field, it is best to remove it. &lt;a href=&#34;https://www.zdnet.com/article/expedia-on-how-one-extra-data-field-can-cost-12m/&#34;&gt;Expedia dropped the “Company” field&lt;/a&gt; from their booking form and saw an increase of $12 million a year in profit.&lt;/p&gt;
&lt;p&gt;It must also be optimized for quick scanning. A widely quoted but often misunderstood &lt;a href=&#34;https://www.nngroup.com/articles/f-shaped-pattern-reading-web-content/&#34;&gt;study by Nielsen Norman Group&lt;/a&gt; showed how reading on the web is F-shaped. This is often bad for users and businesses since it skips important content. The recommended solution is to include important content in the first two paragraphs and have headings with the first two words bearing the most content.&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
    &lt;img loading=&#34;lazy&#34; src=&#34;https://arunrocks.com/static/images/blog/dimorphic-fshaped.png&#34; alt=&#34;F-shaped&#34;  title=&#34;F-shaped reading pattern in heat maps&#34;  width=943 height=&#34;821&#34;  /&gt;
    &lt;figcaption&gt;F-shaped reading pattern in heat maps&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;A homepage can be distinct from a landing page. But for many visitors who come to know about your site say through a link shared on a social network or an ad, the home page is the gateway to your product. So many sites check if the user has not logged in and show a landing page instead.&lt;/p&gt;
&lt;h3 id=&#34;challenges-in-django&#34;&gt;Challenges in Django&lt;/h3&gt;
&lt;p&gt;The challenge for most Django sites is that this requires extensive changes to the base template. A base template defines the basic structure of the site. &lt;a href=&#34;https://docs.djangoproject.com/en/dev/ref/templates/language/#template-inheritance&#34;&gt;Django documentation&lt;/a&gt; explains it further - &lt;em&gt;a base “skeleton” template contains all the common elements of your site and defines blocks that child templates can override&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The landing page differs considerably in content and layout from the inner pages. Here are some of the main differences:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Objectives:&lt;/strong&gt; The primary purpose of the landing page is to typically get users to sign up. The entire page is focussed on convincing the reader to perform the Call to Action (CTA) of clicking the “Sign up” button. Once you have signed up, your objective changes to give a good user experience while using the product i.e. the web application.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Layout&lt;/strong&gt;: Landing pages typically have a simplified and vertical layout where you are scrolling down to view engaging visuals and exciting animations. However a logged in user typically needs a more functional interface where various interface elements like sidebars are always within reach.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Navigation:&lt;/strong&gt; Most modern landing pages remove the top menu entirely along with other links to internal and external pages to simplify the experience. It does not make sense to show the application menu or the user profile drop down to a visitor who has not yet signed up.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Assets&lt;/strong&gt;: Landing pages, like other marketing pages, have scripts and other assets that track the effectiveness of pages like click through rates and conversion metrics. The inner pages would have different assets needed to create and maintain an effective user interface.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Optimizations:&lt;/strong&gt; According to a &lt;a href=&#34;https://dl.acm.org/doi/abs/10.1145/3419394.3423626&#34;&gt;study&lt;/a&gt; of the top 1000 websites, landing pages are 35% heavier but load faster by 56% than internal pages. This could be because the landing page needs to give a much more optimized user experience as it forms the crucial “first impression”.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In theory, a Django application could be crafted with a base template that can accommodate both a landing page and a web application layout. In practice it will be extremely cumbersome. As you have seen these two kinds of pages often have nothing in common. They might even be designed by two different teams. So, given a single base template you will often end up in overriding most of the blocks. There has to be a better way .&lt;/p&gt;
&lt;h3 id=&#34;its-morphin-time&#34;&gt;It&amp;rsquo;s morphin&#39; time!&lt;/h3&gt;
&lt;p&gt;Before we go further, it will be useful to give a name to this common pattern. Despite a lot of research, I couldn’t find any existing literature that names this pattern. So I went ahead and called it a &lt;strong&gt;Dimorphic Home Page&lt;/strong&gt; pattern. The word &lt;a href=&#34;https://www.wikiwand.com/en/Dimorphism&#34;&gt;Dimorphic&lt;/a&gt; means a thing that exists in two different forms. In this case a home page that changes form depending on whether the user has been authenticated or not.&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
    &lt;img loading=&#34;lazy&#34; src=&#34;https://arunrocks.com/static/images/blog/dimorphic-crystals.png&#34; alt=&#34;Dimorphic materials&#34;  title=&#34;Dimorphic materials like Calcite (left) and Aragonite (right) is the same compound (Calcium carbonate) existing in two forms or crystal structures. Pic courtesy: Wikipedia&#34;  width=1560 height=&#34;604&#34;  /&gt;
    &lt;figcaption&gt;Dimorphic materials like Calcite (left) and Aragonite (right) is the same compound (Calcium carbonate) existing in two forms or crystal structures. Pic courtesy: Wikipedia&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Here is a simple view (taken from Edge &lt;a href=&#34;https://github.com/arocks/edge/blob/django3/src/project_name/views.py&#34;&gt;source&lt;/a&gt; ) that implements this solution:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;django.views.generic.base&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TemplateView&lt;/span&gt;


&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;HomePageView&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;TemplateView&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;user_template_name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;users/home.html&amp;#34;&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;anon_template_name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;anons/home.html&amp;#34;&lt;/span&gt;

	&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;get_template_names&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
    	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;user&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;is_authenticated&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
        	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;user_template_name&lt;/span&gt;
    	&lt;span class=&#34;k&#34;&gt;else&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
        	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;anon_template_name&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We have used Class Based Generic Views instead of Function Based Views because they are easy to extend. For instance, if you need to pass a signup form in the context variable (and remove another page reload from conversion) then another view class can be derived easily.&lt;/p&gt;
&lt;p&gt;In terms of organization, the templates for unauthenticated and authenticated users are kept in separate directories named say &lt;code&gt;anon&lt;/code&gt; and &lt;code&gt;users&lt;/code&gt; respectively. This makes it easier to prevent unintentional leakage of sensitive data in unauthenticated pages.&lt;/p&gt;
&lt;h3 id=&#34;designing-a-beautiful-landing-page&#34;&gt;Designing a Beautiful Landing Page&lt;/h3&gt;
&lt;p&gt;The landing page of Edge has been designed based on modern &lt;a href=&#34;https://cxl.com/blog/form-design-best-practices/&#34;&gt;landing page best practices&lt;/a&gt;. If you study several actual landing pages, you would observe many of them use common animation components like &lt;a href=&#34;https://animate.style/&#34;&gt;animate.css&lt;/a&gt; and &lt;a href=&#34;https://wowjs.uk/docs.html&#34;&gt;wow.js&lt;/a&gt;. This is what powers the sliding and dancing images or text as you scroll down revealing new sections.&lt;/p&gt;
&lt;p&gt;The dimorphic Edge homepage is a work in progress but it currently looks like this:&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
    &lt;img loading=&#34;lazy&#34; src=&#34;https://arunrocks.com/static/images/blog/dimorphic-edge.gif&#34; alt=&#34;Edge-width50&#34;  title=&#34;Django Edge homepage before signing in and after signing in (two-frame animation). Hero image courtesy Scale by Flexiple&#34;  width=1125 height=&#34;2436&#34;  /&gt;
    &lt;figcaption&gt;Django Edge homepage before signing in and after signing in (two-frame animation). Hero image courtesy Scale by Flexiple&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Design sensibilities change over time. But the template should be a good starting point for solo Django developers who are not familiar with design. It would be less daunting than starting from a blank HTML document.&lt;/p&gt;
&lt;h3 id=&#34;try-what-is-new&#34;&gt;Try what is new&lt;/h3&gt;
&lt;p&gt;Check out the &lt;a href=&#34;https://github.com/arocks/edge/tree/django3&#34;&gt;Edge Django 3.x branch&lt;/a&gt; with its dimorphic landing page. Follow the instructions in the &lt;a href=&#34;https://github.com/arocks/edge/blob/django3/README.md&#34;&gt;README&lt;/a&gt; to create a quick Django project. We welcome your feedback and contributions.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Staying on the bleeding edge</title>
      <link>https://arunrocks.com/bleeding-edge-django/</link>
      <pubDate>Tue, 09 Mar 2021 11:28:29 +0530</pubDate>
      
      <guid>https://arunrocks.com/bleeding-edge-django/</guid>
      <description>

&lt;div class=&#34;series-box&#34;&gt;
  &lt;p&gt;You are reading a post from a multi-part series of articles&lt;/p&gt;
  &lt;ol&gt;
    
    &lt;li&gt;Staying on the bleeding edge&lt;/li&gt;
    
    &lt;li&gt;
      &lt;a href=&#34;https://arunrocks.com/home-pages-that-morph/&#34;&gt;Home pages that morph&lt;/a&gt;
      &lt;/li&gt;
    &lt;/ol&gt;
&lt;/div&gt;

&lt;p&gt;How fast can you go from getting an amazing product idea to bringing it in front of real users? It is a process that has several steps - some fun but mostly boring. It could also take a long time. In fact the longer it takes, the lower your motivation levels dip and competition starts looming large. This is why we use productivity enhancers like frameworks, libraries and templates not just to reach the users faster but also to ensure that we ship it.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://django-edge.readthedocs.io/&#34;&gt;Django Edge&lt;/a&gt; is a Django project starter template that I &lt;a href=&#34;https://arunrocks.com/introducing-edge-a-modern-django-project-template&#34;&gt;started&lt;/a&gt; in 2014 with the idea of making web apps faster using my go-to toolset - Django, Bootstrap and many of the most useful Django libraries. The project is quite popular with over &lt;a href=&#34;https://github.com/arocks/edge/&#34;&gt;770 stars on Github&lt;/a&gt;. Unlike many other starter templates, it shipped with some essential pages like a homepage, register, login etc that were presentable and working.&lt;/p&gt;
&lt;p&gt;An update to Edge has been long overdue. But the Django landscape has changed a bit. For a long time, the most common use of the framework was as a back-end for a front-end JavaScript framework like React or Vue (and any other possible front-ends like a mobile app). This typically uses the excellent Django Rest Framework (DRF) to build a REST API which the front-end consumes. This could be one possible direction that Edge could take.&lt;/p&gt;
&lt;p&gt;However the use of state-heavy front-end frameworks with millions of dependencies has led to &lt;a href=&#34;https://segment.com/blog/the-deep-roots-of-js-fatigue/&#34;&gt;Javascript fatigue&lt;/a&gt;. The trend is somewhat coming back to back-end rendered pages. Choosing &lt;a href=&#34;https://mcfunley.com/choose-boring-technology&#34;&gt;&amp;ldquo;Boring Technology&amp;rdquo;&lt;/a&gt; might counter-intuitively leave lots of room for innovation in the areas that you may find fun and interesting. There is really &lt;a href=&#34;https://juliensalinas.com/en/htmx-intercoolerjs-django-nlpcloud/&#34;&gt;no need to throw away&lt;/a&gt; Django Templates if you need a single page application thanks to &lt;a href=&#34;https://htmx.org/&#34;&gt;HTMX&lt;/a&gt;. So continuing to ship with beautifully designed templates is another direction that Edge could take as well.&lt;/p&gt;
&lt;p&gt;I was tempted to try this &amp;ldquo;Double-edged&amp;rdquo; approach for a moment. But then I realized that it is already a lot of work to maintain just one open source project. Users who need Django for a REST API will probably find it incomplete unless it is also married with Rest, Vue, Angular or some other shiny new JavaScript framework out of the box. This is a truly fragmented base that keeps switching new frameworks or even abandoning all frameworks.&lt;/p&gt;
&lt;p&gt;Hence I went back to the familiar Edge. Provide a fully working web application starter with the best of what Django can provide. Aim to be a good starting point for &lt;a href=&#34;https://www.listennotes.com/blog/the-boring-technology-behind-a-one-person-23/&#34;&gt;single developer&lt;/a&gt; projects. Focus on the long requested features like social authentication or Docker and improve on what it currently does.&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
    &lt;img loading=&#34;lazy&#34; src=&#34;https://arunrocks.com/static/images/blog/edge-3-beta.jpg&#34; alt=&#34;Django Edge Beta&#34;  title=&#34;Yay!...a working login page&#34;  width=1888 height=&#34;913&#34;  /&gt;
    &lt;figcaption&gt;Yay!...a working login page&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;So this is probably the first of many posts where I share what I am planning to do with Edge. I believe that open development is the best way to build open source projects. Try the beta here: &lt;a href=&#34;https://github.com/arocks/edge/tree/django3&#34;&gt;https://github.com/arocks/edge/tree/django3&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Pull requests are welcome! 😊&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Fitting a Django Application in One File</title>
      <link>https://arunrocks.com/django-application-in-one-file/</link>
      <pubDate>Wed, 09 Dec 2020 22:54:50 +0530</pubDate>
      
      <guid>https://arunrocks.com/django-application-in-one-file/</guid>
      <description>&lt;p&gt;Earlier this week, Anthony a french economics university student wanted to talk to me over Zoom about my &lt;a href=&#34;https://arunrocks.com/ray-tracer-in-python-1-points-in-3d-space-show-notes/&#34;&gt;ray tracer tutorials&lt;/a&gt;. He and his friend were new to Python but were excited to implement their own ray tracer after following my videos. One of the questions that popped up in the conversation was - &amp;ldquo;Can we put all the classes in one file instead of breaking it into individual files per class?&amp;rdquo;. I said, &amp;ldquo;Of course&amp;rdquo; and noticed a wave of relief in their faces. In fact, I explained, my earlier implementation was all in one file and later broken up for better pedagogy.&lt;/p&gt;
&lt;div data-pullquote=&#34;&amp;#34;It might be amusing to some Django developers that we will not start with the startproject command.&#34;&gt;
&lt;/div&gt;
&lt;p&gt;But the charm of an entire project in a single file is compelling. I remember seeing a Sinatra web application a few years ago containing the entire application and assets like HTML templates and CSS in a single file. Presenting all the components in the same file gave a complete high-level overview of the project by simply scrolling up and down.&lt;/p&gt;
&lt;p&gt;Normally, at this point, someone would suggest a microframework. But it is not that easy.&lt;/p&gt;
&lt;h2 id=&#34;microframeworks&#34;&gt;Microframeworks&lt;/h2&gt;
&lt;p&gt;Microframeworks take a minimalistic approach by omitting certain components or directing you to a few recommended components. For instance, &lt;a href=&#34;https://bottlepy.org/docs/dev/&#34;&gt;Bottle&lt;/a&gt; contains basic form handling capabilities but has no protection against &lt;a href=&#34;https://www.wikiwand.com/en/Cross-site_request_forgery&#34;&gt;CSRF&lt;/a&gt; or &lt;a href=&#34;https://www.wikiwand.com/en/Clickjacking&#34;&gt;clickjacking&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So the approach is generally to use another library like &lt;a href=&#34;https://pypi.org/project/bottle-utils-csrf/&#34;&gt;bottle-utils-csrf&lt;/a&gt;. This leaves the task of integration to the developer. This is not to pooh-pooh tiny web frameworks. I love the idea (especially Bottle which I think is really cute). But for public facing sites, I prefer the safety and convenience of Django.&lt;/p&gt;
&lt;p&gt;So I am tempted to try this one-file trick in Django. Let’s try to make a non-trivial web application with forms, templates and images. How does one go about doing something like that?&lt;/p&gt;
&lt;p&gt;Note: if you prefer to watch the video version, click on the video below:&lt;/p&gt;

&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;https://www.youtube.com/embed/7XNChGGoBf0&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allowfullscreen title=&#34;YouTube Video&#34;&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;h2 id=&#34;django-applications-in-one-file&#34;&gt;Django Applications in One File&lt;/h2&gt;
&lt;h3 id=&#34;minimal&#34;&gt;Minimal&lt;/h3&gt;
&lt;p&gt;Let’s start small by creating a minimal Hello World application in Django. It might be amusing to some Django developers that we will not start with the &lt;code&gt;startproject&lt;/code&gt; command. In fact, it is not necessary for Django to work at all. All that initial directory structure and files like settings.py are for your convenience.&lt;/p&gt;
&lt;p&gt;First, create a simple file called &lt;code&gt;app.py&lt;/code&gt; with the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;sys&lt;/span&gt;

&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;django.conf&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;settings&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;django.urls&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;path&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;django.http&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;HttpResponse&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;settings&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;configure&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;DEBUG&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;True&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;# For debugging&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;SECRET_KEY&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;a-bad-secret&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;# Insecure! change this&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;ROOT_URLCONF&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;vm&#34;&gt;__name__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;


&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;home&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;HttpResponse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Welcome!&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;


&lt;span class=&#34;n&#34;&gt;urlpatterns&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;home&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;vm&#34;&gt;__name__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;__main__&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
	&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;django.core.management&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;execute_from_command_line&lt;/span&gt;

	&lt;span class=&#34;n&#34;&gt;execute_from_command_line&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sys&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Yes, that&amp;rsquo;s all you need. There are some bad practices like hard coding the secret key (easily fixed). But the sheer elegance of everything being in hardly a screenful is quite rewarding.&lt;/p&gt;
&lt;p&gt;The command to run this file is: &lt;code&gt;python app.py runserver 8080&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Now we will skip a couple of steps (they are in the video) and move on to a simple &amp;ldquo;Coming Soon&amp;rdquo; landing page.&lt;/p&gt;
&lt;h3 id=&#34;coming-soon-application&#34;&gt;Coming Soon Application&lt;/h3&gt;
&lt;p&gt;The idea of a coming-soon page is to gauge interest in a product before it is released. Such pages must have a clear call to action (CTA) like asking for your email. Ideally it should have minimum friction and yet collect all the relevant information.&lt;/p&gt;
&lt;p&gt;Let’s look at my updated app.py:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;os&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;sys&lt;/span&gt;

&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;django.conf&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;settings&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;django.urls&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;path&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;django.http&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;HttpResponse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;HttpResponseRedirect&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;django.core.wsgi&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;get_wsgi_application&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;django.template&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RequestContext&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Template&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;django&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;forms&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;CSV_LIST&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;thelist.csv&amp;#34;&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;settings&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;configure&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;DEBUG&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;environ&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;DEBUG&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;ALLOWED_HOSTS&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;# Disable host header validation&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;ROOT_URLCONF&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;vm&#34;&gt;__name__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;SECRET_KEY&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;environ&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;SECRET_KEY&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;a-bad-secret&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;TEMPLATES&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[{&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;BACKEND&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;django.template.backends.django.DjangoTemplates&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}],&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;MIDDLEWARE_CLASSES&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
    	&lt;span class=&#34;s2&#34;&gt;&amp;#34;django.middleware.common.CommonMiddleware&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    	&lt;span class=&#34;s2&#34;&gt;&amp;#34;django.middleware.csrf.CsrfViewMiddleware&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    	&lt;span class=&#34;s2&#34;&gt;&amp;#34;django.middleware.clickjacking.XFrameOptionsMiddleware&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;


&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;EnlistForm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;forms&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Form&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;email&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;forms&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;EmailField&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
    	&lt;span class=&#34;n&#34;&gt;required&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;True&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    	&lt;span class=&#34;n&#34;&gt;label&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;False&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    	&lt;span class=&#34;n&#34;&gt;widget&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;forms&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;EmailInput&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;placeholder&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Email&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}),&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;referrer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;forms&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CharField&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;required&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;False&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;widget&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;forms&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;HiddenInput&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt;


&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;home&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;method&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;POST&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
    	&lt;span class=&#34;n&#34;&gt;form&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;EnlistForm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;POST&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
    	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;form&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;is_valid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;
        	&lt;span class=&#34;n&#34;&gt;email&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;form&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cleaned_data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;email&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
        	&lt;span class=&#34;n&#34;&gt;referrer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;form&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cleaned_data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;referrer&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
        	&lt;span class=&#34;n&#34;&gt;ip&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;META&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;REMOTE_ADDR&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
        	&lt;span class=&#34;k&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Got email of {email}&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
        	&lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;open&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CSV_LIST&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;a&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;csv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
            	&lt;span class=&#34;n&#34;&gt;csv&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;write&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;{email},{referrer},{ip}&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
        	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;HttpResponseRedirect&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/thanks/&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;else&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
    	&lt;span class=&#34;n&#34;&gt;form&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;EnlistForm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;initial&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;referrer&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;META&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;HTTP_REFERER&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)})&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;context&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RequestContext&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
    	&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;content&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Sign up for early access&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;form&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;form&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;HttpResponse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MAIN_HTML&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;render&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;


&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;thanks&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;context&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RequestContext&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
    	&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    	&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;content&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Thank you for signing up. We will contact you!&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;form&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;HttpResponse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MAIN_HTML&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;render&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;


&lt;span class=&#34;n&#34;&gt;urlpatterns&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;home&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;thanks/&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;thanks&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;app&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;get_wsgi_application&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;


&lt;span class=&#34;n&#34;&gt;MAIN_HTML&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Template&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
	&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;lt;html&amp;gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  &amp;lt;head&amp;gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;	&amp;lt;title&amp;gt;Coming Soon | Flying Cars&amp;lt;/title&amp;gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;	&amp;lt;meta name=&amp;#34;viewport&amp;#34; content=&amp;#34;width=device-width, initial-scale=1.0&amp;#34;&amp;gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;	&amp;lt;style&amp;gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; 	@import url(&amp;#39;https://fonts.googleapis.com/css2?family=Exo:wght@400;500;600;700;800;900&amp;amp;display=swap&amp;#39;);
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; 	*{
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;   	margin: 0;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;   	padding: 0;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;   	box-sizing: border-box;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;   	font-family: &amp;#39;Exo&amp;#39;, sans-serif;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; 	}
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; 	html,body{
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;   	display: grid;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;   	height: 100%;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;   	width: 100%;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;   	place-items: center;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;   	background-color: #343434;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;   	/* Thanks to Hero Patterns for the background */
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;   	background-image: url(&amp;#34;data:image/svg+xml,%3Csvg xmlns=&amp;#39;http://www.w3.org/2000/svg&amp;#39; viewBox=&amp;#39;0 0 56 28&amp;#39; width=&amp;#39;56&amp;#39; height=&amp;#39;28&amp;#39;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;%3E&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;%3Cpath fill=&amp;#39;%23000000&amp;#39; fill-opacity=&amp;#39;0.4&amp;#39; d=&amp;#39;M56 26v2h-7.75c2.3-1.27 4.94-2 7.75-2zm-26 2a2 2 0 1 0-4 0h-4.09A25.98 25.98 0 0 0 0 16v-2c.67 0 1.34.02 2 .07V14a2 2 0 0 0-2-2v-2a4 4 0 0 1 3.98 3.6 28.09 28.09 0 0 1 2.8-3.86A8 8 0 0 0 0 6V4a9.99 9.99 0 0 1 8.17 4.23c.94-.95 1.96-1.83 3.03-2.63A13.98 13.98 0 0 0 0 0h7.75c2 1.1 3.73 2.63 5.1 4.45 1.12-.72 2.3-1.37 3.53-1.93A20.1 20.1 0 0 0 14.28 0h2.7c.45.56.88 1.14 1.29 1.74 1.3-.48 2.63-.87 4-1.15-.11-.2-.23-.4-.36-.59H26v.07a28.4 28.4 0 0 1 4 0V0h4.09l-.37.59c1.38.28 2.72.67 4.01 1.15.4-.6.84-1.18 1.3-1.74h2.69a20.1 20.1 0 0 0-2.1 2.52c1.23.56 2.41 1.2 3.54 1.93A16.08 16.08 0 0 1 48.25 0H56c-4.58 0-8.65 2.2-11.2 5.6 1.07.8 2.09 1.68 3.03 2.63A9.99 9.99 0 0 1 56 4v2a8 8 0 0 0-6.77 3.74c1.03 1.2 1.97 2.5 2.79 3.86A4 4 0 0 1 56 10v2a2 2 0 0 0-2 2.07 28.4 28.4 0 0 1 2-.07v2c-9.2 0-17.3 4.78-21.91 12H30zM7.75 28H0v-2c2.81 0 5.46.73 7.75 2zM56 20v2c-5.6 0-10.65 2.3-14.28 6h-2.7c4.04-4.89 10.15-8 16.98-8zm-39.03 8h-2.69C10.65 24.3 5.6 22 0 22v-2c6.83 0 12.94 3.11 16.97 8zm15.01-.4a28.09 28.09 0 0 1 2.8-3.86 8 8 0 0 0-13.55 0c1.03 1.2 1.97 2.5 2.79 3.86a4 4 0 0 1 7.96 0zm14.29-11.86c1.3-.48 2.63-.87 4-1.15a25.99 25.99 0 0 0-44.55 0c1.38.28 2.72.67 4.01 1.15a21.98 21.98 0 0 1 36.54 0zm-5.43 2.71c1.13-.72 2.3-1.37 3.54-1.93a19.98 19.98 0 0 0-32.76 0c1.23.56 2.41 1.2 3.54 1.93a15.98 15.98 0 0 1 25.68 0zm-4.67 3.78c.94-.95 1.96-1.83 3.03-2.63a13.98 13.98 0 0 0-22.4 0c1.07.8 2.09 1.68 3.03 2.63a9.99 9.99 0 0 1 16.34 0z&amp;#39;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;%3E&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;%3C/path&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;%3E&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;%3C/svg&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;%3E&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;);
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; 	}
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; 	::selection{
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;   	color: #fff;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;   	background: #FC4782;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; 	}
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; 	.wrapper{
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;   	color: #eee;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;   	max-width: 900px;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;   	text-align: center;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;   	padding: 0 50px;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; 	}
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; 	.signup {
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;   	margin-top: 30px;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;   	margin-bottom: 10px;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; 	}
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; 	.content {
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;   	margin-top: 40px;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;   	margin-bottom: 10px;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; 	}
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;	&amp;lt;/style&amp;gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  &amp;lt;/head&amp;gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  &amp;lt;body&amp;gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;	&amp;lt;div class=&amp;#34;wrapper&amp;#34;&amp;gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  	&amp;lt;svg width=&amp;#34;600&amp;#34; height=&amp;#34;300&amp;#34; version=&amp;#34;1.1&amp;#34; viewBox=&amp;#34;0 0 600 300&amp;#34; xmlns=&amp;#34;http://www.w3.org/2000/svg&amp;#34;&amp;gt;&amp;lt;g transform=&amp;#34;translate(0,312)&amp;#34;&amp;gt;&amp;lt;path d=&amp;#34;m218.36-289.66h163.29c29.039 0 52.417 23.378 52.417 52.417v45.564c0 29.039-23.378 52.417-52.417 52.417h-163.29c-29.039 0-52.417-23.378-52.417-52.417v-45.564c0-29.039 23.378-52.417 52.417-52.417z&amp;#34; fill=&amp;#34;#204a87&amp;#34; stop-color=&amp;#34;#000000&amp;#34; stroke=&amp;#34;#eeeeec&amp;#34; stroke-linecap=&amp;#34;round&amp;#34; stroke-linejoin=&amp;#34;round&amp;#34; stroke-width=&amp;#34;4&amp;#34;/&amp;gt;&amp;lt;g fill=&amp;#34;#729fcf&amp;#34; stroke=&amp;#34;#eeeeec&amp;#34; stroke-linejoin=&amp;#34;round&amp;#34; stroke-width=&amp;#34;4&amp;#34;&amp;gt;&amp;lt;path d=&amp;#34;m240.88-162.15c21.473-37.192 42.946-74.385 64.419-111.58&amp;#34; stop-color=&amp;#34;#000000&amp;#34;/&amp;gt;&amp;lt;g stroke-linecap=&amp;#34;round&amp;#34;&amp;gt;&amp;lt;path d=&amp;#34;m276.15-249.32h-72.081&amp;#34; stop-color=&amp;#34;#000000&amp;#34;/&amp;gt;&amp;lt;path d=&amp;#34;m259.9-221.32h-56.025&amp;#34; stop-color=&amp;#34;#000000&amp;#34;/&amp;gt;&amp;lt;path d=&amp;#34;m267.69-235.32h-63.714&amp;#34; stop-color=&amp;#34;#000000&amp;#34;/&amp;gt;&amp;lt;path d=&amp;#34;m370.37-162.15c-21.473-37.192-42.946-74.385-64.419-111.58&amp;#34; stop-color=&amp;#34;#000000&amp;#34;/&amp;gt;&amp;lt;path d=&amp;#34;m332-249.93h72.081&amp;#34; stop-color=&amp;#34;#000000&amp;#34;/&amp;gt;&amp;lt;path d=&amp;#34;m348.25-221.93h56.025&amp;#34; stop-color=&amp;#34;#000000&amp;#34;/&amp;gt;&amp;lt;path d=&amp;#34;m340.46-235.93h63.714&amp;#34; stop-color=&amp;#34;#000000&amp;#34;/&amp;gt;&amp;lt;path d=&amp;#34;m240.88-162.15c21.473-26.526 42.946-53.051 64.419-79.577&amp;#34; stop-color=&amp;#34;#000000&amp;#34;/&amp;gt;&amp;lt;/g&amp;gt;&amp;lt;path d=&amp;#34;m370.37-162.15c-21.473-26.526-42.946-53.051-64.419-79.577&amp;#34; stop-color=&amp;#34;#000000&amp;#34;/&amp;gt;&amp;lt;/g&amp;gt;&amp;lt;g fill=&amp;#34;#eeeeec&amp;#34;&amp;gt;&amp;lt;path d=&amp;#34;m183.74-116.06-6.3858 17.316h12.795zm-2.6568-4.6378h5.337l13.261 34.795h-4.8942l-3.1696-8.9261h-15.685l-3.1696 8.9261h-4.9641z&amp;#34; style=&amp;#34;text-decoration-color:#000000;text-decoration-line:none&amp;#34;/&amp;gt;&amp;lt;path d=&amp;#34;m222.66-120.7h4.7078v34.795h-4.7078z&amp;#34; style=&amp;#34;text-decoration-color:#000000;text-decoration-line:none&amp;#34;/&amp;gt;&amp;lt;path d=&amp;#34;m271.14-102.22q1.5149.51273 2.9365 2.1907 1.445 1.678 2.8899 4.6145l4.7777 9.5087h-5.0573l-4.4514-8.9261q-1.7246-3.4959-3.356-4.6378-1.6081-1.142-4.4048-1.142h-5.1273v14.706h-4.7078v-34.795h10.627q5.9663 0 8.9028 2.4937t2.9365 7.5278q0 3.2861-1.5382 5.4535-1.5149 2.1674-4.4281 3.0064zm-11.793-14.613v12.352h5.9196q3.4026 0 5.1273-1.5615 1.7479-1.5848 1.7479-4.6378t-1.7479-4.5912q-1.7246-1.5615-5.1273-1.5615z&amp;#34; style=&amp;#34;text-decoration-color:#000000;text-decoration-line:none&amp;#34;/&amp;gt;&amp;lt;path d=&amp;#34;m329.38-118.02v4.9641q-2.3772-2.214-5.0806-3.3094-2.6802-1.0954-5.7099-1.0954-5.9663 0-9.1358 3.659-3.1696 3.6357-3.1696 10.534 0 6.8752 3.1696 10.534 3.1696 3.6357 9.1358 3.6357 3.0297 0 5.7099-1.0954 2.7035-1.0954 5.0806-3.3094v4.9175q-2.4704 1.678-5.2438 2.517-2.7501.83901-5.8264.83901-7.9006 0-12.445-4.8243-4.5446-4.8476-4.5446-13.214 0-8.39 4.5446-13.214 4.5446-4.8476 12.445-4.8476 3.123 0 5.873.839 2.7734.8157 5.1972 2.4704z&amp;#34; style=&amp;#34;text-decoration-color:#000000;text-decoration-line:none&amp;#34;/&amp;gt;&amp;lt;path d=&amp;#34;m366.18-116.06-6.3858 17.316h12.795zm-2.6568-4.6378h5.337l13.261 34.795h-4.8942l-3.1696-8.9261h-15.685l-3.1696 8.9261h-4.9641z&amp;#34; style=&amp;#34;text-decoration-color:#000000;text-decoration-line:none&amp;#34;/&amp;gt;&amp;lt;path d=&amp;#34;m421.6-102.22q1.5149.51273 2.9365 2.1907 1.445 1.678 2.8899 4.6145l4.7777 9.5087h-5.0573l-4.4514-8.9261q-1.7246-3.4959-3.356-4.6378-1.6081-1.142-4.4048-1.142h-5.1272v14.706h-4.7078v-34.795h10.627q5.9663 0 8.9028 2.4937t2.9365 7.5278q0 3.2861-1.5382 5.4535-1.5149 2.1674-4.4281 3.0064zm-11.793-14.613v12.352h5.9196q3.4026 0 5.1272-1.5615 1.7479-1.5848 1.7479-4.6378t-1.7479-4.5912q-1.7246-1.5615-5.1272-1.5615z&amp;#34; style=&amp;#34;text-decoration-color:#000000;text-decoration-line:none&amp;#34;/&amp;gt;&amp;lt;/g&amp;gt;&amp;lt;/g&amp;gt;&amp;lt;/svg&amp;gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  	&amp;lt;h1&amp;gt;All Your Traffic Problems Solved!&amp;lt;/h1&amp;gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  	&amp;lt;h2&amp;gt;Feel the future with affordable levitating cars.&amp;lt;/h2&amp;gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  	&amp;lt;div class=&amp;#34;content&amp;#34;&amp;gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;    	{{ content }}
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;    	{&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;% i&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;f form %}
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;      	&amp;lt;form action=&amp;#34;.&amp;#34; method=&amp;#34;post&amp;#34; class=&amp;#34;enlist_form&amp;#34;&amp;gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;        	{&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;% c&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;srf_token %}
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;        	{{ form.non_field_errors }}
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;        	{{ form.email.errors }}
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;        	{{ form.referrer }}
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;        	{{ form.referrer.errors }}
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;        	{{ form.email }}
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;        	&amp;lt;button type=&amp;#34;submit&amp;#34;&amp;gt;Add Me&amp;lt;/button&amp;gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;      	&amp;lt;/form&amp;gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;    	{&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;% e&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;ndif %}
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  	&amp;lt;/div&amp;gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;	&amp;lt;/div&amp;gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  &amp;lt;/body&amp;gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;lt;/html&amp;gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;


&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;vm&#34;&gt;__name__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;__main__&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
	&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;django.core.management&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;execute_from_command_line&lt;/span&gt;

	&lt;span class=&#34;n&#34;&gt;execute_from_command_line&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sys&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Except for the absence of individual files, most of the code should be familiar to a Django developer. There is a large HTML template (including two SVG images) embedded as a string.&lt;/p&gt;
&lt;p&gt;Note that I do not use the ORM here. Django does seem to need a directory structure for that (Unless any reader could show me how to do it in a single file).&lt;/p&gt;
&lt;p&gt;Hopefully this shows how minimal Django could be. You might be able to use your favourite framework in places which you didn’t think were possible.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>3 Effective Examples of Django Async Views without Sleeping</title>
      <link>https://arunrocks.com/django-async-views-examples/</link>
      <pubDate>Tue, 01 Dec 2020 13:33:19 +0530</pubDate>
      
      <guid>https://arunrocks.com/django-async-views-examples/</guid>
      <description>&lt;p&gt;In August this year, &lt;a href=&#34;https://www.djangoproject.com/weblog/2020/aug/04/django-31-released/&#34;&gt;Django 3.1 arrived&lt;/a&gt; with support for Django async views. This was fantastic news but most people raised the obvious question &amp;ndash; What can I do with it? There have been a few tutorials about Django asynchronous views that demonstrate asynchronous execution while calling &lt;code&gt;asyncio.sleep&lt;/code&gt;. But that merely led to the refinement of the popular question &amp;ndash; What can I do with it besides &lt;strong&gt;sleep&lt;/strong&gt;-ing?&lt;/p&gt;
&lt;div data-pullquote=&#34;&amp;#34;In Django&amp;#39;s MTV (Model Template View) architecture, Views are disproportionately more powerful than others.&#34;&gt;
&lt;/div&gt;
&lt;p&gt;The short answer is &amp;ndash; it is a very powerful technique to write efficient views. For a detailed overview of what asynchronous views are and how they can be used, keep on reading. If you are new to asynchronous support in Django and like to know more background, read my earlier article: &lt;a href=&#34;https://arunrocks.com/a-guide-to-asgi-in-django-30-and-its-performance/&#34;&gt;A Guide to ASGI in Django 3.0 and its Performance&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;django-async-views&#34;&gt;Django Async Views&lt;/h2&gt;
&lt;p&gt;Django now allows you to write views which can run asynchronously. First let&amp;rsquo;s refresh your memory by looking at a simple and minimal &lt;em&gt;synchronous&lt;/em&gt; view in Django:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;HttpResponse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Made a pretty page&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It takes a request object and returns a response object. In a real world project, a view does many things like fetching records from a database, calling a service or rendering a template. But they work synchronously or one after the other.&lt;/p&gt;
&lt;p&gt;In Django&amp;rsquo;s MTV (Model Template View) architecture, Views are disproportionately more powerful than others (I find it comparable to a controller in MVC architecture though these things are debatable). Once you enter a view you can perform almost any logic necessary to create a response. This is why Asynchronous Views are so important. It lets you do more things concurrently.&lt;/p&gt;
&lt;p&gt;It is quite easy to write an asynchronous view. For example the asynchronous version of our minimal example above would be:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;n&#34;&gt;async&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;index_async&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;HttpResponse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Made a pretty page asynchronously.&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is a &lt;em&gt;coroutine&lt;/em&gt; rather than a function. You cannot call it directly. An event loop needs to be created to execute it. But you do not have to worry about that difference since Django takes care of all that.&lt;/p&gt;
&lt;p&gt;Note that this particular view is not invoking anything asynchronously. If Django is running in the classic WSGI mode, then a new event loop is created (automatically) to run this coroutine. So in this case, it might be slightly slower than the synchronous version. But that&amp;rsquo;s because you are not using it to run tasks concurrently.&lt;/p&gt;
&lt;p&gt;So then why bother writing asynchronous views? The limitations of synchronous views  become apparent only at a certain scale. When it comes to large scale web applications probably nothing beats FaceBook.&lt;/p&gt;
&lt;h2 id=&#34;views-at-facebook&#34;&gt;Views at Facebook&lt;/h2&gt;
&lt;p&gt;In August, Facebook &lt;a href=&#34;https://engineering.fb.com/2020/08/07/security/pysa/&#34;&gt;released a static analysis tool&lt;/a&gt; to detect and prevent security issues in Python. But what caught my eye was how the views were written in the examples they had shared. They were all async!&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# views/user.py&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;async&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;get_profile&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;HttpRequest&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;HttpResponse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
   &lt;span class=&#34;n&#34;&gt;profile&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;load_profile&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;GET&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;user_id&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;
   &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
 
&lt;span class=&#34;c1&#34;&gt;# controller/user.py&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;async&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;load_profile&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;user_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
   &lt;span class=&#34;n&#34;&gt;user&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;load_user&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;user_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;# Loads a user safely; no SQL injection&lt;/span&gt;
   &lt;span class=&#34;n&#34;&gt;pictures&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;load_pictures&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;user&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
   &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
 
&lt;span class=&#34;c1&#34;&gt;# model/media.py&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;async&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;load_pictures&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;user_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
   &lt;span class=&#34;n&#34;&gt;query&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;      SELECT *
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;      FROM pictures
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;      WHERE user_id = {user_id}
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;   &amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
   &lt;span class=&#34;n&#34;&gt;result&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;run_query&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;query&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
   &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
 
&lt;span class=&#34;c1&#34;&gt;# model/shared.py&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;async&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;run_query&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;query&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
   &lt;span class=&#34;n&#34;&gt;connection&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;create_sql_connection&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
   &lt;span class=&#34;n&#34;&gt;result&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;connection&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;execute&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;query&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
   &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note that this is not Django but something similar. Currently, Django runs the database code synchronously. But that &lt;a href=&#34;https://www.aeracode.org/2018/06/04/django-async-roadmap/&#34;&gt;may change&lt;/a&gt; sometime in the future.&lt;/p&gt;
&lt;p&gt;If you think about it, it makes perfect sense. Synchronous code can be blocked while waiting for an I/O operation for several microseconds. However, its equivalent asynchronous code would not be tied up and can work on other tasks. Therefore it can handle more requests with lower latencies. More requests gives Facebook (or any other large site) the ability to handle more users on the same infrastructure.&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
    &lt;img loading=&#34;lazy&#34; src=&#34;https://arunrocks.com/static/images/blog/async-illustration-1.jpg&#34; alt=&#34;Illustration&#34;  title=&#34;Scalability Problems in the 1800s, I suppose&#34;  width=793 height=&#34;430&#34;  /&gt;
    &lt;figcaption&gt;Scalability Problems in the 1800s, I suppose&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Even if you are not close to reaching Facebook scale, you could use Python&amp;rsquo;s asyncio as a more predictable threading mechanism to run many things concurrently. A thread scheduler could interrupt in between destructive updates of shared resources leading to difficult to debug race conditions. Compared to threads, coroutines can achieve a higher level of concurrency with very less overhead.&lt;/p&gt;
&lt;h2 id=&#34;misleading-sleep-examples&#34;&gt;Misleading Sleep Examples&lt;/h2&gt;
&lt;p&gt;As I joked earlier, most of the Django async views tutorials show an example involving sleep. Even the official Django release notes had this example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;n&#34;&gt;async&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;my_view&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;asyncio&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sleep&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;0.5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;HttpResponse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;Hello, async world!&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To a Python async guru this code might indicate the possibilities that were not previously possible. But to the vast majority, this code is misleading in many ways.&lt;/p&gt;
&lt;p&gt;Firstly, the sleep happening synchronously or asynchronously makes no difference to the end user. The poor chap who just opened the URL linked to that view will have to wait for 0.5 seconds before it returns a cheeky &amp;ldquo;Hello, async world!&amp;rdquo;. If you are a complete novice, you may have expected an immediate reply and somehow the &amp;ldquo;hello&amp;rdquo; greeting to appear asynchronously half a second later. Of course, that sounds silly but then what is this example trying to do compared to a synchronous &lt;code&gt;time.sleep()&lt;/code&gt; inside a view?&lt;/p&gt;
&lt;p&gt;The answer is, as with most things in the asyncio world, in the &lt;a href=&#34;https://docs.python.org/3/library/asyncio-eventloop.html&#34;&gt;event loop&lt;/a&gt;. If the event loop had some other task waiting to be run then that half second window would give it an opportunity to run that. Note that it may take longer than that window to complete. &lt;em&gt;&lt;a href=&#34;https://arunrocks.com/get-started-with-async-and-await/&#34;&gt;Cooperative Multithreading&lt;/a&gt;&lt;/em&gt; assumes that everyone works quickly and hands over the control promptly back to the event loop.&lt;/p&gt;
&lt;p&gt;Secondly, it does not seem to accomplish anything useful. Some command-line interfaces use sleep to give enough time for users to read a message before disappearing. But it is the opposite for web applications - a faster response from the web server is the key to a better user experience. So by slowing the response what are we trying to demonstrate in such examples?&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
    &lt;img loading=&#34;lazy&#34; src=&#34;https://arunrocks.com/static/images/blog/async-illustration-2.jpg&#34; alt=&#34;Illustration&#34;  title=&#34;Letting them Sleep Would Be Better Idea&#34;  width=659 height=&#34;560&#34;  /&gt;
    &lt;figcaption&gt;Letting them Sleep Would Be Better Idea&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;The best explanation for such simplified examples I can give is &lt;em&gt;convenience&lt;/em&gt;. It needs a bit more setup to show examples which really need asynchronous support. That&amp;rsquo;s what we are trying to explore here.&lt;/p&gt;
&lt;h2 id=&#34;better-examples&#34;&gt;Better examples&lt;/h2&gt;
&lt;p&gt;A rule of thumb to remember before writing an asynchronous view is to check if it is &lt;a href=&#34;https://en.wikipedia.org/wiki/I/O_bound&#34;&gt;I/O bound&lt;/a&gt; or &lt;a href=&#34;https://en.wikipedia.org/wiki/CPU-bound&#34;&gt;CPU-bound&lt;/a&gt;. A view which spends most of the time in a CPU-bound activity for e.g. matrix multiplication or image manipulation would really not benefit from rewriting them to async views. You should be focussing on the I/O bound activities.&lt;/p&gt;
&lt;h3 id=&#34;invoking-microservices&#34;&gt;Invoking Microservices&lt;/h3&gt;
&lt;p&gt;Most large web applications are moving away from a monolithic architecture to one composed of many microservices. Rendering a view might require the results of many internal or external services.&lt;/p&gt;
&lt;p&gt;In our example, an ecommerce site for books renders its front page - like most popular sites - tailored to the logged in user by displaying recommended books. The recommendation engine is typically implemented as a separate microservice that makes recommendations based on past buying history and perhaps a bit of machine learning by understanding how successful its past recommendations were.&lt;/p&gt;
&lt;p&gt;In this case, we also need the results of another microservice that decides which promotional banners to display as a rotating banner or slideshow to the user. These banners are not tailored to the logged in user but change depending on the items currently on sale (active promotional campaign) or date.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s look at how a synchronous version of such a page might look like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sync_home&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&amp;#34;Display homepage by calling two services synchronously&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;context&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{}&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;try&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;response&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;httpx&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PROMO_SERVICE_URL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;response&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;status_code&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;httpx&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;codes&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;OK&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
            &lt;span class=&#34;n&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;promo&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;response&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;json&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;response&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;httpx&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;RECCO_SERVICE_URL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;response&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;status_code&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;httpx&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;codes&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;OK&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
            &lt;span class=&#34;n&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;recco&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;response&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;json&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;except&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;httpx&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;RequestError&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;exc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;An error occurred while requesting {exc.request.url!r}.&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;render&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;index.html&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here instead of the popular Python &lt;a href=&#34;https://requests.readthedocs.io/en/master/&#34;&gt;requests&lt;/a&gt; library we are using the &lt;a href=&#34;https://www.python-httpx.org/&#34;&gt;httpx&lt;/a&gt; library because it supports making synchronous and asynchronous web requests. The interface is almost identical.&lt;/p&gt;
&lt;p&gt;The problem with this view is that the time taken to invoke these services add up since they happen sequentially. The Python process is suspended until the first service responds which could take a long time in a worst case scenario.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s try to run them concurrently using a simplistic (and ineffective) await call:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;n&#34;&gt;async&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;async_home_inefficient&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&amp;#34;Display homepage by calling two awaitables synchronously (does NOT run concurrently)&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;context&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{}&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;try&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;async&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;httpx&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AsyncClient&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;client&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
            &lt;span class=&#34;n&#34;&gt;response&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;client&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PROMO_SERVICE_URL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
            &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;response&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;status_code&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;httpx&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;codes&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;OK&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
                &lt;span class=&#34;n&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;promo&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;response&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;json&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
            &lt;span class=&#34;n&#34;&gt;response&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;client&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;RECCO_SERVICE_URL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
            &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;response&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;status_code&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;httpx&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;codes&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;OK&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
                &lt;span class=&#34;n&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;recco&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;response&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;json&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;except&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;httpx&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;RequestError&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;exc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;An error occurred while requesting {exc.request.url!r}.&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;render&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;index.html&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Notice that the view has changed from a function to a coroutine (due to &lt;code&gt;async def&lt;/code&gt; keyword). Also note that there are two places where we await for a response from each of the services. You don&amp;rsquo;t have to try to understand every line here, as we will explain with a better example.&lt;/p&gt;
&lt;p&gt;Interestingly, this view does not work concurrently and takes the same amount of time as the synchronous view. If you are familiar with asynchronous programming, you might have guessed that simply awaiting a coroutine does not make it run other things concurrently, you will just yield control back to the event loop. The view still gets suspended.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s look at a proper way to run things concurrently:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;n&#34;&gt;async&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;async_home&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&amp;#34;Display homepage by calling two services asynchronously (proper concurrency)&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;context&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{}&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;try&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;async&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;httpx&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AsyncClient&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;client&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
            &lt;span class=&#34;n&#34;&gt;response_p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;response_r&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;asyncio&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gather&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
                &lt;span class=&#34;n&#34;&gt;client&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PROMO_SERVICE_URL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;client&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;RECCO_SERVICE_URL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

            &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;response_p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;status_code&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;httpx&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;codes&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;OK&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
                &lt;span class=&#34;n&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;promo&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;response_p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;json&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
            &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;response_r&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;status_code&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;httpx&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;codes&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;OK&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
                &lt;span class=&#34;n&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;recco&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;response_r&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;json&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;except&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;httpx&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;RequestError&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;exc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;An error occurred while requesting {exc.request.url!r}.&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;render&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;index.html&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If the two services we are calling have similar response times, then this view should complete in _half _the time compared to the synchronous version. This is because the calls happen concurrently as we would want.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s try to understand what is happening here. There is an outer try&amp;hellip;except block to catch request errors while making either of the HTTP calls. Then there is an inner async&amp;hellip;with block which gives a context having the client object.&lt;/p&gt;
&lt;p&gt;The most important line is one with the asyncio.gather call taking the coroutines created by the two &lt;code&gt;client.get&lt;/code&gt; calls. The gather call will execute them concurrently and return only when both of them are completed. The result would be a tuple of responses which we will unpack into two variables &lt;code&gt;response_p&lt;/code&gt; and &lt;code&gt;response_r&lt;/code&gt;. If there were no errors, these responses are populated in the context sent for template rendering.&lt;/p&gt;
&lt;p&gt;Microservices are typically internal to the organization hence the response times are low and less variable. Yet, it is never a good idea to rely solely on synchronous calls for communicating between microservices. As the dependencies between services increases, it creates long chains of request and response calls. Such chains can slow down services.&lt;/p&gt;
&lt;h4 id=&#34;why-live-scraping-is-bad&#34;&gt;Why Live Scraping is Bad&lt;/h4&gt;
&lt;p&gt;We need to address web scraping because so many asyncio examples use them. I am referring to cases where multiple external websites or pages within a website are concurrently fetched and scraped for information like live stock market (or bitcoin) prices. The implementation would be very similar to what we saw in the Microservices example.&lt;/p&gt;
&lt;p&gt;But this is very risky since a view should return a response to the user as quickly as possible. So trying to fetch external sites which have variable response times or throttling mechanisms could be a poor user experience or even worse a browser timeout. Since microservice calls are typically internal, response times can be controlled with proper SLAs.&lt;/p&gt;
&lt;p&gt;Ideally, scraping should be done in a separate process scheduled to run periodically (using &lt;a href=&#34;https://docs.celeryproject.org/en/stable/django/&#34;&gt;celery&lt;/a&gt; or &lt;a href=&#34;https://python-rq.org/&#34;&gt;rq&lt;/a&gt;). The view should simply pick up the scraped values and present them to the users.&lt;/p&gt;
&lt;h3 id=&#34;serving-files&#34;&gt;Serving Files&lt;/h3&gt;
&lt;p&gt;Django addresses the problem of serving files by trying hard not to do it itself. This makes sense from a &amp;ldquo;Do not reinvent the wheel&amp;rdquo; perspective. After all, there are several better solutions to serve static files like &lt;a href=&#34;https://www.nginx.com/&#34;&gt;nginx&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
    &lt;img loading=&#34;lazy&#34; src=&#34;https://arunrocks.com/static/images/blog/async-illustration-3.jpg&#34; alt=&#34;Illustration&#34;  title=&#34;&amp;#39;Serving simultaneously is not for everyone&amp;#39;&#34;  width=716 height=&#34;627&#34;  /&gt;
    &lt;figcaption&gt;&amp;#39;Serving simultaneously is not for everyone&amp;#39;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;But often we need to serve files with dynamic content. Files often reside in a (slower) disk-based storage (we now have much faster SSDs). While this file operation is quite easy to accomplish with Python, it could be expensive in terms of performance for large files. Regardless of the file&amp;rsquo;s size, this is a potentially blocking I/O operation that could potentially be used for running another task concurrently.&lt;/p&gt;
&lt;p&gt;Imagine we need to serve a PDF certificate in a Django view. However the date and time of downloading the certificate needs to be stored in the metadata of the PDF file, for some reason (possibly for identification and validation).&lt;/p&gt;
&lt;p&gt;We will use the &lt;a href=&#34;https://pypi.org/project/aiofiles/&#34;&gt;aiofiles&lt;/a&gt; library here for asynchronous file I/O. The API is almost the same as the familiar Python&amp;rsquo;s built-in file API. Here is how the asynchronous view could be written:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;n&#34;&gt;async&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;serve_certificate&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;timestamp&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;datetime&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;datetime&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;now&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;isoformat&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;

    &lt;span class=&#34;n&#34;&gt;response&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;HttpResponse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;content_type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;application/pdf&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Content-Disposition&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;attachment; filename=certificate.pdf&amp;#34;&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;async&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;aiofiles&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;open&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;homepage/pdfs/certificate-template.pdf&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mode&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;rb&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;contents&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;read&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;response&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;write&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;contents&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;replace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;sa&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;%timestamp%&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;bytes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;timestamp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;utf-8&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;response&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This example illustrates why we need asynchronous template rendering in Django. But until that gets implemented, you could use aiofiles library to pull local files without skipping a beat.&lt;/p&gt;
&lt;p&gt;There are downsides to directly using local files instead of Django&amp;rsquo;s &lt;a href=&#34;https://docs.djangoproject.com/en/3.1/ref/contrib/staticfiles/&#34;&gt;staticfiles&lt;/a&gt;. In the future, when you migrate to a different storage space like Amazon S3, make sure you adapt your code accordingly.&lt;/p&gt;
&lt;h3 id=&#34;handling-uploads&#34;&gt;Handling Uploads&lt;/h3&gt;
&lt;p&gt;On the flip side, uploading a file is also a potentially long, blocking operation. For security and organizational reasons, Django&lt;a href=&#34;https://docs.djangoproject.com/en/3.1/ref/files/&#34;&gt; stores all uploaded content&lt;/a&gt; into a separate &amp;lsquo;media&amp;rsquo; directory.&lt;/p&gt;
&lt;p&gt;If you have a form that allows uploading a file, then we need to anticipate that some pesky user would upload an impossibly large one. Thankfully Django passes the file to the view as chunks of a certain size. Combined with aiofile&amp;rsquo;s ability to write a file asynchronously, we could support highly concurrent uploads.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;n&#34;&gt;async&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;handle_uploaded_file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;async&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;aiofiles&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;open&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;uploads/{f.name}&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;wb+&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;destination&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;chunk&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;chunks&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;
            &lt;span class=&#34;n&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;destination&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;write&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;chunk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;


&lt;span class=&#34;n&#34;&gt;async&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;async_uploader&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;method&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;POST&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;form&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;UploadFileForm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;POST&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;FILES&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;form&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;is_valid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;
            &lt;span class=&#34;n&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;handle_uploaded_file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;FILES&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;file&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;
            &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;HttpResponseRedirect&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;form&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;UploadFileForm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;render&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;upload.html&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;form&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;form&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Again this is circumventing Django&amp;rsquo;s default file upload mechanism, so you need to be careful about the security implications.&lt;/p&gt;
&lt;h2 id=&#34;where-to-use&#34;&gt;Where To Use&lt;/h2&gt;
&lt;p&gt;Django Async project has full backward compatibility as one of its main goals. So you can continue to use your old synchronous views without rewriting them into async. Asynchronous views are not a panacea for all performance issues, so most projects will still continue to use synchronous code since they are quite straightforward to reason about.&lt;/p&gt;
&lt;p&gt;In fact, you can use both async and sync views in the same project. Django will take care of calling the view in the appropriate manner. However, if you are using async views it is recommended to deploy the application on ASGI servers.&lt;/p&gt;
&lt;p&gt;This gives you the flexibility to try asynchronous views gradually especially for I/O intensive work. You need to be careful to pick only async libraries or mix them with sync carefully (use the &lt;a href=&#34;https://docs.djangoproject.com/en/3.1/topics/async/#async-to-sync&#34;&gt;async_to_sync&lt;/a&gt; and &lt;a href=&#34;https://docs.djangoproject.com/en/3.1/topics/async/#sync-to-async&#34;&gt;sync_to_async&lt;/a&gt; adaptors).&lt;/p&gt;
&lt;p&gt;Hopefully this writeup gave you some ideas.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Thanks to &lt;a href=&#34;https://avilpage.com/&#34;&gt;Chillar Anand&lt;/a&gt; and &lt;a href=&#34;https://twitter.com/agrawalritesh_&#34;&gt;Ritesh Agrawal&lt;/a&gt; for reviewing this post. All illustrations courtesy of &lt;a href=&#34;https://www.oldbookillustrations.com/&#34;&gt;Old Book Illustrations&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>A Guide to ASGI in Django 3.0 and its Performance</title>
      <link>https://arunrocks.com/a-guide-to-asgi-in-django-30-and-its-performance/</link>
      <pubDate>Tue, 10 Mar 2020 13:33:29 +0530</pubDate>
      
      <guid>https://arunrocks.com/a-guide-to-asgi-in-django-30-and-its-performance/</guid>
      <description>&lt;p&gt;In Dec 2019, we saw the &lt;a href=&#34;https://docs.djangoproject.com/en/3.0/releases/3.0/&#34;&gt;release of Django 3.0&lt;/a&gt; with an interesting new feature &amp;mdash; support for ASGI servers. I was intrigued by what this meant. When I checked the performance benchmarks of asynchronous Python web frameworks they were ridiculously faster than their synchronous counterparts often by a factor of 3x&amp;ndash;5x.&lt;/p&gt;
&lt;p&gt;So I set out to test Django 3.0 performance with a very simple Docker setup. The results &amp;mdash; though not spectacular &amp;mdash; were still impressive. But before that, you might need a little bit of background about ASGI.&lt;/p&gt;
&lt;h4 id=&#34;before-asgi-there-was-wsgi&#34;&gt;Before ASGI there was WSGI&lt;/h4&gt;
&lt;p&gt;It was 2003 and various Python web frameworks like &lt;a href=&#34;https://www.zope.org/&#34;&gt;Zope&lt;/a&gt;, &lt;a href=&#34;http://quixote.ca/&#34;&gt;Quixote&lt;/a&gt; used to ship with their own web servers or had their own home grown interfaces to talk to popular web servers like Apache.&lt;/p&gt;
&lt;p&gt;Being a Python web developer meant a devout commitment to learning an entire stack but relearning everything if you needed another framework. As you can imagine this led to fragmentation. A &lt;a href=&#34;https://www.python.org/dev/peps/pep-0333/&#34;&gt;PEP 333 &lt;/a&gt;- &amp;ldquo;Python Web Server Gateway Interface v1.0&amp;rdquo; tried to solve this problem by defining a simple standard interface called WSGI (Web Server Gateway Interface). Its brilliance was in its simplicity.&lt;/p&gt;
&lt;p&gt;In fact the entire WSGI specification can be simplified (conveniently leaving out some hairy details) as the &lt;strong&gt;server side&lt;/strong&gt; invoking a callable object (i.e. anything from a Python function to a class with a &lt;strong&gt;call&lt;/strong&gt; method) provided by the framework or the &lt;strong&gt;application&lt;/strong&gt;. If you have a component that can play both roles, then you have created a &amp;ldquo;&lt;strong&gt;middleware&lt;/strong&gt;&amp;rdquo; or an intermediate layer in this pipeline. Thus, WSGI components can be easily chained together to handle requests.&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
    &lt;img loading=&#34;lazy&#34; src=&#34;https://arunrocks.com/static/images/blog/asgi-illustration-1.jpg&#34; alt=&#34;Illustration&#34;  title=&#34;When connecting became easy, merriment followed&#34;  width=643 height=&#34;864&#34;  /&gt;
    &lt;figcaption&gt;When connecting became easy, merriment followed&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;WSGI became so popular that it was adopted not just by the large web frameworks like &lt;a href=&#34;https://www.djangoproject.com/&#34;&gt;Django&lt;/a&gt; and &lt;a href=&#34;https://pylonsproject.org/about-pylons-framework.html&#34;&gt;Pylons&lt;/a&gt; but also by microframeworks like &lt;a href=&#34;https://bottlepy.org/docs/dev/&#34;&gt;Bottle&lt;/a&gt;. Your favourite framework could be plugged into any WSGI-compatible application server and it would work flawlessly. It was so easy and intuitive that there was really no excuse not to use it.&lt;/p&gt;
&lt;h4 id=&#34;road-blocks-to-scale&#34;&gt;Road &amp;lsquo;Blocks&amp;rsquo; to Scale&lt;/h4&gt;
&lt;p&gt;So if we were perfectly fine with WSGI, why did we have to come up with ASGI? The answer will be quite evident if you have followed the path of a webrequest. Check out my &lt;a href=&#34;https://www.youtube.com/watch?v=RLo9RJhbOrQ&#34;&gt;animation of how a webrequest flows into Django&lt;/a&gt;. Notice how the framework is waiting after querying the database before sending the response. This is the drawback of synchronous processing.&lt;/p&gt;
&lt;p&gt;Frankly this drawback was not obvious or pressing until Node.js came into the scene in 2009. Ryan Dahl, the creator of Node.js, was bothered by the &lt;a href=&#34;https://en.wikipedia.org/wiki/C10k_problem&#34;&gt;C10K problem&lt;/a&gt; i.e. why popular web servers like Apache cannot handle 10,000 or more concurrent connections (given a typical web server hardware it would run out of memory) . He &lt;a href=&#34;https://www.youtube.com/watch?v=ztspvPYybIY&#34;&gt;asked&lt;/a&gt; &amp;ldquo;What is the software doing while it queries the database?&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
    &lt;img loading=&#34;lazy&#34; src=&#34;https://arunrocks.com/static/images/blog/asgi-illustration-2.jpg&#34; alt=&#34;Illustration&#34;  title=&#34;Looks like she has been waiting forever&#34;  width=581 height=&#34;864&#34;  /&gt;
    &lt;figcaption&gt;Looks like she has been waiting forever&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;The answer was, of course, nothing. It was waiting for the database to respond. Ryan argued that webservers should not be waiting on I/O activities at all. Instead it should switch to serving other requests and get notified when the slow activity is completed. Using this technique, Node.js could serve many orders of magnitude more users using less memory and on a single thread!&lt;/p&gt;
&lt;p&gt;It was becoming increasingly clear that asynchronous event-based architectures are the right way to solve many kinds of concurrency problems. Probably that is why Python&amp;rsquo;s creator Guido himself worked towards a language level support with the &lt;a href=&#34;https://www.youtube.com/watch?v=aurOB4qYuFM&#34;&gt;Tulip project&lt;/a&gt;, which later became the &lt;a href=&#34;https://docs.python.org/3/library/asyncio.html&#34;&gt;asyncio&lt;/a&gt; module. Eventually Python 3.7 &lt;a href=&#34;https://docs.python.org/3/whatsnew/3.7.html&#34;&gt;added&lt;/a&gt; the new keywords &lt;code&gt;async&lt;/code&gt; and &lt;code&gt;await&lt;/code&gt; to support asynchronous event loops. This has pretty significant consequences in not just how Python code is written but executed as well.&lt;/p&gt;
&lt;h4 id=&#34;two-worlds-of-python&#34;&gt;Two Worlds of Python&lt;/h4&gt;
&lt;p&gt;Though writing asynchronous code in Python might seem as easy as sliding an &lt;strong&gt;async&lt;/strong&gt; keyword in front of a function definition, you have to be very careful not to break an important rule - &lt;em&gt;Do not freely mix synchronous and asynchronous code&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;This is because synchronous code can block an event loop in asynchronous code. Such situations can bring your application to a standstill. As &lt;a href=&#34;https://aeracode.org/2018/02/19/python-async-simplified/&#34;&gt;Andrew Goodwin writes&lt;/a&gt; this splits your code into two worlds - &amp;ldquo;Synchronous&amp;rdquo; and &amp;ldquo;Asynchronous&amp;rdquo; with different libraries and calling styles.&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
    &lt;img loading=&#34;lazy&#34; src=&#34;https://arunrocks.com/static/images/blog/asgi-illustration-3.jpg&#34; alt=&#34;Illustration&#34;  title=&#34;When two worlds collide, results can be quite unexpected&#34;  width=864 height=&#34;468&#34;  /&gt;
    &lt;figcaption&gt;When two worlds collide, results can be quite unexpected&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Coming back to WSGI, this means we cannot simply write an asynchronous callable and plug it in. WSGI was written for a synchronous world. We will need a new mechanism to invoke asynchronous code. But if everyone writes their own mechanisms we would be back to the incompatibility hell we started with. So we need a new standard similar to WSGI for asynchronous code. Hence, &lt;a href=&#34;https://asgi.readthedocs.io/en/latest/introduction.html&#34;&gt;ASGI&lt;/a&gt; was born.&lt;/p&gt;
&lt;p&gt;ASGI had some other goals as well. But before that let&amp;rsquo;s look at two similar web applications greeting &amp;ldquo;Hello World&amp;rdquo; in WSGI and ASGI style.&lt;/p&gt;
&lt;p&gt;In WSGI:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;application&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;environ&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;start_response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;start_response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;200 OK&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Content-Type&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;text/plain&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)])&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;sa&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Hello, World&amp;#34;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In ASGI:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;n&#34;&gt;async&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;application&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;scope&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;receive&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;send&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;send&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;({&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;http.response.start&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;status&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;200&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;headers&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[(&lt;/span&gt;&lt;span class=&#34;sa&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Content-Type&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;text/plain&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)]})&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;send&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;({&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;http.response.body&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;body&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;sa&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Hello World&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Notice the change in the arguments passed into the callables. The &lt;code&gt;scope&lt;/code&gt; argument is similar to the earlier &lt;code&gt;environ&lt;/code&gt; argument. The &lt;code&gt;send&lt;/code&gt; argument corresponds to &lt;code&gt;start_response&lt;/code&gt;. But the &lt;code&gt;receive&lt;/code&gt; argument is new. It allows clients to nonchalantly slip messages to the server in protocols like WebSockets that allow bidirectional communications.&lt;/p&gt;
&lt;p&gt;Like WSGI, the ASGI callables can be chained one after the other to handle web requests (as well as other protocol requests). In fact, ASGI is a superset of WSGI and can call WSGI callables. ASGI also has support for long polling, slow streaming and other exciting response types without side-loading resulting in faster responses.&lt;/p&gt;
&lt;p&gt;Thus, ASGI introduces new ways to build asynchronous web interfaces and handle bi-directional protocols. Neither the client or server needs to wait for each other to communicate - it can happen any time asynchronously. Existing WSGI-based web frameworks being written in synchronous code would not support this event-driven way of working.&lt;/p&gt;
&lt;h3 id=&#34;django-evolves&#34;&gt;Django Evolves&lt;/h3&gt;
&lt;p&gt;This also brings us to the crux of the problem with bringing all the async goodness to Django - all of Django was written in synchronous style code. If we need to write any asynchronous code then there needs to be a clone of the entire Django framework written in asynchronous style. In other words, create two worlds of Django.&lt;/p&gt;
&lt;p&gt;Well, don&amp;rsquo;t panic &amp;mdash; we might not have to write an entire clone as there are clever ways to reuse bits of code between the two worlds. But as Andrew Godwin who leads Django&amp;rsquo;s &lt;a href=&#34;https://code.djangoproject.com/wiki/AsyncProject&#34;&gt;Async Project&lt;/a&gt; rightly remarks &amp;ldquo;it&amp;rsquo;s one of the biggest overhauls of Django in its history&amp;rdquo;. An ambitious project involving reimplementation of components like ORM, request handler, Template renderer etc in asynchronous style. This will be done in phases and in several releases. Here is how Andrew &lt;a href=&#34;https://speakerdeck.com/andrewgodwin/just-add-await-retrofitting-async-into-django?slide=42&#34;&gt;envisions&lt;/a&gt; it (not to be taken as a committed schedule):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Django 3.0 - ASGI Server&lt;/li&gt;
&lt;li&gt;Django 3.1 - Async Views (see an &lt;a href=&#34;#q-when-can-i-write-async-code-in-django&#34;&gt;example&lt;/a&gt; below)&lt;/li&gt;
&lt;li&gt;Django 3.2/4.0 - Async ORM&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You might be thinking what about the rest of the components like Template rendering, Forms, Cache etc. They may still remain synchronous or an asynchronous implementation be fitted somewhere in the future roadmap. But the above are the key milestones in evolving Django to work in an asynchronous world.&lt;/p&gt;
&lt;p&gt;That brings us to the first phase.&lt;/p&gt;
&lt;h3 id=&#34;django-talks-asgi&#34;&gt;Django talks ASGI&lt;/h3&gt;
&lt;p&gt;In 3.0, Django can work in a &amp;ldquo;async outside, sync inside&amp;rdquo; mode. This allows it to talk to all known ASGI servers such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://github.com/django/daphne&#34;&gt;Daphne&lt;/a&gt; - an ASGI reference server, written in Twisted&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.uvicorn.org/&#34;&gt;Uvicorn&lt;/a&gt; - a fast ASGI server based on uvloop and httptools&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://pgjones.gitlab.io/hypercorn/index.html&#34;&gt;Hypercorn&lt;/a&gt; - an ASGI server based on the sans-io hyper, h11, h2, and wsproto libraries&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It is important to reiterate that internally Django is still processing requests synchronously in a threadpool. But the underlying ASGI server would be handling requests asynchronously.&lt;/p&gt;
&lt;p&gt;This means your existing Django projects require no changes. Think of this change as merely a new interface by which HTTP requests can enter your Django application.&lt;/p&gt;
&lt;p&gt;But this is a significant first step in transforming Django from &amp;ldquo;outside-in&amp;rdquo;. You could also start using Django on the ASGI server which is usually faster.&lt;/p&gt;
&lt;h3 id=&#34;how-to-use-asgi&#34;&gt;How to use ASGI?&lt;/h3&gt;
&lt;p&gt;Every Django project (since &lt;a href=&#34;https://docs.djangoproject.com/en/3.0/releases/1.4/#improved-wsgi-support&#34;&gt;version 1.4&lt;/a&gt;) ships with a wsgi.py file, which is a WSGI handler module. While deploying to production, you will point your WSGI server like gunicorn to this file. For instance, you might have seen this line in your &lt;strong&gt;Docker compose&lt;/strong&gt; file&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;command: gunicorn mysite.wsgi:application
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you create a new Django project (for e.g. created by running the &lt;code&gt;django-admin startproject&lt;/code&gt; command) then you will find a brand new file &lt;strong&gt;asgi.py&lt;/strong&gt; alongside wsgi.py. You will need to point your ASGI server (like daphene) to this ASGI handler file. For example, the above line would be changed to:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;command: daphene mysite.asgi:application
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note that this requires the presence of an &lt;strong&gt;asgi.py&lt;/strong&gt; file.&lt;/p&gt;
&lt;h3 id=&#34;running-existing-django-projects-under-asgi&#34;&gt;Running Existing Django Projects under ASGI&lt;/h3&gt;
&lt;p&gt;None of the projects created before Django 3.0 have an asgi.py. So how do you go about creating one? It is quite easy.&lt;/p&gt;
&lt;p&gt;Here is a side-by-side comparison (docstrings and comments omitted) of the wsgi.py and asgi.py for a Django project:&lt;/p&gt;
&lt;table&gt;
  &lt;tr&gt;&lt;th&gt;WSGI&lt;/th&gt;&lt;th&gt;ASGI&lt;/th&gt;&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;
   &lt;pre&gt;import os
&lt;p&gt;from django.core.wsgi import get_wsgi_application&lt;/p&gt;
&lt;p&gt;os.environ.setdefault(&amp;lsquo;DJANGO_SETTINGS_MODULE&amp;rsquo;, &amp;lsquo;mysite.settings&amp;rsquo;)&lt;/p&gt;
&lt;p&gt;application = get_wsgi_application()
&lt;/pre&gt;&lt;/p&gt;
   &lt;/td&gt;
   &lt;td&gt;
   &lt;pre&gt;import os
&lt;p&gt;from django.core.asgi import get_asgi_application&lt;/p&gt;
&lt;p&gt;os.environ.setdefault(&amp;lsquo;DJANGO_SETTINGS_MODULE&amp;rsquo;, &amp;lsquo;mysite.settings&amp;rsquo;)&lt;/p&gt;
&lt;p&gt;application = get_asgi_application()
&lt;/pre&gt;&lt;/p&gt;
   &lt;/td&gt;
  &lt;/tr&gt;   
&lt;/table&gt;
&lt;p&gt;If you are squinting too hard to find the differences, let me help you - everywhere &amp;lsquo;wsgi&amp;rsquo; is replaced by &amp;lsquo;asgi&amp;rsquo;. Yes, it is as straightforward as taking your existing wsgi.py and running a string replacement &lt;code&gt;s/wsgi/asgi/g&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id=&#34;gotchas&#34;&gt;Gotchas&lt;/h4&gt;
&lt;p&gt;You should take care not to call any sync code in the ASGI Handler in your asgi.py. For example, if you make a call to some web API within your ASGI handler for some reason, then it must be an asyncio callable.&lt;/p&gt;
&lt;h3 id=&#34;asgi-vs-wsgi-performance&#34;&gt;ASGI vs WSGI Performance&lt;/h3&gt;
&lt;p&gt;I did a very simple performance test trying out the Django polls project in ASGI and WSGI configurations. Like all performance tests, you should take my results with liberal doses of salt. My &lt;a href=&#34;https://github.com/arocks/django3-asgi-perf&#34;&gt;Docker setup&lt;/a&gt; includes Nginx and Postgresql. The actual load testing was done using the versatile &lt;a href=&#34;https://locust.io/&#34;&gt;Locust&lt;/a&gt; tool.&lt;/p&gt;
&lt;p&gt;The test case was opening a poll form in the Django polls application and submitting a random vote. It makes &lt;em&gt;n&lt;/em&gt; requests per second when there are &lt;em&gt;n&lt;/em&gt; users. The wait time is between 1 and 2 seconds.&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
    &lt;img loading=&#34;lazy&#34; src=&#34;https://arunrocks.com/static/images/blog/asgi-illustration-4.jpg&#34; alt=&#34;Illustration&#34;  title=&#34;Being fast isn&amp;#39;t quite enough, you need to avoid failures&#34;  width=655 height=&#34;864&#34;  /&gt;
    &lt;figcaption&gt;Being fast isn&amp;#39;t quite enough, you need to avoid failures&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;The results shown below indicate around 50% increase in the number of simultaneous users when running in ASGI mode compared to WSGI mode.&lt;/p&gt;
&lt;table&gt;
  &lt;tr&gt;
   &lt;th&gt;&lt;strong&gt;Users&lt;/strong&gt;
   &lt;/th&gt;
   &lt;th&gt;100
   &lt;/th&gt;
   &lt;th&gt;200
   &lt;/th&gt;
   &lt;th&gt;300
   &lt;/th&gt;
   &lt;th&gt;400
   &lt;/th&gt;
   &lt;th&gt;500
   &lt;/th&gt;
   &lt;th&gt;600
   &lt;/th&gt;
   &lt;th&gt;700
   &lt;/th&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;&lt;strong&gt;WSGI Failures&lt;/strong&gt;
   &lt;/td&gt;
   &lt;td&gt;0%
   &lt;/td&gt;
   &lt;td&gt;0%
   &lt;/td&gt;
   &lt;td&gt;0%
   &lt;/td&gt;
   &lt;td&gt;&lt;strong&gt;5%&lt;/strong&gt;
   &lt;/td&gt;
   &lt;td&gt;12%
   &lt;/td&gt;
   &lt;td&gt;35%
   &lt;/td&gt;
   &lt;td&gt;50%
   &lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;&lt;strong&gt;ASGI Failures&lt;/strong&gt;
   &lt;/td&gt;
   &lt;td&gt;0%
   &lt;/td&gt;
   &lt;td&gt;0%
   &lt;/td&gt;
   &lt;td&gt;0%
   &lt;/td&gt;
   &lt;td&gt;0%
   &lt;/td&gt;
   &lt;td&gt;0%
   &lt;/td&gt;
   &lt;td&gt;&lt;strong&gt;15%&lt;/strong&gt;
   &lt;/td&gt;
   &lt;td&gt;20%
   &lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;As the number of simultaneous request ramp up the WSGI or ASGI handler will not be able to cope up beyond a certain point resulting in errors or failures. The requests per second after the WSGI failures start varies wildly. The ASGI performance is much more stable even after failures.&lt;/p&gt;
&lt;p&gt;As the table shows, the number of simultaneous users is around 300 for WSGI and 500 for ASGI on my machine. This is about 66% increase in the number of users the servers can handle without error. Your mileage might vary.&lt;/p&gt;
&lt;h3 id=&#34;frequent-questions&#34;&gt;Frequent Questions&lt;/h3&gt;
&lt;p&gt;I did a talk about ASGI and Django at &lt;a href=&#34;https://wiki.python.org/moin/BangPypers&#34;&gt;BangPypers&lt;/a&gt; recently and there were a lot of interesting questions the audiences raised (even after the event). So I thought I&amp;rsquo;ll address them here (in no particular order):&lt;/p&gt;
&lt;h4 id=&#34;q-is-django-async-the-same-as-channels&#34;&gt;Q. Is Django Async the same as Channels?&lt;/h4&gt;
&lt;p&gt;&lt;a href=&#34;https://channels.readthedocs.io/en/latest/&#34;&gt;Channels&lt;/a&gt; was created to support asynchronous protocols like Websockets and long polling HTTP. Django applications still run &lt;em&gt;synchronously&lt;/em&gt;. Channels is an official Django project but not part of core Django.&lt;/p&gt;
&lt;p&gt;Django Async project will support writing Django applications with asynchronous code in addition to synchronous code. Async is a part of Django core.&lt;/p&gt;
&lt;p&gt;Both were led by Andrew Goodwin.&lt;/p&gt;
&lt;p&gt;These are independent projects in most cases. You can have a project that uses either or both. For example if you need to support a chat application over web sockets, then you can use Channels without using Django&amp;rsquo;s ASGI interface. On the other hand if you want to make an async function in a Django view, then you will have to wait for Django&amp;rsquo;s Async support for views.&lt;/p&gt;
&lt;h4 id=&#34;q-any-new-dependencies-in-django-30&#34;&gt;Q. Any new dependencies in Django 3.0?&lt;/h4&gt;
&lt;p&gt;Installing just Django 3.0 will install the following into your environment:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ pip freeze
asgiref==3.2.3
Django==3.0.2
pytz==2019.3
sqlparse==0.3.0
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;a href=&#34;https://pypi.org/project/asgiref/&#34;&gt;asgiref&lt;/a&gt; library is a new dependency. It contains sync-to-async and async-to-sync function wrappers so that you can call sync code from async and vice versa. It also contains a StatelessServer and a WSGI-to-ASGI adapter.&lt;/p&gt;
&lt;h4 id=&#34;q-will-upgrading-to-django-30-break-my-project&#34;&gt;Q. Will upgrading to Django 3.0 break my project?&lt;/h4&gt;
&lt;p&gt;Version 3.0 might sound like a big change from its previous version Django 2.2. But that is slightly misleading. Django project does not follow semantic version exactly (where a major version number change may break the API) and the differences are explained in the &lt;a href=&#34;https://docs.djangoproject.com/en/dev/internals/release-process/&#34;&gt;Release Process&lt;/a&gt; page.&lt;/p&gt;
&lt;p&gt;You will notice very few serious backward incompatible changes in the Django 3.0 &lt;a href=&#34;https://docs.djangoproject.com/en/3.0/releases/3.0/#backwards-incompatible-changes-in-3-0&#34;&gt;release notes&lt;/a&gt;. If your project does not use any of them, then you can upgrade without any modifications.&lt;/p&gt;
&lt;p&gt;Then why did the version number jump from 2.2 to 3.0? This is explained in the &lt;a href=&#34;https://docs.djangoproject.com/en/dev/internals/release-process/#release-cadence&#34;&gt;release cadence&lt;/a&gt; section:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Starting with Django 2.0, version numbers will use a loose form of&lt;a href=&#34;https://semver.org/&#34;&gt; semantic versioning&lt;/a&gt; such that each version following an LTS will bump to the next &amp;ldquo;dot zero&amp;rdquo; version. For example: 2.0, 2.1, 2.2 (LTS), 3.0, 3.1, 3.2 (LTS), etc.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Since the last release Django 2.2 was long-term support (LTS) release, the following release had to increase the major version number to 3.0. That&amp;rsquo;s pretty much it!&lt;/p&gt;
&lt;h4 id=&#34;q-can-i-continue-to-use-wsgi&#34;&gt;Q. Can I continue to use WSGI?&lt;/h4&gt;
&lt;div data-pullquote=&#34;&amp;#34;Asynchronous programming could be seen as an entirely optional way to write code in Django.&#34;&gt;
&lt;/div&gt;
&lt;p&gt;Yes. Asynchronous programming could be seen as an entirely optional way to write code in Django. The familiar synchronous way of using Django would continue to work and be supported.&lt;/p&gt;
&lt;p&gt;Andrew &lt;a href=&#34;https://aeracode.org/2018/06/04/django-async-roadmap/&#34;&gt;writes&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Even if there is a fully asynchronous path through the handler, WSGI compatibility has to also be maintained; in order to do this, the WSGIHandler will coexist alongside a new ASGIHandler, and run the system inside a one-off eventloop - keeping it synchronous externally, and asynchronous internally.&lt;/p&gt;
&lt;p&gt;This will allow async views to do multiple asynchronous requests and launch short-lived coroutines even inside of WSGI, if you choose to run that way. If you choose to run under ASGI, however, you will then also get the benefits of requests not blocking each other and using less threads&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id=&#34;q-when-can-i-write-async-code-in-django&#34;&gt;Q. When can I write async code in Django?&lt;/h4&gt;
&lt;p&gt;As explained earlier in the Async Project roadmap, it is expected that Django 3.1 will introduce async views which will support writing asynchronous code like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;n&#34;&gt;async&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;view&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;asyncio&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sleep&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;0.5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;HttpResponse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Hello, async world!&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You are free to mix async and sync views, middleware, and tests as much as you want; Django will ensure that you always end up with the right execution context. Sounds pretty awesome, right?&lt;/p&gt;
&lt;p&gt;At the time of writing, this the patch is almost certain to land in 3.1 now, awaiting a final review.&lt;/p&gt;
&lt;h3 id=&#34;wrapping-up&#34;&gt;Wrapping Up&lt;/h3&gt;
&lt;p&gt;We covered a lot of background about what led to Django supporting asynchronous capabilities. We tried to understand ASGI and how it compares to WSGI. We also found some performance improvements in terms of increased number of simultaneous requests in ASGI mode. A number of frequently asked questions related to Django&amp;rsquo;s support of ASGI were also addressed.&lt;/p&gt;
&lt;p&gt;I believe asynchronous support in Django could be a game changer. It will be one of the first large Python web frameworks to evolve into handling asynchronous requests. It is admirable that it is done with a lot of care not to break backward compatibility.&lt;/p&gt;
&lt;p&gt;I usually do not make my tech predictions public (frankly many of them have been proven right over the years). So here goes my tech prediction &amp;mdash; &lt;em&gt;Most Django deployments will use async functionality in five years&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;That should be enough motivation to check it out!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Thanks to Andrew Goodwin for his comments on an early draft. All illustrations courtesy of &lt;a href=&#34;https://www.oldbookillustrations.com/&#34;&gt;Old Book Illustrations&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Understanding Django Channels</title>
      <link>https://arunrocks.com/understanding-django-channels/</link>
      <pubDate>Tue, 03 Jul 2018 06:55:30 +0530</pubDate>
      
      <guid>https://arunrocks.com/understanding-django-channels/</guid>
      <description>&lt;div class=&#34;series-box&#34;&gt;
&lt;p&gt;You are reading a post from a two-part tutorial series on Django Channels&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;a href=&#34;https://arunrocks.com/get-started-with-async-and-await/&#34;&gt;Part 1&lt;/a&gt;&lt;/li&gt;
    &lt;li class=&#34;active&#34;&gt;&lt;a href=&#34;https://arunrocks.com/understanding-django-channels/&#34;&gt;Part 2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id=&#34;django-channels&#34;&gt;Django Channels&lt;/h2&gt;
&lt;p&gt;Django Channels was originally created to solve the problem of handling asynchronous communication protocols like say WebSockets. More and more web applications were providing realtime capabilities like chat and push notifications. Various workarounds were created to make Django support such requirements like running separate socket servers or proxy servers.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://channels.readthedocs.io/en/latest/&#34;&gt;Channels&lt;/a&gt; is an official Django project not just for handling WebSockets and other forms of bi-directional communication but also for running background tasks asynchronously. As of writing, Django Channels 2 is out which is a complete rewrite based on Python 3&amp;rsquo;s async/await based coroutines.&lt;/p&gt;
&lt;p&gt;This article covers the concepts of Django Channels and leads you to a video tutorial implementing a notifications application in Django.&lt;/p&gt;
&lt;p&gt;Here is a simplified block diagram of a typical Channels setup:&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
    &lt;img loading=&#34;lazy&#34; src=&#34;https://arunrocks.com/static/images/blog/django-channels.png&#34; alt=&#34;Django Channels&#34;   width=1634 height=&#34;834&#34;  /&gt;
    
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;How a typical Django Channels infrastructure works&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;A client such as a web browser sends both HTTP/HTTPS and WebSocket traffic to an ASGI server like Daphene. Like WSGI, the ASGI (Asynchronous Server Gateway Interface) specification is a common way for applications servers and applications to interact with each other asynchronously.&lt;/p&gt;
&lt;p&gt;Like a typical Django application, HTTP traffic is handled synchronously i.e. when the browser sends a request, it waits until it is routed to Django and a response is sent back. However, it gets a lot more interesting when WebSocket traffic happens because it can be triggered from either direction.&lt;/p&gt;
&lt;div data-pullquote=&#34;&amp;#34;Ironically, you can write Channel applications without using Channels!&amp;#34;&#34;&gt;
&lt;/div&gt;
&lt;p&gt;Once a WebSocket connection is established, a browser can send or receive messages. A sent message reaches the Protocol type router that determines the next routing handler based on its transport protocol. Hence you can define a router for HTTP and another for WebSocket messages.&lt;/p&gt;
&lt;p&gt;These routers are very similar to Django&amp;rsquo;s URL mappers but map the incoming messages to a consumer (rather than a view). A &lt;strong&gt;consumer&lt;/strong&gt; is like an event handler that reacts to events. It can also send messages back to the browser, thereby containing the logic for a fully bi-directional communication.&lt;/p&gt;
&lt;p&gt;A consumer is a class whose methods you may choose to write either as normal Python functions (synchronous) or as awaitables (asynchronous). Asynchronous code should not mix with synchronous code. So there are conversion functions to convert from async to sync and back. Remember that the Django parts are synchronous. A consumer in fact a valid ASGI application.&lt;/p&gt;
&lt;p&gt;So far, we have not used the channel layer. Ironically, you can write Channel applications without using Channels! But they are not particularly useful as there is no easy communication path between application instances, other than polling a database. Channels provides exactly that, a fast point-to-point and broadcast messaging between application instances.&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;channel&lt;/strong&gt; is like a pipe. A sender sends a message to this pipe from one end and it reaches a listener at the other end. A &lt;strong&gt;group&lt;/strong&gt; defines a group of channels who are all listening to a topic. Every consumer listens to own auto-generated channel accessed by its &lt;code&gt;self.channel_name&lt;/code&gt; attribute.&lt;/p&gt;
&lt;p&gt;In addition to transports, you can trigger a consumer listening to a channel by sending a message, thereby starting a background task. This works as a very quick and simple background worker system.&lt;/p&gt;
&lt;h2 id=&#34;building-a-channels-application-step-by-step&#34;&gt;Building a Channels Application Step-by-step&lt;/h2&gt;
&lt;p&gt;The following screencast covers the creation of a notification application using Django Channels. You can access the &lt;a href=&#34;https://github.com/arocks/channels-example/&#34;&gt;code on Github&lt;/a&gt;. The intermediate projects like the Echo Consumer can be accessed as branches of the git repository.&lt;/p&gt;

&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;https://www.youtube.com/embed/G_EM5WM_08Q&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allowfullscreen title=&#34;YouTube Video&#34;&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;p&gt;The &lt;a href=&#34;https://github.com/arocks/channels-example/blob/master/show-notes.md&#34;&gt;show notes can be accessed on Github&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Check out the video tutorial and let me know if you found it useful! To know more, read the &lt;a href=&#34;https://channels.readthedocs.io/en/latest/&#34;&gt;Django Channels documentation&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;series-box&#34;&gt;
&lt;p&gt;This article contains an excerpt from &lt;a href=&#34;https://arunrocks.com/static/book/django-design-patterns-best-practices-2-ed/&#34;&gt;&#34;Django Design Patterns and Best Practices&#34;&lt;/a&gt; by Arun Ravindran&lt;/p&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>Get started with Async &amp; Await</title>
      <link>https://arunrocks.com/get-started-with-async-and-await/</link>
      <pubDate>Wed, 14 Mar 2018 06:55:30 +0530</pubDate>
      
      <guid>https://arunrocks.com/get-started-with-async-and-await/</guid>
      <description>&lt;div class=&#34;series-box&#34;&gt;
&lt;p&gt;You are reading a post from a two-part tutorial series on Django Channels&lt;/p&gt;
&lt;ul&gt;
    &lt;li class=&#34;active&#34;&gt;&lt;a href=&#34;https://arunrocks.com/get-started-with-async-and-await/&#34;&gt;Part 1&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&#34;https://arunrocks.com/understanding-django-channels/&#34;&gt;Part 2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id=&#34;asyncio&#34;&gt;Asyncio&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://docs.python.org/3/library/asyncio.html&#34;&gt;Asyncio&lt;/a&gt; is a co-operative multitasking library available in Python since version 3.6. &lt;a href=&#34;http://www.celeryproject.org/&#34;&gt;Celery&lt;/a&gt; is fantastic for running concurrent tasks out of process, but there are certain times you would need to run multiple tasks in a single thread inside a single process.&lt;/p&gt;
&lt;p&gt;If you are not familiar with async/await concepts (say from JavaScript or C#) then it involves a bit of steep learning curve. However, it is well worth your time as it can speed up your code tremendously (unless it is completely CPU-bound). Moreover, it helps in understanding other libraries built on top of them like Django Channels.&lt;/p&gt;
&lt;p&gt;This post is an attempt to explain the concepts in a simplified manner rather than try to be comprehensive. I want you to start using asynchronous programming and enjoy it. You can learn the nitty gritties later.&lt;/p&gt;
&lt;div data-pullquote=&#34;&amp;#34;Unlike a normal function call, if you invoke a coroutine its body will not get executed right away&amp;#34;&#34;&gt;
&lt;/div&gt;
&lt;p&gt;All asyncio programs are driven by an &lt;strong&gt;event loop&lt;/strong&gt;, which is pretty much an indefinite loop that calls all registered coroutines in some order until they all terminate. Each coroutine operates cooperatively by yielding control to fellow coroutines at well-defined places. This is called awaiting.&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;coroutine&lt;/strong&gt; is like a special function which can suspend and resume execution. They work like lightweight threads. Native coroutines use the async and await keywords, as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;asyncio&lt;/span&gt;


&lt;span class=&#34;n&#34;&gt;async&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sleeper_coroutine&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;asyncio&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sleep&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;


&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;vm&#34;&gt;__name__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;loop&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;asyncio&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get_event_loop&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;loop&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;run_until_complete&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sleeper_coroutine&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is a minimal example of an event loop running one coroutine named &lt;strong&gt;sleeper_coroutine&lt;/strong&gt;. When invoked this coroutine runs until the await statement and yields control back to the event loop. This is usually where an Input/Output activity occurs.&lt;/p&gt;
&lt;p&gt;The control comes back to the coroutine at the same line when the activity being awaited is completed (after five seconds). Then then coroutine returns or is considered completed.&lt;/p&gt;
&lt;h2 id=&#34;explain-async-and-await&#34;&gt;Explain async and await&lt;/h2&gt;
&lt;p&gt;[TLDR; &lt;a href=&#34;https://www.youtube.com/watch?v=wDESPxBOtvY&#34;&gt;Watch my screencast&lt;/a&gt; to understand this section with a lot more code examples.]&lt;/p&gt;
&lt;p&gt;Initially, I was confused by the presence of the new keywords in Python: &lt;strong&gt;async&lt;/strong&gt; and &lt;strong&gt;await&lt;/strong&gt;. Asynchronous code seemed to be littered with these keywords yet it was not clear what they did or when to use them.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s first look at the &lt;code&gt;async&lt;/code&gt; keyword. Commonly used before a function definition as &lt;code&gt;async def&lt;/code&gt;, it indicates that you are defining a (native) coroutine.&lt;/p&gt;
&lt;p&gt;You should know two things about coroutines:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Don&amp;rsquo;t perform slow or blocking operations synchronously inside coroutines.&lt;/li&gt;
&lt;li&gt;Don&amp;rsquo;t call a coroutine directly like a regular function call. Either schedule it in an event loop or await it from another coroutine.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Unlike a normal function call, if you invoke a coroutine its body will not get executed right away. Instead it will be suspended and returns a coroutine object. Invoking the send method of this coroutine will start the execution of the coroutine body.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;async&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;hi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;     &lt;span class=&#34;k&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;HOWDY!&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;o&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;hi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;o&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;coroutine&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;object&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;hi&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;at&lt;/span&gt; &lt;span class=&#34;mh&#34;&gt;0x000001DAE26E2F68&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;o&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;send&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;HOWDY&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;!&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;Traceback&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;most&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;recent&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;call&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;last&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;File&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;lt;stdin&amp;gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;line&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;module&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;ne&#34;&gt;StopIteration&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, when the coroutine returns it will end in a StopIteration exception. Hence it is better to use the asyncio provided event loop to run a coroutine. The loop will handle exceptions in addition to all other machinery for running coroutines concurrently.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;asyncio&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;loop&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;asyncio&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get_event_loop&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;o&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;hi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;loop&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;run_until_complete&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;o&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;HOWDY&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next we have the &lt;code&gt;await&lt;/code&gt; keyword which must be only used inside a coroutine. If you call another coroutine, chances are that it might get blocked at some point, say while waiting for I/O.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;async&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sleepy&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;     &lt;span class=&#34;n&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;asyncio&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sleep&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;o&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sleepy&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;loop&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;run_until_complete&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;o&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# After three seconds&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;a href=&#34;https://docs.python.org/3/library/asyncio-task.html#asyncio.sleep&#34;&gt;sleep&lt;/a&gt; coroutine from asyncio module is different from its synchronous counterpart &lt;a href=&#34;https://docs.python.org/3/library/time.html#time.sleep&#34;&gt;time.sleep&lt;/a&gt;. It is non-blocking. This means that other coroutines can be executed while this coroutine is awaiting the sleep to be completed.&lt;/p&gt;
&lt;p&gt;When a coroutine uses the await keyword to call another coroutines, it acts like a bookmark. When a blocking operation happens, it suspends the coroutine (and all the coroutines who are await-ing it) and returns control back to the event loop. Later, when the event loop is notified of the completion of the blocking operation, then the execution is resumed from the await expression paused and continues onward.&lt;/p&gt;
&lt;h2 id=&#34;asyncio-vs-threads&#34;&gt;Asyncio vs Threads&lt;/h2&gt;
&lt;p&gt;If you have worked on multi-threaded code, then you might wonder – Why not just use threads? There are several reasons why threads are not popular in Python.&lt;/p&gt;
&lt;div data-pullquote=&#34;&amp;#34;If you can run a maximum of hundreds of threads, then you might be able to run tens of thousands of coroutines given the same memory&amp;#34;&#34;&gt;
&lt;/div&gt;
&lt;p&gt;Firstly, threads need to be synchronized while accessing shared resources or we will have race conditions. There are several types of synchronization primitives like locks but essentially, they involve waiting which degrades performance and could cause deadlocks or starvation.&lt;/p&gt;
&lt;p&gt;A thread may be interrupted any time. Coroutines have well-defined places where execution is handed over i.e. co-operative multitasking. As a result, you may make changes to a shared state as long as you leave it in a known state. For instance you can retrieve a field from a database, perform calculations and overwrite the field without worrying that another coroutine might have interrupted you in between. All this is possible without locks.&lt;/p&gt;
&lt;p&gt;Secondly, coroutines are lightweight. Each coroutine needs an order of magnitude less memory than a thread. If you can run a maximum of hundreds of threads, then you might be able to run tens of thousands of coroutines given the same memory. Thread switching also takes some time (few milliseconds). This means you might be able to run more tasks or serve more concurrent users (just like how Node.js works on a single thread without blocking).&lt;/p&gt;
&lt;p&gt;The downsides of coroutines is that you cannot mix blocking and non-blocking code. So once you enter the event loop, rest of the code driven by it must be written in asynchronous style, even the standard or third-party libraries you use. This might make using some older libraries with synchronous code somewhat difficult.&lt;/p&gt;
&lt;p&gt;If you really want to call asynchronous code from synchronous or vice versa, then do read this &lt;a href=&#34;https://www.aeracode.org/2018/02/19/python-async-simplified/&#34;&gt;excellent overview&lt;/a&gt; of various cases and adaptors you can use by Andrew Godwin.&lt;/p&gt;
&lt;h2 id=&#34;the-classic-web-scraper-example&#34;&gt;The Classic Web-scraper Example&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s look at an example of how we can rewrite synchronous code into asynchronous. We will look at a webscraper which downloads pages from a couple of URLs and measures its size. This is a common example because it is very I/O bound which shows a significant speedup when handled concurrently.&lt;/p&gt;
&lt;h3 id=&#34;synchronous-web-scraping&#34;&gt;Synchronous web scraping&lt;/h3&gt;
&lt;p&gt;The synchronous scraper uses Python 3 standard libraries like urllib. It downloads the home page of three popular sites and the fourth is a large file to simulate a slow connection. It prints the respective page sizes and the total running time.&lt;/p&gt;
&lt;p&gt;Here is the code for the synchronous scraper:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# sync.py&lt;/span&gt;
&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&amp;#34;Synchronously download a list of webpages and time it&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;urllib.request&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;urlopen&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;time&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;time&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;sites&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;https://news.ycombinator.com/&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;https://www.yahoo.com/&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;https://github.com/&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;


&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;find_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;url&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;req&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;url&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;urlopen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;req&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;page&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;response&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;read&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;page&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;


&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;site&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sites&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;find_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;site&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Read {:8d} chars from {}&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;format&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;site&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;


&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;vm&#34;&gt;__name__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;start_time&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;time&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Ran in {:6.3f} secs&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;format&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;time&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;start_time&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;On a test laptop, this code took 5.4 seconds to run. It is the cumulative loading time of each site. Let&amp;rsquo;s see how asynchronous code runs.&lt;/p&gt;
&lt;h3 id=&#34;asynchronous-web-scraping&#34;&gt;Asynchronous web scraping&lt;/h3&gt;
&lt;p&gt;This asyncio code requires installation of a few Python asynchronous network libraries such as aiohttp and aiodns. They are mentioned in the docstring.&lt;/p&gt;
&lt;p&gt;Here is the code for the asynchronous scraper – it is structured to be as close as possible to the synchronous version so it is easier to compare:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# async.py&lt;/span&gt;
&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;Asynchronously download a list of webpages and time it
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;Dependencies: Make sure you install aiohttp using: pip install aiohttp aiodns
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;asyncio&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;aiohttp&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;time&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;time&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Configuring logging to show timestamps&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;logging&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;logging&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;basicConfig&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;format&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;%(asctime)s&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt; &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;%(message)s&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;datefmt&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;[%H:%M:%S]&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;log&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;logging&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;getLogger&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;setLevel&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;logging&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;INFO&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;sites&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;https://news.ycombinator.com/&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;https://www.yahoo.com/&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;https://github.com/&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;


&lt;span class=&#34;n&#34;&gt;async&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;find_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;session&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;url&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;START {}&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;format&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;url&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;async&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;session&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;url&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;RESPONSE {}&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;format&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;url&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;page&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;response&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;read&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;PAGE {}&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;format&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;url&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;url&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;page&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;


&lt;span class=&#34;n&#34;&gt;async&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;tasks&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;async&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;aiohttp&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ClientSession&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;session&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;site&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sites&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
            &lt;span class=&#34;n&#34;&gt;tasks&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;append&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;find_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;session&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;site&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;results&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;asyncio&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gather&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tasks&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;site&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;size&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;results&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Read {:8d} chars from {}&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;format&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;site&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;


&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;vm&#34;&gt;__name__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;start_time&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;time&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;loop&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;asyncio&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get_event_loop&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;loop&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;set_debug&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;True&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;loop&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;run_until_complete&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Ran in {:6.3f} secs&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;format&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;time&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;start_time&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The main function is a coroutine which triggers the creation of a separate coroutine for each website. Then it awaits until all these triggered coroutines are completed. As a best practice, the web session object is passed to avoid re-creating new sessions for each page.&lt;/p&gt;
&lt;p&gt;The total running time of this program on the same test laptop is 1.5 s. This is a speedup of 3.6x on the same single core. This surprising result can be better understood if we can visualize how the time was spent, as shown below:&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
    &lt;img loading=&#34;lazy&#34; src=&#34;https://arunrocks.com/static/images/blog/async-await.png&#34; alt=&#34;Comparing scrapers&#34;   width=1703 height=&#34;920&#34;  /&gt;
    
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;A simplistic representation comparing tasks in the synchronous and asynchronous scrapers&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The synchronous scraper is easy to understand. Scraping activity needs very little CPU time and the majority of the time is spent waiting for the data to arrive from the network. Each task is waiting for the previous task to complete. As a result the tasks cascade sequentially like a waterfall.&lt;/p&gt;
&lt;p&gt;On the other hand the asynchronous scraper starts the first task and as soon as it starts waiting for I/O, it switches to the next task. The CPU is hardly idle as the execution goes back to the event loop as soon as the waiting starts. Eventually the I/O completes in the same amount of time but due to the multiplexing of activity, the overall time taken is drastically reduced.&lt;/p&gt;
&lt;p&gt;In fact, the asynchronous code can be speeded up further. The standard asyncio event loop is written in pure Python and provided as a reference implementation. You can consider faster implementations like &lt;a href=&#34;https://github.com/MagicStack/uvloop&#34;&gt;uvloop&lt;/a&gt; for further speedup (my running time came down to 1.3 secs).&lt;/p&gt;
&lt;h2 id=&#34;concurrency-is-not-parallelism&#34;&gt;Concurrency is not Parallelism&lt;/h2&gt;
&lt;p&gt;Concurrency is the ability to perform other tasks while you are waiting on the current task. Imagine you are cooking a lot of dishes for some guests. While waiting for something to cook, you are free to do other things like peeling onions or cutting vegetables. Even when one person cooks, typically there will be several things happening &lt;em&gt;concurrently&lt;/em&gt;.&lt;/p&gt;
&lt;div data-pullquote=&#34;&amp;#34;Optimal usage of your computing resources require both concurrency and parallelism&amp;#34;&#34;&gt;
&lt;/div&gt;
&lt;p&gt;Parallelism is when two or more execution engines are performing a task. Continuing on our analogy, this is when two or more cooks work on the same dish to (hopefully) save time.&lt;/p&gt;
&lt;p&gt;It is very easy to confuse concurrency and parallelism because they can happen at the same time. You could be concurrently running tasks without parallelism or vice versa. But they refer to two different things. Concurrency is a way of structuring your programs while Parallelism refers to how it is executed.&lt;/p&gt;
&lt;p&gt;Due to the Global Interpreter Lock, we cannot run more than one thread of the Python interpreter (to be specific, the standard CPython interpreter) at a time even in multicore systems. This limits the amount of parallelism which we can achieve with a single instance of the Python process.&lt;/p&gt;
&lt;p&gt;Optimal usage of your computing resources require both concurrency and parallelism. Concurrency will help you avoid idling the processor core while waiting for say I/O events. While parallelism will help distribute work among all the available cores.&lt;/p&gt;
&lt;p&gt;In both cases, you are not executing synchronously i.e. waiting for a task to finish before moving on to another task. Asynchronous systems might seem to be the most optimal. However, they are harder to build and reason about.&lt;/p&gt;
&lt;h2 id=&#34;why-another-asynchronous-framework&#34;&gt;Why another Asynchronous Framework?&lt;/h2&gt;
&lt;p&gt;Asyncio is by no means the first cooperative multitasking or light-weight thread library. If you have used gevent or eventlet, you might find asyncio needs more explicit separation between synchronous and asynchronous code. This is usually a good thing.&lt;/p&gt;
&lt;p&gt;Gevent, relies on monkey-patching to change blocking I/O calls to non-blocking ones. This can lead to hard to find performance issues due to an unpatched blocking call slowing the event loop. As the Zen says, &amp;lsquo;Explicit is better than Implicit&amp;rsquo;.&lt;/p&gt;
&lt;p&gt;Another objective of asyncio was to provide a standardized concurrency framework for all implementations like gevent or Twisted. This not only reduces duplicated efforts by library authors but also ensures that code is portable for end users.&lt;/p&gt;
&lt;p&gt;Personally, I think the asyncio module can be more streamlined. There are a lot of ideas which somewhat expose implementation details (e.g. native coroutines vs generator-based coroutines). But it is useful as a standard to write future-proof code.&lt;/p&gt;
&lt;h2 id=&#34;can-we-use-asyncio-in-django&#34;&gt;Can we use asyncio in Django?&lt;/h2&gt;
&lt;p&gt;Strictly speaking, the answer is No. Django is a synchronous web framework. You might be able to run a seperate worker process, say in Celery, to run an embedded event loop. This can be used for I/O background tasks like web scraping.&lt;/p&gt;
&lt;p&gt;However, &lt;a href=&#34;https://channels.readthedocs.io/en/latest/&#34;&gt;Django Channels&lt;/a&gt; changes all that. Django might fit in the asynchronous world after all. But that&amp;rsquo;s the subject of another post.&lt;/p&gt;
&lt;div class=&#34;series-box&#34;&gt;
&lt;p&gt;This article contains an excerpt from &lt;a href=&#34;https://arunrocks.com/static/book/django-design-patterns-best-practices-2-ed/&#34;&gt;&#34;Django Design Patterns and Best Practices&#34;&lt;/a&gt; by Arun Ravindran&lt;/p&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>Interview with Daniel Roy Greenfeld (PyDanny)</title>
      <link>https://arunrocks.com/interview-with-daniel-roy-greenfeld-pydanny/</link>
      <pubDate>Fri, 09 Feb 2018 15:15:11 +0530</pubDate>
      
      <guid>https://arunrocks.com/interview-with-daniel-roy-greenfeld-pydanny/</guid>
      <description>&lt;p&gt;Daniel Roy Greenfeld needs no introduction to Djangonauts. Co-author of the book &lt;a href=&#34;https://www.twoscoopspress.com/products/two-scoops-of-django-1-8&#34;&gt;Two Scoops of Django&lt;/a&gt; which is probably on the shelves of any serious Django practitioner. But PyDanny, as he is fondly known as, is also a wonderful fiction author, fitness enthusiast and a lot more.&lt;/p&gt;
&lt;p&gt;Having known Daniel for a while as a wonderful friend and a great inspiration, I am so excited that he agreed to my interview. Let&amp;rsquo;s get started&amp;hellip;&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
    &lt;img loading=&#34;lazy&#34; src=&#34;https://arunrocks.com/static/images/blog/pydanny.jpg&#34; alt=&#34;PyDanny Photo&#34;   width=500 height=&#34;753&#34;  /&gt;
    
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How did the idea of writing an ice-cream themed book occur?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The first 50 pages that I wrote were angry and were for a book with an angry name. You see, I was tired of having to pick up after sloppy or unwise coding practices on rescue projects. I was furious and wanted to fix the world.&lt;/p&gt;
&lt;p&gt;However, I was getting stuck in what I wanted to say, or didn&amp;rsquo;t know things. I kept asking my normal favorite resource for help, Audrey Roy Greenfeld. Eventually she started to write (or rewrite) whole sections and I realized that I wasn&amp;rsquo;t writing the book alone.&lt;/p&gt;
&lt;p&gt;Therefore I asked Audrey to be my co-author. She&amp;rsquo;s a cheerful person and said that if she were to accept, the book had to be lightened. That meant changing the name. After a lot of different title names discussed over many ice cream sessions, we decided to use the subject matter at hand. Which worked out well as the ice cream theme made for a good example subject.&lt;/p&gt;
&lt;div data-pullquote=&#34;&amp;#34;Neither of us are big believers in multi-tasking, so sticking to one thing is important to us.&amp;#34;&#34;&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;How do you and Audrey collaborate while writing a book?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We take turns writing original material that interests us. The other person follows them and acts as editor and proofreader. We go back and forth a few hundred times and there you go.&lt;/p&gt;
&lt;p&gt;For tech writing we use Git as version control and LaTeX for formatting. For fiction we use Google docs followed by some Python scripts that merge and format the files.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What&amp;rsquo;s the most exciting recent development in Django? Where do you think it can improve?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I like the new URL system as it&amp;rsquo;s really nice for beginners and advanced coders alike. While I like writing regular expressions, I&amp;rsquo;m the exception in this case.&lt;/p&gt;
&lt;p&gt;Where I think where Django can improve is having more non-US/Europe/Australian representation within the DSF and in the core membership. In short, most of Django core looks like me, and I think that&amp;rsquo;s wrong. Many of the best Django (and Python) people look nothing like me, and they deserve more recognition. While having Anna Makarudze on the DSF board is a wonderful development, as a community we can still do better in core.&lt;/p&gt;
&lt;p&gt;In the case of Django&amp;rsquo;s core team, I believe this has happened because all the major Django conferences are in the US, Europe, and Australia, and from what I&amp;rsquo;ve seen over the years it&amp;rsquo;s through participation in those events is how most people get onto the Django core team. The DSF is aware of the problem, but I think more people should raise it as an issue. More people vocalizing this as a problem will get it resolved more quickly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;With the Ambria fantasy series, you have proven to be a prolific fiction author too. Reminds me Lewis Carroll who wrote children&amp;rsquo;s books and mathematical treatises. What is the difference in the writing process while writing fiction and non-fiction?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For us, the process is very similar. We both write and we both review our stuff. The difference is that if we make a mistake in our fiction, it&amp;rsquo;s not as critical. That means that the review process for fiction is a lot easier on us then it is to write technical books or articles. I can&amp;rsquo;t begin to tell you what a load that is off my shoulders.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why fantasy? Any literary influences?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We like fantasy because we can just let our imaginations run away with us. For the Ambria series, our influences include Tolkien, Joseph Campbell, Glen Cook, Greek mythology, and various equine and religious studies.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Do you have a daily writing routine?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Like coding on a fun project, when we get to write, we get up early and just start working. When we get hungry or thirsty we stop. The day seems to fly by and we are very happy. We try not to mix writing days with coding days, as we like to focus on one thing at a time. Neither of us are big believers in multi-tasking, so sticking to one thing is important to us.&lt;/p&gt;
&lt;div data-pullquote=&#34;&amp;#34;It&amp;#39;s our responsibility to the future to be aware that the tools we are playing with have a lot of power&amp;#34;&#34;&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;What&amp;rsquo;s your favorite part of the writing process?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Getting to write with my favorite person in the whole world, Audrey Roy Greenfeld. :-)&lt;/p&gt;
&lt;p&gt;Also, having people read our stuff and comment on it, both positively and negatively.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Do you ever get writer&amp;rsquo;s block?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Not usually. Our delays are almost always because of other things getting in the way. We&amp;rsquo;re very fortunate that way!&lt;/p&gt;
&lt;p&gt;When I do get writers block, I try to do something active. Be it exercise or fix something in the house that needs it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Considering you can do cartwheels, I am assuming you are pretty fit. Do you think technology folks don&amp;rsquo;t give it enough importance?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m older than I look but even dealing with an unpleasant knee injury move faster and better than 90% of software developers. And when I look at other coders my age, I see people old before their years. I believe youth is fleeting unless you take a little bit of time every day to keep your strength and flexibility.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Anything else you would like to say?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To paraphrase Jurassic Park, &amp;ldquo;Just because you can do a thing doesn&amp;rsquo;t mean you should do a thing.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;As software developers, we have skills that let us do amazing things. With enough time and experience, we can do pretty much anything we are asked to do. That said, we should consider whether or not we should always do what we are asked to do.&lt;/p&gt;
&lt;p&gt;For example, the combined power of image recognition, big data, and distributed systems is really fun to play with, but we need to be aware that these tools can be dangerous. In the past year we&amp;rsquo;ve seen it used to affect opinion and elections, and this is only the beginning. It&amp;rsquo;s our responsibility to the future to be aware that the tools we are playing with have a lot of power, and that the people who are paying us to use them might not have the best intentions.&lt;/p&gt;
&lt;p&gt;Hence why I like to say, &amp;ldquo;Just because you can do a thing doesn&amp;rsquo;t mean you should do a thing.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Do checkout &lt;a href=&#34;https://www.twoscoopspress.com/products/two-scoops-of-django-1-8&#34;&gt;&amp;ldquo;Two Scoops of Django 1.11: Best Practices for the Django Web Framework&amp;rdquo;&lt;/a&gt; by Two Scoops Press&lt;/strong&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Django Release Schedule and Python 3</title>
      <link>https://arunrocks.com/django-release-schedule-and-python-3/</link>
      <pubDate>Tue, 30 Jan 2018 06:59:49 +0530</pubDate>
      
      <guid>https://arunrocks.com/django-release-schedule-and-python-3/</guid>
      <description>&lt;p&gt;Do long term releases confuse you? For the longest time I was not sure which version of Ubuntu to download - the latest release or the LTS? I see a number of Django developers confused about Django&amp;rsquo;s releases. So I prepared this handy guide to help you choose (or confuse?).&lt;/p&gt;
&lt;h2 id=&#34;which-version-to-use&#34;&gt;Which Version To Use?&lt;/h2&gt;
&lt;p&gt;Django has now &lt;a href=&#34;https://www.djangoproject.com/weblog/2015/jun/25/roadmap/&#34;&gt;standardized on a release schedule&lt;/a&gt; with three kinds of releases:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Feature Release&lt;/strong&gt;: These releases will have new features or improvements to existing features. It will happen every 8 months and will have 16 months of extended support from release. They have version numbers like A.B (note there&amp;rsquo;s no minor version).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Long-Term Support (LTS) Release&lt;/strong&gt;: These are special kind of feature releases, which have a longer extended support of three years from the release date. These releases will happen every two years. They have version numbers like A.2 (since every third feature release will be a LTS). LTS releases have few months of overlap to aid in a smoother migration.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Patch Release&lt;/strong&gt;: These releases are bug fixes or security patches. It is recommended to deploy them as soon as possible. Since they have minimal breaking changes, these upgrades should be painless to apply. They have version numbers like A.B.C&lt;/p&gt;
&lt;p&gt;Django roadmap visualized below should make the release approach clearer:&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
    &lt;img loading=&#34;lazy&#34; src=&#34;https://arunrocks.com/static/images/blog/django-releases.png&#34; alt=&#34;Django Releases (LTS and feature releases) explained&#34;   width=1741 height=&#34;1240&#34;  /&gt;
    
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;The dates are indicative and may change. This is not an official diagram but something that I created for my understanding.&lt;/p&gt;
&lt;p&gt;The big takeaway is that Django 1.11 LTS will be the last release to support Python 2 and it is supported until April 2020. Subsequent versions will use only Python 3.&lt;/p&gt;
&lt;p&gt;The right Django version for you will be based on how frequent you can upgrade your Django installation and what features you need. If your project is actively developed and the Django version can be upgraded at least once in 16 months, then you should install the latest feature release regardless of whether it is LTS or non-LTS.&lt;/p&gt;
&lt;p&gt;Otherwise, if your project is only occasionally developed then you should pick the most recent LTS version. Upgrading your project&amp;rsquo;s Django dependency from one feature release to another can be a non-trivial effort. So, read the release notes and plan accordingly.&lt;/p&gt;
&lt;p&gt;In any case, make sure you install Patch Releases as soon as they are released. Now, if you are still on Python 2 then read on.&lt;/p&gt;
&lt;h2 id=&#34;python-3-has-crossed-tipping-point&#34;&gt;Python 3 has crossed tipping point&lt;/h2&gt;
&lt;p&gt;When I decided to use Python 3 only while writing my book &amp;ldquo;Django Design Patterns and Best Practices&amp;rdquo; in 2015, it was a time when Python 2 versus Python 3 was hotly debated. However, to me Python 3 seemed much more cleaner without arcane syntax like class methods named &lt;code&gt;__unicode__&lt;/code&gt;  and classes needing to derive from &lt;code&gt;object&lt;/code&gt; parent class.&lt;/p&gt;
&lt;p&gt;Now, it is quite a different picture. We just saw how Django no longer supports Python 2 except for the last LTS release. This is a big push for many Python shops to consider Python 3.&lt;/p&gt;
&lt;p&gt;Many platforms have upgraded their default Python interpreter. Starting 1st March 2018, Python 3 is announced to be the default &amp;ldquo;python&amp;rdquo; in Homebrew installs. ArchLinux had completely switched to Python 3 since 2010.&lt;/p&gt;
&lt;p&gt;Fedora has switched to Python 3 as its system default since &lt;a href=&#34;https://fedoraproject.org/wiki/Changes/Python_3_as_Default&#34;&gt;version 23&lt;/a&gt;. Even though &lt;code&gt;python&lt;/code&gt; command will launch &lt;code&gt;python3&lt;/code&gt;, the symlink &lt;code&gt;/usr/bin/python&lt;/code&gt; will still point to &lt;code&gt;python2&lt;/code&gt; for backward compatibility. So it is probably a good idea to use &lt;code&gt;#!/usr/bin/env python&lt;/code&gt; idiom in your shell scripts.&lt;/p&gt;
&lt;p&gt;On 26 April 2018, when Ubuntu 18.04 LTS (Bionic Beaver) will be released, it is planned to be have &lt;a href=&#34;https://wiki.ubuntu.com/Python/Python36Transition&#34;&gt;Python 3.6 as default&lt;/a&gt;. Further upstream, the next Debian release in testing - Debian 10 (Buster) &lt;a href=&#34;https://wiki.ubuntu.com/Python/Python36Transition&#34;&gt;is expected to transition to Python 3.6&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Moving to packages, the &lt;a href=&#34;https://python3wos.appspot.com/&#34;&gt;Python 3 Wall of Superpowers&lt;/a&gt; shows that with the backing of 190 out of 200 packages, at the time of writing, we have nearly all popular Python packages on Python 3. The only notable package remaining is supervisor, which is about to turn green in &lt;a href=&#34;https://github.com/Supervisor/supervisor/blob/master/README.rst&#34;&gt;supervisor 4.0 (unreleased)&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;common-python-3-migration-blockers&#34;&gt;Common Python 3 Migration Blockers&lt;/h3&gt;
&lt;p&gt;You might be aware of atleast one project which is still on Python 2. It could be open source or an internal project, which may be stuck in Python 3 for a number of reasons. I&amp;rsquo;ve come across a number of such projects and here is my response to such reasons:&lt;/p&gt;
&lt;h4 id=&#34;reason-1-my-project-is-too-complex&#34;&gt;Reason 1: My Project is too complex&lt;/h4&gt;
&lt;p&gt;Some very large and complex projects like NumPy or Django have been migrated sucessfully. You can learn the &lt;a href=&#34;https://docs.djangoproject.com/en/1.11/topics/python3/&#34;&gt;migration strategies of projects like Django&lt;/a&gt;. Django maintained a common codebase for Python 2 and 3 using the &lt;a href=&#34;https://pypi.python.org/pypi/six&#34;&gt;six&lt;/a&gt; (2 × 3=6, get it?) library before switching to Python 3 only.&lt;/p&gt;
&lt;h4 id=&#34;reason-2-i-still-have-time&#34;&gt;Reason 2: I still have time&lt;/h4&gt;
&lt;p&gt;It is closer than you think. &lt;a href=&#34;https://pythonclock.org/&#34;&gt;Python clock&lt;/a&gt; shows there is a little more than 2 years and 2 months left for Python 2 support.&lt;/p&gt;
&lt;p&gt;In fact, you have had a lot of time. It has been ten years since Python 3 was announced. That is a lot of overlap to transition from one version to another.&lt;/p&gt;
&lt;p&gt;In today&amp;rsquo;s &amp;lsquo;move fast and break things&amp;rsquo; world, a lot of projects decide to abruptly stop support and ask you to migrate as soon as a new release is out. This is a lot more realistic assumption for enterprises which need a lot more planning and testing.&lt;/p&gt;
&lt;h4 id=&#34;reason-3-i-have-to-learn-python-3&#34;&gt;Reason 3: I have to learn Python 3&lt;/h4&gt;
&lt;p&gt;But you already know most of it! You might need about 10 mins to learn the differences. In fact, I have written a post to guide &lt;a href=&#34;https://arunrocks.com/python-3-cheatsheet-for-djangonauts/&#34;&gt;Django coders to Python 3&lt;/a&gt;. Small Django/Python 2 projects need only trivial changes to work on Python 3.&lt;/p&gt;
&lt;p&gt;You might see many old blog posts about Python 3 being buggy or slow. Well, that has not been true for a while. Not only it is extremely stable and bug-free, it is actually used in production by several companies. Performance-wise it has been getting faster in every release, so it is faster than Python 2 in most cases and slower in a few.&lt;/p&gt;
&lt;p&gt;Of course, there are lot of awesome new features and libraries added to Python 3. You can learn them as and when you need them. I would recommend reading the release notes to understand them. I will mention my favourites soon.&lt;/p&gt;
&lt;h4 id=&#34;reason-4-nobody-is-asking&#34;&gt;Reason 4: Nobody is asking&lt;/h4&gt;
&lt;p&gt;Some people have the philosophy that if nobody is asking then nobody cares. Well, they do care if the application they run is on an unsupported technology. Better plan for the eventual transition than rush it on a higher budget.&lt;/p&gt;
&lt;h2 id=&#34;are-you-missing-out&#34;&gt;Are you missing out?&lt;/h2&gt;
&lt;p&gt;&lt;figure&gt;
    &lt;img loading=&#34;lazy&#34; src=&#34;https://arunrocks.com/static/images/blog/box-of-chocs.jpg&#34; alt=&#34;Image by https://pixabay.com/en/users/GlenisAymara-856260/&#34;   width=1280 height=&#34;720&#34;  /&gt;
    
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;To me, the biggest reason to switch was that all the newest and greatest features were coming to Python 3. My favourite top three exclusive features in Python 3 are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://docs.python.org/3/library/asyncio.html&#34;&gt;&lt;strong&gt;asyncio&lt;/strong&gt;&lt;/a&gt;: One of the coolest technologies I picked up recently. The learning process is sometimes mind-bending. But the performance boost in the right situations is incredible.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://docs.python.org/3/library/asyncio.html&#34;&gt;&lt;strong&gt;f-strings&lt;/strong&gt;&lt;/a&gt;: They are so incredibly expressive that you would want to use them everywhere. Instant love!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://docs.python.org/3/whatsnew/3.6.html#new-dict-implementation&#34;&gt;dict&lt;/a&gt;: New compact dict implementation which uses less memory and are ordered!&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Yes, &lt;a href=&#34;https://en.wikipedia.org/wiki/Fear_of_missing_out&#34;&gt;FOMO&lt;/a&gt; is real.&lt;/p&gt;
&lt;p&gt;Apart from my personal reasons, I would recommend everyone to migrate so that the community benefits from investing efforts into a common codebase. Plus we can all be consistent on which Python to recommend to beginners. &lt;a href=&#34;https://www.python.org/dev/peps/pep-0020/&#34;&gt;Because&lt;/a&gt;&amp;hellip;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There should be one&amp;ndash; and preferably only one &amp;ndash;obvious way to do it.
Although that way may not be obvious at first unless you&amp;rsquo;re Dutch.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class=&#34;series-box&#34;&gt;
&lt;p&gt;This article contains an excerpt from the upcoming second edition of book &lt;a href=&#34;http://djangopatternsbook.github.io/&#34;&gt;&#34;Django Design Patterns and Best Practices&#34;&lt;/a&gt; by Arun Ravindran&lt;/p&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>Python 3 Cheatsheet for Djangonauts</title>
      <link>https://arunrocks.com/python-3-cheatsheet-for-djangonauts/</link>
      <pubDate>Wed, 20 May 2015 19:08:00 +0530</pubDate>
      
      <guid>https://arunrocks.com/python-3-cheatsheet-for-djangonauts/</guid>
      <description>&lt;p&gt;&lt;strong&gt;If you are already convinced to use Python 3 then you can directly jump to the section &lt;a href=&#34;#python-2-vs-python-3&#34;&gt;&amp;ldquo;Python 2 vs Python 3&amp;rdquo;&lt;/a&gt; for the cheatsheet&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;There is an intense debate whenever Python 3 is mentioned. Some think it is an unnecessary shift and Python 2 series should be continued. However, I chose Python 3 for my &lt;a href=&#34;http://djangopatternsbook.github.io/&#34;&gt;book&lt;/a&gt; because I strongly believe that it is the future of the language. Besides, the divide might not be as large you think.&lt;/p&gt;
&lt;h3 id=&#34;why-python-3&#34;&gt;Why Python 3?&lt;/h3&gt;
&lt;p&gt;Think of your favourite programming language and what you love about it. Now think of things that you don&amp;rsquo;t like about it or wish was improved. Sometimes these improvements might break older codebases but you badly want them.&lt;/p&gt;
&lt;p&gt;Now imagine if the creator of the language takes upon himself/herself to revamp the language and rid of its warts. This is what actually led to Python 3 - Guido led the efforts to clean-up some fundamental design flaws with the 2.x series based on over fifteen years of experience developing a successful language.&lt;/p&gt;
&lt;p&gt;While the development of Python 3 started in 2006, its first release, Python 3.0, was on December 3, 2008. The main reasons for a backwards incompatible version were – switching to Unicode for all strings, increased use of iterators, cleanup of deprecated features like old-style classes and some new syntactic additions like the &lt;code&gt;nonlocal&lt;/code&gt; statement.&lt;/p&gt;
&lt;p&gt;Python 2.7 development was supposed to end in 2015 but was extended for five more years through 2020. There will not be a Python 2.8. Soon all major Linux distributions would have completely switched to using Python 3 as a default. Many PaaS providers like Heroku already support Python 3.4.&lt;/p&gt;
&lt;p&gt;Python 2 and Python 3 have been in parallel development by the core development team for a number of years. Eventually, Python 3 is expected to be the future of the language.&lt;/p&gt;
&lt;h3 id=&#34;porting-django&#34;&gt;Porting Django&lt;/h3&gt;
&lt;p&gt;The reaction to Python 3 in the Django community was rather mixed. Even though the language changes between version 2 and 3 were small (and over time, reduced), porting the entire Django codebase was a significant migration effort.&lt;/p&gt;
&lt;p&gt;Django has been supporting Python 3 since version 1.5. In fact, the strategy was to rewrite the code into Python 3 and deal with Python 2 as a backward compatibility requirement.&lt;/p&gt;
&lt;p&gt;Most of the packages listed in the &lt;a href=&#34;https://python3wos.appspot.com/&#34;&gt;Python 3 Wall of Superpowers&lt;/a&gt; have turned green (indicating they have support for Python 3). Almost all the red ones have an actively developed Python 3 port. Also worth noting is the &lt;a href=&#34;http://djangowos.com/&#34;&gt;Django Wall of Superpowers&lt;/a&gt; with over 67% of the top 200 Django packages having a Python 3 port.&lt;/p&gt;
&lt;h3 id=&#34;python-3-advantage&#34;&gt;Python 3 Advantage&lt;/h3&gt;
&lt;p&gt;Many newcomers to Django wonder whether to start using Python 2 or 3. I recommend starting with Python 3 for the following reasons:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Better syntax&lt;/strong&gt;: It fixes a lot of ugly syntax like &lt;code&gt;izip&lt;/code&gt;, &lt;code&gt;xrange&lt;/code&gt; and &lt;code&gt;__unicode__&lt;/code&gt; with the cleaner and more straightforward &lt;code&gt;zip&lt;/code&gt;, &lt;code&gt;range&lt;/code&gt; and &lt;code&gt;__str__&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Sufficient third-party support&lt;/strong&gt;: Of the top 200 third party libraries, more than 80% have Python 3 support.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;No legacy code&lt;/strong&gt;: Since they are creating a new project rather than dealing with legacy code which needs to support an older version.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Default in Modern Platforms&lt;/strong&gt;: It is already  the default Python interpreter in Arch Linux. Ubuntu and Fedora plan to complete the switch in a future release.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;It is easy&lt;/strong&gt;: From a Django development point of view, there are so few changes that it can be learnt in a few minutes.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The last point is important. Even if you know Python 2, you can pick up Python 3 in a short time.&lt;/p&gt;
&lt;h2 id=&#34;python-2-vs-python-3&#34;&gt;Python 2 vs Python 3&lt;/h2&gt;
&lt;p&gt;This section covers the most important changes in Python 3 from a Django developer&amp;rsquo;s perspective. To understand the full list of changes, please refer to the recommended reading section in the end.&lt;/p&gt;
&lt;p&gt;The examples are given in both Python 2 and Python 3. Depending on your installation, all Python 3 commands might need to be changed from &lt;code&gt;python&lt;/code&gt; to &lt;code&gt;python3&lt;/code&gt; or &lt;code&gt;python3.4&lt;/code&gt; to invoke the interpreter.&lt;/p&gt;
&lt;h3 id=&#34;change-all-__unicode__-methods-into-__str__&#34;&gt;Change all __unicode__ methods into __str__&lt;/h3&gt;
&lt;p&gt;In Python 3, the &lt;code&gt;__str__()&lt;/code&gt; method is called for string representation of your models rather than the awkward sounding &lt;code&gt;__unicode__()&lt;/code&gt; method. This is one of the most evident ways to identify Python 3 ported code.&lt;/p&gt;
&lt;table class=&#34;sidebyside&#34;&gt;
  &lt;thead&gt;
&lt;tr&gt;
  &lt;th&gt;Python 2&lt;/th&gt;
  &lt;th&gt;Python 3&lt;/th&gt;
&lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
&lt;tr&gt;
  &lt;td&gt;&lt;pre&gt;
&lt;p&gt;class Person(models.Model):
name = models.TextField()&lt;/p&gt;
&lt;p&gt;def &lt;strong&gt;unicode&lt;/strong&gt;(self):
return self.name&lt;/p&gt;
&lt;p&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/p&gt;
  &lt;td&gt;&lt;pre&gt;
&lt;p&gt;class Person(models.Model):
name = models.TextField()&lt;/p&gt;
&lt;p&gt;def &lt;strong&gt;str&lt;/strong&gt;(self):
return self.name&lt;/p&gt;
&lt;p&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/p&gt;
&lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;This reflects the difference in the way Python 3 treats strings. In Python 2, the human readable representation of a class could be returned by &lt;code&gt;__str__()&lt;/code&gt; (bytes) or &lt;code&gt;__unicode__()&lt;/code&gt; (text). However, in Python 3 the readable representation is simply returned by &lt;code&gt;__str__()&lt;/code&gt; (text).&lt;/p&gt;
&lt;h3 id=&#34;all-classes-inherit-from-object&#34;&gt;All Classes Inherit from object&lt;/h3&gt;
&lt;p&gt;Python 2 has two kinds of classes – old-style (classic) and new-style. New-style classes are classes which directly or indirectly inherit from &lt;code&gt;object&lt;/code&gt;. Only new style classes can use Python&amp;rsquo;s advanced features like slots, descriptors and properties. Many of these are used by Django. However, classes were still old-style by default for compatibility reasons.&lt;/p&gt;
&lt;p&gt;In Python 3, the old-style classes don&amp;rsquo;t exist anymore. As seen below, even if you don&amp;rsquo;t explicitly mention any parent classes the &lt;code&gt;object&lt;/code&gt; class will be present as a base. So, all classes are new-style.&lt;/p&gt;
&lt;table class=&#34;sidebyside&#34;&gt;
  &lt;thead&gt;
&lt;tr&gt;
  &lt;th&gt;Python 2&lt;/th&gt;
  &lt;th&gt;Python 3&lt;/th&gt;
&lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
&lt;tr&gt;
  &lt;td&gt;&lt;pre&gt;
&lt;p&gt;&amp;gt;&amp;gt;&amp;gt; class CoolMixin:
&amp;hellip;     pass
&amp;gt;&amp;gt;&amp;gt; CoolMixin.&lt;strong&gt;bases&lt;/strong&gt;
()&lt;/p&gt;
&lt;p&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/p&gt;
  &lt;td&gt;&lt;pre&gt;
&lt;p&gt;&amp;gt;&amp;gt;&amp;gt; class CoolMixin:
&amp;hellip;     pass
&amp;gt;&amp;gt;&amp;gt; CoolMixin.&lt;strong&gt;bases&lt;/strong&gt;
(&amp;lt;class &amp;lsquo;object&amp;rsquo;&amp;gt;,)&lt;/p&gt;
&lt;p&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/p&gt;
&lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;calling-super-is-easier&#34;&gt;Calling super() is Easier&lt;/h3&gt;
&lt;p&gt;The simpler call to &lt;code&gt;super()&lt;/code&gt;, without any arguments, will save you some typing in Python 3.&lt;/p&gt;
&lt;table class=&#34;sidebyside&#34;&gt;
  &lt;thead&gt;
&lt;tr&gt;
  &lt;th&gt;Python 2&lt;/th&gt;
  &lt;th&gt;Python 3&lt;/th&gt;
&lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
&lt;tr&gt;
  &lt;td&gt;&lt;pre&gt;
class CoolMixin(object):
&lt;p&gt;def do_it(self):
return super(CoolMixin,
self).do_it()
&lt;/pre&gt;&lt;/td&gt;&lt;/p&gt;
  &lt;td&gt;&lt;pre&gt;
class CoolMixin:
&lt;p&gt;def do_it(self):
return super().do_it()
&lt;/pre&gt;&lt;/td&gt;&lt;/p&gt;
&lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Specifying the class name and instance is optional, thereby making your code DRY and less prone to errors while refactoring.&lt;/p&gt;
&lt;h3 id=&#34;relative-imports-must-be-explicit&#34;&gt;Relative Imports Must be Explicit&lt;/h3&gt;
&lt;p&gt;Imagine the following directory structure for a package named &lt;code&gt;app1&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/app1
  /__init__.py
  /models.py
  /tests.py
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now, in Python 3, let us run the following in the parent directory of &lt;code&gt;app1&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ echo &amp;quot;import models&amp;quot; &amp;gt; app1/tests.py
$ python -m app1.tests
Traceback (most recent call last):
   ... omitted ...
ImportError: No module named &#39;models&#39;
$ echo &amp;quot;from . import models&amp;quot; &amp;gt; app1/tests.py
$ python -m app1.tests
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&#34;successfully-import-ed&#34;&gt;Successfully import-ed&lt;/h4&gt;
&lt;p&gt;Within a package, you should use explicit relative imports while referring to a sibling module. You can omit &lt;code&gt;__init__.py&lt;/code&gt; in Python 3, though it is commonly used to identify a package.&lt;/p&gt;
&lt;p&gt;In Python 2, you could use &lt;code&gt;import models&lt;/code&gt; to successfully import &lt;code&gt;models.py&lt;/code&gt; module. But it was ambiguous and could accidentally import any other &lt;code&gt;models.py&lt;/code&gt; in your Python path. Hence this is forbidden in Python 3 and discouraged in Python 2 as well. Use &lt;code&gt;from . import models&lt;/code&gt; instead.&lt;/p&gt;
&lt;h3 id=&#34;httprequest-and-httpresponse-have-str-and-bytes-types&#34;&gt;HttpRequest and HttpResponse have str and bytes Types&lt;/h3&gt;
&lt;p&gt;In Python 3, according to PEP 3333 (amendments to the WSGI standard), we are careful not to mix data coming from or leaving via HTTP, which will be in bytes; as opposed to text within the framework, which will be native (Unicode) strings.&lt;/p&gt;
&lt;p&gt;Essentially, for &lt;code&gt;HttpRequest&lt;/code&gt; and &lt;code&gt;HttpResponse&lt;/code&gt; objects:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Headers will be always str objects&lt;/li&gt;
&lt;li&gt;Input and output streams will be always byte objects&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Unlike Python 2, the string and bytes are not implicitly converted while performing comparisons or concatenations with each other. Strings mean Unicode strings only.&lt;/p&gt;
&lt;h3 id=&#34;exception-syntax-changes-and-improvements&#34;&gt;Exception Syntax Changes and Improvements&lt;/h3&gt;
&lt;p&gt;Exception handling syntax and functionality has been significantly improved in Python 3.&lt;/p&gt;
&lt;p&gt;In Python 3, you cannot use the comma separated syntax for the except clause. Use the &lt;code&gt;as&lt;/code&gt; keyword instead:&lt;/p&gt;
&lt;table class=&#34;sidebyside&#34;&gt;
  &lt;thead&gt;
&lt;tr&gt;
  &lt;th&gt;Python 2&lt;/th&gt;
  &lt;th&gt;Python 3&lt;/th&gt;
&lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
&lt;tr&gt;
  &lt;td&gt;&lt;pre&gt;
try:
  pass
except BaseException, e:
  pass
  &lt;/pre&gt;&lt;/td&gt;
  &lt;td&gt;&lt;pre&gt;
try:
  pass
except BaseException as e:
  pass
  &lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The new syntax is recommended for Python 2 as well.&lt;/p&gt;
&lt;p&gt;In Python 3, all exceptions must be derived (directly or indirectly) from &lt;code&gt;BaseException&lt;/code&gt;. In practice, you would create your custom exceptions by deriving from the &lt;code&gt;Exception&lt;/code&gt; class.&lt;/p&gt;
&lt;p&gt;As a major improvement in error reporting, if an exception occurs while handling an exception then the entire chain of exceptions are reported:&lt;/p&gt;
&lt;table class=&#34;sidebyside&#34;&gt;
  &lt;thead&gt;
&lt;tr&gt;
  &lt;th&gt;Python 2&lt;/th&gt;
  &lt;th&gt;Python 3&lt;/th&gt;
&lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
&lt;tr&gt;
  &lt;td&gt;&lt;pre&gt;
&gt;&gt;&gt; try:
...   print(undefined)
... except Exception:
...   print(oops)
...
Traceback (most recent call last):
  File &#34;&lt;stdin&gt;&#34;, line 4, in &amp;lt;module&amp;gt;
  NameError: name &#39;oops&#39; is not defined
&lt;/pre&gt;&lt;/td&gt;
  &lt;td&gt;&lt;pre&gt;
&gt;&gt;&gt; try:
...   print(undefined)
... except Exception:
...   print(oops)
...
Traceback (most recent call last):
  File &#34;&amp;lt;stdin&amp;gt;&#34;, line 2, in &amp;lt;module&amp;gt;
  NameError: name &#39;undefined&#39; is not defined
&lt;p&gt;During the handling of the preceding
exception, another exception occurred:&lt;/p&gt;
&lt;p&gt;Traceback (most recent call last):
File &amp;ldquo;&amp;lt;stdin&amp;gt;&amp;rdquo;, line 4, in &amp;lt;module&amp;gt;
NameError: name &amp;lsquo;oops&amp;rsquo; is not defined&lt;/p&gt;
&lt;p&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/p&gt;
&lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Once you get used to this feature, you will definitely miss it in Python 2.&lt;/p&gt;
&lt;h3 id=&#34;standard-library-reorganized&#34;&gt;Standard Library Reorganized&lt;/h3&gt;
&lt;p&gt;The core developers have cleaned-up and better organized the Python standard library. For instance &lt;code&gt;SimpleHTTPServer&lt;/code&gt; now lives in the &lt;code&gt;http.server&lt;/code&gt; module:&lt;/p&gt;
&lt;table class=&#34;sidebyside&#34;&gt;
  &lt;thead&gt;
&lt;tr&gt;
  &lt;th&gt;Python 2&lt;/th&gt;
  &lt;th&gt;Python 3&lt;/th&gt;
&lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
&lt;tr&gt;
  &lt;td&gt;&lt;pre&gt;
$ python -m SimpleHTTPServer
Serving HTTP on 0.0.0.0 port 8000 ...
  &lt;/pre&gt;&lt;/td&gt;
  &lt;td&gt;&lt;pre&gt;
$ python -m http.server
Serving HTTP on 0.0.0.0 port 8000 ...
  &lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;new-goodies&#34;&gt;New Goodies&lt;/h3&gt;
&lt;p&gt;Python 3 is not just about language fixes. It is also where bleeding-edge Python development happens. This means improvements to the language in terms of syntax, performance and built-in functionality.&lt;/p&gt;
&lt;p&gt;Some of the notable new modules added to Python 3 are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;asyncio&lt;/code&gt; : Asynchronous I/O, event loop, coroutines and tasks&lt;/li&gt;
&lt;li&gt;&lt;code&gt;unittest.mock&lt;/code&gt; : Mock object library for testing&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pathlib&lt;/code&gt; : Object-oriented filesystem paths&lt;/li&gt;
&lt;li&gt;&lt;code&gt;statistics&lt;/code&gt; : Mathematical statistics functions&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Even if some of these modules might have backports to Python 2, it is more appealing to migrate to Python 3 and leverage them as built-in modules.&lt;/p&gt;
&lt;h4 id=&#34;pyvenv-and-pip-are-built-in&#34;&gt;Pyvenv and Pip are Built-in&lt;/h4&gt;
&lt;p&gt;Most serious Python developers prefer to use virtual environments. virtualenv is quite popular to isolate your project setup from the system-wide Python installation. Thankfully, Python 3.3 is integrated with a similar functionality using the &lt;code&gt;venv&lt;/code&gt; module.&lt;/p&gt;
&lt;p&gt;Since Python 3.4, a fresh virtual environment will be pre-installed with pip, a popular installer:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ python -m venv djenv
[djenv] $ source djenv/bin/activate
[djenv] $ pip install django
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Notice that the command prompt changes to indicate that your virtual environment has been activated.&lt;/p&gt;
&lt;h3 id=&#34;other-changes&#34;&gt;Other Changes&lt;/h3&gt;
&lt;p&gt;We cannot possibly fit all the Python 3 changes and improvements in this post. But the other commonly cited changes are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;print is now a function&lt;/strong&gt; : Previously it was a statement i.e. arguments were not in parenthesis.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Integers don&amp;rsquo;t overflow&lt;/strong&gt; : &lt;code&gt;sys.maxint&lt;/code&gt; is outdated, integers will have unlimited precision.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inequality operator &lt;code&gt;&amp;lt;&amp;gt;&lt;/code&gt; is removed&lt;/strong&gt; : Use &lt;code&gt;!=&lt;/code&gt; instead.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;True Integer Division&lt;/strong&gt; : In Python 2, &lt;code&gt;3 / 2&lt;/code&gt; would evaluate to 1. It will be correctly evaluated to &lt;code&gt;1.5&lt;/code&gt; in Python 3.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use &lt;code&gt;range&lt;/code&gt; instead of &lt;code&gt;xrange&lt;/code&gt;&lt;/strong&gt; : &lt;code&gt;range()&lt;/code&gt; will now return iterators as &lt;code&gt;xrange()&lt;/code&gt; used to work before.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dictionary keys are views&lt;/strong&gt; : &lt;code&gt;dict&lt;/code&gt; and &lt;code&gt;dict&lt;/code&gt;-like classes (like &lt;code&gt;QueryDict&lt;/code&gt;) will return iterators instead of lists for &lt;code&gt;keys()&lt;/code&gt;, &lt;code&gt;items()&lt;/code&gt; and &lt;code&gt;values()&lt;/code&gt; method calls.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;series-box&#34;&gt;
&lt;p&gt;This article is an excerpt from the book &lt;a href=&#34;http://djangopatternsbook.github.io/&#34;&gt;&#34;Django Design Patterns and Best Practices&#34;&lt;/a&gt; by Arun Ravindran&lt;/p&gt;
&lt;/div&gt;
&lt;h2 id=&#34;further-information&#34;&gt;Further Information&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Read &lt;em&gt;What&amp;rsquo;s New In Python 3.0&lt;/em&gt; by Guido &lt;a href=&#34;https://docs.python.org/3/whatsnew/3.0.html&#34;&gt;https://docs.python.org/3/whatsnew/3.0.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;To find what is new in each release of Python, read _What&amp;rsquo;s New in Python_&lt;a href=&#34;https://docs.python.org/3/whatsnew/&#34;&gt;https://docs.python.org/3/whatsnew/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;For richly detailed answers about Python 3 read &lt;em&gt;Python 3 Q &amp;amp; A&lt;/em&gt; by Nick Coghlan &lt;a href=&#34;http://python-notes.curiousefficiency.org/en/latest/python3/questions_and_answers.html&#34;&gt;http://python-notes.curiousefficiency.org/en/latest/python3/questions_and_answers.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
  </channel>
</rss>
