It’s not uncommon for new Django developers to become understandably confused by Django’s usage of the word “app”. So before we get into Django app design, it’s very important that we go over some definitions.
The Golden Rule of Django App Design
James Bennett is a Django core developer. He taught us everything that we know about good Django app design.
The art of creating and maintaining a good Django app is that it should follow the truncated Unix philosophy according to Douglas McIlroy: ‘Write programs that do one thing and do it well
A Practical Way
from Two Scoops of Django 3
Imagine that we’re creating a web application for our fictional ice cream shop called “Two Scoops”. Picture us getting ready to open the shop: polishing the countertops, making the first batches of ice cream, and building the website for our shop.
- A flavors app to track all of our ice cream flavors and list them on our website.
- A blog app for the official Two Scoops blog.
- An events app to display listings of our shop’s events on our website: events such as Strawberry Sundae Sundays and Fudgy First Fridays.
What Name Your Django Apps
We like to use naming systems that are dull, boring, and obvious. In fact, we advocate doing the following:
When possible keep to single word names like flavors, animals
, blog
, polls
, dreams
, estimates
, and finances
. A good, easy-to-remember app name makes the project easier to maintain.
As a general rule, the app’s name should be a plural version of the app’s main model, but there are many good exceptions to this rule, blog being one of the most common ones.
Don’t just consider the app’s main model, though. You should also consider how you want your URLs to appear when choosing a name. If you want your site’s blog to appear at http://www.example.com/weblog/, then consider naming your app weblog rather than blog, posts, or blogposts, even if the main model is Post, to make it easier for you to see which app corresponds with which part of the site.
When in Doubt, Keep Apps Small
Try and keep your apps small. Remember, it’s better to have many small apps than to have a few giant apps.
Common Apps Module
Here are common modules seen in 99% of Django apps. These will prove very familiar to most readers, but we’re placing this here for those just coming into the world of Django. For reference, any module ending with a slash (‘/’) represents a Python package, which can contain one or more modules.
in our Apps
├── core
│ ├── __init__.py
│ ├── asgi.py
│ ├── settings
│ │ ├── base.py
│ │ └── development.py
│ ├── urls.py
│ └── wsgi.py
├── db.sqlite3
└── manage.py
Settings and Requirements Files
settings that can be controlled in the settings module, most of which come with default values. Settings are loaded when your server starts up, and experienced Django developers stay away from trying to change settings in production since they require a server restart.
Best Practice Settings
- All settings files need to be version-controlled. This is especially true in production environments, where dates, times, and explanations for settings changes absolutely must be tracked.
- Don’t Repeat Yourself. You should inherit from a base settings file rather than cutting-and-pasting from one file to another.
- Keep secret keys safe. They should be kept out of version control.
Using Multiple Settings File
Instead of having one settings.py file, with this setup you have a settings/ directory containing your settings files. This directory will typically contain something like the following:
for our project
core/settings
├── base.py # base settings
└── development.py # for development
for base settings
# base settings
"""
Django settings for core project.
Generated by 'django-admin startproject' using Django 4.0.
For more information on this file, see
https://docs.djangoproject.com/en/4.0/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.0/ref/settings/
"""
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.0/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-d=dx&eu7ey(ophx@_p-15damar_tc@^v-8uo&devaj9qhh%*k('
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# 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',
]
ROOT_URLCONF = 'core.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'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 = 'core.wsgi.application'
# Database
# https://docs.djangoproject.com/en/4.0/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
# Password validation
# https://docs.djangoproject.com/en/4.0/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/4.0/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.0/howto/static-files/
STATIC_URL = 'static/'
# Default primary key field type
# https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
for development settings
# development settings
from .base import *
# Installed Apps Settings
INSTALLED_APPS += []
DEBUG = True
# Database Settings
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
Important Settings for Base
by modified BASE_DIR
like
BASE_DIR = Path(__file__).resolve().parent.parent.parent
for SQLite3 outside from settings/
directory like
├── core
│ ├── __init__.py
│ ├── asgi.py
│ ├── settings
│ │ ├── base.py
│ │ └── development.py
│ ├── urls.py
│ └── wsgi.py
├── db.sqlite3 # the database moved on outside settings
└── manage.py
Run Server Management
for development settings
python manage.py shell --settings=config.settings.development
python manage.py runserver --settings=config.settings.development
For Production Settings
python manage.py shell --settings=config.settings.production
python manage.py runserver --settings=config.settings.production
Modify manage.py
file
for default settings
modify the manage.py
default settings like this
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
def main():
"""Run administrative tasks."""
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'core.settings.development')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == '__main__':
main()
and you can run the server like this
python manage.py runserver
Conclusion
Don’t worry too hard about getting app design perfect. It’s an art, not a science. Sometimes you have to rewrite them or break them up. That’s okay.
with django two scoops standard we can break down our django app with easies to maintenance