<?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: gr1nch3</title>
    <description>The latest articles on DEV Community by gr1nch3 (@gr1nch3).</description>
    <link>https://dev.to/gr1nch3</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%2F471499%2Fbc5cfef8-58ca-4103-adbf-95d3da7cd083.jpeg</url>
      <title>DEV Community: gr1nch3</title>
      <link>https://dev.to/gr1nch3</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gr1nch3"/>
    <language>en</language>
    <item>
      <title>Creating a Reusable Django app</title>
      <dc:creator>gr1nch3</dc:creator>
      <pubDate>Sun, 02 Oct 2022 17:57:26 +0000</pubDate>
      <link>https://dev.to/gr1nch3/creating-a-reusable-django-app-47de</link>
      <guid>https://dev.to/gr1nch3/creating-a-reusable-django-app-47de</guid>
      <description>&lt;p&gt;Django Versatility does not stop at creating APIs or Impressive Web apps, We can also create packages from the apps within our Django Projects. In this article, we’ll be creating a package, uploading it to test.pypi and looking at how to use that package with other projects.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cnLRijny--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2Axdk_hsbIJPcVVtuxz_DeHw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cnLRijny--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2Axdk_hsbIJPcVVtuxz_DeHw.png" alt="" width="800" height="325"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How Reusable?
&lt;/h2&gt;

&lt;p&gt;Before We begin, it is crucial to understand how the package we intend to create will work in the projects of others. Will our package gives functions to the project, or will it work as a standalone and interact with the database? Is my package going to need data from the project? Will my package pass data to the template? Etc. Answering these questions can help you better grasp how to structure your package.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating your Package
&lt;/h2&gt;

&lt;p&gt;We’ll be using &lt;a href="https://github.com/gr1nch3/django_memo.git"&gt;This repo&lt;/a&gt; (also below) to create our package. It’s a simple memo app that allows users to save and check memos if it’s a task.&lt;br&gt;
&lt;a href="https://github.com/gr1nch3/django_memo.git"&gt;&lt;strong&gt;GitHub - gr1nch3/django_memo: A simple Django memo application&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The project structure should be like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;django_memo
  |_django_memo
  |_memo
  |_theme
  |_manage.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The first step is to move the app we want to turn into a package to another folder, you can copy or cut it to the folder. You should pick a meaningful name for the folder, since it’s what your package will be referenced by. I’ll name mine django-memo. Outside that folder, we will create a virtual environment.(make sure your package and its virtual environment are in a separate workspace or folder&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# first
python3 -m venv my-env
# second
source my-env/bin/activate # macos/linux
my-env/scripts/activate.bat # windows
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Next is to install twine and setuptools, we’ll use them to build our package and test it.&lt;/p&gt;

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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Extras
&lt;/h3&gt;

&lt;p&gt;In the folder you moved your app to(django-memo in my case), we are going to add the following files that will configure and build your package: *&lt;em&gt;setup.cfg, LICENSE, pyproject.toml, README.md **and **MANIFEST.in *&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;pyproject.toml&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Add the following to your **pyproject.toml **file, and make sure the setuptools version matches the one you’ve installed.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[build-system]
requires = ['setuptools &amp;gt;= 65.3.0', 'wheel']
build-backend = 'setuptools.build_meta:__legacy__'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;setup.cfg&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This file contains the metadata for **PyPI **and other requirements for your package. Make sure to check the requirements for your package version and set accordingly.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[metadata]
name = django-memo
version = 1.2
description = A Django app to take and manage memo
readme = "README.md"
long_description = file: README.md 
long_description_content_type=text/markdown
url = [https://www.example.com/](https://www.example.com/)
author = gr1nch3
author_email = example[@gmail.com](mailto:lloydm763@gmail.com)
license = MIT License
classifiers =
    Environment :: Web Environment
    Framework :: Django
    Framework :: Django :: 4.0 # set your version
    Intended Audience :: Developers
    License :: OSI Approved :: MIT License
    Operating System :: OS Independent
    Programming Language :: Python
    Programming Language :: Python :: 3
    Programming Language :: Python :: 3 :: Only
    Programming Language :: Python :: 3.9
    Programming Language :: Python :: 3.10
    Topic :: Communications :: Chat

[options]
include_package_data = true
packages = find:
python_requires = &amp;gt;=3.9
install_requires =
    Django &amp;gt;= 4.0 # set your version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Note: **the **long_description **by default is .rst, but .md works for me. The **long_description **and **long_description_content_type **needed to be configured like that to pass the **twine&lt;/strong&gt; check.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;README&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Your README file needs to be properly written in order to upload to pypi. It should also tell how to set up your package in a Django project.&lt;/p&gt;

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

memo is a Django app to create memos and manage them

Detailed documentation is in the "docs" directory.

Quick start
-----------

1. Add "memo" to your INSTALLED_APPS setting like this::

INSTALLED_APPS = [
        ...
        'memo',
  ]

2. Include the memo URLconf in your project urls.py like this::

path('memo/', include('memo.urls')),

3. Run ``python manage.py migrate`` to create the memo models.

4. Visit '[http://127.0.0.1:8000/memo/'](http://127.0.0.1:8000/memo/') to check out your memos
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;LICENSE&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The License will contain the license for your package. We’ll use a MIT License&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# MIT License

Copyright (c) [year] [your full name]

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;MANIFEST.in&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The manifest will include other files, folders and templates that your package needs.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;include LICENSE
include README.md
recursive-include docs *
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;setup.py&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;required to build the package&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from setuptools import setup

setup()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;After all the configurations, your package should look like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...(workspace or folder)
  |_my-env
  |_django-memo
    |_memo
    |_LICENSE
    |_MANIFEST.in
    |_pyproject.toml
    |_README.md
    |_setup.cfg
    |_setup.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Configuring our model
&lt;/h2&gt;

&lt;p&gt;In this section, we will configure our memo model to work with the projects it will be installed in. Since the memo model requires an abstract user. We’ll set it so that the package gets the user model from the settings. Just passing the user model to the settings (with AUTH_USER_MODEL) and accessing it as settings.AUTH_USER_MODEL for our memo model would pass the model as a string. So we’ll use the get_user_model() from django.contrib.auth. Our memo model structure will change to the following:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.db import models

from django.contrib.auth import get_user_model # new

MemoUser = get_user_model() # new
# Create your models here.

# ---------------------------------------------------------------------------- #
#                           model of the memo detail                           #
# ---------------------------------------------------------------------------- #

class Memo(models.Model):
                             # new
    user = models.ForeignKey(MemoUser, on_delete=models.CASCADE)
    title = models.CharField(max_length=100)
    memo = models.TextField(blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    is_completed = models.BooleanField(default=False)

def __str__(self):
        return self.title

class Meta:
        db_table = 'memo'
        verbose_name = 'Memo'
        verbose_name_plural = 'Memos'
        ordering = ['-created_at']
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Note: If you were to pass a model to the package and use it as a foreign key, you can check out the code for the get_user_model() function, it works for passing other models as well, and you would only need to set it up in the settings.py.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing our Package
&lt;/h2&gt;

&lt;p&gt;At this point, we’ve built and structured our app and have all files needed to turn it to a package.&lt;/p&gt;

&lt;h3&gt;
  
  
  Build
&lt;/h3&gt;

&lt;p&gt;There are two ways we could create the dist folder that contains the package.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;We could use setuptools and run the command python setup.py sdist in the directory that contains our app and the packaging files, and we would get a build that would still pass the twine check .&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We could also use the python build module’s python3 -m build command and get a similar result, and we would also get the wheel for the package&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Test
&lt;/h3&gt;

&lt;p&gt;After you have created your dist folder, run the command twine check dist/* in the folder that contains the dist and you should see a message like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# if you used the first method
Checking dist/django-memo-1.2.tar.gz: PASSED

# if you used the second method
Checking dist/django_memo-1.2-py3-none-any.whl: PASSED
Checking dist/django-memo-1.2.tar.gz: PASSED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Installing our Package
&lt;/h3&gt;

&lt;p&gt;To install our package locally in a project, we can run the following command: python -m pip install -U ./dist/django-memo-1.2.tar.gz .&lt;/p&gt;
&lt;h2&gt;
  
  
  Uploading our Package
&lt;/h2&gt;

&lt;p&gt;We are going to upload our package to &lt;a href="https://test.pypi.org/"&gt;test.PyPI&lt;/a&gt;. Make sure to create an account. When done, go to account settings and add API token and create a token. Remember to copy your token someplace safe because you’ll be using it for uploads to test.PyPI. To upload to the real PyPI, you can use your credentials.&lt;/p&gt;

&lt;p&gt;After creating the token, in your terminal, run the following command:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3 -m twine upload --repository testpypi dist/*
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You’ll be prompted for a username, and you should set the username value to &lt;strong&gt;token&lt;/strong&gt; . When you receive the prompt for a password, you add the token value you copied for the password. Results should be something similar:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Uploading django_memo-1.2-py3-none-any.whl
100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 10.7/10.7 kB • 00:05 • 14.2 MB/s
Uploading django-memo-1.2.tar.gz
100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 9.6/9.6 kB • 00:00 • 9.6 MB/s

View at:
[https://test.pypi.org/project/django-memo/1.2/](https://test.pypi.org/project/django-memo/1.2/)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Congratulations! You Just created your first working package! If you follow the link from the result in your terminal, you should see your package on test.PyPI.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JqVBeJlf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3200/1%2AqgHT6KbYWGPdatiTKM4XSw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JqVBeJlf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3200/1%2AqgHT6KbYWGPdatiTKM4XSw.png" alt="" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To view the package, check it out in this repo:&lt;br&gt;
&lt;a href="https://github.com/gr1nch3/django-memo"&gt;&lt;strong&gt;GitHub - gr1nch3/django-memo&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>django</category>
      <category>python</category>
    </item>
    <item>
      <title>Django + Tailwind Simplified</title>
      <dc:creator>gr1nch3</dc:creator>
      <pubDate>Sun, 02 Oct 2022 17:54:33 +0000</pubDate>
      <link>https://dev.to/gr1nch3/django-tailwind-simplified-22a2</link>
      <guid>https://dev.to/gr1nch3/django-tailwind-simplified-22a2</guid>
      <description>&lt;p&gt;Liquid syntax error: Unknown tag 'load'&lt;/p&gt;
</description>
      <category>django</category>
      <category>tailwindcss</category>
      <category>css</category>
      <category>python</category>
    </item>
    <item>
      <title>Django Chat App (Without Django Channels)</title>
      <dc:creator>gr1nch3</dc:creator>
      <pubDate>Sun, 02 Oct 2022 17:52:04 +0000</pubDate>
      <link>https://dev.to/gr1nch3/django-chat-app-without-django-channels-1ia4</link>
      <guid>https://dev.to/gr1nch3/django-chat-app-without-django-channels-1ia4</guid>
      <description>&lt;p&gt;Ever wondered what a Django chat application would be like without looking like it's based on discord or slack? Look no further! This article is about that thought being brought to life.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--o_DLrTlZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3196/1%2AMRxB2HJ_rnNkAD220IPaVA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--o_DLrTlZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3196/1%2AMRxB2HJ_rnNkAD220IPaVA.png" alt="" width="800" height="359"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm assuming that you already have some knowledge in python and python Django. you might need a bit of tailwind knowledge if you want to modify the templates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating your Project
&lt;/h2&gt;

&lt;p&gt;create a folder called **chat_django **and navigate to the folder.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir chat_django &amp;amp;&amp;amp; cd chat_django
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;For this Project, I will use a virtual environment.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# first
python3 -m venv env
# second
source env/bin/activate # macos/linux
env/scripts/activate.bat # windows
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Next, install Django and &lt;a href="https://github.com/django-crispy-forms/crispy-tailwind"&gt;cripsy_tailwind&lt;/a&gt;. Crispy_tailwind is the tailwind version of bootstrap's cripsy_form used to style forms templates.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# install django
pip install Django
# install crispy tailwind
pip install crispy-tailwind
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now, we create our Django project.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;django-admin startproject django_chat &amp;amp;&amp;amp; cd django_chat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Finally, create an app called &lt;strong&gt;chat.&lt;/strong&gt;&lt;/p&gt;

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

&lt;/div&gt;
&lt;h2&gt;
  
  
  Setting up your Project
&lt;/h2&gt;

&lt;p&gt;We are going to make the following changes to our Project &lt;strong&gt;settings.py&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At the top of &lt;strong&gt;settings.py&lt;/strong&gt; add import os.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QE7QFjPt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AZ4UJCVUfF-zNrxptxyZbEw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QE7QFjPt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AZ4UJCVUfF-zNrxptxyZbEw.png" alt="importing os to avoid PostSix error and get the theme path" width="800" height="344"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To our **INSTALLED_APPS = [] **we'll add our custom app(chat), crispy forms, and crispy_tailwind.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4Zibbvyn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AWE9RUCoXkcRICZLvE3n2aA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4Zibbvyn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AWE9RUCoXkcRICZLvE3n2aA.png" alt="" width="800" height="773"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will be storing our static files/folders and templates in a folder called **theme **in our Django project directory.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir theme
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Your project folder should be something like this.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;chat_django
|_env
|_django_chat
  |_chat
  |_django_chat
  |_theme
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Go to your theme directory and create these three directories: &lt;strong&gt;src&lt;/strong&gt;, &lt;strong&gt;templates&lt;/strong&gt;, and &lt;strong&gt;static&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd theme &amp;amp;&amp;amp; mkdir src templates static
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We are going to make those folders accessible to Django since they are not in Django's default specified location.&lt;/p&gt;

&lt;p&gt;in your **settings.py **add&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(BASE_DIR / 'themes/templates')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;to the **TEMPLATES = [] **like so:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5foS6hM1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2988/1%2AiiWoPuYceHReoC0NIGKYTA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5foS6hM1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2988/1%2AiiWoPuYceHReoC0NIGKYTA.png" alt="" width="800" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In your &lt;strong&gt;settings.py **add a **STATICFILES_DIRS = []&lt;/strong&gt;, this will tell Django which directory to read the static files from.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wF3Pr2E3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2616/1%2AHxCuwzaOJeBTLfZEAvM7Mg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wF3Pr2E3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2616/1%2AHxCuwzaOJeBTLfZEAvM7Mg.png" alt="" width="800" height="201"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;we should be done with the &lt;strong&gt;settings.py&lt;/strong&gt; for now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Chat app setup
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Models
&lt;/h3&gt;

&lt;p&gt;In the **models.py **of our chat app, we are going to create a User model and a Message model.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;User Model: For our user model, we will be extending the &lt;strong&gt;AbstractUser **from the **django.contrib.auth.models&lt;/strong&gt;. we are using the AbstractUser to get the auth benefits of the Django default User model. Our User model will have two fields. A username field, and an email field. Both will be unique.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zNFe8Qf7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2620/1%2ABa-9KNtt0vwZHi7EpIEYIg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zNFe8Qf7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2620/1%2ABa-9KNtt0vwZHi7EpIEYIg.png" alt="" width="800" height="434"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Message Model: We'll use Django's default database model for the message model. We'll add a field for the sender and recipient which will be a reference to the **UserProfile **model. We'll also add a date field, to get the DateTime of the messages, and a is_read field to mark read messages&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BkFKznfu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3936/1%2ASOQ8xqOi3wF5vetPGhVdSg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BkFKznfu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3936/1%2ASOQ8xqOi3wF5vetPGhVdSg.png" alt="" width="800" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Below the &lt;strong&gt;Message&lt;/strong&gt; Model Meta class, we are going to add two functions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;**get_all_messages(id_1, id_2): **the function takes your primary key and the primary key of the person whose chat inbox you're opening and gets all the messages between you two and sorts them by date.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Kmf5zy8W--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/5148/1%2APcHXmdrxp32_dSuDHOi91Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Kmf5zy8W--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/5148/1%2APcHXmdrxp32_dSuDHOi91Q.png" alt="" width="800" height="292"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;**get_message_list(u): **takes your primary key, filters all messages that have either your primary key as the recipient or the sender, sorts them by username and date, and returns them while removing all other messages that do not have your primary key.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5HzIyxVS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4976/1%2A9xWh2OrNrUX0JvCroDlqxA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5HzIyxVS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4976/1%2A9xWh2OrNrUX0JvCroDlqxA.png" alt="" width="800" height="363"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Form
&lt;/h3&gt;

&lt;p&gt;Create a forms.py file in your &lt;strong&gt;chat&lt;/strong&gt; app. Since we want users to signup for the app, we are going to create a custom signup form using **UserCreationForm **from the **django.contrib.auth.forms. **Because we are using crispy forms, the only fields we'll need to call in our Signup form will be the username and the email; the rest will be taken care of by the **UserCreationForm. **The form will add password fields and create a user with no admin or staff privileges.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--i6DZzlFc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3324/1%2AAFTgctQnJQh_5fxcOpu0KQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--i6DZzlFc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3324/1%2AAFTgctQnJQh_5fxcOpu0KQ.png" alt="" width="800" height="543"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Views
&lt;/h2&gt;

&lt;p&gt;For the **views.py, **we will be creating four views :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;signup view&lt;/strong&gt;: sign up users&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;messages list view&lt;/strong&gt;: display all messages per user for the user logged in&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;inbox view&lt;/strong&gt;: a chat view between you and the other user&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;users list view&lt;/strong&gt;: to find new users to chat with&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Before we continue with creating the views, at the top of the views file, you need to import the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--C03r2_4j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2748/1%2AXHGM52qP9wRpThYfcPqvyA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--C03r2_4j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2748/1%2AXHGM52qP9wRpThYfcPqvyA.png" alt="" width="800" height="324"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now for the views:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Signup View&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PKv-0p9v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4708/1%2A8AxmBsjNFpRH5oCcc5SgwQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PKv-0p9v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4708/1%2A8AxmBsjNFpRH5oCcc5SgwQ.png" alt="A signup view that logs the user in after they signup" width="800" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Messages list view&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4vB8BUvF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3968/1%2AceQ09UXmH2y8XVrkCJTg_Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4vB8BUvF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3968/1%2AceQ09UXmH2y8XVrkCJTg_Q.png" alt="The view has a LoginRequiredMixin, so authenticated users can only access it. Uses the get_message_list function from the message model" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Inbox view&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ywD7Yb2r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3700/1%2AEJjOK2hv9EmjMyT1umr6Hg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ywD7Yb2r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3700/1%2AEJjOK2hv9EmjMyT1umr6Hg.png" alt="We are using a username in the url instead of the primary key. The above code gets the username for the view and also passes the user name to the post function" width="800" height="372"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RA_kjWbp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/5752/1%2AHcByJ6M-ytGHQZmNvuIxPg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RA_kjWbp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/5752/1%2AHcByJ6M-ytGHQZmNvuIxPg.png" alt="Uses the get_all_messages and get_message_list to display messages in the chat and the messages list for the template" width="800" height="345"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UX8pjBqH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4672/1%2AuBpTQMMmQWncJrq6LEdyLg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UX8pjBqH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4672/1%2AuBpTQMMmQWncJrq6LEdyLg.png" alt="This function is called on to send a message in the chat." width="800" height="321"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;UserListsView&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NySgv_rq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3936/1%2AaLPOTOzd3lGEL8KOR2Xd9w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NySgv_rq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3936/1%2AaLPOTOzd3lGEL8KOR2Xd9w.png" alt="Display all users, excluding the user logged in" width="800" height="304"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Urls
&lt;/h3&gt;

&lt;p&gt;By default, Django apps are not created with a urls.py file, so you'll need to create it as you did with the forms.py. We are not going to build custom logout and login views, so we'll use Django's default &lt;strong&gt;LoginView&lt;/strong&gt; and &lt;strong&gt;LogoutView&lt;/strong&gt; views from the &lt;strong&gt;django.contrib.auth.views&lt;/strong&gt;. All we'll need to do is to render a template or a url redirect (for LogoutView) for the default auth views.&lt;/p&gt;

&lt;p&gt;In the urls.py add the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OJAl1UeJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3868/1%2AQsGYnPIDl7RabsxcrU83wA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OJAl1UeJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3868/1%2AQsGYnPIDl7RabsxcrU83wA.png" alt="" width="800" height="356"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Settings again?
&lt;/h2&gt;

&lt;p&gt;For our final tweak in settings.py we are going to add**AUTH_USER_MODEL **to specify which model we want to authenticate as the user model, we will also set the urls for the login and logout views and the redirect urls.&lt;/p&gt;

&lt;p&gt;Add the following code under the STATICFILES_DIRS&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_LXPkqQc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2APj-iKuW8-4H03DR4-NRafw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_LXPkqQc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2APj-iKuW8-4H03DR4-NRafw.png" alt="" width="800" height="582"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Theme/Templates/static
&lt;/h2&gt;

&lt;p&gt;To set up the tailwind, static, and templates, check out this article:&lt;br&gt;
&lt;a href="https://medium.com/@gr1nch3/django-tailwind-simplified-8befa0a281d4"&gt;&lt;strong&gt;Django + Tailwind Simplified&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  crispy_tailwind
&lt;/h3&gt;

&lt;p&gt;To use crispy tailwind with our crispy forms, we need to add the following to the settings.py&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zQMMTZUc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2008/1%2A0aW_Tu4O0J_huarx7TAXcA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zQMMTZUc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2008/1%2A0aW_Tu4O0J_huarx7TAXcA.png" alt="" width="800" height="354"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When done, the results should be:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pJ7JpLZC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3200/1%2AWlCmGSMDbJbe4ydQfeZJsQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pJ7JpLZC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3200/1%2AWlCmGSMDbJbe4ydQfeZJsQ.png" alt="" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Project git: &lt;a href="https://github.com/gr1nch3/django_chat.git"&gt;https://github.com/gr1nch3/django_chat.git&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

&lt;h2&gt;
  
  
  Extras
&lt;/h2&gt;

&lt;p&gt;To continue the Project, you could add:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;unread messages count&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;a group chat feature&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;maybe a better template than I did&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;images or files upload within the chat&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

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