Django Setup for Enterprise Applications

Deepak Kabbur

Table of Contents

  1. Introduction
  2. Audience
  3. Prerequisites
  4. Let’s Start Project
  5. Setup Directory Structure
  6. Setup Custom User app
  7. Setting Environment Variables
  8. FAQ

1. Introduction

Django is a very popular Python Web framework that encourages rapid development and clean, pragmatic design. Its free and Open Source. Some of the busiest sites on the Web leverage Django’s ability to quickly and flexibly scale.

Today will discuss about Django setup and directory structure which helps to scale and maintain the project in the long run.

2. Audience

  • Who have basic knowledge of Django.
  • Who desire to learn advance Django.
  • Developer/Professional/Student who wants to scale Django project.
  • Company to start Enterprise Web application with Django.
  • Of Course! Who loves Django.

3. Prerequisites

  1. Mac/Linux/Windows with Python Installed(Preferred Latest Version with Pyenv).
  2. Pipenv/Pip package manager.
  3. Github Repository (Optional) or any other version control tool.

Verify setup

$ python --version
Python 3.8.0

$ pipenv --version
pipenv, version 2018.11.26

4. Lets’s Start Project

I believe system setup is done as prescribed in prerequisites section and verified. Create new directory in workspace.

$ cd workspace/python
$ mkdir demo
$ cd demo

4.1 Lets create virtual environment using pipenv.

$ pipenv --python 3.8.0
Creating a virtualenv for this project…
Pipfile: /Users/home/projects/python/nyasa-api/Pipfile
Using /Users/home/.pyenv/versions/3.8.0/bin/python3 (3.8.0) to create virtualenv…
.
.
.
 Successfully created virtual environment!
Virtualenv location: /Users/home/.local/share/virtualenvs/nyasa-api-yFS2yA7M
Creating a Pipfile for this project…

4.2 Install Django package

Below command install latest version of Django.

$ pipenv install django
Installing django…
Adding django to Pipfile's [packages]…
✔ Installation Succeeded

4.3 Start django project

$ django-admin startproject demo .
$ python manage.py startserver
Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).

You have 17 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.

September 09, 2020 - 16:22:26
Django version 2.2.16, using settings 'nyasa.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

Congratulations!

You have successfully created project. Check default Django home page at http://127.0.0.1:8000

5. Setup Directory Structure

Now we comes to important step of project setup. Before going to change directory structure lets understand why we changing it.

Is it mandatory to change directory structure?

No but its good to be organized. What you think ha?

Why Directory structure is important?

Directory structure is very important for any project. How we plan for Home before constructing like Living room, Kitchen, Bedroom etc… every space has its own importance and purpose. Same in project directory structure each directory has its own importance and purpose.

Directory Structure we going to create and its purposes.

  • apps this directory contains all the future apps created using startapp command.
  • config contains all the configurations and settings related to project.
  • common all common code, modules or utils. These are the important directories. We can add more as per requirement or need.
Note : create __init__.py file inside each directory. We use it as Python package.

5.1 Add apps package inside demo directory.

$ cd  demo
$ mkdir apps
$ touch apps/__init__.py

Lets configure Django to consider apps directory as parent of all apps.

Open demo/settings.py and add following line.

import sys

sys.path.insert(0, os.path.join(BASE_DIR, "apps"))

5.2 Add config package. Goto parent directory.

This directory contains the all the settings, urls and wsgi.py related to project.

$ cd ..
$ mkdir config
$ cd config
$ touch __init__.py
$ mkdir settings
$ touch settings/__init__.py
$ touch settings/django.py
  • Copy all the contents of demo/settings to config/settings/django.py
  • Move wsgi.py and urls.py files to config.
  • Update BASE_DIR, WSGI_APPLICATION, ROOT_URLCONF config/settings/django.py
BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
WSGI_APPLICATION = "demo.config.wsgi.application"
ROOT_URLCONF = "demo.config.urls"
  • Update settings module in manage.py
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'demo.config.settings.django')

Run the local server and verify its working correctly.

5.3 Add common package same as we added apps and config. Which contains the common code which is applicable to whole project.

6. Setup Custom User app

Now its time to create custom user app.

The purpose of custom app

  • Full control on User model.
  • Full control on Authentication and Authorization.
  • Flexibility add new fields to User model.
  • Segregate User related features/code in one place.
  • Add more flexibility while developing API related to User.

6.1 Create custom user app.

$ cd demo/apps
$ mkdir users
$ cd ../..
$ django-admin startapp  users  ./demo/apps/users/
$ ls demo/apps/users/
__init__.py admin.py    apps.py     migrations  models.py   tests.py    views.py

6.2 Create User model.

Add following lines to apps/users/model

from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
from django.utils.translation import ugettext_lazy as _
from django.utils import timezone

class User(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(
        _("email address"), unique=True, blank=False, max_length=254, validators=[]
    )

    active = models.BooleanField(_("active"), default=False, help_text=_("Active user"))

    first_name = models.CharField(_("First Name"), max_length=254, blank=True)
    last_name = models.CharField(_("Last Name"), max_length=254, blank=True)
    is_active = models.BooleanField(default=True)
    is_email_verified = models.BooleanField(default=False)
    is_staff = models.BooleanField(
        _("staff status"),
        default=False,
        help_text=_(
            "Designates whether the user can log into this admin site."
            "Unselect this instead of deleting accounts."
        ),
    )
    date_created = models.DateTimeField(_("date created"), default=timezone.now)

    USERNAME_FIELD = "email"

    def save(self, *args, **kwargs):
        self.email = self.email.lower()
        super(User, self).save(*args, **kwargs)

    def __str__(self):
        return self.email

    class Meta:
        verbose_name_plural = "users"
        ordering = ["-date_created", "email"]
        indexes = [
            models.Index(fields=["email"]),
            models.Index(fields=["first_name", "last_name"]),
        ]

6.3 Configure user app.

add following line to config/settings/django.py

AUTH_USER_MODEL = "users.User"
# configure users app. Add it to INSTALLED_APPS at end.
INSTALLED_APPS = [
    '...',
    'users'
]

6.4 Make Migrations

$ python manage.py makemigrations
Migrations for 'users':
  nyasa/apps/users/migrations/0001_initial.py
    - Create model User
    - Create index users_user_email_6f2530_idx on field(s) email of model user
    - Create index users_user_first_n_6d862e_idx on field(s) first_name, last_name of model user

6.5 Run Migrations

$ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions, users
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0001_initial... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying auth.0012_alter_user_first_name_max_length... OK
  Applying users.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying sessions.0001_initial... OK

6.6 Verify server is running.

$ python manage.py runserver
Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).
September 09, 2020 - 19:41:22
Django version 3.1.1, using settings 'nyasa.config.settings.django'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

7. Setting Environment Variables.

Purpose of environment variables

  • Hide the confidential data like credentials, secrete keys, API tokens/credentials etc.
  • Never add credentials in code.
  • Flexibility to set credenatials environment dev/test/production.
  • Flexibility to developers to setup in local.
  • Never push credentials or confidential data to versioning tool.

7.1 Install django-environ package.

$ pipenv install django-environ
Installing django-environ…
Adding django-environ to Pipfile's [packages]…
✔ Installation Succeeded
Pipfile.lock (91d23f) out of date, updating to (a6086c)…
Locking [dev-packages] dependencies…
Locking [packages] dependencies…
✔ Success!

7.2 Create .env file in parent directory.

DEBUG=on
SECRET_KEY=your-secret-key

NOTE: Add .env to .gitignore. Never push this file to repository.

7.3 Configure djnago-environ. In demo/settings/django.py add following.

# Set parent directory for environ
base = environ.Path(__file__) - 4
# Rediang file and export env variables
environ.Env.read_env(env_file=base(".env"))
env = environ.Env()

# update following
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = env("SECRET_KEY")

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = env("DEBUG")

7.4 Auto export of environment variables.

Wheneever we activate pipenv shell environment variables are set.

$ pipenv shell
Loading .env environment variables…
Launching subshell in virtual environment…
 . /Users/home/.local/share/virtualenvs/nyasa-api-yFS2yA7M/bin/activate

Hurray!. Setup is done.

Django Setup for Enterprise Applications Repository

Using this repository as template for your new project.

$ mkdir demo
$ cd demo
$ django-admin startproject demo . --template https://github.com/deepakkabbur/django-setup/archive/master.zip

NOTE: Please read Documentation. If your are using it as template

8. FAQ

8.1 Error ImportError: Couldn't import Django ?

activate virtual environment

$ pipenv shell

8.2 Error ModuleNotFoundError: No module named users

Update BASE_DIR as mentioned above. Refer to 5.2 and 6.3