7 Days Challenge to Push Your Hard skill Using Django Part 2: Build Better Project Structure and Understand Golden Rule In Django
hello welcome to another blog post, in this post I will talk about structuring the Django project so that it is easy for developers to understand and manage and can easily include various features, this is the second day of the challenge “7 Days Push Your Hard Skill Using Django” let’s see how the tip is
Understanding The Golden Rule of Django Apps Design
when creating a Django project, it is required that each of those applications should focus on the task, each application must focus on the task, otherwise, the application will be difficult to describe and the size will be enormous, and will be difficult to manage, therefore the application must be broken down into several parts.
Practical Example Apps in Django Project
I will show a comparison between 2 project structures, namely the default and the one that is made modularly based on the function of each application
Uncommon Apps Module
to build a better project structure we must separate them based on a function and where it will be used, whether in production or locally, in development condition or ready for production, Let's look default Django Project when we created with django-admin startproject <project_name>
shown bellow
mysite/
manage.py
mysite/
__init__.py
settings.py
urls.py
asgi.py
wsgi.py
and here if you create apps
.
├── manage.py
├── mysite
│ ├── asgi.py
│ ├── __init__.py
│ ├── __pycache__
│ │ ├── __init__.cpython-39.pyc
│ │ └── settings.cpython-39.pyc
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
└── polls
├── admin.py
├── apps.py
├── __init__.py
├── migrations
│ └── __init__.py
├── models.py
├── tests.py
└── views.py
with default structure, we can manage one or two apps in Django but how to manage 3 or more Django apps if an inside app has multiple services or function, definitely going to be difficult to manage and manage, because it’s confusing 😩, now I will share tips Best Practice Build Better Structure in Django Projects.
Here are some tips on why we need to change the default project structure in Django
- Naming Django Apps
- Keep Django Apps Small
How to Naming Django Apps
other tips A very important little tip is how to name Django Apps, if possible keep single-word names like blog
, admin
etc
Keep your Django Apps Small
like a UNIX philosophy, “each app should be tightly focused on its task” mean is keep your apps, program, or system modular and focused in one task, because if apps have a multiple service or task, it will cause confusion if our Django project becomes big, therefore solving apps by task is very important.
Common Apps Module
here is a Common Apps Module
.
├── apps
│ ├── api
│ │ ├── admin.py
│ │ ├── apps.py
│ │ ├── __init__.py
│ │ ├── migrations
│ │ │ └── __init__.py
│ │ ├── models.py
│ │ ├── tests.py
│ │ └── views.py
│ ├── __init__.py
│ └── store
│ ├── admin.py
│ ├── apps.py
│ ├── __init__.py
│ ├── migrations
│ │ └── __init__.py
│ ├── models.py
│ ├── tests.py
│ └── views.py
├── config
│ ├── asgi.py
│ ├── __init__.py
│ ├── settings
│ │ ├── base.py
│ │ ├── __init__.py
│ │ └── local.py
│ ├── urls.py
│ └── wsgi.py
├── db.sqlite3
├── manage.py
├── README.md
└── requirements
├── base.txt
└── local.txt
in that structure, we separate apps in a specific directory, in this case, we have two apps called blog
and store
they separated in a specific directory called apps
it makes the application very easy to manage and easily added with new features for the system may be modular and easier to import the required modules 😄
Using Multiple Settings Files In Django
By default Django, there is only one settings.py file, but we can use more than one settings file in Django, therefore we can make it even more modular, this is necessary because when we deploy a Django project to production we need to make sure that the configuration is It’s true that it’s ready on a production server, but what if we need to develop an application that we have deployed again, what if a new developer is involved in developing the application, how can our application be easily developed and understood by other developers?
Of course, the question is very important, why? because we don’t want to rewrite the settings.py file if it’s already in production, other than that what if each developer rewrites the settings.py file differently, it would be very confusing and time-consuming, so we can make settings that are more modular. and in accordance with the task that has been determined.
this is the same as the django framework’s philosophy, which is Don’t repeat yourself
okay, let's take an example to create a module named settings
like this
.
├── base.py
├── __init__.py
└── local.py
in a settings
, the module has a 2 file base.py
and local.py
base.py
Base Settings Configurationlocal.py
Inheritance frombase.py
but Configured in local development Only
now let's configure base.py
in this file, we create base settings configs like TEMPLATES, STATIC_DIRS, MEDIA_ROOT, INSTALLED_APPS, MIDDLEWARE, SECURITY, DATABASE, and many others
# settings/base.py"""
Django settings for config project.
Generated by 'django-admin startproject' using Django 3.2.3.
For more information on this file, see
https://docs.djangoproject.com/en/3.2/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.2/ref/settings/
"""
from pathlib import Path
from os.path import abspath, dirname, join
import environ
# Build paths inside the project like this: BASE_DIR / 'subdir'.
# BASE DIR PATH SETTINGS
# Handling Mapping Path Using Function
"""
using this function if need to mapping basedirs or test path
"""
def root(*dirs):
base_dir = join(dirname(__file__), '..', '..')
return abspath(join(base_dir, *dirs))
# OLD CONFIG
# BASE_DIR = environ.Path(__file__) - 3
# APPS_DIR = BASE_DIR.path("apps")
# CONFIG_DIRS = BASE_DIR.path("config")
# NEW CONFIG
BASE_DIR = Path(__file__).resolve().parent.parent.parent
APPS_DIR = BASE_DIR / 'apps'
CONFIG_DIRS = BASE_DIR / 'config'
# STATIC AND MEDIA CONFIG
MEDIA_ROOT = BASE_DIR / 'media'
STATIC_ROOT = BASE_DIR / 'static_root'
# LOAD ENVIRONTMENT
env = environ.Env()
env.read_env('.env')
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
# Config URL
ROOT_URLCONF = 'config.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / 'templates'],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'config.wsgi.application'
# DJANGO CORE
DEBUG = env.bool("DJANGO_DEBUG", False)
# Database
# https://docs.djangoproject.com/en/3.2/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
# Password validation
# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/3.2/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.2/howto/static-files/
STATIC_URL = '/static/'
# Default primary key field type
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
now let's create settings for local development, in this example local.py
like this
"""
local development setings
"""
from .base import *
# DEBUG SETTINGS
DEBUG = True
# SECRET_KEY CONFIG
SECRET_KEY = env('DJANGO_SECRET_KEY')
now to use is this settings
modules change default settings file in manage.py
# project_root/manage.pydef main():
"""Run administrative tasks."""
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings.local')...
How To Register New Apps
finally, you create all Django apps in a specific directory if you need to register apps in settings, register apps in settings/base.py
file and register inside INSTALLED_APPS
like this
# settings/base.py
INSTALLED_APPS = (
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"django.contrib.sites",
# your apps <-
"apps.api",
"apps.store")
Break Down Requirements file
Try to imagine what if the needs in a production server and in development using the package version and using some additional modules or there are development dependencies.
well for that we can break down some modules that will be installed and used according to the stages, for example, we use the coverage module for testing purposes but in production we no longer need it, to solve this we can break the requirements file, let's create two requirements called base.txt
and local.txt
# base.txt
Django==3.2.3
psycopg2-binary
djangorestframework
django-environ
in local.txt
extend base.txt
like this
-r base.txt # include base.txt
coverage==5.5
now let's look a requirements
folder
.
├── base.txt
└── local.txt
now install with include folder path like this
pip install -r requirements/local.txt
after install run manage.py
python manage.py runserver
and open http://localhost:8000/ in the browser
Conclusion
a project structure like this can make it easier to develop a site using Django and is easy to manage because the structure is modular and easy to understand and has standards, in the second days of the challenge I have learned “how to manage your project” 😄