Rohan Yeole - HomepageRohan Yeole

Best Practices for Structuring a Django Project

By Rohan Yeole

A well-structured Django project not only accelerates development but also ensures maintainability and scalability. This guide walks you through a clean and scalable Django boilerplate I’ve developed, based on industry best practices. Whether you're just starting or refining an existing setup, this guide will help you build Django projects like a pro.

Overview

We'll cover the following:

  • Virtual Environments
  • Creating the Project
  • Managing Requirements
  • Settings Management
  • App Organization
  • Common Utilities (Makefile Shortcuts)

Use a Virtual Environment (VE)

Virtual environments keep your project dependencies isolated, avoiding version conflicts and global pollution.

Why It Matters

  • Prevents conflicts with global packages
  • Avoids permission issues
  • Keeps each project’s dependencies organized

Create & Activate VE

python -m venv .venv --prompt django-first
source .venv/bin/activate
pip install "Django~=5.0.0"
On Ubuntu, install python3-venv via apt if not available.

Creating the Django Project

A common beginner mistake is creating unnecessary nested folders.

Common Structure (Not Ideal)

django-admin startproject djangofirst
Results in:
Django_First/
└── djangofirst/
├── djangofirst/
└── manage.py
Recommended: Use config/ for Settings
django-admin startproject config .
Produces:
Django_First/
├── config/
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
└── manage.py
This separates configuration logic (config) from the root directory, keeping things clean.

Managing Requirements

Most developers only use a single requirements.txt, which is fine for small projects. But for scalable apps, separate your environments.

Best Practice

Create a requirements/ folder:

requirements/
├── base.txt
└── dev.txt
base.txt
Django~=5.0
django-environ==0.11.2
dev.txt
-r base.txt
ipython==8.18.1
django-extensions==3.2.3
Use pip install -r requirements/dev.txt to install all development dependencies.

Splitting Settings for Environments

The default settings.py becomes hard to manage as your project grows. Instead, split settings by environment.

Directory Structure

config/
└── settings/
├── base.py
└── dev.py
base.py

Defines shared settings:

BASE_DIR = Path(__file__).resolve().parent.parent.parent

INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
# ...
]

MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
# ...
]

ROOT_URLCONF = "config.urls"
WSGI_APPLICATION = "config.wsgi.application"
dev.py

Environment-specific overrides:

import environ
from .base import *

env = environ.Env(DEBUG=(bool, True))
environ.Env.read_env(str(BASE_DIR / ".env"))

SECRET_KEY = env("SECRET_KEY")
DEBUG = env.bool("DEBUG", default=True)
ALLOWED_HOSTS = ["*"]

INSTALLED_APPS += ["django_extensions"]

DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "db.sqlite3",
}
}
Keep secrets like SECRET_KEY and database credentials in a .env file.

Organizing Django Apps

Many devs put apps directly in the root directory, cluttering the workspace.

Best Practice: Use an apps/ Folder

mkdir apps
cd apps
python3 ../manage.py startapp your_app
Bonus: Core App for Shared Models

Use a core app to house common logic.

Example: apps/core/abstracts/models.py

from django.db import models

class CreatedModifiedAbstract(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
modified_at = models.DateTimeField(auto_now=True)

class Meta:
abstract = True
Now, any model can inherit from CreatedModifiedAbstract.

Developer Efficiency with Makefile

Long commands slow you down. Use a Makefile for shortcuts.

Sample Makefile

dev-start:
python manage.py runserver --settings=config.settings.dev

dev-install:
pip install -r requirements/dev.txt

dev-startapp:
cd apps && python3 ../manage.py startapp $(app) --settings=config.settings.dev

dev-makemigrations:
python manage.py makemigrations --settings=config.settings.dev

dev-shell:
python manage.py shell --settings=config.settings.dev
Usage:
make dev-start
make dev-install
make dev-startapp app=blog
Final Project Structure
Django_First/
├── apps/
│ └── core/
│ └── abstracts/
│ └── models.py
├── config/
│ ├── settings/
│ │ ├── base.py
│ │ └── dev.py
│ ├── urls.py
│ └── wsgi.py
├── requirements/
│ ├── base.txt
│ └── dev.txt
├── manage.py
└── Makefile
Conclusion

Django is incredibly powerful, but many developers struggle with messy project structures that limit scalability. With this structured boilerplate:

  • Your project remains clean and maintainable
  • You can switch between dev, staging, and production environments easily
  • Your development process becomes significantly more productive