<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: brunomichetti</title>
    <description>The latest articles on DEV Community by brunomichetti (@brunomichetti).</description>
    <link>https://dev.to/brunomichetti</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F476845%2F36fcb042-3a8c-4032-9dd3-9bf0ead283a5.jpeg</url>
      <title>DEV Community: brunomichetti</title>
      <link>https://dev.to/brunomichetti</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/brunomichetti"/>
    <language>en</language>
    <item>
      <title>How to manage large files with Heroku and Amazon S3 Buckets in Django Projects</title>
      <dc:creator>brunomichetti</dc:creator>
      <pubDate>Tue, 16 Aug 2022 13:58:33 +0000</pubDate>
      <link>https://dev.to/rootstrap/how-to-manage-large-files-with-heroku-and-amazon-s3-buckets-in-django-projects-4g9m</link>
      <guid>https://dev.to/rootstrap/how-to-manage-large-files-with-heroku-and-amazon-s3-buckets-in-django-projects-4g9m</guid>
      <description>&lt;p&gt;As a developer, I’ve recently worked on a Django API  that processes large-sized images and videos. The system requires the admin to upload those mentioned files, and since the API is deployed in &lt;a href="https://www.heroku.com/home"&gt;Heroku&lt;/a&gt;, we used to get the &lt;a href="https://devcenter.heroku.com/articles/request-timeout"&gt;TIMEOUT&lt;/a&gt; error. &lt;/p&gt;

&lt;p&gt;This happens because it takes some time to upload a file that is not light causing Heroku to crash. So, what can we do if we don’t want to reduce the size or the quality of the files? &lt;/p&gt;

&lt;p&gt;In this blog post, I will provide a solution for this problem and will explain the flow and tools used. This information will hopefully help you with any working Django project that requires the management of large files.&lt;/p&gt;

&lt;h2&gt;
  
  
  The software architecture and flow
&lt;/h2&gt;

&lt;p&gt;After discussing different approaches, my team and I decided to maintain the files in &lt;a href="https://aws.amazon.com/s3/?trk=5970b1e9-218b-48cc-9862-f23c151d81b2&amp;amp;sc_channel=ps&amp;amp;sc_campaign=acquisition&amp;amp;sc_medium=ACQ-P%7CPS-GO%7CBrand%7CDesktop%7CSU%7CStorage%7CS3%7CLATAMO%7CES%7CText&amp;amp;s_kwcid=AL!4422!3!590443989051!p!!g!!amazon%20s3&amp;amp;ef_id=Cj0KCQjw2MWVBhCQARIsAIjbwoM-y4_A0WSI9atLGA_qdo1hmdoy46Oo_4xJMp8b07gLS0R3UDn5qgQaAtheEALw_wcB:G:s&amp;amp;s_kwcid=AL!4422!3!590443989051!p!!g!!amazon%20s3"&gt;Amazon S3 buckets&lt;/a&gt;. These are containers where you can store objects (such as images and videos) and access them with fast performance. &lt;/p&gt;

&lt;p&gt;As an example, if a Django model has an image attribute, let’s call it profile_picture, then we store the file in a bucket, and store the corresponding URL to that file in the database. So, if the Frontend requires the picture, the Backend returns the corresponding URL for that instance. &lt;/p&gt;

&lt;p&gt;But, we don’t want everyone on the internet to have access to the image in the bucket, we only wish for the Frontend to do that. That’s why we have to configure the bucket as private. &lt;/p&gt;

&lt;p&gt;Now, we need to answer: if the bucket is private, how does our Frontend access the files in it?. Well, in this case, we have to generate a pre-signed URL, that is a URL to grant temporary access to the file.&lt;/p&gt;

&lt;p&gt;Here I will explain the proposed solution:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Store the system files in private buckets of Amazon S3.&lt;/li&gt;
&lt;li&gt;Frontend and/or Django admin upload the files directly to a private Amazon S3 bucket.&lt;/li&gt;
&lt;li&gt;The Backend stores the corresponding URL of each file.&lt;/li&gt;
&lt;li&gt;When the Django admin creates/updates a file attribute for a given instance, the file is uploaded directly to the bucket, and the corresponding URL is stored in the database.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Explanatory interaction diagram:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MmcZJeHZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0gdybytp3pzoxzxhy09u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MmcZJeHZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0gdybytp3pzoxzxhy09u.png" alt="Image description" width="626" height="240"&gt;&lt;/a&gt;&lt;br&gt;
When Frontend is about to upload a file:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It requests the Backend to get a valid upload URL to upload it to the private bucket.&lt;/li&gt;
&lt;li&gt;The Backend generates and sends the upload URL.&lt;/li&gt;
&lt;li&gt;The Frontend uses the upload URL to store the file in the private bucket.&lt;/li&gt;
&lt;li&gt;After the upload, the Frontend sends the file URL to the Backend to store it for the corresponding file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Explanatory interaction diagram:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--z2FIzNuP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tgnjej87oc5pb0oivt1q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--z2FIzNuP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tgnjej87oc5pb0oivt1q.png" alt="Image description" width="639" height="306"&gt;&lt;/a&gt;&lt;br&gt;
When the Backend sends the URL of a file to the Frontend:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It uses a function to generate a pre-signed URL so the Frontend can access the file in the private bucket.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Explanatory interaction diagram:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3O3F4zXW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kh6olelfi3q6sbxqhhav.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3O3F4zXW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kh6olelfi3q6sbxqhhav.png" alt="Image description" width="643" height="264"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  The tools I used
&lt;/h1&gt;

&lt;p&gt;Now that we have defined the solution flow, let’s talk about the tools. The first one I want to mention is &lt;a href="https://github.com/bradleyg/django-s3direct"&gt;django-s3direct&lt;/a&gt;, a library to directly upload files to the Amazon bucket from the admin panel.  Also, it provides a model field that corresponds to the URL stored in the database. &lt;/p&gt;

&lt;p&gt;On the other hand, we will use &lt;a href="https://boto3.amazonaws.com/v1/documentation/api/latest/index.html"&gt;boto3&lt;/a&gt; to generate the pre-signed URLs that the Backend sends to the Frontend in order to access the file. This library also generates the upload URL to allow the Frontend to upload files without the need of knowing the Amazon credentials. &lt;/p&gt;

&lt;p&gt;In the following section, I’ll show the corresponding configurations.&lt;/p&gt;
&lt;h1&gt;
  
  
  Amazon S3 private bucket
&lt;/h1&gt;

&lt;p&gt;I won't speak about the creation of buckets as there is plenty of documentation available. Next up, I’ll describe the configuration of the bucket to make it private and integrate it with django-s3direct. &lt;/p&gt;

&lt;p&gt;Assuming you have already created the bucket and you have a user with access ID, access secret key, and permissions, these are the next steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Log in to Amazon S3 and create the bucket. Make sure you have the permissions.&lt;/li&gt;
&lt;li&gt;Select the bucket, and go to the Permission tab.&lt;/li&gt;
&lt;li&gt;In the bucket policy, paste the next policy:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AllowPublicRead"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Principal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"AWS"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"s3:GetObject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"s3:PutObject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"s3:PutObjectAcl"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"s3:ListMultipartUploadParts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"s3:AbortMultipartUpload"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::&amp;lt;name-of-bucket&amp;gt;/*"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Change  by your bucket name.&lt;/li&gt;
&lt;li&gt;Now in the same tab, block all the public access to make it private:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3m-yWxXS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qyn3lr6eonwcag56as9s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3m-yWxXS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qyn3lr6eonwcag56as9s.png" alt="Image description" width="652" height="213"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Finally, in the same tab, paste this CORS configuration (needed by django-s3direct):
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"AllowedHeaders"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"AllowedMethods"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="s2"&gt;"HEAD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="s2"&gt;"PUT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="s2"&gt;"POST"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="s2"&gt;"DELETE"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"AllowedOrigins"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"ExposeHeaders"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="s2"&gt;"ETag"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"MaxAgeSeconds"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And that’s it, you have configured your private bucket. Keep in mind,  if you want to change the policy in the future, first need to uncheck the blocking access.&lt;/p&gt;
&lt;h1&gt;
  
  
  Django-s3direct library
&lt;/h1&gt;

&lt;p&gt;Now I will explain the use of the django-s3direct library to directly upload the files from the Django admin. &lt;/p&gt;

&lt;p&gt;If you have a model that has a file attribute, when you change that attribute, this library will directly upload the file from the browser without sending it to the server. This is to avoid the named timeout error. &lt;/p&gt;

&lt;p&gt;Let’s go step by step on how to get this configured:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install &lt;a href="https://github.com/bradleyg/django-s3direct"&gt;django-s3direct&lt;/a&gt; in your project.&lt;/li&gt;
&lt;li&gt;Add the library to your &lt;strong&gt;INSTALLED_APPS&lt;/strong&gt; list in the settings:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# your settings file
&lt;/span&gt;
&lt;span class="n"&gt;INSTALLED_APPS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; 
    &lt;span class="err"&gt;…&lt;/span&gt;
    &lt;span class="s"&gt;'s3direct'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="err"&gt;…&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Make sure you have the &lt;strong&gt;APP_DIRS&lt;/strong&gt; configuration set as True in your &lt;strong&gt;TEMPLATES&lt;/strong&gt; settings:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# your settings file
&lt;/span&gt;
&lt;span class="n"&gt;TEMPLATES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
   &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="err"&gt;…&lt;/span&gt;
        &lt;span class="s"&gt;'APP_DIRS'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="err"&gt;…&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Add django-s3direct urls to the urlpatterns list in your main urls.py file:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.urls&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;include&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;

&lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="n"&gt;urlpatterns&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'s3direct/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'s3direct.urls'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Add the configuration corresponding to Amazon to your settings (strongly recommended to put the access id and secret key values in environment variables):
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# your settings file
&lt;/span&gt;
&lt;span class="c1"&gt;# If these are set to None, the EC2 instance profile and IAM role are used.
&lt;/span&gt;&lt;span class="n"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'your-aws-access-key-id'&lt;/span&gt;
&lt;span class="n"&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'your-aws-secret-access-key'&lt;/span&gt;
&lt;span class="c1"&gt;# Bucket name
&lt;/span&gt;&lt;span class="n"&gt;AWS_STORAGE_BUCKET_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'your-aws-s3-bucket-name'&lt;/span&gt;
&lt;span class="c1"&gt;# The region of your bucket, more info:
# http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region
&lt;/span&gt;&lt;span class="n"&gt;AWS_S3_REGION_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'eu-west-1'&lt;/span&gt;
&lt;span class="c1"&gt;# The endpoint of your bucket, more info:
# http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region
&lt;/span&gt;&lt;span class="n"&gt;AWS_S3_ENDPOINT_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'https://s3.eu-west-1.amazonaws.com'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Run collect static if needed:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python manage.py collectstatic
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Now you can define in your model a file attribute corresponding to an image or video. Let’s take a look at an example:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.db&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;s3direct.fields&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;S3DirectField&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Example&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;S3DirectField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dest&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'example_destination'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;And, what is example_destination? When you define a file attribute as an S3DirectField, you have to specify the dest parameter. There you have to put the string corresponding to the key in the &lt;strong&gt;S3DIRECT_DESTINATIONS&lt;/strong&gt; dictionary in the configuration.&lt;/li&gt;
&lt;li&gt;Let’s look at an example of the configuration to understand this better:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# your settings file
&lt;/span&gt;
&lt;span class="n"&gt;S3DIRECT_DESTINATIONS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="s"&gt;'example_destination'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="s"&gt;'key'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'images/example-images/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="s"&gt;'region'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AWS_S3_REGION_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="s"&gt;'acl'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'private'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="s"&gt;'allow_existence_optimization'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Inside each dictionary, you can configure a lot of parameters and check the library documentation to know them. - This example has the key where you define the folders where you want to store the corresponding file inside the bucket.
You can test that it’s working by creating an instance of the class in the Django admin:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.contrib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;admin&lt;/span&gt;

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


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ExampleAdmin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ModelAdmin&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
   &lt;span class="n"&gt;fields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'image'&lt;/span&gt;&lt;span class="p"&gt;,)&lt;/span&gt;


&lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Example&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ExampleAdmin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Now you should go to django admin and you will see something like this:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lhaFhwj9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1tn1vg2o6gqcntu6shix.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lhaFhwj9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1tn1vg2o6gqcntu6shix.png" alt="Image description" width="425" height="205"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Then if you select an image, the library will directly upload the image to the private bucket and store the corresponding URL in the database. The Backend won’t receive a file, just a string URL. After the correct upload, you will see something like:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kjWFe2Uz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oiuc4jsyd14a4phj4zm1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kjWFe2Uz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oiuc4jsyd14a4phj4zm1.png" alt="Image description" width="376" height="335"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;And the stored URL will have this structure:
&lt;code&gt;https://s3.&amp;lt;region-name&amp;gt;.amazonaws.com/&amp;lt;bucket-name&amp;gt;/&amp;lt;key&amp;gt;/&amp;lt;file-name&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;If you click on the name of the picture, the browser will try to open it, but you won’t be able to see it because the bucket is private, and that’s ok. Also, if you click on REMOVE, the file will be removed from the instance but it will continue existing in the bucket.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Customize the name of the pictures
&lt;/h2&gt;

&lt;p&gt;As highlighted, in the &lt;strong&gt;S3DIRECT_DESTINATIONS&lt;/strong&gt; dictionary, you can configure in the key attribute the folders route to store the files corresponding to the given destination. &lt;/p&gt;

&lt;p&gt;But what happens when you upload a file with the same name as another existing one in the same folder? &lt;/p&gt;

&lt;p&gt;Well, that will overwrite the file, and I assume you don’t want that because it can be the file of another instance in your system. &lt;/p&gt;

&lt;p&gt;Here are two tips for this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add a timestamp to the file name to avoid repeated file names in the system.&lt;/li&gt;
&lt;li&gt;Use a slugify function to manage spaces and/or invalid characters in the file name.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you do that, you can avoid a lot of future problems. Let’s look at an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# your settings file
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.utils&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;timezone&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.utils.text&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;slugify&lt;/span&gt;


&lt;span class="err"&gt;…&lt;/span&gt; 


&lt;span class="n"&gt;EXAMPLE_DEST_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'images/example-images/'&lt;/span&gt;
&lt;span class="n"&gt;TIMESTAMP_FORMAT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'%m-%d-%Y_%H-%M-%S-%f'&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;normalize_filename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
   &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;extension&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;splitext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;time_stamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;timezone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TIMESTAMP_FORMAT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;time_stamp&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;--&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;slugify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}{&lt;/span&gt;&lt;span class="n"&gt;extension&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;


&lt;span class="n"&gt;S3DIRECT_DESTINATIONS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="s"&gt;'example_destination'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="s"&gt;'key'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;EXAMPLE_DEST_KEY&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;normalize_filename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s"&gt;'region'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AWS_S3_REGION_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s"&gt;'acl'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'private'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s"&gt;'allow_existence_optimization'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, for each new file, we apply a normalization of the file name. First, we normalize the filename using the slugify function from Django, and then we append at the beginning the timestamp. &lt;/p&gt;

&lt;p&gt;If we upload a file with the name image.png, the system will store that file with the form &lt;code&gt;&amp;lt;timestamp&amp;gt;--image.png&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Another example is if we have a file with the name &lt;code&gt;FILE with SPACEs.png&lt;/code&gt;, the system will store &lt;code&gt;&amp;lt;timestamp&amp;gt;--file-with-spaces.png&lt;/code&gt;. This is super easy to understand and solves a lot of problems. &lt;/p&gt;

&lt;p&gt;Now, in this next section, we will see how to return presigned files to the Frontend.&lt;/p&gt;

&lt;p&gt;It’s important to note, that this mentioned normalization will be executed only when uploading files in the Django admin. To be consistent, it would be nice to make the same normalization in the Frontend when it has to upload a file.&lt;/p&gt;

&lt;h1&gt;
  
  
  Boto3 and pre-signed URL
&lt;/h1&gt;

&lt;p&gt;We know how to configure a private Amazon S3 bucket, and how to integrate it with django-s3direct to directly upload a file from the Django admin. &lt;/p&gt;

&lt;p&gt;Now, we need to know how to do the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Send a pre-signed URL from the Backend to the Frontend so this last can access the existing file in the private bucket.&lt;/li&gt;
&lt;li&gt;Send a pre-signed upload URL from the Backend to the Frontend so this last can upload a file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s now look at how we do this using the boto3 library.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generate and send a view pre-signed URL
&lt;/h2&gt;

&lt;p&gt;Since the bucket is private, if we take a file URL in the database and we try to access it, we won’t be able to. We would then see something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uMf5mQrS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tsw5xom756m0lv4y5ab0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uMf5mQrS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tsw5xom756m0lv4y5ab0.png" alt="Image description" width="619" height="137"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is why we need to generate a pre-signed URL in the Backend for the corresponding file to be temporarily available for the Frontend. For this I use the boto3 library, let’s look at the used functions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# some utils file for boto3 functions
&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;boto3&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Session&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Dict&lt;/span&gt;

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

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_object_key_from_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
   &lt;span class="s"&gt;'''
   Returns the object key for the given url
   '''&lt;/span&gt;
   &lt;span class="n"&gt;endpoint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AWS_S3_ENDPOINT_URL&lt;/span&gt;
   &lt;span class="n"&gt;bucket_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AWS_STORAGE_BUCKET_NAME&lt;/span&gt;

   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;bucket_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_presigned_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;object_key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
   &lt;span class="s"&gt;'''
   Returns a presigned URL for the given object key
   '''&lt;/span&gt;
   &lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Session&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="n"&gt;aws_access_key_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;aws_secret_access_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;region_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AWS_S3_REGION_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;s3client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'s3'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s3client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;generate_presigned_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="n"&gt;ClientMethod&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'get_object'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;Params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="s"&gt;'Bucket'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AWS_STORAGE_BUCKET_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="s"&gt;'Key'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;object_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="p"&gt;},&lt;/span&gt;
       &lt;span class="n"&gt;ExpiresIn&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AWS_PRESIGNED_URL_EXPIRATION_TIME_MINUTES&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, the function get_object_key_from_url obtains the object key from the file URL. As mentioned, the object key is the route of folders and the file name in the bucket. &lt;/p&gt;

&lt;p&gt;Why do we need the object key? We need it to generate the presigned URL of the file. That object key will be used in the get_presigned_url function for that purpose.&lt;/p&gt;

&lt;p&gt;The next thing to do is to execute that function when the Frontend makes a GET request and needs to access the file. &lt;/p&gt;

&lt;p&gt;There are several ways of doing that, and I’m going to show you one that I find easy to understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a property in the model, that corresponds to the pre-signed attribute:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# your models file
&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.db&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;s3direct.fields&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;S3DirectField&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;example_app.s3_files&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;get_object_key_from_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;get_presigned_url&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Example&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
   &lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;S3DirectField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dest&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'example_destination'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

   &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;property&lt;/span&gt;
   &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;presigned_image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;get_presigned_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_object_key_from_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;The presigned_image property first extracts the object key for the stored URL and then generates the pre-signed one to send it to the Frontend.&lt;/li&gt;
&lt;li&gt;Now add the property to a model serializer:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;rest_framework&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;serializers&lt;/span&gt;

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


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

   &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
       &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Example&lt;/span&gt;
       &lt;span class="n"&gt;fields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'presigned_image'&lt;/span&gt;&lt;span class="p"&gt;,)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;This way, if you use that serializer to send the data to the Frontend, it will return a pre-signed URL in the presigned_image field.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A pre-signed URL looks like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://&amp;lt;bucket name&amp;gt;.s3.amazonaws.com/images/&amp;lt;object key&amp;gt;?&amp;lt;lots of needed parameters&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;With that URL, the file will be available for the time period defined in your settings as in the example.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generate an upload pre-signed URL
&lt;/h2&gt;

&lt;p&gt;Last but not least, I’m going to explain how to send an upload URL from the Backend to the Frontend. Imagine we have an app where the users have profile pictures and the Frontend needs to upload the image. &lt;/p&gt;

&lt;p&gt;The flow would then look like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Frontend generates the object key of the image file (recommend adding a timestamp and normalizing the file name as in the example in the previous section).&lt;/li&gt;
&lt;li&gt;The Frontend sends the object key in a POST request to the Backend.&lt;/li&gt;
&lt;li&gt;The Backend takes the object key and generates a pre-signed upload URL.&lt;/li&gt;
&lt;li&gt;The Frontend uploads the image using the pre-signed upload URL.&lt;/li&gt;
&lt;li&gt;The Frontend sends the image URL to the backend so it can be stored in the database.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s look at an example of this function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_presigned_url_dict_to_upload_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;object_key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
   &lt;span class="s"&gt;'''
   Returns a dict with the necessary data to upload a file for the given key
   '''&lt;/span&gt;
   &lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Session&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="n"&gt;aws_access_key_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;aws_secret_access_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;region_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AWS_S3_REGION_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;s3client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'s3'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

   &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s3client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;generate_presigned_post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="n"&gt;Bucket&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AWS_STORAGE_BUCKET_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;object_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;Fields&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="s"&gt;'acl'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'private'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="p"&gt;},&lt;/span&gt;
       &lt;span class="n"&gt;Conditions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
           &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;'acl'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'private'&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
       &lt;span class="p"&gt;],&lt;/span&gt;
       &lt;span class="n"&gt;ExpiresIn&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AWS_PRESIGNED_URL_EXPIRATION_TIME_MINUTES&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="p"&gt;)&lt;/span&gt;

   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, let’s look at an example in a viewset for the action POST to receive an object key and return the necessary information to upload the file.&lt;/p&gt;

&lt;p&gt;First, we must define the serializer like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;rest_framework&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;serializers&lt;/span&gt;

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


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

   &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
       &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Example&lt;/span&gt;
       &lt;span class="n"&gt;fields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'presigned_image'&lt;/span&gt;&lt;span class="p"&gt;,)&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ExampleUploadURLSerializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serializers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Serializer&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
   &lt;span class="n"&gt;object_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;serializers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
   &lt;span class="n"&gt;upload_url_dict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;serializers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DictField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;required&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Second, we must define the viewset with the corresponding action:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;rest_framework&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;viewsets&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;rest_framework.decorators&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;rest_framework.response&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;rest_framework.request&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;example_app.models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Example&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;example_app.serializers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ExampleSerializer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ExampleUploadURLSerializer&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;example_app.s3_files&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;get_presigned_url_dict_to_upload_file&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ExampleViewSet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;viewsets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ModelViewSet&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
   &lt;span class="n"&gt;serializer_class&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ExampleSerializer&lt;/span&gt;
   &lt;span class="n"&gt;queryset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Example&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;all&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

   &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;methods&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'post'&lt;/span&gt;&lt;span class="p"&gt;,),&lt;/span&gt; &lt;span class="n"&gt;url_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'upload-url'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;upload_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
       &lt;span class="n"&gt;serializer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ExampleUploadURLSerializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="n"&gt;serializer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_valid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raise_exception&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

       &lt;span class="n"&gt;object_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;serializer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;validated_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'object_key'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

       &lt;span class="n"&gt;upload_url_dict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_presigned_url_dict_to_upload_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;object_key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

       &lt;span class="n"&gt;return_serializer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ExampleUploadURLSerializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
           &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;'object_key'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;object_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'upload_url_dict'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;upload_url_dict&lt;/span&gt;&lt;span class="p"&gt;,}&lt;/span&gt;
       &lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="n"&gt;return_serializer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_valid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raise_exception&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;return_serializer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;validated_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HTTP_200_OK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, after this, we are sending the necessary information to upload the file. And that’s it! We have finished the proposed solution. &lt;/p&gt;

&lt;p&gt;I have created a &lt;a href="https://github.com/brunomichetti/example_django"&gt;public repo&lt;/a&gt; where you can see this little example project to get further insight. If you’d like, you can download it and give it a try for yourself.&lt;/p&gt;

&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;p&gt;Throughout this blog, I presented a solution for a common problem for developers - managing big files in Django projects that are deployed using Heroku. &lt;/p&gt;

&lt;p&gt;I detailed in-depth the defined flow and tools I used, as well as providing some useful tips and examples to help you create a good solution. &lt;/p&gt;

&lt;p&gt;However, this doesn’t mean that the workaround we found is the only possible one. But it could very well be the most efficient. &lt;/p&gt;

&lt;p&gt;I hope you enjoyed reading and if you have another process that you think is useful, feel free to let us know in the comments section. Thanks for reading! &lt;/p&gt;

</description>
      <category>django</category>
      <category>python</category>
      <category>aws</category>
      <category>heroku</category>
    </item>
    <item>
      <title>Testing in Django &amp; Django REST – Useful Tools &amp; Best Practices</title>
      <dc:creator>brunomichetti</dc:creator>
      <pubDate>Mon, 06 Jun 2022 19:44:10 +0000</pubDate>
      <link>https://dev.to/rootstrap/testing-in-django-django-rest-useful-tools-best-practices-1ie4</link>
      <guid>https://dev.to/rootstrap/testing-in-django-django-rest-useful-tools-best-practices-1ie4</guid>
      <description>&lt;p&gt;If you are a developer, you already know how important testing is in any software project. In particular, automatic testing, as it can help you to corroborate your coding, and quickly see what your program does what you want it to do. It also helps to corroborate any new changes in your code that didn’t break any previous functionalities.&lt;/p&gt;

&lt;p&gt;In saying that, does this mean that if you have automatic tests then your project won’t have any errors? It does not. As computer scientist Edsger W. Dijkstra once said:&lt;/p&gt;

&lt;p&gt;“Program testing can be used to show the presence of bugs, but never to show their absence”.&lt;/p&gt;

&lt;p&gt;This phrase helps us to understand that we can’t be sure that a program is perfect, but, testing is fundamental to help us discover errors and make fixes and improvements. As a person that works in software development, I can say that it’s a lot better when you discover an error rather than your client or a user in production. In this article, I’ll talk about basic knowledge in automatic testing, useful tools, and good practices in &lt;a href="https://www.djangoproject.com/"&gt;Django&lt;/a&gt; projects, with a focus on API’s.&lt;/p&gt;

&lt;h1&gt;
  
  
  Testing in Django &amp;amp; Django REST Framework
&lt;/h1&gt;

&lt;p&gt;Django has very nice &lt;a href="https://docs.djangoproject.com/en/3.2/topics/testing/"&gt;documentation about testing&lt;/a&gt;, and &lt;a href="https://www.django-rest-framework.org/api-guide/testing/"&gt;Django REST Framework too&lt;/a&gt;. So, in this blog, I’ll talk about the main tools in those two frameworks, and what you can do and use to improve your testing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Main Testing Classes
&lt;/h2&gt;

&lt;p&gt;Django provides several classes for testing. The one I’ll talk about here is &lt;a href="https://docs.djangoproject.com/en/3.2/topics/testing/tools/#django.test.TestCase"&gt;TestCase&lt;/a&gt;, which is very useful if your application uses databases.&lt;br&gt;
As the name states, to create a test case in your Django project, you will define a class that inherits from TestCase. By doing this, you can use all the methods and properties of the named class that will help you to create and execute your tests. Then you will define different functions that will correspond to each unit test inside the test case. Let’s see an example of the structure of a test case:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# your test file
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.test&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TestCase&lt;/span&gt;


&lt;span class="c1"&gt;# class to define a test case for login
&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserLoginTestCase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TestCase&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="c1"&gt;# some setup here, explained later
&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_correct_login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# unit test
&lt;/span&gt;        &lt;span class="c1"&gt;# Corroborate the expected scenario
&lt;/span&gt;        &lt;span class="p"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_if_password_incorrect_then_cant_login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# unit test
&lt;/span&gt;        &lt;span class="c1"&gt;# Corroborate that user's password needs to be only the correct one
&lt;/span&gt;        &lt;span class="p"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_if_user_not_registered_cant_login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# unit test
&lt;/span&gt;        &lt;span class="c1"&gt;# Corroborate that user's are able to login only if they're registered
&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, you can use the &lt;a href="https://docs.djangoproject.com/en/3.2/topics/testing/tools/#django.test.Client"&gt;Client class&lt;/a&gt; of Django which simulates a dummy browser so you can make HTTP requests and test how your Django API responds.&lt;/p&gt;

&lt;p&gt;Since we are focusing on API testing, I want to talk about &lt;a href="https://www.django-rest-framework.org/api-guide/testing/#api-test-cases"&gt;APITestCase&lt;/a&gt;, a class of Django REST framework that is a mirror of TestCase but uses a different client class: &lt;a href="https://www.django-rest-framework.org/api-guide/testing/#apiclient"&gt;APIClient&lt;/a&gt;. This client extends the TestClient, meaning that it has the same functionalities and adds others such as the credentials function. This function is very useful to overwrite authentication headers, for example, using OAuth1, OAuth2, or any simple token authentication scheme.&lt;br&gt;
So, if you are working on a project with the Django REST framework, you can change the previous example in this way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# your test file
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;rest_framework.test&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;APITestCase&lt;/span&gt;


&lt;span class="c1"&gt;# class to define a test case of login
&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserLoginTestCase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;APITestCase&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Main Testing Functions
&lt;/h2&gt;

&lt;p&gt;The aforementioned classes each have a set of methods that will help you through the testing. With these functions, you are able to corroborate that your software works as expected and make necessary test fixtures.&lt;br&gt;
A test fixture is an environment that you can create to run your tests using consistency. Using fixtures you can make sure that certain conditions are met before the execution. For example, to have a determined set of data in your testing database, or to create needed objects. Here is a list of the main ones:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;setUp&lt;/code&gt; and &lt;code&gt;tearDown&lt;/code&gt;: These are functions to be executed before (setUp) and after (tearDown) in each unit test. These are very useful for fixtures.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;setUpClass&lt;/code&gt; and &lt;code&gt;tearDownClass&lt;/code&gt;: In an analogous way of setUp and tearDown, these functions are executed before (setUpClass) and after (tearDownClass) during the whole test case. This means that it is executed only once for a test case. Since they’re used by Django to make important configurations, if you overwrite these methods in your test case class, don’t forget to call the super implementation inside the functions.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;setUpTestData&lt;/code&gt;: this function can be used to have a class-level atomic block to define data for the whole test case. That means that this function automatically rollbacks the changes in the database after the finalization of all the unit tests in the test case. This is mainly used to load data to your test database.&lt;/li&gt;
&lt;li&gt;Assert methods: Django has the set of &lt;a href="https://docs.python.org/3/library/unittest.html#assert-methods"&gt;assert methods from unittest&lt;/a&gt;, and has &lt;a href="https://docs.djangoproject.com/en/3.2/topics/testing/tools/#assertions"&gt;another ones created for the framework&lt;/a&gt;. These methods, such as &lt;code&gt;assertEqual&lt;/code&gt;, &lt;code&gt;assertIsNone&lt;/code&gt;, &lt;code&gt;assertTrue&lt;/code&gt;, etc, can be used in the unit test to check the different conditions that have to be met. For example, in the unit test of login, you can assert that the response has a status code of 200 because you want to make sure that if the data is sent correctly, then your application has to return the response with that code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can avoid using these functions, or use any combination of them. They’re not needed, but they’re very useful and will help you a lot.&lt;/p&gt;
&lt;h2&gt;
  
  
  Test Discovery &amp;amp; Databases
&lt;/h2&gt;

&lt;p&gt;Where do you have to put your test classes? By default, Django recognizes any file that fulfills the pattern &lt;code&gt;test*.py&lt;/code&gt; under the current working directory. That is, any file under the directory that starts with a test, and of course, has the &lt;code&gt;.py&lt;/code&gt; extension. Inside it, Django will execute any function in the test case class starting with test.&lt;br&gt;
When you run your tests, you can pass a parameter indicating the desired pattern just in case you want to use a different one. With that behavior, the place to put the test cases can be anywhere, but I recommend dividing the tests into the several Django apps that you may have in your project. For example, if you have a Django app called &lt;code&gt;users&lt;/code&gt; that has the models and functionalities related to the users in your project, you can define in there a test folder as a module (adding the init.py file) with all the tests that cover that important part: tests for login, for sign-up, for user data, account deletion, etc. Something similar to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my_project
   |__django_apps
       |__users
          |__test
             |__ __init__.py
             |__ test_login.py
             |__ test_signup.py
             |__ test_delete_user.py
             ...
        ...
    ...
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Regarding the databases, when you run your tests by default, Django creates one and then destroys it after the finalization. This is to avoid conflicts between your production and/or development databases, as well as your testing database. You can define and customize a database for tests, inside the &lt;code&gt;DATABASES&lt;/code&gt; dictionary, adding another one named &lt;code&gt;TEST&lt;/code&gt;. Something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DATABASES = {
    'default': {
        'ENGINE': '&amp;lt;engine&amp;gt;',
        'NAME': '&amp;lt;database name&amp;gt;',
        'USER': '&amp;lt;database user&amp;gt;',
        ...
    },
    ...
    'TEST': {
        # testing database customization here
            'NAME': '&amp;lt;your testing database name&amp;gt;',
            # some other customization, for example the user user, password, etc
        },
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Take a look at the &lt;a href="https://docs.djangoproject.com/en/3.2/ref/settings/#test"&gt;available keys&lt;/a&gt; for the TEST dictionary. If you don’t define it, Django will create a database naming it equal to your database in the default settings, appending the _test suffix.&lt;/p&gt;

&lt;h1&gt;
  
  
  Useful Tools
&lt;/h1&gt;

&lt;p&gt;In this section, I will talk about two external tools that are very helpful for fixtures: &lt;a href="https://faker.readthedocs.io/en/master/"&gt;Faker&lt;/a&gt; and &lt;a href="https://factoryboy.readthedocs.io/en/stable/"&gt;Factory Boy&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Faker
&lt;/h2&gt;

&lt;p&gt;Faker is a python package used to generate fake but realistic data. You can use its functionalities to load data into your testing database, generate data for the requests that you want to test, generate data for the models, etc. Faker has a huge and diverse set of possibilities. You can generate execution time, for example, first names, last names, phone numbers, dates, passwords, emails, etc.&lt;/p&gt;

&lt;p&gt;Additionally, you can pass parameters to the functions to generate data with different constraints, for example, you can obtain a password specifying if you want to use special characters or not, the desired length, and if you want to have an upper case or not, etc. Take a look at the Faker &lt;a href="https://faker.readthedocs.io/en/master/providers.html"&gt;providers&lt;/a&gt; to see all the different fake but realistic data that you can generate for your tests. Instead of using for example &lt;a href="mailto:user_test@mail.com"&gt;user_test@mail.com&lt;/a&gt; for your test cases, you can have data that is closer to reality and improve the quality.&lt;/p&gt;

&lt;h2&gt;
  
  
  Factory Boy
&lt;/h2&gt;

&lt;p&gt;If you use factories for tests, you define in a class the data structure that you want to have in your testing database. Then in your tests, it will be easier to have instances of your models, and loaded data with the desired structure. Factory Boy is a tool to replace static, hard-to-maintain fixtures using factories. Also, you can combine it with Faker to have factories with fake but realistic data. Let’s see an example:&lt;/p&gt;

&lt;p&gt;In this case, we can see a static fixture of Django, to load data to the testing database in a model called Person, which has a first name and last name. This JSON file defines two instances:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"myapp.person"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"pk"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"fields"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"first_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"John"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"last_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Lennon"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"myapp.person"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"pk"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"fields"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"first_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Paul"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"last_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"McCartney"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let’s see the analogous definition using Factory Boy and Faker:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;factory&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Faker&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;myapp&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt; 

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PersonFactory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DjangoModelFactory&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt;

    &lt;span class="n"&gt;first_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Faker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'first_name'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;last_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Faker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'last_name'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this, you can use functions that Factory Boy provides, for example, &lt;code&gt;PersonFactory.create_batch(2)&lt;/code&gt; to create instantly 2 instances in your testing database of Persons with different and realistic first and last names. In the JSON case, if you want to have for example 10 instances, you will need to add them and define new first and last names explicitly. And if you want to have huge datasets, the JSON file will be enormous and hard to maintain, while in the factory case you only need to call a function. Also, what if the model Person changes? In the JSON case, you have to update one by one each defined instance. In the factory case, you only need to change a class definition. Factory Boy documentation has a section called &lt;a href="https://factoryboy.readthedocs.io/en/stable/recipes.html"&gt;common recipes&lt;/a&gt;, where you can find useful tools, practices, and tips from the library. Here is a list of interesting functionalities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can create factories of models including the model relationships using the RelatedFactory or SubFactory class.&lt;/li&gt;
&lt;li&gt;Use the create function to create a new instance of the model in the factory and save it into the testing database. If you want to have instances but without saving them into the database, use build instead.&lt;/li&gt;
&lt;li&gt;In an analogous way, you can create and save into the database N instances of the model in the factory using &lt;code&gt;create_batch(N)&lt;/code&gt;, and &lt;code&gt;build_batch(N)&lt;/code&gt; if you don’t want to save them.&lt;/li&gt;
&lt;li&gt;You can define an attribute in a factory that selects a choice of a set of choices just like a Django model choice field, using &lt;code&gt;random_element&lt;/code&gt; of Faker. In the next section, we will see an example of this.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Test Example &amp;amp; Good Practices
&lt;/h1&gt;

&lt;p&gt;In this section, I want to wrap up and show a little example. This is the tiny reality: In the project, we have a Django app called users where we have the user model that has a username, phone_number, and a category in the system, that could be admin, common user, and guest. The user can sign-up and login into the application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Model &amp;amp; Factory Definition
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# model.py in the Django app called users
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.db&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.contrib.auth.models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AbstractUser&lt;/span&gt;


&lt;span class="c1"&gt;# class to define choices
&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Category&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TextChoices&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;GUEST&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'G'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'Guest user'&lt;/span&gt;
    &lt;span class="n"&gt;COMMON_USER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'C'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'Common user'&lt;/span&gt;
    &lt;span class="n"&gt;ADMIN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'A'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'Admin user'&lt;/span&gt;


&lt;span class="c1"&gt;# user model that inherits from AbstractUser
# there is no need to define a username field
# because is defined in the parent class
&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AbstractUser&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;phone_number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;blank&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;category&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Category&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'G'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let’s see the implementation of the user factory. This file is inside a test folder in the users Django app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# factory.py inside users/test
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;faker&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Faker&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;FakerClass&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Sequence&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;factory&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Faker&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;post_generation&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;users.models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Category&lt;/span&gt;


&lt;span class="n"&gt;CATEGORIES_VALUES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;Category&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserFactory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DjangoModelFactory&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;

    &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Faker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'user_name'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;phone_number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Faker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'phone_number'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;category&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Faker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'random_element'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;CATEGORIES_VALUES&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;post_generation&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;password&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;extracted&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Sequence&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;extracted&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;extracted&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;FakerClass&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;special_chars&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;digits&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;upper_case&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;lower_case&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_password&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A couple of things about this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the &lt;code&gt;Meta&lt;/code&gt; class inside the factory, we have to indicate the corresponding model.&lt;/li&gt;
&lt;li&gt;In the category attribute, we use &lt;code&gt;random_element&lt;/code&gt; of Faker to randomly select a choice of the Category choice list. We’ve defined &lt;code&gt;CATEGORIES_VALUES&lt;/code&gt; to specify which part of the choice we want to take. That is because each element in the choices list is a tuple, where the first part is the value, and the second one the explanatory text. So, that &lt;code&gt;CATEGORIES_VALUES&lt;/code&gt; set has only that first part for each element.&lt;/li&gt;
&lt;li&gt;Through the &lt;code&gt;post_generator&lt;/code&gt; decorator and the password function, we indicate that at the moment of the creation of a user instance, we can pass a desired password to be used, or else we generate one using the Faker functionality.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Django Test Case
&lt;/h2&gt;

&lt;p&gt;Now, let’s see an example of testing for the user sign-up functionality. The implementation of the authentication part for this example project has been made using dj-rest-auth. I won’t talk about that, but if you want to know more, please take a look at &lt;a href="https://www.rootstrap.com/blog/registration-and-authentication-in-django-apps-with-dj-rest-auth/"&gt;this blog&lt;/a&gt;. This is a test_singup.py file inside the test folder of the user Django app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.urls&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;reverse&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;rest_framework&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;rest_framework.test&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;APITestCase&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;APIClient&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;users.test.factory&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;UserFactory&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;users.models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Category&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;faker&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Faker&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserSignUpTestCase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;APITestCase&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;classmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;setUpClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;setUpClass&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_object&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UserFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_saved&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UserFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;APIClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;signup_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reverse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'rest_register'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;faker_obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Faker&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_if_data_is_correct_then_signup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Prepare data
&lt;/span&gt;        &lt;span class="n"&gt;signup_dict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="s"&gt;'username'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;'password1'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'test_Pass'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;'password2'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'test_Pass'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;'phone_number'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;phone_number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;'category'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="c1"&gt;# Make request
&lt;/span&gt;        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;signup_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;signup_dict&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;# Check status response
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HTTP_201_CREATED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;# Check database
&lt;/span&gt;        &lt;span class="n"&gt;new_user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;new_user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;new_user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;phone_number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;phone_number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_if_username_already_exists_dont_signup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Prepare data with already saved user
&lt;/span&gt;        &lt;span class="n"&gt;signup_dict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="s"&gt;'username'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_saved&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;'password1'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'test_Pass'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;'password2'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'test_Pass'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;'phone_number'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_saved&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;phone_number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;'category'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_saved&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="c1"&gt;# Make request
&lt;/span&gt;        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;signup_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;signup_dict&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;# Check status response
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HTTP_400_BAD_REQUEST&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'username'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
            &lt;span class="s"&gt;'A user with that username already exists.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;# Check database
&lt;/span&gt;        &lt;span class="c1"&gt;# Check that there is only one user with the saved username
&lt;/span&gt;        &lt;span class="n"&gt;username_query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_saved&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username_query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Well, in this file we have a test case, defined as &lt;code&gt;UserSignUpTestCase&lt;/code&gt;, and two unit tests inside, one to test the expected case, and the other to test an error case. I want to list a couple of main points to discuss good practices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Take a look at the unit tests names: You can name them as you want (always starting with test unless you change the pattern). A good practice is to make a name that describes it. This will help you when testing and debugging, for example, if a test fails and you want to trace the error.&lt;/li&gt;
&lt;li&gt;In the &lt;code&gt;setUpClass&lt;/code&gt; method, we call the &lt;code&gt;super()&lt;/code&gt; function, remembering that it’s important for Django. Also, we set up the needed instances, such as the API client, a user, and a faker instance. Besides we load a user to the database with the create function.&lt;/li&gt;
&lt;li&gt;Notice that the &lt;code&gt;sign_up&lt;/code&gt; URL defined in the &lt;code&gt;setUpClass&lt;/code&gt; method, uses &lt;code&gt;reverse&lt;/code&gt; from Django. You can put directly the URL string if you want. By using reverse, you obtain an URL entering the related name. In the dj-rest-auth package, the related name is rest_register. I recommend you use reverse in your project to improve maintainability. When you define URLs, give them a name, and then in the tests use reverse. After that, if a URL changes, you won’t need to change anything in the tests, because reverse solves this.&lt;/li&gt;
&lt;li&gt;The general structure chosen for the unit test is:

&lt;ul&gt;
&lt;li&gt;Prepare data: You can use the instance generated with build to obtain the data for the request.&lt;/li&gt;
&lt;li&gt;Make the request: Use the APIClient to make the request.&lt;/li&gt;
&lt;li&gt;Check the response: Check the response data (if there is data) and status. When working with Django REST framework, I recommend using &lt;a href="https://www.django-rest-framework.org/api-guide/status-codes/"&gt;status&lt;/a&gt;. With this, you have the HTTP status codes in a cleaner way. If you don’t want to, you can just put the number directly.&lt;/li&gt;
&lt;li&gt;Check the database: If the request generates changes in the database, please corroborate it to make sure that the functionality modifies it correctly. If you have the case that doesn’t modify the database, it’s a good practice to test that the database remains without changes (just as in the second unit test).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This was an example of a Test Case with two unit tests. You can add more unit tests, for example, to test if some data is incorrect in the request or the user can’t sign-up. Besides you can add in that file (or another file) more test case classes, for example, to test the login functionality of the app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running Your Tests
&lt;/h2&gt;

&lt;p&gt;Once you have coded a couple of tests, you can execute them with this command in the main folder of the project (the one that has the manage.py file):&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;This will search for all of your tests files under that folder and then execute them, showing the error or success of each unit test.&lt;/p&gt;

&lt;h3&gt;
  
  
  Customize the Execution of the Tests
&lt;/h3&gt;

&lt;p&gt;You can customize the test execution, for example, you can indicate to test:&lt;/p&gt;

&lt;p&gt;Only a Django app, specifying &lt;code&gt;&amp;lt;Django app name&amp;gt;&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Only a file in a given Django app, specifying &lt;code&gt;&amp;lt;Django app name&amp;gt;.path.to.file&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python manage.py test users.test.test_signup
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Only a test case class, specifying: &lt;code&gt;&amp;lt;Django app name&amp;gt;.path.to.file.ClassName&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python manage.py test users.test.test_signup.UserSignUpTestCase
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Only a unit test function, specifying &lt;code&gt;&amp;lt;Django app name&amp;gt;.path.to.file.ClassName.function_name&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python manage.py test users.test.test_signup.UserSignUpTestCase.test_if_data_is_correct_then_signup
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also add some flags to the command to customize the execution, for example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;--keepdb&lt;/code&gt; to avoid erasing the database between executions. This can improve the speed.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--parallel&lt;/code&gt; to run the tests in parallel improving also the speed on multi-core hardware. If you do this make sure they’re well isolated.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;p&gt;Throughout this blog, I’ve presented some basics of testing with Django and Django REST framework. Also, I showcased some useful tools and good practices that are more focused on API’s. I highlighted some examples, and how to run and customize your tests with the named framework. I hope you enjoyed reading and I hope that this blog can help you to test and improve your own Django API projects.&lt;/p&gt;

&lt;p&gt;Read this article and more content in the Rootstrap blog: &lt;a href="https://www.rootstrap.com/blog"&gt;https://www.rootstrap.com/blog&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to Manage your Python projects with Pipenv &amp; Pyenv</title>
      <dc:creator>brunomichetti</dc:creator>
      <pubDate>Mon, 06 Jun 2022 16:17:09 +0000</pubDate>
      <link>https://dev.to/rootstrap/how-to-manage-your-python-projects-with-pipenv-pyenv-3hp7</link>
      <guid>https://dev.to/rootstrap/how-to-manage-your-python-projects-with-pipenv-pyenv-3hp7</guid>
      <description>&lt;p&gt;A Python virtual environment is an important tool for developers when separating project dependencies in isolated environments. If working locally on several Python projects, developers may need to use different Python versions on each.&lt;/p&gt;

&lt;p&gt;By doing this, they will be able to install different packages and have different versions of the named packages for each environment.&lt;/p&gt;

&lt;p&gt;However, this can generate a lot of compatibility issues unless you manage them correctly using virtual environments. There are many ways to do this and I will highlight two tools to do so: &lt;a href="https://github.com/pyenv/pyenv"&gt;Pyenv&lt;/a&gt; and &lt;a href="https://pipenv-fork.readthedocs.io/en/latest/"&gt;Pipenv&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Python Virtual Environments
&lt;/h1&gt;

&lt;p&gt;In the following image, you can see an abstract example of different Python projects containing the different combinations of packages that you can install:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BUPcl68f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7wd63k57dxq5gjaku8fp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BUPcl68f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7wd63k57dxq5gjaku8fp.png" alt="Image description" width="768" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each big colored box represents a Python virtual environment. It’s common for certain package versions to be supported only by determined Python versions. Also, you may need a determined version of a package in one project and another version for others. As well as this, a determined version of a package can generate conflicts with packages or Python versions.&lt;/p&gt;

&lt;p&gt;Many combinations of compatibility issues can be found but by having those isolated environments you can avoid them. You will be able to install, uninstall, update, etc in one virtual environment, without affecting the rest of them. As mentioned, there are many tools to do this, and I will talk about the ones I find easy to understand and use.&lt;/p&gt;

&lt;h1&gt;
  
  
  Pyenv
&lt;/h1&gt;

&lt;p&gt;Pyenv is a tool used to manage different Python versions. With this tool you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install several Python versions.&lt;/li&gt;
&lt;li&gt;Set/change the global(default) Python version in your computer.&lt;/li&gt;
&lt;li&gt;Set/change a Python version locally for a project.&lt;/li&gt;
&lt;li&gt;Create and manage virtual environments.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;On macOS, you can install this tool using Homebrew:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;brew install pyenv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To install it on other platforms, you can watch &lt;a href="https://github.com/pyenv/pyenv#installation"&gt;this section in the GitHub docs&lt;/a&gt;. After the installation, edit your used shell startup script (.bashrc, .zshrc, .bash_profile, …) adding the following line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if command -v pyenv 1&amp;gt;/dev/null 2&amp;gt;&amp;amp;1; then
  eval "$(pyenv init -)"
fi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then reload your shell startup script. An example if you have .bashrc:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd
source .bashrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s it! You have installed Pyenv successfully.&lt;/p&gt;

&lt;h2&gt;
  
  
  Managing Python Versions
&lt;/h2&gt;

&lt;p&gt;Now let’s take a look at the possible Python versions that you can install through Pyenv, executing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pyenv install --list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will see a large list of Python versions. You can pick one to install it, let’s say 3.9.1:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pyenv install 3.9.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can run that command with any version that you want to have installed on your computer. To see all the installed versions, just run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pyenv versions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, you can set the global version that you want to use in your system, this will be the default one. For example, if you have already installed 3.8.8, you can set it as the global version running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pyenv global 3.8.8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can change that, of course, by executing the command again with the desired installed version. If you want to check your global version, just run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python -V
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With Pyenv, you can have a global and a local version for each project. To set a local version, go to the project folder in the terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd ~/path/to/the/project/folder
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And set the local version, for example, 3.9.1:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pyenv local 3.9.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a .python-version file in the folder indicating the current local Python version for the project. Also, if you run python -V in that folder, you will see the local version, and not the global one.&lt;/p&gt;

&lt;p&gt;So, to sum up, you have the following useful commands at your disposal:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;pyenv install --list&lt;/code&gt; to see the available Python versions you can install.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pyenv versions&lt;/code&gt; to see the installed Python versions.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pyenv global &amp;lt;Python version&amp;gt;&lt;/code&gt; to set an installed Python version as global.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pyenv local &amp;lt;Python version&amp;gt;&lt;/code&gt; to set an installed Python version for a given project folder.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pyenv uninstall &amp;lt;Python version&amp;gt;&lt;/code&gt; to uninstall an already installed Python version.&lt;/li&gt;
&lt;li&gt;Pyenv also allows us to manage environments with a &lt;a href="https://github.com/pyenv/pyenv-virtualenv"&gt;plugin called pyenv-virtualenv&lt;/a&gt;. However, I prefer to use Pipenv. Let’s take a look.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Pipenv
&lt;/h1&gt;

&lt;p&gt;Pipenv is a tool used to manage the required packages in a Python project. With this tool you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automatically create or delete a virtual environment.&lt;/li&gt;
&lt;li&gt;Install, uninstall and update packages maintaining the desired versions.&lt;/li&gt;
&lt;li&gt;Set up very quickly a working Python environment.
Have a list of the installed packages and the corresponding version.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you use Pipenv in your projects, you will have two special files in the root folder, both generated and changed automatically. Those are:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Pipfile&lt;/code&gt;: A file that specifies the installed packages in your virtual environment for development and execution.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Pipfile.lock&lt;/code&gt;: A file that specifies which versions of the installed packages (detailed in the Pipfile) has to be used.&lt;br&gt;
Also has another important metadata.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With Pipenv, is very easy to work on projects with other developers using the same packages and versions as it provides the files containing all that information. Developers must simply run a command to have the same environment in their own computer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;On macOS, you can install this tool using Homebrew:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;brew install pipenv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that’s it. You’re ready to start! To install it on other platforms, check out this &lt;a href="https://pipenv-fork.readthedocs.io/en/latest/install.html#installing-pipenv"&gt;section in the pipenv docs&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating Virtual Environments
&lt;/h2&gt;

&lt;p&gt;Now, let’s look at how to create a virtual environment for a Python project. First, go to the project folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd ~/path/to/the/project/folder
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then execute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pipenv install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a virtual environment and:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you already have a &lt;code&gt;Pipfile&lt;/code&gt; and a &lt;code&gt;Pipfile.lock&lt;/code&gt;: it will also install all the specified packages on them.&lt;/li&gt;
&lt;li&gt;If you don’t have a &lt;code&gt;Pipfile&lt;/code&gt; and a &lt;code&gt;Pipfile.lock&lt;/code&gt;: it will generate them for that environment.
This is how a &lt;code&gt;Pipfile&lt;/code&gt; recently created looks like:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]

[dev-packages]

[requires]
python_version = "3.7"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Under the [packages] section, you will see the installed packages for execution – the ones that your Python program will need to be executed correctly.&lt;/p&gt;

&lt;p&gt;Under the [dev-packages] section, you will see the packages that are needed only for development. Also, you can see in that example that the used Python version is 3.7.&lt;/p&gt;

&lt;p&gt;If you use Pyenv, the pipenv install command will use the global Python version of your system. But as you know, you can specify a local Python version in your project. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pyenv local 3.8.8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And, if you want to use that local Python version, you can indicate that to Pipenv by executing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pipenv install --python 3.8.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, what if you want to delete the created virtual environment to create another one? You can do so by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pipenv --rm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another important thing to remember is to activate the created virtual environment, which you do by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pipenv shell
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this command, you “have entered” your virtual environment. In your terminal, you can see if you have already activated the virtual environment, if you see the name between brackets at the beginning of the line, as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bVNmbzWS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bfk33egzam6ta3bp71zl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bVNmbzWS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bfk33egzam6ta3bp71zl.png" alt="Image description" width="709" height="323"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There you can see that after the &lt;code&gt;pipenv shell&lt;/code&gt; command has been executed, the name of the virtual environment appeared between brackets at the beginning of the line. To deactivate the virtual environment, just run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;exit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Managing Packages
&lt;/h2&gt;

&lt;p&gt;Ok, so you now know how to create, delete, activate and deactivate a virtual environment. Now let’s see how to manage the packages inside them. First, don’t forget to activate the virtual environment. To install a package, for example &lt;a href="https://pypi.org/project/django-drip-campaigns/"&gt;django-drip-campaings&lt;/a&gt;, you can execute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pipenv install django-drip-campaigns
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install the latest available version of that package.&lt;/li&gt;
&lt;li&gt;Automatically update the &lt;code&gt;Pipfile&lt;/code&gt; file adding the package.&lt;/li&gt;
&lt;li&gt;Automatically update the &lt;code&gt;Pipfile.lock&lt;/code&gt; file adding the package version and some other important metadata.
Now the Pipfile file looks like this:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]
django-drip-campaigns = "*"

[dev-packages]

[requires]
python_version = "3.8"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, the package was installed under the [packages] section. As previously mentioned, in the [dev-packages] section you only install what’s needed for development.&lt;/p&gt;

&lt;p&gt;For example, you want to have flake8 in your project, which is only required by the development process. To install it under the [dev-packages] section, execute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pipenv install flake8 --dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, you will see something like this in the &lt;code&gt;Pipfile&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[packages]
django-drip-campaigns = "*"

[dev-packages]
flake8 = "*"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, what if you need a specific version of a package? For example – Django, not the latest but the 2.2 version. Then run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pipenv install django==2.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the &lt;code&gt;Pipfile&lt;/code&gt; is updated and will resemble something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[packages]
django-drip-campaigns = "*"
django = "==2.2"

[dev-packages]
flake8 = "*"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the Django package line, you don’t see the &lt;code&gt;“*”&lt;/code&gt;, you instead see the specific version indicated in the command. If you need to uninstall a package, for example django-drip-campaigns, just run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pipenv uninstall django-drip-campaigns
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That command will uninstall the package and remove the information from the &lt;code&gt;Pipfile&lt;/code&gt; and &lt;code&gt;Pipfile.lock&lt;/code&gt; files. Now suppose you need the latest version of Django in your project (not the 2.2 version). To update a package to the latest version, you have to:&lt;/p&gt;

&lt;p&gt;Change the &lt;code&gt;django = "==2.2"&lt;/code&gt; line in the &lt;code&gt;Pipfile&lt;/code&gt; by &lt;code&gt;django = "*"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pipenv update django
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively, you can uninstall Django and then install it again without specifying the version. You can repeat those steps to downgrade a package version instead of upgrading it.&lt;/p&gt;

&lt;p&gt;You can do a lot of things with Pipenv, but the previously mentioned throughout are the main features. Pretty easy, right? Now let’s see a summary of the mentioned commands provided by Pipenv:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;pipenv install&lt;/code&gt; to create a virtual environment.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pipenv install --python &amp;lt;Python version&amp;gt;&lt;/code&gt; to create a virtual environment indicating the desired Python version (that you have installed using Pyenv).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pipenv --rm&lt;/code&gt; to delete the current virtual environment.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pipenv shell&lt;/code&gt; to activate the created virtual environment.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;exit&lt;/code&gt; to deactivate an already activated virtual environment.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now let’s take a look at the summary of the commands after the virtual environment has been activated:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;pipenv install &amp;lt;package name&amp;gt;&lt;/code&gt; to install the latest version of the package under the [packages] section.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pipenv install &amp;lt;package name&amp;gt;==&amp;lt;package version&amp;gt;&lt;/code&gt; to install a specified version of a package, under the [packages] section.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pipenv update &amp;lt;package name&amp;gt;&lt;/code&gt; to update a version package (update or downgrade) to the one that you have previously specified in the Pipfile.&lt;/li&gt;
&lt;li&gt;Adding --dev to the previous commands, Pipenv will do the same but under the [dev-packages] section.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pipenv uninstall &amp;lt;package name&amp;gt;&lt;/code&gt; to uninstall a package.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;As highlighted throughout, I have presented two different tools for managing Python projects using virtual environments. There are many ways to do this, but I showcased the two I believe to be the most effective.&lt;/p&gt;

&lt;p&gt;As tools, Pyenv and Pipenv are tidy and maintainable as well as easy to understand and use. Pyenv is used to manage different Python versions, whereas Pipenv is used to manage Python packages.&lt;/p&gt;

&lt;p&gt;I really like using both and I hope you are encouraged to try these tools for Python development. Thank you for reading and stay tuned for more useful content.&lt;/p&gt;

&lt;p&gt;Read this article and more content in the Rootstrap blog: &lt;a href="https://www.rootstrap.com/blog"&gt;https://www.rootstrap.com/blog&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Registration and Authentication in Django apps with dj-rest-auth</title>
      <dc:creator>brunomichetti</dc:creator>
      <pubDate>Mon, 15 Mar 2021 21:10:53 +0000</pubDate>
      <link>https://dev.to/rootstrap/registration-and-authentication-in-django-apps-with-dj-rest-auth-4l6a</link>
      <guid>https://dev.to/rootstrap/registration-and-authentication-in-django-apps-with-dj-rest-auth-4l6a</guid>
      <description>&lt;p&gt;A huge amount of existing applications have registration and authentication for users. Maybe every developer in the world has implemented something related to this in their work or while they learned. After the creation of the &lt;a href="https://www.django-rest-framework.org/"&gt;Django REST framework&lt;/a&gt;, Django developers started to implement more and more app-level REST API endpoints.&lt;br&gt;&lt;br&gt;
As a result, an open-source package called &lt;a href="https://dj-rest-auth.readthedocs.io/en/latest/index.html"&gt;dj-rest-auth&lt;/a&gt; has been created to provide a set of REST API endpoints to handle user registration and authentication tasks. In this article I will not only talk about this particular package but will also give you some tips to avoid some of the most common problems faced when configuring it.&lt;/p&gt;
&lt;h3&gt;
  
  
  The dj-rest-auth package
&lt;/h3&gt;

&lt;p&gt;If you are a Django developer and you are coding a REST API with authentication, you will find the dj-rest-auth package very useful. This project is a fork from &lt;a href="https://github.com/Tivix/django-rest-auth"&gt;django-rest-auth&lt;/a&gt; that is no longer maintained.&lt;br&gt;&lt;br&gt;
As said, dj-rest-auth provides a set of REST API endpoints to manage user registration and authentication. After an easy &lt;a href="https://dj-rest-auth.readthedocs.io/en/latest/installation.html"&gt;installation and configuration&lt;/a&gt;, you will have endpoints for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User registration with optional activation.&lt;/li&gt;
&lt;li&gt;Login and logout.&lt;/li&gt;
&lt;li&gt;Retrieve and update the Django User model.&lt;/li&gt;
&lt;li&gt;Password change.&lt;/li&gt;
&lt;li&gt;Password reset via e-mail.&lt;/li&gt;
&lt;li&gt;Social media authentication.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You don't need to do too much work to have those functionalities in your app. Besides, given that dj-rest-auth is an open source package, it has the advantage of being used by lots of programmers that can find errors, propose and add improvements, and so on. So, if you use dj-rest-auth you can be sure that you are using code created and maintained by an open source community.&lt;/p&gt;
&lt;h3&gt;
  
  
  Browsable endpoints
&lt;/h3&gt;

&lt;p&gt;Thanks to the Django REST framework, most of the endpoints that dj-rest-auth provides are browsables. This means that if you have added the package to your Django app, you can test those endpoints through the browser. As an example, if you open the browser and put the URL of the login endpoint, you will see something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iUfVcUwv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p69m1566vlacf0q7ydnx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iUfVcUwv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p69m1566vlacf0q7ydnx.png" alt="Browsable Endpoint"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the image above you can enter a username, email, and password to test the login functionality. The message of &lt;code&gt;Method GET not allowed&lt;/code&gt; is not an error. It means that your endpoint doesn't allow the GET method but you can test it doing a POST. That method is possible because the corresponding blue button is shown.&lt;br&gt;&lt;br&gt;
As you can see, it's very useful to very quickly have a nice interface to use while you are coding.&lt;/p&gt;
&lt;h3&gt;
  
  
  Configuration
&lt;/h3&gt;

&lt;p&gt;The documented installation and minimal configuration of dj-rest-auth is pretty clear and I won't talk about that in this blog post. The main idea of this section is to tell you about the big set of possibilities that you can have in your Django app just by adjusting a couple of parameters. This package uses &lt;a href="https://django-allauth.readthedocs.io/en/latest/index.html"&gt;django-allauth&lt;/a&gt; behind so you can take advantage of all the &lt;a href="https://django-allauth.readthedocs.io/en/latest/configuration.html"&gt;available settings&lt;/a&gt; in your own app. For example, you can define these parameters in your app configuration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ACCOUNT_EMAIL_REQUIRED (false by default):&lt;/code&gt;: If true, the user is required to provide an e-mail address when signing up.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ACCOUNT_LOGOUT_ON_PASSWORD_CHANGE (false by default)&lt;/code&gt;: If true, users will automatically be logged out once they have reset their password.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ACCOUNT_USER_MODEL_EMAIL_FIELD ('email' by default)&lt;/code&gt;: The name of the field in the user model containing the email.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ACCOUNT_USERNAME_REQUIRED (true by default)&lt;/code&gt;: If true, the user is required to enter a username when signing up.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ACCOUNT_EMAIL_VERIFICATION ('optional' by default)&lt;/code&gt;: Determines the e-mail verification method during signup. The possibilities are one of &lt;code&gt;mandatory&lt;/code&gt;, &lt;code&gt;optional&lt;/code&gt;, or &lt;code&gt;none&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And many other parameters. As a conclusion, we can say that adjusting a couple of parameters in your Django app settings, you get lots of different behaviors for the registration and authentication.&lt;/p&gt;
&lt;h4&gt;
  
  
  Note:
&lt;/h4&gt;

&lt;p&gt;To better understand the examples in the next sections:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You need to follow the dj-rest-auth installation steps.&lt;/li&gt;
&lt;li&gt;Have installed django-allauth.&lt;/li&gt;
&lt;li&gt;Make sure you have the authentication backends in your settings:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;AUTHENTICATION_BACKENDS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;# allauth specific authentication methods, such as login by e-mail
&lt;/span&gt;    &lt;span class="s"&gt;'allauth.account.auth_backends.AuthenticationBackend'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;# Needed to login by username in Django admin, regardless of allauth
&lt;/span&gt;    &lt;span class="s"&gt;'django.contrib.auth.backends.ModelBackend'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Customization
&lt;/h3&gt;

&lt;p&gt;If you are coding a REST API with Django and Django REST framework, you may need to customize the functionalities related to the registration and authentication. With those frameworks and dj-rest-auth it's quite simple. You can customize the Django User model, the views, the serializers, the main functionalities, etc.&lt;br&gt;&lt;br&gt;
For example, let's define a custom User model with a unique email, with no username, with a gender and a phone number attribute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# models.py in the users Django app
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.db&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.contrib.auth.models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AbstractUser&lt;/span&gt;


&lt;span class="n"&gt;GENDER_SELECTION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'M'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'Male'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'F'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'Female'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'NS'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'Not Specified'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CustomUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AbstractUser&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# We don't need to define the email attribute because is inherited from AbstractUser
&lt;/span&gt;    &lt;span class="n"&gt;gender&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;GENDER_SELECTION&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;phone_number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In our settings, we have to use the Django parameter called &lt;code&gt;AUTH_USER_MODEL&lt;/code&gt; to specify our User model. If the &lt;code&gt;CustomUser&lt;/code&gt; model is defined in an app called &lt;code&gt;users&lt;/code&gt;, we must add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;AUTH_USER_MODEL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'users.CustomUser'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Besides, we have to add in our settings these parameters to use the email as the User identifier in our app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;ACCOUNT_AUTHENTICATION_METHOD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'email'&lt;/span&gt;
&lt;span class="n"&gt;ACCOUNT_USERNAME_REQUIRED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
&lt;span class="n"&gt;ACCOUNT_EMAIL_REQUIRED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;span class="n"&gt;ACCOUNT_UNIQUE_EMAIL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, let's configure a signup without email verification just for now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;ACCOUNT_EMAIL_VERIFICATION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'none'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'll talk about account verification later.&lt;br&gt;&lt;br&gt;
Now we need to add our custom serializer to define the two added attributes and use them in the registration. The custom register serializer needs to be a child class of the one named &lt;code&gt;RegisterSerializer&lt;/code&gt; that dj-rest-auth provides. Also we have to overwrite the save method to set those values that came in the request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# serializers.py in the users Django app
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.db&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;transaction&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;rest_framework&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;serializers&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;dj_rest_auth.registration.serializers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;RegisterSerializer&lt;/span&gt;

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


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CustomRegisterSerializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RegisterSerializer&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;gender&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;serializers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ChoiceField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;GENDER_SELECTION&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;phone_number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;serializers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Define transaction.atomic to rollback the save operation in case of error
&lt;/span&gt;    &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;atomic&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gender&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'gender'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;phone_number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'phone_number'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can't forget to tell dj-rest-auth to use the recently created serializer. Let's add the &lt;code&gt;CustomRegisterSerializer&lt;/code&gt; to the settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;REST_AUTH_REGISTER_SERIALIZERS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;'REGISTER_SERIALIZER'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'users.serializers.CustomRegisterSerializer'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After this, if we go to the registration endpoint, we would see something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--avuqWKKP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t5m2k4gw13lj55r56h9s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--avuqWKKP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t5m2k4gw13lj55r56h9s.png" alt="Registration endpoint"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The username appears in the browsable endpoint, but thanks to the configuration you can leave it empty.&lt;br&gt;&lt;br&gt;
And that's it! We have added a customized registration endpoint to our Django app. Now we can create users with email, gender, and phone number, and make some tests around the login functionality too.&lt;/p&gt;
&lt;h3&gt;
  
  
  Use of JWT
&lt;/h3&gt;

&lt;p&gt;When an app manages authentication, a good and standard implementation of authentication by token authorization is using &lt;a href="https://auth0.com/docs/tokens/json-web-tokens"&gt;JWT (JSON web tokens)&lt;/a&gt;. JWTs are a good way of securely transmitting information between parties because they can be signed, which means you can be sure that the senders are who they say they are. We can easily configure our Django app to use JWT. First we need to install &lt;a href="https://pypi.org/project/djangorestframework-simplejwt/"&gt;djangorestframework-simplejwt&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;pip&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="n"&gt;djangorestframework&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;simplejwt&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add to the settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;REST_FRAMEWORK&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;'DEFAULT_AUTHENTICATION_CLASSES'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;'dj_rest_auth.jwt_auth.JWTCookieAuthentication'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;REST_USE_JWT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;span class="n"&gt;JWT_AUTH_COOKIE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'my-app-auth'&lt;/span&gt; &lt;span class="c1"&gt;# The cookie key name can be the one you want
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we are good to go! We have an app that manages the authentication with JWT.&lt;/p&gt;

&lt;h3&gt;
  
  
  The User endpoint
&lt;/h3&gt;

&lt;p&gt;If you need to modify or just retrieve the information of an authenticated user; you can use an endpoint provided by dj-rest-auth: &lt;code&gt;dj-rest-auth/user/&lt;/code&gt;. It's a very useful endpoint in the case you want the user to be able to modify its own information.&lt;br&gt;&lt;br&gt;
What happens if you have customized the Django user model? Well, in that case you need to overwrite the user serializer to be able to see and update those added attributes. Let's continue with the example of a customized model with a gender and a phone number. In that case we need to tell dj-rest-auth to use the customized serializer already created (&lt;code&gt;CustomRegisterSerializer&lt;/code&gt;) as the user's detail serializer, adding this to the settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;REST_AUTH_SERIALIZERS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;'USER_DETAILS_SERIALIZER'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'users.serializers.CustomRegisterSerializer'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that definition, we can retrieve and update the gender and phone_number of an authenticated user with the named endpoint. Let's say now, that our app only allows the gender to be updated after registration. In the &lt;code&gt;CustomRegisterSerializer&lt;/code&gt; the phone number can be modified of course, because we want the user to add that value at the moment of the registration. We can define then another serializer that doesn't allow the phone number to be modified. Let's call it &lt;code&gt;CustomUserDetailSerializer&lt;/code&gt; and add it in the same file that is &lt;code&gt;CustomRegisterSerializer&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# serializers.py in the users Django app
&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;

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

&lt;span class="p"&gt;...&lt;/span&gt;

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

    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CustomUser&lt;/span&gt;
        &lt;span class="n"&gt;fields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;'pk'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;'email'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;'phone_number'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;'gender'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;read_only_fields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'pk'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'email'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'phone_number'&lt;/span&gt;&lt;span class="p"&gt;,)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we have to add this as the correct user details serializer in our settings, replacing &lt;code&gt;CustomRegisterSerializer&lt;/code&gt; with the new one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;REST_AUTH_SERIALIZERS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;'USER_DETAILS_SERIALIZER'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'users.serializers.CustomUserDetailsSerializer'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And this is what you will see in the endpoint of the user:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9gahAAKn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1nl88puoo1l3gtk1gsgt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9gahAAKn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1nl88puoo1l3gtk1gsgt.png" alt="User details"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see in the picture, the only value that can be modified is the gender.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sign-up with email verification
&lt;/h3&gt;

&lt;p&gt;It's possible to configure email verification at the moment that a user registers. This means that a successfully registered user has to check the inbox and confirm through the received email that he really is the owner of the email account. To do this, go to your settings and turn on email verification:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Your settings file
&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="n"&gt;ACCOUNT_EMAIL_VERIFICATION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'mandatory'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this, after a correct sign-up your app will send a verification email to the entered account. But you didn't finish: as dj-rest-auth &lt;a href="https://dj-rest-auth.readthedocs.io/en/latest/api_endpoints.html#registration"&gt;documentation&lt;/a&gt; says, after enabling the email verification, you need to add a path to your urls that will be used by the verification view:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Your urls file
&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;dj_rest_auth.registration.views&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;VerifyEmailView&lt;/span&gt;

&lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="n"&gt;urlpatterns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;'dj-rest-auth/account-confirm-email/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;VerifyEmailView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;as_view&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'account_email_verification_sent'&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you don't do that, you will get a &lt;a href="https://docs.djangoproject.com/en/3.1/ref/exceptions/#noreversematch"&gt;NoReverseMatch&lt;/a&gt; error.&lt;br&gt;&lt;br&gt;
Also, let's use a django-allauth configuration to activate the email account after the user clicks on the link received in the email. Add this to your settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Your settings file
&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;ACCOUNT_CONFIRM_EMAIL_ON_GET&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And add this path to your urls file &lt;code&gt;before&lt;/code&gt; the definition of the &lt;code&gt;dj-rest-auth&lt;/code&gt; registration path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Your urls file
&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;dj_rest_auth.registration.views&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;VerifyEmailView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ConfirmEmailView&lt;/span&gt;

&lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="n"&gt;urlpatterns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;'dj-rest-auth/registration/account-confirm-email/&amp;lt;str:key&amp;gt;/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;ConfirmEmailView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;as_view&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;# Needs to be defined before the registration path
&lt;/span&gt;    &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'dj-rest-auth/registration/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'dj_rest_auth.registration.urls'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'dj-rest-auth/account-confirm-email/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;VerifyEmailView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;as_view&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'account_email_verification_sent'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That path needs to be there to avoid a template error in dj-rest-auth. As mentioned, dj-rest-auth it's an open source software and sometimes we can find some errors. The good thing of this is that anyone can address the discovered bugs.&lt;br&gt;&lt;br&gt;
Having this configuration, the user will be redirected to the login page after clicking in the received link. Don't forget to set the &lt;code&gt;LOGIN_URL&lt;/code&gt; parameter in your settings, otherwise you can get an error if the default value is not a valid URL of your app. During development, you can set the &lt;code&gt;LOGIN_URL&lt;/code&gt; as the login endpoint; remember that dj-rest-auth has browsable endpoints thanks to Django REST framework. So you can test sign-up flow by setting for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Your settings file
&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;LOGIN_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'http://localhost:8000/dj-rest-auth/login'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, you need to specify to Django the email backend that is in charge of sending the emails of your app.&lt;/p&gt;

&lt;h4&gt;
  
  
  Email backend
&lt;/h4&gt;

&lt;p&gt;The &lt;a href="https://docs.djangoproject.com/en/3.1/topics/email/#email-backends"&gt;Django email backend&lt;/a&gt; is the component that handles the sending of an email. You can choose among different possibilities that Django provides. The most common are SMTP and console backend.&lt;/p&gt;

&lt;p&gt;You can configure an SMTP server by adding:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Your settings file
&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="n"&gt;EMAIL_BACKEND&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'django.core.mail.backends.smtp.EmailBackend'&lt;/span&gt;
&lt;span class="n"&gt;EMAIL_HOST&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'your.email.host'&lt;/span&gt;
&lt;span class="n"&gt;EMAIL_USE_TLS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;span class="n"&gt;EMAIL_PORT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;587&lt;/span&gt;
&lt;span class="n"&gt;EMAIL_HOST_USER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'your email host user'&lt;/span&gt;
&lt;span class="n"&gt;EMAIL_HOST_PASSWORD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'your email host password'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You have to choose the &lt;code&gt;EMAIL_HOST&lt;/code&gt;, for example &lt;code&gt;'smtp.gmail.com'&lt;/code&gt;. In the &lt;code&gt;EMAIL_HOST_USER&lt;/code&gt; and &lt;code&gt;EMAIL_HOST_PASSWORD&lt;/code&gt; parameters put the information of the account that will be the email sender. If you are using Gmail as a mail server you will need to allow less secure apps and display unlock captcha. After this, your Django app will send verification emails for all the new users. I recommend you to use environment variables to keep sensitive information in your settings such as keys, the email host account, and its password, etc.&lt;br&gt;&lt;br&gt;
In real applications the best way to do this is integrating with an email service such as &lt;a href="https://sendgrid.com/docs/for-developers/sending-email/django/"&gt;SendGrid&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the second option, you can locally test the sign-up feature during development, by setting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Your settings file
&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;EMAIL_BACKEND&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'django.core.mail.backends.console.EmailBackend'&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case the email is sent and received by the console. So after a successful registration you will see in the console something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uLTPBNLJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ozcxc99zq23qjwuir9vz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uLTPBNLJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ozcxc99zq23qjwuir9vz.png" alt="Email console"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you open your browser and go to the link shown in the printed email, the user's account will be activated and you will be redirected to the &lt;code&gt;LOGIN_URL&lt;/code&gt;. Now you are able to login with the entered email and password.&lt;br&gt;&lt;br&gt;
And there it is! You have configured sign-up with email verification. Let's see how to customize the emails that your application sends.&lt;/p&gt;
&lt;h3&gt;
  
  
  Email templates
&lt;/h3&gt;

&lt;p&gt;Django allauth provides a few templates that are used by dj-rest-auth at the moment of sending the emails. As shown in previous section, the verification email printed in console has a template defined by the django-allauth package. It's possible to customize those email templates by overwriting a couple of files. First of all, let's create a &lt;code&gt;template&lt;/code&gt; folder inside your main Django app folder.&lt;br&gt;&lt;br&gt;
From now on, let's assume that the name of your main Django app folder is &lt;code&gt;myapp&lt;/code&gt;; so you need to add this in your &lt;code&gt;TEMPLATES&lt;/code&gt; settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Your settings file
&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="n"&gt;TEMPLATES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;'BACKEND'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'django.template.backends.django.DjangoTemplates'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;'DIRS'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BASE_DIR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'myapp/templates'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;# Add this inside the DIRS list
&lt;/span&gt;        &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="s"&gt;'APP_DIRS'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you have to overwrite the corresponding template files for the desired customization. In this case, the path used by dj-rest-auth will be &lt;code&gt;myapp/templates/account/email/&lt;/code&gt;. In there you can add these files to overwrite the ones used by default:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;email_confirmation_message.txt&lt;/li&gt;
&lt;li&gt;email_confirmation_signup_message.txt&lt;/li&gt;
&lt;li&gt;email_confirmation_signup_subject.txt&lt;/li&gt;
&lt;li&gt;email_confirmation_subject.txt&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, to customize the email confirmation message, you have to create an &lt;code&gt;email_confirmation_message.txt&lt;/code&gt; file in &lt;code&gt;myapp/templates/account/email/&lt;/code&gt;. You can even reuse some of the content of the default file that you can find in the &lt;a href="https://github.com/pennersr/django-allauth/tree/master/allauth/templates/account/email"&gt;github repository of django-allauth&lt;/a&gt;. Besides, you can set a value to the &lt;code&gt;ACCOUNT_EMAIL_SUBJECT_PREFIX&lt;/code&gt; parameter in your settings, to add a prefix to the subjects in the emails of your app.&lt;br&gt;&lt;br&gt;
It's important to say that there are some variables defined in the email templates that are needed and you have to keep them in case you overwrite the files. For example, this is the file of &lt;code&gt;email_confirmation_message.txt&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;{% load account %}{% user_display user as user_display %}{% load i18n %}{%
autoescape off %}{% blocktrans with site_name=current_site.name
site_domain=current_site.domain %}Hello from {{ site_name }}! You're receiving
this e-mail because user {{ user_display }} has given your e-mail address to
register an account on {{ site_domain }}. To confirm this is correct, go to {{
activate_url }} {% endblocktrans %} {% blocktrans with
site_name=current_site.name site_domain=current_site.domain %}Thank you from {{
site_name }}! {{ site_domain }}{% endblocktrans %} {% endautoescape %}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There you have &lt;code&gt;activate_url&lt;/code&gt;, that is the link for the user confirmation. So you can remove for example the &lt;code&gt;site_name&lt;/code&gt; if you want (or change it to show a different one) but you definitely have to keep the &lt;code&gt;activate_url&lt;/code&gt; value. Otherwise, registered users won't be able to activate their accounts. Summarizing this section, if you decide to overwrite the &lt;code&gt;email_confirmation_message.txt&lt;/code&gt;, your project structure will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;root-project-folder
    |__myapp
    |    |__templates
    |        |__account
    |            |__email
    |                |__email_confirmation_message.txt
    |
    ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's see about the reset password functionality and how to customize it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reset password
&lt;/h3&gt;

&lt;p&gt;If you want to have a reset password feature in your app, you can do it very easily with dj-rest-auth. The first thing to say is that by default you can't test it as a browsable endpoint because it will show a &lt;code&gt;NoReverseMatch&lt;/code&gt; error. So you need to add this path to your urls file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Your urls file
&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;dj_rest_auth.views&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;PasswordResetConfirmView&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="n"&gt;urlpatterns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;'rest-auth/password/reset/confirm/&amp;lt;slug:uidb64&amp;gt;/&amp;lt;slug:token&amp;gt;/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;PasswordResetConfirmView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;as_view&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'password_reset_confirm'&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now you are good to go! You can test the browsable endpoint which receives the email of the registered user, and dj-rest-auth sends the instructions to reset the password. You need of course to have configured the email backend.&lt;br&gt;&lt;br&gt;
You are able to modify the email template for the reset password functionality too. Assuming that you have already configured the &lt;code&gt;TEMPLATES&lt;/code&gt; folder as in the previous section example, you can create a file in &lt;code&gt;myapp/templates/registration/&lt;/code&gt; called &lt;code&gt;password_reset_email.html&lt;/code&gt; to overwrite the one used by default. Why do you have to define it there? Because is the &lt;a href="https://github.com/django/django/tree/master/django/contrib/admin/templates/registration"&gt;default path used by Django&lt;/a&gt;. You can even reuse some code of the default file, that looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;{% load i18n %}{% autoescape off %} {% blocktranslate %}You're receiving this
email because you requested a password reset for your user account at {{
site_name }}.{% endblocktranslate %} {% translate "Please go to the following
page and choose a new password:" %} {% block reset_link %} {{ protocol }}://{{
domain }}{% url 'password_reset_confirm' uidb64=uid token=token %} {% endblock
%} {% translate 'Your username, in case you’ve forgotten:' %} {{
user.get_username }} {% translate "Thanks for using our site!" %} {%
blocktranslate %}The {{ site_name }} team{% endblocktranslate %} {%
endautoescape %}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As said in the email validation section, remember to keep some of the needed variables in the template. In this case the most important is the &lt;code&gt;url&lt;/code&gt; with the &lt;code&gt;uid&lt;/code&gt; and the &lt;code&gt;token&lt;/code&gt; that are required to update the user's password.&lt;br&gt;&lt;br&gt;
 After these steps, you have finished the reset password functionality customization! Taking the previous section into account, your project folder would be now like this one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;root-project-folder
    |__myapp
    |    |__templates
    |        |__account
    |        |   |__email
    |        |        |__email_confirmation_message.txt
    |        |__registration
    |            |__password_reset_email.html
    |
    ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's see in the last section how we can modify some of the default variables used in the templates.&lt;/p&gt;

&lt;h3&gt;
  
  
  Customize variables used in the templates
&lt;/h3&gt;

&lt;p&gt;Let's think about this example: What if you want to modify the URL sent by default in the reset password email template? Well, Django allows you to define variables to be used in the templates by creating your own template tags. The first thing you need to do is define the custom value desired for the URL in your settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Your settings file
&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;CUSTOM_PASSWORD_RESET_CONFIRM&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'desired URL'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then you have to create two files under &lt;code&gt;myapp/templatetags/&lt;/code&gt;: One has to be an empty &lt;code&gt;__init__.py&lt;/code&gt; file, and the other one registers and gets the tags. Let's call it &lt;code&gt;password_reset_template_load.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;template&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.conf&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;

&lt;span class="n"&gt;register&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Library&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;register&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;simple_tag&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_settings_var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, go to your customized email template that you have created to overwrite the default one, and load the defined value by adding &lt;code&gt;{% load password_reset_template_load %}&lt;/code&gt; at the top of the file, and after that add the line that has the custom value (in this particular case don't forget the &lt;code&gt;uid&lt;/code&gt; and &lt;code&gt;token&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;// Your template {% load password_reset_template_load %} ... {% get_settings_var
'CUSTOM_PASSWORD_RESET_CONFIRM' %}?uidb64={{ uid }}&lt;span class="err"&gt;&amp;amp;&lt;/span&gt;token={{ token }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With these settings you have defined your custom template tags. I'm going to show you the final project structure with all the customization that I talked about:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;root-project-folder
    |__myapp
    |    |__templates
    |    |   |__account
    |    |   |   |__email
    |    |   |        |__email_confirmation_message.txt
    |    |   |__registration
    |    |       |__password_reset_email.html
    |    |__templatetags
    |        |__password_reset_template_load.py
    ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From now on, the email for password reset will show a customized URL. Remember that this was an example, you can create any template tag you want and use it in any template you have.&lt;/p&gt;

&lt;h4&gt;
  
  
  Notes
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;If while trying this you have an error that shows &lt;code&gt;Site matching query does not exist.&lt;/code&gt;, you can solve it by adding &lt;code&gt;SITE_ID = 1&lt;/code&gt; to your settings.&lt;/li&gt;
&lt;li&gt;When you create your own templatetags make sure that the main app is added in the &lt;code&gt;INSTALLED_APPS&lt;/code&gt; list in your settings.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;I have presented a very useful package to handle registration and authentication with a set of REST API endpoints.&lt;br&gt;
With minimal configuration, you can add endpoints to your Django app that already have those features implemented. We reviewed some advantages of the package, how easy it is to customize it, and code snippet examples.&lt;br&gt;&lt;br&gt;
In addition to this, I have shown you how to implement email validation at sign-up, and how to customize the emails that are sent by your app. We learned about the reset password functionality, and finally how to customize the templates with your own desired values. I recommend using the presented package because it solves lots of common problems and provides a set of features that are very important for most applications. Maybe in the future, you can not only use it but also contribute to it.&lt;/p&gt;

&lt;p&gt;Original blog on &lt;a href="http://www.rootstrap.com/"&gt;Rootstrap&lt;/a&gt;&lt;/p&gt;

</description>
      <category>django</category>
      <category>python</category>
    </item>
    <item>
      <title>Registration and Authentication in your Django app with dj-rest-auth</title>
      <dc:creator>brunomichetti</dc:creator>
      <pubDate>Thu, 12 Nov 2020 16:07:44 +0000</pubDate>
      <link>https://dev.to/rootstrap/registration-and-authentication-in-your-django-app-with-dj-rest-auth-4ioc</link>
      <guid>https://dev.to/rootstrap/registration-and-authentication-in-your-django-app-with-dj-rest-auth-4ioc</guid>
      <description>&lt;p&gt;A huge amount of existing applications have registration and authentication for users. Maybe every developer in the world has implemented something related to this in their work or while they learned. After the creation of the &lt;a href="https://www.django-rest-framework.org/"&gt;Django REST framework&lt;/a&gt;, Django developers started to implement more and more app-level REST API endpoints.&lt;br&gt;&lt;br&gt;
As a result, an open-source package called &lt;a href="https://dj-rest-auth.readthedocs.io/en/latest/index.html"&gt;dj-rest-auth&lt;/a&gt; has been created to provide a set of REST API endpoints to handle user registration and authentication tasks. In this article I will not only talk about this particular package but will also give you some tips to avoid some of the most common problems faced when configuring it.&lt;/p&gt;
&lt;h3&gt;
  
  
  The dj-rest-auth package
&lt;/h3&gt;

&lt;p&gt;If you are a Django developer and you are coding a REST API with authentication, you will find the dj-rest-auth package very useful. This project is a fork from &lt;a href="https://github.com/Tivix/django-rest-auth"&gt;django-rest-auth&lt;/a&gt; that is no longer maintained.&lt;br&gt;&lt;br&gt;
As said, dj-rest-auth provides a set of REST API endpoints to manage user registration and authentication. After an easy &lt;a href="https://dj-rest-auth.readthedocs.io/en/latest/installation.html"&gt;installation and configuration&lt;/a&gt;, you will have endpoints for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User registration with optional activation.&lt;/li&gt;
&lt;li&gt;Login and logout.&lt;/li&gt;
&lt;li&gt;Retrieve and update the Django User model.&lt;/li&gt;
&lt;li&gt;Password change.&lt;/li&gt;
&lt;li&gt;Password reset via e-mail.&lt;/li&gt;
&lt;li&gt;Social media authentication.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You don't need to do too much work to have those functionalities in your app. Besides, given that dj-rest-auth is an open source package, it has the advantage of being used by lots of programmers that can find errors, propose and add improvements, and so on. So, if you use dj-rest-auth you can be sure that you are using code created and maintained by an open source community.&lt;/p&gt;
&lt;h3&gt;
  
  
  Browsable endpoints
&lt;/h3&gt;

&lt;p&gt;Thanks to the Django REST framework, most of the endpoints that dj-rest-auth provides are browsables. This means that if you have added the package to your Django app, you can test those endpoints through the browser. As an example, if you open the browser and put the URL of the login endpoint, you will see something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--K1MZ-eMw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/yyza8ym4bw6ypnzei45y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--K1MZ-eMw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/yyza8ym4bw6ypnzei45y.png" alt="Browsable endpoint"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the image above you can enter a username, email, and password to test the login functionality. The message of &lt;code&gt;Method GET not allowed&lt;/code&gt; is not an error. It means that your endpoint doesn't allow the GET method but you can test it doing a POST. That method is possible because the corresponding blue button is shown.&lt;br&gt;&lt;br&gt;
As you can see, it's very useful to very quickly have a nice interface to use while you are coding.&lt;/p&gt;
&lt;h3&gt;
  
  
  Configuration
&lt;/h3&gt;

&lt;p&gt;The documented installation and minimal configuration of dj-rest-auth is pretty clear and I won't talk about that in this blog post. The main idea of this section is to tell you about the big set of possibilities that you can have in your Django app just by adjusting a couple of parameters. This package uses &lt;a href="https://django-allauth.readthedocs.io/en/latest/index.html"&gt;django-allauth&lt;/a&gt; behind so you can take advantage of all the &lt;a href="https://django-allauth.readthedocs.io/en/latest/configuration.html"&gt;available settings&lt;/a&gt; in your own app. For example, you can define these parameters in your app configuration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ACCOUNT_EMAIL_REQUIRED (false by default):&lt;/code&gt;: If true, the user is required to provide an e-mail address when signing up.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ACCOUNT_LOGOUT_ON_PASSWORD_CHANGE (false by default)&lt;/code&gt;: If true, users will automatically be logged out once they have reset their password.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ACCOUNT_USER_MODEL_EMAIL_FIELD ('email' by default)&lt;/code&gt;: The name of the field in the user model containing the email.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ACCOUNT_USERNAME_REQUIRED (true by default)&lt;/code&gt;: If true, the user is required to enter a username when signing up.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ACCOUNT_EMAIL_VERIFICATION ('optional' by default)&lt;/code&gt;: Determines the e-mail verification method during signup. The possibilities are one of &lt;code&gt;mandatory&lt;/code&gt;, &lt;code&gt;optional&lt;/code&gt;, or &lt;code&gt;none&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And many other parameters. As a conclusion, we can say that adjusting a couple of parameters in your Django app settings, you get lots of different behaviors for the registration and authentication.&lt;/p&gt;
&lt;h4&gt;
  
  
  Note:
&lt;/h4&gt;

&lt;p&gt;To better understand the examples in the next sections:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You need to follow the dj-rest-auth installation steps.&lt;/li&gt;
&lt;li&gt;Have installed django-allauth.&lt;/li&gt;
&lt;li&gt;Make sure you have the authentication backends in your settings:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;AUTHENTICATION_BACKENDS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;# allauth specific authentication methods, such as login by e-mail
&lt;/span&gt;    &lt;span class="s"&gt;'allauth.account.auth_backends.AuthenticationBackend'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;# Needed to login by username in Django admin, regardless of allauth
&lt;/span&gt;    &lt;span class="s"&gt;'django.contrib.auth.backends.ModelBackend'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Customization
&lt;/h3&gt;

&lt;p&gt;If you are coding a REST API with Django and Django REST framework, you may need to customize the functionalities related to the registration and authentication. With those frameworks and dj-rest-auth it's quite simple. You can customize the Django User model, the views, the serializers, the main functionalities, etc.&lt;br&gt;&lt;br&gt;
For example, let's define a custom User model with a unique email, with no username, with a gender and a phone number attribute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# models.py in the users Django app
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.db&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.contrib.auth.models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AbstractUser&lt;/span&gt;


&lt;span class="n"&gt;GENDER_SELECTION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'M'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'Male'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'F'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'Female'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'NS'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'Not Specified'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CustomUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AbstractUser&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# We don't need to define the email attribute because is inherited from AbstractUser
&lt;/span&gt;    &lt;span class="n"&gt;gender&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;GENDER_SELECTION&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;phone_number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In our settings, we have to use the Django parameter called &lt;code&gt;AUTH_USER_MODEL&lt;/code&gt; to specify our User model. If the &lt;code&gt;CustomUser&lt;/code&gt; model is defined in an app called &lt;code&gt;users&lt;/code&gt;, we must add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;AUTH_USER_MODEL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'users.CustomUser'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Besides, we have to add in our settings these parameters to use the email as the User identifier in our app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;ACCOUNT_AUTHENTICATION_METHOD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'email'&lt;/span&gt;
&lt;span class="n"&gt;ACCOUNT_USERNAME_REQUIRED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
&lt;span class="n"&gt;ACCOUNT_EMAIL_REQUIRED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;span class="n"&gt;ACCOUNT_UNIQUE_EMAIL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, let's configure a signup without email verification just for now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;ACCOUNT_EMAIL_VERIFICATION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'none'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'll talk about account verification later.&lt;br&gt;&lt;br&gt;
Now we need to add our custom serializer to define the two added attributes and use them in the registration. The custom register serializer needs to be a child class of the one named &lt;code&gt;RegisterSerializer&lt;/code&gt; that dj-rest-auth provides. Also we have to overwrite the save method to set those values that came in the request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# serializers.py in the users Django app
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.db&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;transaction&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;rest_framework&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;serializers&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;dj_rest_auth.registration.serializers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;RegisterSerializer&lt;/span&gt;

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


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CustomRegisterSerializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RegisterSerializer&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;gender&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;serializers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ChoiceField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;GENDER_SELECTION&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;phone_number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;serializers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Define transaction.atomic to rollback the save operation in case of error
&lt;/span&gt;    &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;atomic&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gender&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'gender'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;phone_number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'phone_number'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can't forget to tell dj-rest-auth to use the recently created serializer. Let's add the &lt;code&gt;CustomRegisterSerializer&lt;/code&gt; to the settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;REST_AUTH_REGISTER_SERIALIZERS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;'REGISTER_SERIALIZER'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'users.serializers.CustomRegisterSerializer'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After this, if we go to the registration endpoint, we would see something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nOzICDBg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/5vcm9rvprq17zmom8k3z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nOzICDBg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/5vcm9rvprq17zmom8k3z.png" alt="Registration example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The username appears in the browsable endpoint, but thanks to the configuration you can leave it empty.&lt;br&gt;&lt;br&gt;
And that's it! We have added a customized registration endpoint to our Django app. Now we can create users with email, gender, and phone number, and make some tests around the login functionality too.&lt;/p&gt;
&lt;h3&gt;
  
  
  Use of JWT
&lt;/h3&gt;

&lt;p&gt;When an app manages authentication, a good and standard implementation of authentication by token authorization is using &lt;a href="https://auth0.com/docs/tokens/json-web-tokens"&gt;JWT (JSON web tokens)&lt;/a&gt;. JWTs are a good way of securely transmitting information between parties because they can be signed, which means you can be sure that the senders are who they say they are. We can easily configure our Django app to use JWT. First we need to install &lt;a href="https://pypi.org/project/djangorestframework-simplejwt/"&gt;djangorestframework-simplejwt&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;pip&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="n"&gt;djangorestframework&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;simplejwt&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add to the settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;REST_FRAMEWORK&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;'DEFAULT_AUTHENTICATION_CLASSES'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;'dj_rest_auth.jwt_auth.JWTCookieAuthentication'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;REST_USE_JWT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;span class="n"&gt;JWT_AUTH_COOKIE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'my-app-auth'&lt;/span&gt; &lt;span class="c1"&gt;# The cookie key name can be the one you want
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we are good to go! We have an app that manages the authentication with JWT.&lt;/p&gt;

&lt;h3&gt;
  
  
  The User endpoint
&lt;/h3&gt;

&lt;p&gt;If you need to modify or just retrieve the information of an authenticated user; you can use an endpoint provided by dj-rest-auth: &lt;code&gt;dj-rest-auth/user/&lt;/code&gt;. It's a very useful endpoint in the case you want the user to be able to modify its own information.&lt;br&gt;&lt;br&gt;
What happens if you have customized the Django user model? Well, in that case you need to overwrite the user serializer to be able to see and update those added attributes. Let's continue with the example of a customized model with a gender and a phone number. In that case we need to tell dj-rest-auth to use the customized serializer already created (&lt;code&gt;CustomRegisterSerializer&lt;/code&gt;) as the user's detail serializer, adding this to the settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;REST_AUTH_SERIALIZERS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;'USER_DETAILS_SERIALIZER'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'users.serializers.CustomRegisterSerializer'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that definition, we can retrieve and update the gender and phone_number of an authenticated user with the named endpoint. Let's say now, that our app only allows the gender to be updated after registration. In the &lt;code&gt;CustomRegisterSerializer&lt;/code&gt; the phone number can be modified of course, because we want the user to add that value at the moment of the registration. We can define then another serializer that doesn't allow the phone number to be modified. Let's call it &lt;code&gt;CustomUserDetailSerializer&lt;/code&gt; and add it in the same file that is &lt;code&gt;CustomRegisterSerializer&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# serializers.py in the users Django app
&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;

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

&lt;span class="p"&gt;...&lt;/span&gt;

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

    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CustomUser&lt;/span&gt;
        &lt;span class="n"&gt;fields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;'pk'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;'email'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;'phone_number'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;'gender'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;read_only_fields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'pk'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'email'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'phone_number'&lt;/span&gt;&lt;span class="p"&gt;,)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we have to add this as the correct user details serializer in our settings, replacing &lt;code&gt;CustomRegisterSerializer&lt;/code&gt; with the new one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;REST_AUTH_SERIALIZERS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;'USER_DETAILS_SERIALIZER'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'users.serializers.CustomUserDetailsSerializer'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And this is what you will see in the endpoint of the user:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--14r9w69u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/zehllw3i7as15uunwunn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--14r9w69u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/zehllw3i7as15uunwunn.png" alt="User endpoint"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see in the picture, the only value that can be modified is the gender.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sign-up with email verification
&lt;/h3&gt;

&lt;p&gt;It's possible to configure email verification at the moment that a user registers. This means that a successfully registered user has to check the inbox and confirm through the received email that he really is the owner of the email account. To do this, go to your settings and turn on email verification:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Your settings file
&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="n"&gt;ACCOUNT_EMAIL_VERIFICATION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'mandatory'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this, after a correct sign-up your app will send a verification email to the entered account. But you didn't finish: as dj-rest-auth &lt;a href="https://dj-rest-auth.readthedocs.io/en/latest/api_endpoints.html#registration"&gt;documentation&lt;/a&gt; says, after enabling the email verification, you need to add a path to your urls that will be used by the verification view:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Your urls file
&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;dj_rest_auth.registration.views&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;VerifyEmailView&lt;/span&gt;

&lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="n"&gt;urlpatterns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;'dj-rest-auth/account-confirm-email/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;VerifyEmailView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;as_view&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'account_email_verification_sent'&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you don't do that, you will get a &lt;a href="https://docs.djangoproject.com/en/3.1/ref/exceptions/#noreversematch"&gt;NoReverseMatch&lt;/a&gt; error.&lt;br&gt;&lt;br&gt;
Also, let's use a django-allauth configuration to activate the email account after the user clicks on the link received in the email. Add this to your settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Your settings file
&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;ACCOUNT_CONFIRM_EMAIL_ON_GET&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And add this path to your urls file &lt;code&gt;before&lt;/code&gt; the definition of the &lt;code&gt;dj-rest-auth&lt;/code&gt; registration path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Your urls file
&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;dj_rest_auth.registration.views&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;VerifyEmailView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ConfirmEmailView&lt;/span&gt;

&lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="n"&gt;urlpatterns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;'dj-rest-auth/registration/account-confirm-email/&amp;lt;str:key&amp;gt;/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;ConfirmEmailView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;as_view&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;# Needs to be defined before the registration path
&lt;/span&gt;    &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'dj-rest-auth/registration/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'dj_rest_auth.registration.urls'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'dj-rest-auth/account-confirm-email/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;VerifyEmailView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;as_view&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'account_email_verification_sent'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That path needs to be there to avoid a template error in dj-rest-auth. As mentioned, dj-rest-auth it's an open source software and sometimes we can find some errors. The good thing of this is that anyone can address the discovered bugs.&lt;br&gt;&lt;br&gt;
Having this configuration, the user will be redirected to the login page after clicking in the received link. Don't forget to set the &lt;code&gt;LOGIN_URL&lt;/code&gt; parameter in your settings, otherwise you can get an error if the default value is not a valid URL of your app. During development, you can set the &lt;code&gt;LOGIN_URL&lt;/code&gt; as the login endpoint; remember that dj-rest-auth has browsable endpoints thanks to Django REST framework. So you can test sign-up flow by setting for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Your settings file
&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;LOGIN_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'http://localhost:8000/dj-rest-auth/login'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, you need to specify to Django the email backend that is in charge of sending the emails of your app.&lt;/p&gt;

&lt;h4&gt;
  
  
  Email backend
&lt;/h4&gt;

&lt;p&gt;The &lt;a href="https://docs.djangoproject.com/en/3.1/topics/email/#email-backends"&gt;Django email backend&lt;/a&gt; is the component that handles the sending of an email. You can choose among different possibilities that Django provides. The most common are SMTP and console backend.&lt;/p&gt;

&lt;p&gt;You can configure an SMTP server by adding:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Your settings file
&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="n"&gt;EMAIL_BACKEND&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'django.core.mail.backends.smtp.EmailBackend'&lt;/span&gt;
&lt;span class="n"&gt;EMAIL_HOST&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'your.email.host'&lt;/span&gt;
&lt;span class="n"&gt;EMAIL_USE_TLS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;span class="n"&gt;EMAIL_PORT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;587&lt;/span&gt;
&lt;span class="n"&gt;EMAIL_HOST_USER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'your email host user'&lt;/span&gt;
&lt;span class="n"&gt;EMAIL_HOST_PASSWORD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'your email host password'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You have to choose the &lt;code&gt;EMAIL_HOST&lt;/code&gt;, for example &lt;code&gt;'smtp.gmail.com'&lt;/code&gt;. In the &lt;code&gt;EMAIL_HOST_USER&lt;/code&gt; and &lt;code&gt;EMAIL_HOST_PASSWORD&lt;/code&gt; parameters put the information of the account that will be the email sender. If you are using Gmail as a mail server you will need to allow less secure apps and display unlock captcha. After this, your Django app will send verification emails for all the new users. I recommend you to use environment variables to keep sensitive information in your settings such as keys, the email host account, and its password, etc.&lt;br&gt;&lt;br&gt;
In real applications the best way to do this is integrating with an email service such as &lt;a href="https://sendgrid.com/docs/for-developers/sending-email/django/"&gt;SendGrid&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the second option, you can locally test the sign-up feature during development, by setting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Your settings file
&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;EMAIL_BACKEND&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'django.core.mail.backends.console.EmailBackend'&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case the email is sent and received by the console. So after a successful registration you will see in the console something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1N9ykI0x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/uhv7ss9ar1atbnqqg56q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1N9ykI0x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/uhv7ss9ar1atbnqqg56q.png" alt="Console email"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you open your browser and go to the link shown in the printed email, the user's account will be activated and you will be redirected to the &lt;code&gt;LOGIN_URL&lt;/code&gt;. Now you are able to login with the entered email and password.&lt;br&gt;&lt;br&gt;
And there it is! You have configured sign-up with email verification. Let's see how to customize the emails that your application sends.&lt;/p&gt;
&lt;h3&gt;
  
  
  Email templates
&lt;/h3&gt;

&lt;p&gt;Django allauth provides a few templates that are used by dj-rest-auth at the moment of sending the emails. As shown in previous section, the verification email printed in console has a template defined by the django-allauth package. It's possible to customize those email templates by overwriting a couple of files. First of all, let's create a &lt;code&gt;template&lt;/code&gt; folder inside your main Django app folder.&lt;br&gt;&lt;br&gt;
From now on, let's assume that the name of your main Django app folder is &lt;code&gt;myapp&lt;/code&gt;; so you need to add this in your &lt;code&gt;TEMPLATES&lt;/code&gt; settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Your settings file
&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="n"&gt;TEMPLATES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;'BACKEND'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'django.template.backends.django.DjangoTemplates'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;'DIRS'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BASE_DIR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'myapp/templates'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;# Add this inside the DIRS list
&lt;/span&gt;        &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="s"&gt;'APP_DIRS'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you have to overwrite the corresponding template files for the desired customization. In this case, the path used by dj-rest-auth will be &lt;code&gt;myapp/templates/account/email/&lt;/code&gt;. In there you can add these files to overwrite the ones used by default:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;email_confirmation_message.txt&lt;/li&gt;
&lt;li&gt;email_confirmation_signup_message.txt&lt;/li&gt;
&lt;li&gt;email_confirmation_signup_subject.txt&lt;/li&gt;
&lt;li&gt;email_confirmation_subject.txt&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, to customize the email confirmation message, you have to create an &lt;code&gt;email_confirmation_message.txt&lt;/code&gt; file in &lt;code&gt;myapp/templates/account/email/&lt;/code&gt;. You can even reuse some of the content of the default file that you can find in the &lt;a href="https://github.com/pennersr/django-allauth/tree/master/allauth/templates/account/email"&gt;github repository of django-allauth&lt;/a&gt;. Besides, you can set a value to the &lt;code&gt;ACCOUNT_EMAIL_SUBJECT_PREFIX&lt;/code&gt; parameter in your settings, to add a prefix to the subjects in the emails of your app.&lt;br&gt;&lt;br&gt;
It's important to say that there are some variables defined in the email templates that are needed and you have to keep them in case you overwrite the files. For example, this is the file of &lt;code&gt;email_confirmation_message.txt&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;{% load account %}{% user_display user as user_display %}{% load i18n %}{%
autoescape off %}{% blocktrans with site_name=current_site.name
site_domain=current_site.domain %}Hello from {{ site_name }}! You're receiving
this e-mail because user {{ user_display }} has given your e-mail address to
register an account on {{ site_domain }}. To confirm this is correct, go to {{
activate_url }} {% endblocktrans %} {% blocktrans with
site_name=current_site.name site_domain=current_site.domain %}Thank you from {{
site_name }}! {{ site_domain }}{% endblocktrans %} {% endautoescape %}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There you have &lt;code&gt;activate_url&lt;/code&gt;, that is the link for the user confirmation. So you can remove for example the &lt;code&gt;site_name&lt;/code&gt; if you want (or change it to show a different one) but you definitely have to keep the &lt;code&gt;activate_url&lt;/code&gt; value. Otherwise, registered users won't be able to activate their accounts. Summarizing this section, if you decide to overwrite the &lt;code&gt;email_confirmation_message.txt&lt;/code&gt;, your project structure will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;root-project-folder
    |__myapp
    |    |__templates
    |        |__account
    |            |__email
    |                |__email_confirmation_message.txt
    |
    ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's see about the reset password functionality and how to customize it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reset password
&lt;/h3&gt;

&lt;p&gt;If you want to have a reset password feature in your app, you can do it very easily with dj-rest-auth. The first thing to say is that by default you can't test it as a browsable endpoint because it will show a &lt;code&gt;NoReverseMatch&lt;/code&gt; error. So you need to add this path to your urls file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Your urls file
&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;dj_rest_auth.views&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;PasswordResetConfirmView&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="n"&gt;urlpatterns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;'rest-auth/password/reset/confirm/&amp;lt;slug:uidb64&amp;gt;/&amp;lt;slug:token&amp;gt;/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;PasswordResetConfirmView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;as_view&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'password_reset_confirm'&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now you are good to go! You can test the browsable endpoint which receives the email of the registered user, and dj-rest-auth sends the instructions to reset the password. You need of course to have configured the email backend.&lt;br&gt;&lt;br&gt;
You are able to modify the email template for the reset password functionality too. Assuming that you have already configured the &lt;code&gt;TEMPLATES&lt;/code&gt; folder as in the previous section example, you can create a file in &lt;code&gt;myapp/templates/registration/&lt;/code&gt; called &lt;code&gt;password_reset_email.html&lt;/code&gt; to overwrite the one used by default. Why do you have to define it there? Because is the &lt;a href="https://github.com/django/django/tree/master/django/contrib/admin/templates/registration"&gt;default path used by Django&lt;/a&gt;. You can even reuse some code of the default file, that looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;{% load i18n %}{% autoescape off %} {% blocktranslate %}You're receiving this
email because you requested a password reset for your user account at {{
site_name }}.{% endblocktranslate %} {% translate "Please go to the following
page and choose a new password:" %} {% block reset_link %} {{ protocol }}://{{
domain }}{% url 'password_reset_confirm' uidb64=uid token=token %} {% endblock
%} {% translate 'Your username, in case you’ve forgotten:' %} {{
user.get_username }} {% translate "Thanks for using our site!" %} {%
blocktranslate %}The {{ site_name }} team{% endblocktranslate %} {%
endautoescape %}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As said in the email validation section, remember to keep some of the needed variables in the template. In this case the most important is the &lt;code&gt;url&lt;/code&gt; with the &lt;code&gt;uid&lt;/code&gt; and the &lt;code&gt;token&lt;/code&gt; that are required to update the user's password.&lt;br&gt;&lt;br&gt;
 After these steps, you have finished the reset password functionality customization! Taking the previous section into account, your project folder would be now like this one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;root-project-folder
    |__myapp
    |    |__templates
    |        |__account
    |        |   |__email
    |        |        |__email_confirmation_message.txt
    |        |__registration
    |            |__password_reset_email.html
    |
    ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's see in the last section how we can modify some of the default variables used in the templates.&lt;/p&gt;

&lt;h3&gt;
  
  
  Customize variables used in the templates
&lt;/h3&gt;

&lt;p&gt;Let's think about this example: What if you want to modify the URL sent by default in the reset password email template? Well, Django allows you to define variables to be used in the templates by creating your own template tags. The first thing you need to do is define the custom value desired for the URL in your settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Your settings file
&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;CUSTOM_PASSWORD_RESET_CONFIRM&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'desired URL'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then you have to create two files under &lt;code&gt;myapp/templatetags/&lt;/code&gt;: One has to be an empty &lt;code&gt;__init__.py&lt;/code&gt; file, and the other one registers and gets the tags. Let's call it &lt;code&gt;password_reset_template_load.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;template&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.conf&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;

&lt;span class="n"&gt;register&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Library&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;register&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;simple_tag&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_settings_var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, go to your customized email template that you have created to overwrite the default one, and load the defined value by adding &lt;code&gt;{% load password_reset_template_load %}&lt;/code&gt; at the top of the file, and after that add the line that has the custom value (in this particular case don't forget the &lt;code&gt;uid&lt;/code&gt; and &lt;code&gt;token&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;// Your template {% load password_reset_template_load %} ... {% get_settings_var
'CUSTOM_PASSWORD_RESET_CONFIRM' %}?uidb64={{ uid }}&lt;span class="err"&gt;&amp;amp;&lt;/span&gt;token={{ token }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With these settings you have defined your custom template tags. I'm going to show you the final project structure with all the customization that I talked about:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;root-project-folder
    |__myapp
    |    |__templates
    |    |   |__account
    |    |   |   |__email
    |    |   |        |__email_confirmation_message.txt
    |    |   |__registration
    |    |       |__password_reset_email.html
    |    |__templatetags
    |        |__password_reset_template_load.py
    ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From now on, the email for password reset will show a customized URL. Remember that this was an example, you can create any template tag you want and use it in any template you have.&lt;/p&gt;

&lt;h4&gt;
  
  
  Notes
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;If while trying this you have an error that shows &lt;code&gt;Site matching query does not exist.&lt;/code&gt;, you can solve it by adding &lt;code&gt;SITE_ID = 1&lt;/code&gt; to your settings.&lt;/li&gt;
&lt;li&gt;When you create your own templatetags make sure that the main app is added in the &lt;code&gt;INSTALLED_APPS&lt;/code&gt; list in your settings.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;I have presented a very useful package to handle registration and authentication with a set of REST API endpoints.&lt;br&gt;
With minimal configuration, you can add endpoints to your Django app that already have those features implemented. We reviewed some advantages of the package, how easy it is to customize it, and code snippet examples.&lt;br&gt;&lt;br&gt;
In addition to this, I have shown you how to implement email validation at sign-up, and how to customize the emails that are sent by your app. We learned about the reset password functionality, and finally how to customize the templates with your own desired values. I recommend using the presented package because it solves lots of common problems and provides a set of features that are very important for most applications. Maybe in the future, you can not only use it but also contribute to it.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Managing Drip Campaigns with Rootstrap Django Drip Library</title>
      <dc:creator>brunomichetti</dc:creator>
      <pubDate>Wed, 28 Oct 2020 19:26:06 +0000</pubDate>
      <link>https://dev.to/rootstrap/managing-drip-campaigns-with-rootstrap-django-drip-library-381e</link>
      <guid>https://dev.to/rootstrap/managing-drip-campaigns-with-rootstrap-django-drip-library-381e</guid>
      <description>&lt;p&gt;At &lt;a href="https://www.rootstrap.com/"&gt;Rootstrap&lt;/a&gt; we work with many initiatives, one of them is the Open Source one. The main goal in this case, is to analyze, maintain and develop open source software (OSS). In this blog post I'm going to talk about a particular project named Django Drip Campaigns and how was the process of publishing it as a &lt;a href="https://pypi.org/"&gt;pypi&lt;/a&gt; package.&lt;br&gt;&lt;br&gt;
Pypi (that stands for Python Package Index) is a repository of software for the &lt;a href="https://www.python.org/"&gt;Python&lt;/a&gt; programming language that helps us find and install software developed by the Python community. One of our contributions to the OSS community is to publish and maintain the mentioned project and I want to share that experience in this article.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Django Drip Campaigns Project
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://django-drip-campaigns.readthedocs.io/en/latest/"&gt;Django Drip Campaigns Project&lt;/a&gt; is an open source app to create drip campaigns for email using &lt;a href="https://docs.djangoproject.com/en/3.1/ref/contrib/admin/"&gt;Django’s admin&lt;/a&gt; interface and a User queryset. This means that using this app, you are able to easily schedule and send emails to the registered users, creating querysets in a friendly interface.&lt;br&gt;&lt;br&gt;
For example, you can very quickly configure your app to send a periodic email to the users that haven't logged in in a day or more, send a custom email to the users that registered more than a week ago, etc. To do this, you only need to define one or more querysets in the admin page.&lt;br&gt;
If you want to install it and work with it, you can follow the simple steps documented in &lt;a href="https://github.com/rootstrap/django-drip-campaigns"&gt;the github page of Django Drip Campaigns&lt;/a&gt;.&lt;br&gt;&lt;br&gt;
We didn't create this project, we just made a fork of the one written by &lt;a href="https://zapier.com/z/qO/"&gt;Zapier&lt;/a&gt; that is no longer maintained. After this, we worked on fixing some bugs, doing a couple of enhancements, creating more documentation and publishing the app as a &lt;a href="https://pypi.org/project/django-drip-campaigns/"&gt;pypi package&lt;/a&gt;.&lt;br&gt;&lt;br&gt;
Since it's published, any programmer that wants to use this project in his django app is able to quickly download it with a simple command described in the mentioned docs.&lt;/p&gt;
&lt;h3&gt;
  
  
  Features
&lt;/h3&gt;

&lt;p&gt;After a successful installation and configuration, you are able to easily create drip campaigns for email using the admin interface of Django. If you don't have an admin user, create one with the &lt;a href="https://docs.djangoproject.com/en/3.0/intro/tutorial02/#creating-an-admin-user"&gt;django createsuperuser command&lt;/a&gt;. After this, login into Django's admin page and click on &lt;code&gt;Drips&lt;/code&gt; to manage them. There you are able to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;View created and sent drips.&lt;/li&gt;
&lt;li&gt;Create a new drip.&lt;/li&gt;
&lt;li&gt;Select and delete drips.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  Creating a new drip
&lt;/h4&gt;

&lt;p&gt;Click on the &lt;code&gt;ADD DRIP +&lt;/code&gt; button to create a new drip. You will see a page like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_RrWpmHE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/7ut6rq24ewoqom1qxy6g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_RrWpmHE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/7ut6rq24ewoqom1qxy6g.png" alt="Add drip"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the next section I will talk about the queryset rules that you can build in an easy way to create very useful drips.&lt;/p&gt;
&lt;h4&gt;
  
  
  Queryset rules
&lt;/h4&gt;

&lt;p&gt;When you create a drip, you need at least one queryset so the users in it will be the ones that receive the defined email. In the &lt;code&gt;METHOD TYPE&lt;/code&gt; menu you are able to choose to filter or to exclude the users in the defined queryset.&lt;br&gt;&lt;br&gt;
On the other hand, when you click in the &lt;code&gt;FIELD NAME OF USER&lt;/code&gt; input, you will see the fields of your User model, and the fields of your user model in the models related to it:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zD0zld0v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/mof5vrk84rvs30vfc0vo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zD0zld0v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/mof5vrk84rvs30vfc0vo.png" alt="Look Up Fields"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the previous image, for example, &lt;code&gt;last_login&lt;/code&gt; is the field in the User model, and &lt;code&gt;groups__user__id&lt;/code&gt; is the user id from the Groups model that is related to it. So you can enter the name of the field or select it from the list that you see when you click on the input.&lt;br&gt;&lt;br&gt;
After the selection of the field name, you have to choose the type of lookup that you want to do over the field. The possibilities are &lt;code&gt;exactly&lt;/code&gt;, &lt;code&gt;exactly (case insensitive)&lt;/code&gt;, &lt;code&gt;contains&lt;/code&gt;, &lt;code&gt;contains (case insensitive)&lt;/code&gt;, &lt;code&gt;greater than&lt;/code&gt;, &lt;code&gt;greater than or equal to&lt;/code&gt;, &lt;code&gt;less than&lt;/code&gt;, etc. This lookup type will be done over the user field and the &lt;code&gt;FIELD VALUE&lt;/code&gt; that you enter.&lt;br&gt;&lt;br&gt;
The &lt;code&gt;FIELD VALUE&lt;/code&gt; input can be a string, a number, or a regular expression. The correctness of the queryset rule will depend on the type of the user field, the lookup type, and the field value.&lt;br&gt;&lt;br&gt;
When you enter a user field that has a date type, Django Drip Campaigns allows you to enter a date value in natural language combining the current time and some operation with seconds, hours, days, etc. For example, if you have selected the field &lt;code&gt;last_login&lt;/code&gt; that has a date type, and you want to create a drip to send emails to the users who logged in exactly one week ago; you can enter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;now-1 week
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;now- 1 w
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Possible operations and values:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add (&lt;code&gt;+&lt;/code&gt;) or subtract (&lt;code&gt;-&lt;/code&gt;) dates.&lt;/li&gt;
&lt;li&gt;On the left side of the operation, write the current datetime value: &lt;code&gt;now&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;On the right side of the operation:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;seconds&lt;/code&gt; or &lt;code&gt;s&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;minutes&lt;/code&gt; or &lt;code&gt;m&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;hours&lt;/code&gt; or &lt;code&gt;h&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;days&lt;/code&gt; or &lt;code&gt;d&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;weeks&lt;/code&gt; or &lt;code&gt;w&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If you enter the number &lt;code&gt;1&lt;/code&gt;, you can write &lt;code&gt;second&lt;/code&gt;, &lt;code&gt;minute&lt;/code&gt;, etc.&lt;/li&gt;
&lt;li&gt;Don't enter a space between &lt;code&gt;now&lt;/code&gt; and the operation symbol. Optionally you can add (or not) a space around the number value.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's see some examples of the date values that you can enter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;now-1 day&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;now+ 8days&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;now+ 1 h&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;now-4hours&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;now- 3 weeks&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;now-1 weeks&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To finalize this subsection, I would like to show you two examples to clarify the queryset rules creation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Send a recordatory email to the users that haven't logged in for a week or more:

&lt;ul&gt;
&lt;li&gt;method type: &lt;code&gt;filter&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;user field: &lt;code&gt;last_login&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;lookup type: &lt;code&gt;less than or equal to&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;field value: &lt;code&gt;now- 1 week&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Send an email to the users that have a gmail account, excluding the ones that registered yesterday:

&lt;ul&gt;
&lt;li&gt;Rule 1:&lt;/li&gt;
&lt;li&gt;method type: &lt;code&gt;filter&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;user field: &lt;code&gt;email&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;lookup type: &lt;code&gt;contains&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;field value: &lt;code&gt;gmail&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Rule 2:&lt;/li&gt;
&lt;li&gt;method type: &lt;code&gt;exclude&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;user field: &lt;code&gt;date_joined&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;lookup type: &lt;code&gt;exactly&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;field value: &lt;code&gt;now- 1 d&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you can see, the queryset rules creation is very powerful and for each drip you can add as many as you want.&lt;/p&gt;

&lt;h4&gt;
  
  
  View the timeline of a drip
&lt;/h4&gt;

&lt;p&gt;In the django admin, you can select a drip and then click on the &lt;code&gt;VIEW TIMELINE&lt;/code&gt; button to view the emails expected to be sent with the corresponding receivers:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZPKTMXPm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/oj8zd5wrg2jwb9untbvs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZPKTMXPm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/oj8zd5wrg2jwb9untbvs.png" alt="TimeLine"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Message class
&lt;/h4&gt;

&lt;p&gt;By default, Django Drip creates and sends messages that are instances of Django’s &lt;code&gt;EmailMultiAlternatives&lt;/code&gt; class. If you want to customize in any way the message that is created and sent, you can do that by creating a subclass of &lt;code&gt;EmailMessage&lt;/code&gt; and overriding any method that you want to behave differently. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.core.mail&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;EmailMessage&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;drip.drips&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DripMessage&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PlainDripEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DripMessage&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;property&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;EmailMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_message&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In that example, &lt;code&gt;PlainDripEmail&lt;/code&gt; overrides the message property of the base &lt;code&gt;DripMessage&lt;/code&gt; class to create a simple &lt;code&gt;EmailMessage&lt;/code&gt; instance instead of an &lt;code&gt;EmailMultiAlternatives&lt;/code&gt; instance.&lt;/p&gt;

&lt;p&gt;In order to be able to specify that your custom message class should be used for a drip, you need to configure it in the &lt;code&gt;DRIP_MESSAGE_CLASSES&lt;/code&gt; setting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;DRIP_MESSAGE_CLASSES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;'plain'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'myproj.email.PlainDripEmail'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will allow you to choose in the admin, for each drip, whether the &lt;code&gt;default&lt;/code&gt; (&lt;code&gt;DripMessage&lt;/code&gt;) or &lt;code&gt;plain&lt;/code&gt; message class should be used for generating and sending the messages to users.&lt;/p&gt;

&lt;h4&gt;
  
  
  Send drips
&lt;/h4&gt;

&lt;p&gt;To send the created and enabled drips, run the command:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;You can use cron to schedule the drips.&lt;/p&gt;

&lt;h3&gt;
  
  
  What we have been doing in the project
&lt;/h3&gt;

&lt;p&gt;As I said, we didn't create this project. We forked it and started to make some fixes and improvements. The first thing we did was to upgrade the used Django version. Now it has django 3.0.7.&lt;br&gt;&lt;br&gt;
Besides we started to create the documentation with &lt;a href="https://www.sphinx-doc.org/en/master/"&gt;Sphinx&lt;/a&gt; to have this project in &lt;a href="https://readthedocs.org/"&gt;Read the Docs&lt;/a&gt; in the future.&lt;br&gt;&lt;br&gt;
Another enhancement was to add &lt;a href="https://flake8.pycqa.org/en/latest/"&gt;flake8&lt;/a&gt; to enforce the use of style guides in the code. Finally we added an integration with &lt;a href="https://travis-ci.com/"&gt;travis-ci&lt;/a&gt; to have a continuous integration service on any change in the project.&lt;br&gt;&lt;br&gt;
We registered and fixed some issues such as the view of the User fields, and configuration problems to run the app locally. There are some issues to address and discover yet so if you like OSS you are more than welcome to work with Django Drip Campaigns.&lt;br&gt;&lt;br&gt;
In the open source initiative we wanted to publish this app as a pypi package, so I'll explain this a little more in the next section.&lt;/p&gt;
&lt;h3&gt;
  
  
  Publish a pypi package
&lt;/h3&gt;

&lt;p&gt;Despite Django Drip Campaigns is still a work in progress, we already published the package in PyPI. It's nothing fancy, but it's a must to know a few things before starting, so in this section, I'll be talking about the main steps for publishing an app.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Project structure: Your project needs a couple of files in a determined place to be published correctly. An appropriate structure could be:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;root_project_folder/
  |
  |__ docs/    # Documentation files
  |__ project_folder/  # Code of the app
  |__ AUTHORS.md
  |__ LICENSE.txt
  |__ MANIFEST.in
  |__ README.md
  |__ setup.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;&lt;p&gt;AUTHORS: Specify the author's information of your project in this file.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;LICENSE: You have to specify the license of the project. That is a document that provides legally binding guidelines for the use and distribution of software. In OSS the most known are &lt;a href="https://en.wikipedia.org/wiki/BSD_licenses"&gt;BSD&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/MIT_License"&gt;MIT&lt;/a&gt;. We used an MIT license in this case.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;MANIFEST: Here you can specify the files that aren't programming files but you want to include anyway in the build of your project. For example the authors file, the docs, etc.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;README.md: A file where you introduce and explain your project. It's very important because otherwise you can have a very good and useful project but if new people see it and don't understand what it does nor how it works, then it won't be used.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;setup.py: This is a fundamental file. It contains a global &lt;code&gt;setup&lt;/code&gt; function that is in charge of the building and configuration of your project at the moment of the installation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;docs folder: Here is where the files of the documentation are.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can see examples of the described files in the &lt;a href="https://github.com/rootstrap/django-drip-campaigns"&gt;django-drip-campaigns github page&lt;/a&gt;. Of course your project can have other files, the ones mentioned are the most important to publish a pypi package.&lt;br&gt;&lt;br&gt;
Having all set and ready to be published, you need now to &lt;a href="https://pypi.org/account/register/"&gt;register in the pypi.org page&lt;/a&gt;. After you are registered, go inside the terminal to your project folder and follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install &lt;code&gt;setuptools&lt;/code&gt; and &lt;code&gt;wheel&lt;/code&gt;. They are used to generate the distribution package: a group of files needed to upload your app.
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3 -m pip install --user --upgrade setuptools wheel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Generate the distribution package. The next command will create all the necessary files under a &lt;code&gt;dist/&lt;/code&gt; folder:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3 setup.py sdist bdist_wheel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Install &lt;a href="https://packaging.python.org/key_projects/#twine"&gt;twine&lt;/a&gt;, that a allows you to upload your app as a package:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3 -m pip install --user --upgrade twine
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Once installed, run twine to upload the archives under &lt;code&gt;dist/&lt;/code&gt;. This will ask for a user and a password, that are the ones you used on the registration at pypi:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3 -m twine upload --repository pypi dist/*
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If everything went well, you have published your project as a pypi package. Now you anyone is able to download it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip3 install &amp;lt;project-name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;In this blog post I talked about the Django Drip Campaigns project, its main features and what we did with it at Rootstrap. We love to make contributions to OSS because it's a wonderful way of learning, of sharing knowledge, and creating useful programs to be used by other programmers.&lt;br&gt;&lt;br&gt;
Besides I talked about the experience and how to publish a project as a pypi package so anyone who wants to give it a try can download it with a simple command.&lt;br&gt;&lt;br&gt;
OSS gives a great opportunity not only to see how some other group of people solves a problem addressed by the program, but also to purpose and contribute with fixes and improvements. Finally, I hope you have enjoyed this blog and feel motivated to use and work with Django Drip Campaigns and to contribute with OSS.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>A prediction experiment with Machine Learning</title>
      <dc:creator>brunomichetti</dc:creator>
      <pubDate>Mon, 28 Sep 2020 21:38:29 +0000</pubDate>
      <link>https://dev.to/rootstrap/a-prediction-experiment-with-machine-learning-333a</link>
      <guid>https://dev.to/rootstrap/a-prediction-experiment-with-machine-learning-333a</guid>
      <description>&lt;p&gt;I recently participated in a Machine Learning workshop at Rootstrap, where my coworkers and I learned about the basics of data science, did some research, and created interesting experiments. We had the opportunity to choose among the studied Machine Learning algorithms and work with them. So, I decided to do an experiment where a mathematical model predicts the life expectancy of a country. That is, given some data of a given country, we can make a prediction of its life expectancy in a determined year. The experiment was made in a &lt;a href="https://jupyter.org/"&gt;jupyter notebook&lt;/a&gt;, using the &lt;a href="https://www.python.org/"&gt;python programming language&lt;/a&gt;, and the &lt;a href="https://scikit-learn.org/stable/"&gt;scikit learn library&lt;/a&gt;. In this blog, I’m going to talk about my experience and explain a little bit about the work I did and the new things that I have learned.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prediction in Machine Learning
&lt;/h3&gt;

&lt;p&gt;The word prediction in machine learning refers to the output of a trained model, representing the most likely value that will be obtained for a given input. The model is trained with historical data, and then predicts a selected property of the data for new inputs.&lt;br&gt;
Prediction is used in lots of different areas, since it allows us to make highly accurate guesses about many things, such as predicting what the stock markets will do on any given day, predict results in sports, or even help the medical industry predict diseases.&lt;br&gt;
The algorithms for prediction are classified as supervised learning algorithms since they need a training dataset with correct examples to learn from them. This means that the first thing I had to do to start the experiment was finding a dataset, which contains information about countries, including, of course, their life expectancy.&lt;/p&gt;
&lt;h3&gt;
  
  
  The dataset
&lt;/h3&gt;

&lt;p&gt;I used a public dataset of Life expectancy from kaggle to train the model. It comes from a statistical analysis of the factors that might influence the life expectancy of a country. The dataset is a big table containing information about each country, and several factors over several years. The years are from 2000 to 2015, and some of the factors are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Adult Mortality: Adult mortality rates of both sexes (probability of dying between 15 and 60 years per 1000 population).&lt;/li&gt;
&lt;li&gt;infant deaths: Number of infant deaths per 1000 population.
Alcohol: Alcohol, recorded per capita (15+) consumption (in liters of pure alcohol).&lt;/li&gt;
&lt;li&gt;Hepatitis B: Hepatitis B immunization coverage among 1-year-olds (%).&lt;/li&gt;
&lt;li&gt;Under-five deaths: Number of under-five deaths per 1000 population.&lt;/li&gt;
&lt;li&gt;Polio: Polio (Pol3) immunization coverage among 1-year-olds (%).&lt;/li&gt;
&lt;li&gt;Total expenditure: General government expenditure on health as a percentage of total government expenditure (%).&lt;/li&gt;
&lt;li&gt;Population: Population of the country.&lt;/li&gt;
&lt;li&gt;Income composition of resources: Human development index in terms of income composition of resources (index ranging from 0 to 1).&lt;/li&gt;
&lt;li&gt;Schooling: Number of years of schooling (years).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This dataset has 22 columns and 2,938 rows of data. I needed to preprocess the data before training the model. Why did I need that? because when we work in machine learning, we can hardly use the data in the way we get it. First, we need to solve consistency problems, prepare the data for the format and type that the model expects, and remove useless information, etc. If we don’t address those problems, we can’t affirm that the result of the algorithm achieves the main goal. For example, some of the problems could be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Missing data.&lt;/li&gt;
&lt;li&gt;Work with different types of data.&lt;/li&gt;
&lt;li&gt;Work with different formats of data.&lt;/li&gt;
&lt;li&gt;Properties of the data with null values.&lt;/li&gt;
&lt;li&gt;The data format is different from the one that the algorithm expects.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the next section, I talk about the problems I had to face, and how they can be solved.&lt;/p&gt;
&lt;h3&gt;
  
  
  Preprocessing the dataset
&lt;/h3&gt;

&lt;p&gt;The process of applying the necessary transformations to the data in order to prepare it for the model is called data cleaning. There are several kinds of problems addressed in data cleaning, the ones that I faced are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Null values: some of the rows in the dataset had null values, and given that machine learning models are mathematical models, they can’t work with that kind of input.&lt;/li&gt;
&lt;li&gt;Unnormalized data: some machine learning models don't work well if they have variables that have many different ranges of values.&lt;/li&gt;
&lt;li&gt;Problems with types: I needed to solve how to pass to a mathematical model, values that weren’t numbered, for example, a categorical variable.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this section, I talk about some approaches to solve those problems.&lt;/p&gt;
&lt;h4&gt;
  
  
  Null values
&lt;/h4&gt;

&lt;p&gt;When a row has empty spaces, that is null values in the dataset, we can delete that row, or fill those empty spaces with data. I didn’t choose to delete the rows, because I would lose a big part of the dataset, and models don’t work well if they are trained with small datasets or I might be removing relevant information. So I decided to fill the null values. To do this, there are many techniques. For example, choosing a default value, or “simulating a distribution of the data” and selecting a value of that simulation. I chose the second example because using the simulation I’m able to generate numbers similar to the real values. I’ll explain a little bit the method in the next section.&lt;/p&gt;
&lt;h4&gt;
  
  
  Simulate a probability distribution
&lt;/h4&gt;

&lt;p&gt;A random variable is a quantity that is produced by a random process. Besides, a probability distribution is a summary of probabilities for the values of a random variable. Knowing this, we can select a column of the dataset that has null values, and simulate its probability distribution. After this, we can randomly select a value in order to fill the null values affecting our dataset. So for each column in the dataset that has some null values, I executed these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Plot a histogram of the column using the &lt;a href="https://matplotlib.org/api/_as_gen/matplotlib.pyplot.hist.html"&gt;hist function in python&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Compare the histogram with the graph of known distributions: normal, truncated normal, uniform, exponential, etc.&lt;/li&gt;
&lt;li&gt;Select the probability distribution that has the most similar graph to the histogram.&lt;/li&gt;
&lt;li&gt;Simulate the selected probability distribution.&lt;/li&gt;
&lt;li&gt;For each null value in the column, fill it randomly choosing a value from the simulation.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here we can see a comparison with a histogram of a column in the dataset, and the selected probability distribution simulation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WXMyLFHe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/cr9lxm5rklt61pwfejd0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WXMyLFHe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/cr9lxm5rklt61pwfejd0.png" alt="Exp comparison"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this case, the histogram from the original data is similar to an exponential distribution. Thus, the simulation was done using an exponential distribution with the scale and size parameters taken from the original data. Another example:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--t-Q_OfGP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/g96vtn6wsq1m5sxcekj7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--t-Q_OfGP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/g96vtn6wsq1m5sxcekj7.png" alt="Normal comparison"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this second example, the histogram of the original data is very similar to a normal distribution. In an analogous way, I have simulated a normal distribution with parameters taken from the original data.&lt;/p&gt;

&lt;p&gt;In the case that the histogram does not resemble any probability distribution, we can divide the mentioned histogram into intervals (looking at the graph) and approximate a probability for each one. After this, we can create a function that returns a random value of an interval, selecting it with the probabilities set. Here is an example of this case:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JMwpvT5y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/1fkstikbaxfcvp2nslse.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JMwpvT5y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/1fkstikbaxfcvp2nslse.png" alt="No distribution"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And the definition of the probabilities set is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Simulate ranges
ranges_list = [
    range(1,10),
    range(10, 40),
    range(40, 60),
    range(60, 70),
    range(70, 80),
    range(80, 90),
    range(90, 100)
]
probs = [0.05, 0.02, 0.03, 0.05, 0.1, 0.2, 0.55]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After those definitions, I created a function that gets one interval from the &lt;code&gt;ranges_list&lt;/code&gt; according to the probabilities set and returns a randomly selected value within that interval. That value is the one that fills the empty space.&lt;/p&gt;

&lt;h4&gt;
  
  
  One hot-encoding
&lt;/h4&gt;

&lt;p&gt;As I said, mathematical models need to work with numbers. In the dataset, I had some data that took values from a set of words, such as the country column. I needed to map each country's name to a number. But if I did that, it could have happened that the model gave more importance to a country for having a larger number. The solution to this problem is to use other techniques such as one hot-encoding: generate a new column for each country name, and put 1 if the country row has that name, and 0 if not. Here is a simple example:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qE5ZqT6O--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/4usb9bnjh2zqbjvltz5b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qE5ZqT6O--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/4usb9bnjh2zqbjvltz5b.png" alt="One-hot enconding"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the end, I could have deleted one column of the countries, knowing that if a row has 0 in all the countries’ columns, that means that the row has the missing country name. It’s a good way to optimize the amount of data that I work with. I didn't do that because I wanted to have all the countries for better understanding of the results.&lt;/p&gt;

&lt;h4&gt;
  
  
  Split and normalize the dataset
&lt;/h4&gt;

&lt;p&gt;Supervised learning algorithms need a train dataset to learn from it. Besides, it needs another dataset different from the train dataset, to check if the model has learned correctly. The second one is named test dataset. I only had one dataset, so I had to split it. The scikit learn library provides us with the split function, called &lt;a href="https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.train_test_split.html"&gt;train_test_split&lt;/a&gt;. With this, we can get two datasets from the original one. Generally, the split is 80% train and 20% test.&lt;br&gt;
On the other hand, when the features in the dataset have different range values, we need to normalize them. If we have a column in the dataset that has values between 0 and 1, and another column that has values between -1000 and 100000, the model can lose information or represent our data in an incorrect way. There are different scalers in scikit learn library, I used the &lt;a href="https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.MinMaxScaler.html"&gt;MinMaxScaler&lt;/a&gt; that scales all the values in a range between two values. With that class, I created two kinds of scalers: one for the target variable (the life expectancy) and other for the rest of the features. Doing this separation of scalers, I am able to use the first scaler to convert the results to the original range, and compare that with the original values from the testing data.&lt;/p&gt;

&lt;h3&gt;
  
  
  The models
&lt;/h3&gt;

&lt;p&gt;In statistics, there is a kind of process named regression analysis. The processes of this kind are used to estimate the relationship of one variable (often called the target variable), with one or more other variables (often called features, or predictors). This is what I did in the experiment, considering the life expectancy column in the dataset as the target variable, and the rest of the columns as the predictors.&lt;br&gt;
The scikit learn library provides us with lots of machine learning models already implemented, and among them, the regressors. In this section, I’m going to give a general idea of the used models in the experiment.&lt;/p&gt;

&lt;h4&gt;
  
  
  Linear Regression
&lt;/h4&gt;

&lt;p&gt;In linear regression, the relationship between the target variable and the predictors is modeled using a linear function:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Y5DE3Fj0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/7hv2o5za4fcb4yzp65io.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Y5DE3Fj0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/7hv2o5za4fcb4yzp65io.png" alt="Regression"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The main goal is to find the unknown coefficients, which are estimated from the data. That’s why prediction is a supervised learning algorithm. I used a linear regression with two regularization methods: Lasso and Ridge Regression.&lt;br&gt;
On one hand, the LASSO (Least Absolute Shrinkage and Selection Operator) regression is a process that uses shrinkage. Shrinkage is where data values are shrunk towards a central point, like the mean. Lasso regression performs L1 regularization, which adds a penalty equal to the absolute value of the magnitude of coefficients. Some coefficients can become zero and have been eliminated from the model, something very useful when we have lots of parameters. As I said, I used the &lt;a href="https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.Lasso.html"&gt;implementation of Lasso from scikit learn&lt;/a&gt;. With this python class, we can use the fit function to train the model with the preprocessed and scaled dataset, and then use the predict function with new inputs to obtain the prediction of the life expectancy.&lt;br&gt;
On the other hand, the Ridge regression performs L2 regularization, that is, a penalty using the Euclidean norm. Generally, this algorithm reduces the coefficients but doesn't eliminate them. It’s good to use this type of model when we have overfitting problems. As the Lasso regression, scikit learn provides also a &lt;a href="https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.Ridge.html"&gt;python class for Ridge regression&lt;/a&gt;, with the fit and predict functions.&lt;/p&gt;

&lt;h4&gt;
  
  
  Decision trees
&lt;/h4&gt;

&lt;p&gt;In regression, a decision tree is a type of model that builds a regression in the form of a tree structure. It breaks down the dataset into smaller subsets while at the same time develops an associated decision tree. In that tree, the leaf nodes are results, and the other nodes are decisions.&lt;br&gt;
In the experiment, I used the Random Forest model, which builds several decision trees (that is why it is called forest) and then ensembles them. Each tree takes only a random subset of the features and makes the decisions from it. What does “ensembles” mean in machine learning? Well, ensemble methods use multiple learning algorithms to obtain better predictive performance than the one that could be obtained from any of the constituent learning algorithms alone. Random forest it’s also &lt;a href="https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestRegressor.html?highlight=random%20forest%20regressor#sklearn.ensemble.RandomForestRegressor"&gt;implemented in scikit learn&lt;/a&gt; and has the fit and predict functions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Metrics and results
&lt;/h3&gt;

&lt;p&gt;How do we know if the regression model works well? We can use some metrics to analyze that. As I mentioned, it’s a common practice to split the dataset into training and testing datasets. The training dataset it’s used by the model to learn, and the testing dataset it’s used to evaluate the correctness of the resultant model.&lt;br&gt;
How do we do this evaluation? By the moment of the evaluation, we have a trained model, and a testing dataset that has two main parts: a set of instances of the data, let’s say &lt;code&gt;X_test&lt;/code&gt;, and a set of the corresponding correct result for each instance in &lt;code&gt;X_test&lt;/code&gt;, let’s call it &lt;code&gt;Y_test&lt;/code&gt;. A good way to measure how well our model works is by applying the predict function on &lt;code&gt;X_test&lt;/code&gt;, and comparing that result with the correct one (&lt;code&gt;Y_test&lt;/code&gt;). To make the comparison we have a couple of metrics that we can use:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9mY0Atk_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/7qq3mib6iguj2nsj49lj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9mY0Atk_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/7qq3mib6iguj2nsj49lj.png" alt="Errors definitions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can figure out, the closer to 0, the better results.&lt;br&gt;
In the experiment I used R-squared, Mean squared, and Root mean squared error. For each trained model, I did a measurement of those errors, and also, I used the created scalers for the target variable to scale back the result and compare the values in the original range. In these tables you can see the results of each model:&lt;/p&gt;

&lt;p&gt;Results with scaled data&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--40OfLt3b--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/pu63vjf8xeu9g24p2vr3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--40OfLt3b--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/pu63vjf8xeu9g24p2vr3.png" alt="Scaled data results"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Results in the original range&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BAyMZZYO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/jblyikj4j1fr4m7rwnr8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BAyMZZYO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/jblyikj4j1fr4m7rwnr8.png" alt="Original range"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The conclusion is that Ridge and Random Forest regression work better than Lasso for this dataset, given that the errors are closer to 0. Besides, scaling back and comparing in the original range, we saw that the error in those cases are both approximately 2 years, a good threshold to predict life expectancy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;In this blog I talked about a prediction experiment with machine learning. It was very interesting to me and I learned a lot. I hope that at this point you enjoyed your reading, and understood the main ideas of the general process of prediction. Also, I mentioned important concepts of machine learning such as supervised learning, preprocessing the data, training and testing the models, etc. We saw some of the most used models in regression, and a way to evaluate them in order to see how well they are working. Finally, after reading this blog I hope that you feel inspired to work with machine learning because it’s fun and helps us solve lots of amazing and interesting problems.&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>python</category>
      <category>jupyter</category>
    </item>
    <item>
      <title>A quick classification experiment using machine learning</title>
      <dc:creator>brunomichetti</dc:creator>
      <pubDate>Mon, 28 Sep 2020 21:27:00 +0000</pubDate>
      <link>https://dev.to/rootstrap/a-quick-classification-experiment-using-machine-learning-36e4</link>
      <guid>https://dev.to/rootstrap/a-quick-classification-experiment-using-machine-learning-36e4</guid>
      <description>&lt;p&gt;My team recently faced a brand new challenge: developing a way to classify job positions written in natural language by lots of different people. It sounds simple, but there are a few factors that made this problem hard to solve. Job positions can be ambiguous depending on language usage and new job positions appear all the time. &lt;/p&gt;

&lt;p&gt;The set of possible positions we needed to classify is extremely wide. A few quick examples: Digital Marketing, Public Relations, Founder and Inventor of X. Creating a program with enough "if" statements to accurately analyze job positions and classify them based on the words they contain would be almost impossible. Besides that, the appearance of new job positions not yet entered into our program would cause the classifier to fail frequently. &lt;/p&gt;

&lt;p&gt;But what if it was possible to train a program about the nature of different job positions to face new job titles and classify them accordingly? Well, it is. And that’s where machine learning comes into play. &lt;/p&gt;

&lt;h3&gt;
  
  
  The classification problem
&lt;/h3&gt;

&lt;p&gt;The problem we faced is easy to explain: classify job positions by areas and levels. Given a set of classes, we needed to build a classifier that has a job position as the input, and the corresponding class as the output. Because we need to use two different criteria for accurate classification of job positions, we needed to create two classifiers: one for the area and one for level. For example, if an area classifier receives "CEO and Founder," it has to return the “Business” class, and the level classifier needs to return the “C-Suite” class. &lt;/p&gt;

&lt;p&gt;The problem is simple, but the solution is not. We knew machine learning was frequently used for applications like this and started searching for the tools we’d need to create our program.&lt;/p&gt;

&lt;h3&gt;
  
  
  Applying machine learning
&lt;/h3&gt;

&lt;p&gt;Machine learning focuses on the development of computer programs that can use data to learn on their own. The difference between this and regular programs that execute prespecified instructions is that machine learning algorithms can use previous experience to face new incoming data and act accordingly. &lt;/p&gt;

&lt;p&gt;This means that machine learning programs learn using the data we provide them. A real-world example of this can be seen in this excerpt taken from "&lt;a href="https://www.cs.huji.ac.il/~shais/UnderstandingMachineLearning/understanding-machine-learning-theory-algorithms.pdf"&gt;Understanding Machine Learning: From Theory to Algorithms&lt;/a&gt;." &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Rats Learning to Avoid Poisonous Baits&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;"&lt;em&gt;When rats encounter food items with novel look or smell, they will first eat very small amounts, and subsequent feeding will depend on the flavor of the food and its physiological effect. If the food produces an ill effect, the novel food will often be associated with the illness, and subsequently, the rats will not eat it. Clearly, there is a learning mechanism in play here – the animal used past experience with some food to acquire expertise in detecting the safety of this food. If past experience with the food was negatively labeled, the animal predicts that it will also have a negative effect when encountered in the future.&lt;/em&gt;"&lt;/p&gt;

&lt;h4&gt;
  
  
  Supervised learning
&lt;/h4&gt;

&lt;p&gt;Supervised learning is a subset of machine learning where we provide the algorithms with "labeled data." This means a dataset filled with correct examples is used to construct the mathematical model that the algorithm uses to classify job titles. In this particular case, the algorithm needs a set with elements in the form: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;example job position&amp;gt;, &amp;lt;corresponding classification&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;But what does learning mean in this scenario? The main concept here is that machine learning algorithms represent their knowledge of a problem using a mathematical model. They choose initial values for the model’s parameters, process the dataset, compare it with the correct results, and then go back to further refine the parameters. &lt;/p&gt;

&lt;p&gt;This process is repeated until the algorithms obtain the parameters that best fit the correct dataset. &lt;/p&gt;

&lt;h4&gt;
  
  
  Scikit learn
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://scikit-learn.org/stable/index.html"&gt;Scikit-learn&lt;/a&gt; is a great resource to work with for any machine learning project. It’s an open-source library coded in &lt;a href="https://www.python.org/"&gt;Python&lt;/a&gt; with lots of tools for predictive data analysis. It has far too many functions to cover in a single article, but we recommend clicking over and having a look if this sort of thing piques your interest. "&lt;a href="https://scikit-learn.org/stable/tutorial/text_analytics/working_with_text_data.html"&gt;Working With Text Data&lt;/a&gt;" was one of the examples we found particularly valuable for our machine learning application. &lt;/p&gt;

&lt;h4&gt;
  
  
  Selected classes
&lt;/h4&gt;

&lt;p&gt;Our team tested two classes from Scikit learn: &lt;a href="https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.SGDClassifier.html?highlight=sgdclassifier#sklearn.linear_model.SGDClassifier"&gt;SGDClassifier&lt;/a&gt; and &lt;a href="https://scikit-learn.org/stable/modules/generated/sklearn.neural_network.MLPClassifier.html?highlight=mlp#sklearn.neural_network.MLPClassifier"&gt;MLPClassifier&lt;/a&gt;. Classification algorithms try to minimize the cost of errors from a loss function during training. &lt;/p&gt;

&lt;p&gt;The SGDClassifier class uses linear classifiers, minimizing the loss function using the Stochastic Gradient Descent training method. That’s where this class gets its name, and the methodology behind it is to iterate through data using a gradient of the function to achieve the minimum cost of errors. &lt;/p&gt;

&lt;p&gt;The MLPClassifier is an abbreviation of a neural network called Multi-Layer Perceptron. Neural networks are quite complex and out of this article’s scope. What you need to know is that both classes represent supervised learning algorithms and follow the same overall construction process. &lt;/p&gt;

&lt;h3&gt;
  
  
  General working process
&lt;/h3&gt;

&lt;p&gt;Scikit-learn allows us to build classifiers and measure their results. With the tools provided by the Scikit library, it’s possible to solve this problem in a few ways. Here’s the overall framework we followed:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Create the dataset&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Split the dataset&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Represent documents as vectors of real numbers&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fit and tune the classifier &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Many different learning algorithms can be used as classifiers. The implementation might be slightly different depending on the tool, but this general process is the same for most classification problems. &lt;/p&gt;

&lt;h4&gt;
  
  
  Create the dataset
&lt;/h4&gt;

&lt;p&gt;Supervised learning requires a dataset with correctly classified examples. The first step is creating this dataset. It’s made by humans, and there’s no way around it. It’s boring but fundamental. Since the dataset will be used by the algorithm to train and adjust the mathematical model, it’s important to make sure all of the examples are correctly classified. &lt;/p&gt;

&lt;p&gt;The size of the example dataset required to train the model depends on the problem. It’s vital to have a representative dataset for each possible classification. For example, if we wanted to create a classifier that receives an image of a pet and classifies that as a dog, cat, or other, we would need a representative dataset containing several examples with a wide variety of cat images, dog images, and other pet images. &lt;/p&gt;

&lt;h4&gt;
  
  
  Split the dataset
&lt;/h4&gt;

&lt;p&gt;After constructing the classifier, we need to validate that it’s working properly. To do this, a testing set is required. Note that you can’t use the same dataset for training and testing. The testing process has to be conducted using a set unknown to the classifier. That ensures the classifier works as expected with new, incoming data. &lt;/p&gt;

&lt;p&gt;We need to split the dataset into two sets: a training set used for the learning process, and a test set to test how the classifier is working. A general guide is to keep 80% for training and 20% for testing, but there are many different methods to generate this ratio. &lt;/p&gt;

&lt;h4&gt;
  
  
  Represent documents as vectors of real numbers
&lt;/h4&gt;

&lt;p&gt;Because a classifier builds a mathematical model to represent its &lt;em&gt;knowledge&lt;/em&gt; and it’s easier to compute numbers than strings, we have to transform each sentence from a string into vectors of real numbers. This is known as &lt;a href="https://scikit-learn.org/stable/modules/feature_extraction.html#text-feature-extraction"&gt;text feature extraction&lt;/a&gt;. The goal is to extract important information from each document to represent the training and testing sets as a collection of vectors. &lt;/p&gt;

&lt;p&gt;Scikit-learn provides a few functions and classes that can help us with this. The &lt;a href="https://scikit-learn.org/stable/modules/generated/sklearn.feature_extraction.text.CountVectorizer.html?highlight=countvectorizer#sklearn.feature_extraction.text.CountVectorizer"&gt;CountVectorizer&lt;/a&gt; class is used for tokenization and occurrence counting. The tokenization consists of separating the text into a set of its containing words according to a selected separator and the right criteria. Occurrence counting is a technique that creates a vector filled with the number of times each containing word occurs. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://scikit-learn.org/stable/modules/generated/sklearn.feature_extraction.text.TfidfTransformer.html?highlight=tfidf#sklearn.feature_extraction.text.TfidfTransformer"&gt;TfidfTransformer&lt;/a&gt; is another useful class that creates a vector based on the frequency of each word in a document. The main idea is to minimize the impact of frequently occurring words in the English language (the, a, is, etc.) that aren’t important during classification. &lt;/p&gt;

&lt;p&gt;In summary, we need to transform the collection of documents into a set of vectors that we can use to train the classifier’s learning algorithm. There are many ways to go about this, and if you’re interested in learning more, check out the &lt;a href="https://scikit-learn.org/stable/modules/feature_extraction.html?highlight=tfidf"&gt;feature extraction tutorial&lt;/a&gt; Scikit has available. &lt;/p&gt;

&lt;h4&gt;
  
  
  Fit and tune the classifier
&lt;/h4&gt;

&lt;p&gt;This is where the algorithm starts to learn. A supervised learning algorithm has parameters and hyperparameters. The parameters represent the algorithms knowledge and they are adjusted by the algorithm using the training set. An example of a parameter would be the weight selected for a determined input feature. &lt;/p&gt;

&lt;p&gt;The hyperparameters are related to the training process and impact the way the algorithm learns. Some examples of hyperparameters are the maximum number of iterations, the fault tolerance, the number of hidden layers in a neural network, etc. &lt;/p&gt;

&lt;p&gt;The SGDClassifier and MLPClassifier both have a function named fit that chooses the best parameters to fit the training set. However, the hyperparameters are defined by default. We can vary and combine them to optimize our results, but since there are so many possible combinations of these hyperparameters, this process can be quite tedious. Scikit-learn helps us find the most optimal combination of hyperparameters with the &lt;a href="https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.GridSearchCV.html?highlight=gridsearch#sklearn.model_selection.GridSearchCV"&gt;GridSearchCV&lt;/a&gt; class. This class uses a technique called cross-validation while trying all of the provided combinations of hyperparameters and measures the results from part of the training set. This part of the set is named the validation set, and it’s where the class stores the hyperparameter combination that achieves the best results. &lt;/p&gt;

&lt;p&gt;This is the process of tuning a classifier. After this part, we have a classifier instance and we can use the function predict to get the classification of new incoming job positions. &lt;/p&gt;

&lt;h3&gt;
  
  
  How do we know if the classifier is working as expected?
&lt;/h3&gt;

&lt;p&gt;If we want to check on how our classifier is working, it’s time to use the testing set. Several metrics are used in classification problems and Scikit-learn has a few functions to work with them. Our team used a function called metrics. This function compares the classifier’s prediction of the testing set with the correct results and returns metrics that help us define whether or not the classifier is working as expected. We have a prediction for each category of classification, and we focused on some specific metrics returned by the function to gauge the accuracy of our classifier. These metrics are:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lcSccUlt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/vlj6k5nbkx040jaw2bh9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lcSccUlt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/vlj6k5nbkx040jaw2bh9.png" alt="F1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Where tp means true positives, fp = false positives, and fn = false negatives. Precision is the number of elements classified as true positive over the total number of elements classified as positive. &lt;/p&gt;

&lt;p&gt;The recall is the number of correctly classified elements over the total number of truly positive elements. These metrics are taken by the function for each classification category, and they will all output a number between zero and one. The closer to one, the better. We focused on the F score, a harmonic measure between precision and recall. If we get good precision but bad recall, the classifier isn’t working as expected. So, if the F score is close to one, we know our classifier is working accurately. &lt;/p&gt;

&lt;h3&gt;
  
  
  Overfitting and underfitting
&lt;/h3&gt;

&lt;p&gt;There are two common problems in the classification process: overfitting and underfitting. To explain this, let’s use the pet classifier example from above. The goal is to create a classifier that receives an image of a pet and classifies that as a dog, cat, or other. &lt;/p&gt;

&lt;p&gt;If we create a training set using only images of big dogs like a Labrador or a Saint Bernard, then the classifier won’t classify a Chihuahua as a dog. This is an example of overfitting. Our classifier fits particular cases of the training set, so when new input comes, the classifier doesn’t respond as expected. The problem here is that our training set is too specific.&lt;/p&gt;

&lt;p&gt;On the other hand, if we create the training set using only images of white dogs, then the classifier will classify a white cat as a dog, and a white hampster as a dog, etc. This is underfitting. Our training set is much too broad. Here’s an image that illustrates these problems in a way that’s a little easier to visualize:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kKcJ6DZe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/mwrn7oc7nbsd4hhvfa9i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kKcJ6DZe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/mwrn7oc7nbsd4hhvfa9i.png" alt="Overfitting"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How can we avoid these common problems? &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Create representative training and test sets with good proportions of each category&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Do not overload the training set with overly specific cases&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tune the classifier by changing the hyperparameters&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use cross-validation&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use early stopping techniques (stop the training before overfitting occurs)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Our results
&lt;/h3&gt;

&lt;p&gt;After many mistakes, tests, and iterations, we were able to create classifiers that work exceedingly well. These are the results we achieved for level classification: &lt;/p&gt;

&lt;p&gt;MLPClassifier&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                precision    recall  f1-score   support

     C-Suite       0.90      0.93      0.92        29
    Director       0.97      0.92      0.94        37
     Manager       0.90      0.95      0.92        19
       Other       0.93      0.95      0.94        41
          VP       1.00      0.96      0.98        24

    accuracy                           0.94       150
   macro avg       0.94      0.94      0.94       150
weighted avg       0.94      0.94      0.94       150
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;SGDClassifier&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;               precision    recall  f1-score   support

     C-Suite       0.97      0.97      0.97        29
    Director       0.97      0.92      0.94        37
     Manager       1.00      1.00      1.00        19
       Other       0.95      1.00      0.98        41
          VP       1.00      1.00      1.00        24

    accuracy                           0.97       150
   macro avg       0.98      0.98      0.98       150
weighted avg       0.97      0.97      0.97       150
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The f1-score (F score) is close to one, so it’s safe to say the classifier is working as we expected. With perfect precision and recall in more than one category, you can see the SGDClassifier works slightly better than the MLPClassifier. &lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;In this article, we talked about using machine learning to solve a real-world classification problem our team recently encountered. It’s also a great little demo of our work. The Scikit-learn library has a ton of different machine learning tools anybody can use to tackle a variety of problems. We went over the general process used to build a classifier and a few common hiccups you may encounter. We know other techniques can be used to improve our work and that’s why the machine learning universe is so amazing. You’re always able to learn and discover more, and as an engineering team, that keeps us motivated and happy to continue working.&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>python</category>
      <category>jupyter</category>
    </item>
    <item>
      <title>Django: Tips and good practices
</title>
      <dc:creator>brunomichetti</dc:creator>
      <pubDate>Mon, 28 Sep 2020 21:16:56 +0000</pubDate>
      <link>https://dev.to/rootstrap/django-tips-and-good-practices-43fp</link>
      <guid>https://dev.to/rootstrap/django-tips-and-good-practices-43fp</guid>
      <description>&lt;p&gt;&lt;strong&gt;Abstract&lt;/strong&gt;: The Django framework save time and effort and help to create apps and REST APIs with maintainable code. This blog gives some practical examples of what to do and what not to do when you code in Python using Django.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Summary&lt;/strong&gt;: This blog explains why good code structure and configuration is important in any environment. It describes Django’s main concepts and some easy ways to implement web app functionalities with existing tools that solve general problems. I also recommend good practices for efficiency and APIs and packages for session management and testing. Finally, I describe some things that, from my experience, are best to avoid. &lt;/p&gt;

&lt;h2&gt;
  
  
  Start with good code
&lt;/h2&gt;

&lt;p&gt;Like all software developers, I want to create maintainable code. It’s not just for me but also for my partners. It feels good to know that the programs you use or maintain have good code quality and what you construct is easy to change, reuse, update, review, and so on.  &lt;/p&gt;

&lt;p&gt;I recently learned to code in Python programming language by using the Django and Django REST frameworks. Now I want to share some tips and good practices for developing REST APIs with those technologies. When I face a programming problem, I first try to solve it. Then I look for an even better way to reach the solution. I write that information down and store it, so I can share what I learn with others. This blog is compiled from the notes I took when I learned Django. My goal is to help others learn Django too. It’s also a good place to start for people who just want to learn code.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Django and Django REST frameworks
&lt;/h2&gt;

&lt;p&gt;Django is a solid framework for developing web apps with Python language. It’s fast, secure, scalable, and well documented. If you want to build REST APIs, you can combine Django with the Django REST framework to generate a base project in just a few seconds. These webpages tell you more:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.djangoproject.com"&gt;Django&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.django-rest-framework.org"&gt;Django REST&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Tip: Don’t reinvent the wheel.  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Any teacher of computer science might say to students: Don't reinvent the wheel. For example, you might run into a problem when you’re coding that already has a documented solution. It's better and faster to take advantage of a known solution than to spend time creating a new one. There are many open source projects that perform common tasks to solve general problems. You can use them for free on your apps, and you can also make contributions and propose improvements!&lt;br&gt;
So if you want to create a REST API, there’s no need to reinvent the wheel. Use the Django frameworks to design that kind of app, and use the maintained tools to attack the common problems you encounter.  &lt;/p&gt;
&lt;h2&gt;
  
  
  Scaffolding and configuration structure
&lt;/h2&gt;

&lt;p&gt;As I said, anyone can quickly create a base project with Django frameworks. Detailed commands for that are in Django’s documentation. It’s a good practice to build a structure that increases maintainability. Then we can easily create a different configuration for each environment we use. Some examples are development, production, and testing. &lt;br&gt;
By default, Django generates a settings.py file for all the configurations of a project. That means several if's separate each part for each environment. This way is better:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keep the general configuration, which is common to all environments, in a base file.&lt;/li&gt;
&lt;li&gt;Then create different files that correspond to each of the different environments.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this simple example, I change the file &lt;em&gt;settings.py&lt;/em&gt; in a project named &lt;strong&gt;example_project&lt;/strong&gt; for a settings folder containing the next files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;__init__.py&lt;/li&gt;
&lt;li&gt;base.py&lt;/li&gt;
&lt;li&gt;development.py&lt;/li&gt;
&lt;li&gt;production.py&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The __init__.py file defines which configuration to use, depending on the environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;importlib&lt;/span&gt;

&lt;span class="c1"&gt;# by default use development
&lt;/span&gt;&lt;span class="n"&gt;ENV_ROLE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'ENV_ROLE'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'development'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;env_settings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;importlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;import_module&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;f'example_project.settings.&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ENV_ROLE&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;globals&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;vars&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env_settings&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="err"&gt;    &lt;/span&gt;
&lt;span class="c1"&gt;# import local settings if present
&lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;.local&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="c1"&gt;# noqa
&lt;/span&gt;&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;ImportError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="err"&gt;    &lt;/span&gt;&lt;span class="k"&gt;pass&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;With the __init__.py file, I define an environment variable named &lt;strong&gt;ENV_ROLE&lt;/strong&gt; for each environment. The value is the name of the configuration file that corresponds to that environment. For example, in my production environment, I create the ENV_ROLE variable with the &lt;code&gt;production&lt;/code&gt; value. Then I use the &lt;em&gt;production.py&lt;/em&gt;  file to set the specific configuration in the production environment.&lt;/p&gt;

&lt;p&gt;By creating environment variables, you can separate the configurations of the different environments. Examples are different databases for development and production or different allowed hosts. In the &lt;em&gt;base.py&lt;/em&gt; file, don’t forget to set the common configurations for all environments like INSTALLED_APPS, MIDDLEWARE, and TEMPLATES.&lt;/p&gt;

&lt;h3&gt;
  
  
  One project, multiple apps
&lt;/h3&gt;

&lt;p&gt;Several applications might exist in a single Django project. In Django context, an app is a set of related functionalities and models. Some more good practices are to build scaffolding that shows where the apps are in order to define standard locations for general functions and classes. In short, we want an orderly and easy-to-maintain structure.&lt;/p&gt;

&lt;p&gt;This code creates a suggested scaffolding:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;project_name
|
|__project_name (Put all the settings for the app here.)
|    |__ __init__.py
|    |__settings
|          |__ __init__.py
|          |__ base.py
|          |__ development.py
|          |__ staging.py
|          |__ production.py
|          ...
|    |__wsgi.py
|    |__asgi.py(optional)
|    |__urls.py
|    ...
|
|__templates (These general templates are loaded last in the application.)
|
|__api
|  |__ __init__.py
|  ...
|  |__ urls.py (Use this file to route the apps located under the applications folder.)
|
|__applications
|   |__ __init__.py
|   |__app1
|    ... |__models.py (Split the folder and import models in __init__ if necessary.)
|        |__views.py
|        |__serializers.py
|        |__urls.py
|        |__test
|        |   ...  
|        |__templates (Optional and not present if the project is API only.)
|        |
|        |__api.py (Optional and not present if the project is API only.)
|        ... (Add more files if they’re needed.)
|
|__utils
|   |__util_1.py
|   |__util_2.py
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This structure isn’t mandatory, but it’s a good way to increase maintainability. In my suggested scaffolding, there’s a special app, named api. In api, I define the routing of the other apps in the applications folder. In the utils folder, I also define the project’s general functions and utilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  Main concepts of Django and Django REST
&lt;/h2&gt;

&lt;p&gt;To work with Django and Django REST, it’s important to understand these concepts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Model&lt;/strong&gt; classes provide an object-relational map (ORM) for the underlying database. A model is mapped to a table in the database. You can query the databases without any SQL programming. With models, it’s easy to define tables and relationships between them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Views&lt;/strong&gt; are in charge of the process of requests. They function as controllers. You can implement them in many ways, such as functions or classes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Serializer&lt;/strong&gt; classes provide control of data types and structures of requests and responses. I like to define them as interfaces for the backend of the web app.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Templates&lt;/strong&gt; are files with static and dynamic content. They’re made up of some static code and other elements that depend on the context.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are many ways to implement the functionalities of a REST API by using the Django frameworks. There are also many ways to implement views and serializers. For general design and any bugs you might run into, I recommend the generic tested and maintained solutions, such as Generic views. &lt;/p&gt;

&lt;h3&gt;
  
  
  Generic views
&lt;/h3&gt;

&lt;p&gt;The Django REST framework has generic views that perform common tasks related to the model instances. Some examples are retrieve information, create, destroy, list, and update. With &lt;a href="https://www.django-rest-framework.org/api-guide/generic-views"&gt;Django’s generic views&lt;/a&gt;, you only need to define the class view as a child of the generic view, depending on your needs. The rest is solved by the framework. &lt;br&gt;
To learn how to implement the generic view functionality to generate a list of instances for a given model, let’s look at these classes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.db&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="err"&gt;    &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="err"&gt;    &lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IntegerField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now we create a serializer to see the details of an instance of that model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;rest_framework&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;serializers&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;applications.people.models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Person&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PersonDetailSerializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serializers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ModelSerializer&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="err"&gt;    &lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="err"&gt;        &lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Person&lt;/span&gt;
&lt;span class="err"&gt;        &lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'age'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Next, we define a view that lists all the instances:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;rest_framework&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;generics&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;applications.people.serializers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;PersonDetailSerializer&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PeopleListView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;generics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListCreateAPIView&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="err"&gt;    &lt;/span&gt;&lt;span class="n"&gt;queryset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;all&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="err"&gt;    &lt;/span&gt;&lt;span class="n"&gt;serializer_class&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PersonDetailSerializer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And that's it! It only takes a few lines to create generic view functionality. In the &lt;code&gt;queryset&lt;/code&gt; attribute, we tell the view which instances we want to list. In &lt;code&gt;serializer_class&lt;/code&gt;, we select the data structure. Everything else is already solved.&lt;/p&gt;

&lt;h3&gt;
  
  
  Customize functions
&lt;/h3&gt;

&lt;p&gt;The many generic views in the Django documentation meet a wide range of functionality needs. Some examples are &lt;code&gt;CreateAPIView&lt;/code&gt;, &lt;code&gt;ListAPIView&lt;/code&gt;, &lt;code&gt;RetrieveAPIView&lt;/code&gt;, and &lt;code&gt;RetrieveDestroyAPIView&lt;/code&gt;. But what if you want to customize the functions and change the default behavior? You can redefine &lt;code&gt;get&lt;/code&gt;, &lt;code&gt;post&lt;/code&gt;, &lt;code&gt;put&lt;/code&gt;, &lt;code&gt;delete&lt;/code&gt;, and other methods. You can also use the mixins to redefine the methods and specific functions like &lt;code&gt;create&lt;/code&gt;, &lt;code&gt;update&lt;/code&gt;, &lt;code&gt;destroy&lt;/code&gt;, and others. The generic views and serializers aren’t required, but they can simplify a lot work. Serializers also cover some issues related to requests and responses, so we don't have to worry about them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Data validation
&lt;/h3&gt;

&lt;p&gt;The next good practice I want to share is how to locate the validation of incoming data. For example, you might have values for the fields of serializers in your web app. You want to run some checks on them when a new request comes into the REST API. In the &lt;code&gt;PersonDetailSerializer&lt;/code&gt;, you can do a field-level validation that just defines a function named &lt;code&gt;validate_&amp;lt;field_name&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let's add a function in the serializer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;pythonclass&lt;/span&gt; &lt;span class="n"&gt;PersonDetailSerializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serializers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ModelSerializer&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;validate_age&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="err"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="err"&gt;            &lt;/span&gt;&lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;serializers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ValidationError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Age must be a positive number.'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="err"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="err"&gt;   &lt;/span&gt; 

&lt;span class="err"&gt;    &lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="err"&gt;        &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Complex validations
&lt;/h3&gt;

&lt;p&gt;Sometimes you need to define a more complex validation inside the serializer class. An example is validating constraints between fields. A good way to do that is with the validate function: &lt;code&gt;validate(self, data)&lt;/code&gt;.&lt;br&gt;
In summary, serializers are a good way to validate incoming data. In the previous example, &lt;code&gt;PersonDetailSerializer&lt;/code&gt; is attached to the Person model. So by default, it does basic validation related to the model. For example, if the incoming name length is bigger than 50 characters, then the serializer raises an exception, because the maximum length was defined in the model. You don’t need to make that explicit in the serializer. With Django, you can also define serializers that aren’t attached to models, nest serializers and relationships between them, and more. Serializers are very powerful.&lt;/p&gt;
&lt;h3&gt;
  
  
  Templates
&lt;/h3&gt;

&lt;p&gt;Finally, let’s talk about templates. As I mentioned, they’re great for generating dynamic code in Django. For example, template files can be used by the project frontend or to send emails.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Tip: Be aware of the order of apps defined in the project configuration, INSTALLED_APPS list.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It’s important to take order into account because it’s common for several apps to provide different versions of the same resource like a template or static file. If that happens, Django’s default behavior is to first check in the templates folder of the first app in the list. But that can cause problems. Order matters. By knowing this, we can change the order of the INSTALLED_APPS according to our needs. Or we can just explicitly define the desired paths for specific resources. For a configuration example, read the Django docs.&lt;/p&gt;
&lt;h2&gt;
  
  
  Session management
&lt;/h2&gt;

&lt;p&gt;Most web applications have users and authentication methods. In the spirit of don't reinvent the wheel, I recommend using an existing customizable solution for session management: django-rest-auth. You can easily integrate this set of REST API endpoints with your project. It resolves user registration, sign in, and sign out, as well as social account integration. Just use the provided endpoints and customize the models and functions to adapt them to your needs. For more information, see the &lt;a href="https://django-rest-auth.readthedocs.io/en/latest"&gt;Django REST authentication docs&lt;/a&gt;. &lt;/p&gt;
&lt;h2&gt;
  
  
  Create efficient programs
&lt;/h2&gt;

&lt;p&gt;No matter what technology you use, it’s always a good practice to create efficient programs.&lt;/p&gt;

&lt;p&gt;Django has a database-abstraction API to makes queries easily. As an example, let’s take another look at our Person model. First, we query the database for instances of people who are over 18 years old with this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;over_18_people&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;age__gte&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As its name suggests, the &lt;code&gt;filter&lt;/code&gt; function filters the query according to our criteria. &lt;code&gt;__gte&lt;/code&gt; means greater than or equal to.&lt;/p&gt;

&lt;p&gt;Now imagine that we also have people’s pets in our database:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.db&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;applications.people.models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Person&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="err"&gt;    &lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ForeignKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;related_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'pets'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;on_delete&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CASCADE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="err"&gt;    &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;ForeignKey&lt;/code&gt; defines a relationship between &lt;code&gt;Person&lt;/code&gt; and &lt;code&gt;Pet&lt;/code&gt;. A pet can belong to one person, and one person can have many pets. We might want to print the name of each person and the information about each person’s pets for everyone in the system. This example shows an intuitive way to do that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;all&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;span class="err"&gt;    &lt;/span&gt;&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="err"&gt;    &lt;/span&gt;&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'pets info:'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="err"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;pet&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;all&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;span class="err"&gt;        &lt;/span&gt;&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="err"&gt;    &lt;/span&gt;&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'---'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This solution works well, but how many times do the queries have to run? The answer is N + 1 times: once to get all the people and N times to get each person’s pets, assuming N is the number of people in the database. If the value of N is very large, that makes a lot of queries. &lt;br&gt;
Let’s look at another solution to the same problem:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;all&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;prefetch_related&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'pets'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="err"&gt;    &lt;/span&gt;&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="err"&gt;    &lt;/span&gt;&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'pets info:'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="err"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;pet&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="err"&gt;        &lt;/span&gt;&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="err"&gt;    &lt;/span&gt;&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'---'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This code also solves the problem, but the number of times it accesses the database is 1. That’s a big difference.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Tip: Minimize the number of queries.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Finally, let’s imagine your database is in another server, and a single query takes 1 ms to run. If there are 10,000 people in it, then the solution in the first example solution would take about 10 seconds to get things done. That’s much longer than the 1 ms it would take with second example.&lt;/p&gt;

&lt;p&gt;To save time and resources, write code that minimizes the number of accesses to the database. The Django API has lots of functions that do the exact same thing in lots of different ways. Choose the ones that minimize the number of queries because it’s always faster to work in memory. Learn to write efficient code by exploring Django’s documentation about &lt;a href="https://docs.djangoproject.com/en/2.2/topics/db/queries"&gt;attributes and functions&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The importance of testing
&lt;/h2&gt;

&lt;p&gt;I won’t say that testing is a good practice because it’s way more than that. Testing is essential for every project. Every application needs testing, and I take that for granted.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Tip: Use Factory boy and Faker.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In most of the cases, you’ll need to generate initial data for testing. So a programmer might run tests that have an “initial system” with previously loaded instances and relationships between them. This improves the quality, maintainability, and velocity of testing. &lt;br&gt;
You can load initial data with Django, using fixtures, migrations, and other functionalities. Now let’s look at a JSON fixture that takes the &lt;code&gt;Person&lt;/code&gt; class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;    &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"applications.person"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;    &lt;/span&gt;&lt;span class="nl"&gt;"pk"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;    &lt;/span&gt;&lt;span class="nl"&gt;"fields"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Rick Sanchez"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;      &lt;/span&gt;&lt;span class="nl"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;70&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;    &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"applications.person"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;    &lt;/span&gt;&lt;span class="nl"&gt;"pk"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;    &lt;/span&gt;&lt;span class="nl"&gt;"fields"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Summer Smith"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;      &lt;/span&gt;&lt;span class="nl"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;By defining this fixture, we provide two instances at the beginning of the tests, and we generate new test cases with this as starting point. What if we want to test a bigger list of people? It would be cumbersome to enter info for each person manually, and the fixture file would need a huge number of lines. Fortunately, we don’t have to do that because the named tool &lt;a href="https://factoryboy.readthedocs.io/en/latest"&gt;Factory boy&lt;/a&gt; gives us a better way.&lt;/p&gt;

&lt;h3&gt;
  
  
  Factory boy
&lt;/h3&gt;

&lt;p&gt;With Factory boy, you can generate test data with a just few lines, which improves maintainability. You can also define classes attached to the model classes. So at the same time that you run tests, you can easily create instances in memory or in the database and also replace any static hard-to-maintain fixtures. This example is related to the &lt;code&gt;Person&lt;/code&gt; class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;factory&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;applications.people.models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Person&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PersonFactory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DjangoModelFactory&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="err"&gt;    &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sequence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'John Doe{0}'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="err"&gt;    &lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;

&lt;span class="err"&gt;    &lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="err"&gt;        &lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Person&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To generate 100 instances of people for my tests with this definition, I run this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;PersonFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_batch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As you can see, it’s very simple. Whit the &lt;code&gt;name&lt;/code&gt; defined as &lt;code&gt;Sequence(lambda n: 'John Doe{0}'.format(n))&lt;/code&gt;, the tool generates users with the names John Doe0, John Doe1, John Doe2, and so on. &lt;br&gt;
Faker&lt;br&gt;
The Faker tool is a package that generates fake random and realistic data. When you integrate it with Factory boy, it generates more significant tests with more realistic initial data. To see this integration in action, let’s change the factory class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;factory&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;applications.people.models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Person&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PersonFactory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Factory&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="err"&gt;    &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Faker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="err"&gt;    &lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;

&lt;span class="err"&gt;    &lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="err"&gt;        &lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Person&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now, if we execute the &lt;code&gt;create_batch(100)&lt;/code&gt; function, we generate 100 people with realistic random names. Faker has a &lt;code&gt;pyint&lt;/code&gt; function that generates random integers for &lt;code&gt;age&lt;/code&gt;. To learn more about this package, read the &lt;a href="https://faker.readthedocs.io/en/master"&gt;Faker docs&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Tip: Use tools to replace static fixtures.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Define good initial data for testing and keep it maintainable. For more ways to integrate these tools with Django, take a look at the common recipes in the Factory boy documentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to avoid
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Excessive use of signals
&lt;/h3&gt;

&lt;p&gt;Django and Django REST have many tools and methods to attack several problems in a lot of ways. Signals are a good tool but they can cause problems if they’re used the wrong way.&lt;/p&gt;

&lt;p&gt;Signals implement the observer design pattern, and it’s important to understand these concepts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;Signal&lt;/strong&gt; is an element that corresponds to an event. A signal can send notifications about the related event to it. In the observer pattern, the signal corresponds to the subject.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Receivers&lt;/strong&gt; are the callables connected to a given signal. In the observer pattern, they correspond to the observer. After the associated event occurs and triggers the signal, each receiver is notified by that signal.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With the signals tool, you can send a notification after some predefined event. Some examples are when a new object in a model is created or destroyed, or a change is made in a relationship between models. To explore all the &lt;a href="https://docs.djangoproject.com/en/2.2/topics/signals"&gt;functionalities of signals&lt;/a&gt;, read the Django signal documentation.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Tip: Be careful with signals.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Overuse of signals often generates mysterious side effects that degrade maintainability. These problems happen because signals are triggered after selected events. Programmers who forget that or simply don’t know it sometimes run unwanted code in the wrong places.&lt;/p&gt;

&lt;p&gt;Whenever you change something about the events that trigger a signal, you might need to make changes in the corresponding signals. It’s easy to forget to check that because these signals are defined in other files.&lt;/p&gt;

&lt;p&gt;To save time and effort, avoid the overuse of signals. For example, you might have two apps &lt;strong&gt;A&lt;/strong&gt; and &lt;strong&gt;B&lt;/strong&gt;, where &lt;strong&gt;A&lt;/strong&gt; needs to trigger a function in &lt;strong&gt;B&lt;/strong&gt;. If app &lt;strong&gt;A&lt;/strong&gt; already knows app &lt;strong&gt;B&lt;/strong&gt;, then don’t use signals. In this case, app &lt;strong&gt;A&lt;/strong&gt; will import the needed functions from app &lt;strong&gt;B&lt;/strong&gt; and make the calls directly.&lt;br&gt;
 &lt;/p&gt;
&lt;h3&gt;
  
  
  When signals are useful
&lt;/h3&gt;

&lt;p&gt;A good use for signals is for breaking circular dependencies between Django apps. For example, you might have app &lt;strong&gt;A&lt;/strong&gt; that depends on another app &lt;strong&gt;B&lt;/strong&gt;, where &lt;strong&gt;B&lt;/strong&gt; also needs things from &lt;strong&gt;A&lt;/strong&gt;. A signal can break that circular dependency. Another example is if you have a model of third-party apps that you have no control over, and you want to trigger a process after some event of the model. Signals are also helpful in that scenario.&lt;/p&gt;
&lt;h3&gt;
  
  
  url versus path
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Tip: Don't define urls with regular expressions unless is neccesary.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you search internet for help to code in Django, you’ll probably find example code with the &lt;code&gt;url&lt;/code&gt; function. And you might try to use it to solve your problem.&lt;/p&gt;

&lt;p&gt;For an example of how the &lt;code&gt;url&lt;/code&gt; function works, let’s define a URL with this general form:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;api/v1/people/&amp;lt;token&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Where &lt;code&gt;&amp;lt;token&amp;gt;&lt;/code&gt; can be a string with any character. Whit the named function would be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;r'^api/v1/people/(?P&amp;lt;token&amp;gt;[\w\-]+)/$'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It’s much easier to define the URL by using a Django dispatcher named path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'api/v1/people/&amp;lt;str:token&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The difference between these methods is that the first one needs regular expressions. The second one has defined types that already cover the most common cases. At times, you might need to use regular expressions anyway. There’s a function for that named &lt;strong&gt;re_path&lt;/strong&gt;. You can learn more about &lt;a href="https://docs.djangoproject.com/en/2.2/topics/http/urls"&gt;URL dispatcher&lt;/a&gt; in the Django documentations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learning Django
&lt;/h2&gt;

&lt;p&gt;In this blog, I shared many of the lessons I learned by programming with the Django frameworks. I also recommended good practices for developing web apps, structures, functionalities, and general programming. This information can help you improve the quality and maintainability of your code. To make things easier for you, I described some of the problems I found with these tools and provided solutions for them.&lt;/p&gt;

&lt;p&gt;I talked first about the importance of a good structure and configuration for several environments. Then main concepts of Django related to easy ways of implementing functionalities, taking advantage of tools already implemented to solve general problems. After that, I recommended some practices for efficiency, and then APIs and packages for session management and testing. Finally I talked about things that are better to avoid, because I already faced those problems before and I would like other people could skip them while learning these tools. I still have a lot to learn about Django and Django REST framework, but I hope what I’ve learned so far and shared with you has been useful and interesting.&lt;/p&gt;

</description>
      <category>python</category>
      <category>django</category>
      <category>webdev</category>
      <category>testing</category>
    </item>
  </channel>
</rss>
