Back
Featured image of post Two Scoop of Django 3 Project Structure

Two Scoop of Django 3 Project Structure

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

Licensed under CC BY-NC-SA 4.0
Last updated on Jan 11, 2022 23:42 +0700
comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy