Django Directory Structure
Introduction
When you create a new Django project, one of the first things you'll notice is the specific directory structure that Django sets up for you. Understanding this structure is crucial for efficiently developing Django applications, as it follows Django's "batteries-included" philosophy by organizing your code in a logical and maintainable way.
In this tutorial, we'll explore Django's directory structure at both the project and application levels. You'll learn what each file and directory is responsible for, how they interact with each other, and best practices for organizing your Django projects.
Django Project vs. Application
Before diving into the directory structure, it's important to understand the distinction between a Django project and a Django application:
- A project is the entire web application, containing multiple apps, settings, and configurations.
- An application is a modular component within a project that performs a specific function.
A single Django project can contain multiple applications, and an application can be reused across multiple projects.
Creating a Django Project
Let's start by creating a new Django project to explore its structure. First, make sure you have Django installed:
pip install django
Now, let's create a new project:
django-admin startproject myproject
This command creates a directory called myproject
with the following structure:
myproject/
├── manage.py
└── myproject/
├── __init__.py
├── asgi.py
├── settings.py
├── urls.py
└── wsgi.py
Project Structure Explained
Let's examine each file and directory:
manage.py
This is a command-line utility that lets you interact with your Django project in various ways. It's essentially a thin wrapper around the django-admin
command.
You can use it to run the development server, create applications, work with the database, and more:
# Run the development server
python manage.py runserver
# Create migrations
python manage.py makemigrations
# Apply migrations
python manage.py migrate
The Inner myproject/
Directory
This is your actual Python package for the project. Its name is the Python package name you'll use to import anything from within it (e.g., myproject.urls
).
__init__.py
This empty file tells Python that this directory should be considered a Python package.
asgi.py
An entry-point for ASGI-compatible web servers to serve your project. ASGI (Asynchronous Server Gateway Interface) is the successor to WSGI, supporting asynchronous code.
settings.py
This crucial file contains all the configuration for your Django project. Here's where you define things like:
- Database configuration
- Installed apps
- Middleware classes
- Template configuration
- Static files settings
- Security settings
The default settings.py
file includes comments explaining each setting. Here's a snippet:
# Database configuration
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
# Installed apps
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
urls.py
This file defines the URL declarations for your Django project; essentially, a "table of contents" for your Django-powered site.
Here's what the default urls.py
looks like:
from django.contrib import admin
from django.urls import path
urlpatterns = [
path('admin/', admin.site.urls),
]
wsgi.py
An entry-point for WSGI-compatible web servers to serve your project. WSGI (Web Server Gateway Interface) is the standard Python interface between web servers and applications.
Creating a Django Application
Let's add an application to our project:
python manage.py startapp blog
This creates a new directory called blog
with the following structure:
blog/
├── __init__.py
├── admin.py
├── apps.py
├── migrations/
│ └── __init__.py
├── models.py
├── tests.py
└── views.py
Your project structure now looks like this:
myproject/
├── blog/
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── migrations/
│ │ └── __init__.py
│ ├── models.py
│ ├── tests.py
│ └── views.py
├── manage.py
└── myproject/
├── __init__.py
├── asgi.py
├── settings.py
├── urls.py
└── wsgi.py
Application Structure Explained
Let's examine each file and directory in the app:
__init__.py
As with the project directory, this empty file makes the app directory a Python package.
admin.py
This file is used to register models with Django's built-in admin interface. For example:
from django.contrib import admin
from .models import Post
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
list_display = ('title', 'author', 'published_date')
list_filter = ('published_date', 'author')
search_fields = ('title', 'content')
apps.py
This file contains the application configuration. It's where you can define application-specific settings.
from django.apps import AppConfig
class BlogConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'blog'
migrations/
This directory contains database migrations for your app. Migrations are Django's way of propagating changes you make to your models into your database schema.
models.py
This is where you define your application's data models using Django's ORM (Object-Relational Mapping):
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
class Post(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
published_date = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.title
tests.py
This file is for writing tests for your application:
from django.test import TestCase
from .models import Post
from django.contrib.auth.models import User
class PostModelTest(TestCase):
def setUp(self):
self.user = User.objects.create_user(username='testuser', password='12345')
def test_post_creation(self):
post = Post.objects.create(
title="Test Post",
content="This is a test post content",
author=self.user
)
self.assertEqual(post.title, "Test Post")
self.assertEqual(post.author, self.user)
views.py
This file contains the view functions or classes that handle requests and return responses:
from django.shortcuts import render, get_object_or_404
from .models import Post
def post_list(request):
posts = Post.objects.all().order_by('-published_date')
return render(request, 'blog/post_list.html', {'posts': posts})
def post_detail(request, pk):
post = get_object_or_404(Post, pk=pk)
return render(request, 'blog/post_detail.html', {'post': post})
Extending the Application Structure
Django's default application structure is minimalistic. In real-world projects, you'll typically add more files and directories to better organize your code. Here are some common additions:
Templates
Templates contain your HTML files with Django template language. Create a templates
directory within your app:
blog/
└── templates/
└── blog/
├── base.html
├── post_list.html
└── post_detail.html
Static Files
Static files include CSS, JavaScript, and images. Create a static
directory within your app:
blog/
└── static/
└── blog/
├── css/
│ └── style.css
├── js/
│ └── script.js
└── images/
└── logo.png
URLs
For larger applications, it's common to have a dedicated urls.py
file for the app:
# blog/urls.py
from django.urls import path
from . import views
app_name = 'blog'
urlpatterns = [
path('', views.post_list, name='post_list'),
path('post/<int:pk>/', views.post_detail, name='post_detail'),
]
Then, in the main project's urls.py
:
# myproject/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('blog/', include('blog.urls', namespace='blog')),
]
Forms
Add a forms.py
file for your form classes:
# blog/forms.py
from django import forms
from .models import Post
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ('title', 'content')
Best Practices for Organizing Django Projects
As your project grows, consider these best practices:
1. Follow Django's App-Centric Philosophy
Build your project as a collection of small, focused apps that each do one thing well. Avoid creating "mega-apps" that handle too many responsibilities.
2. Separate Settings for Different Environments
Split your settings into base, development, testing, and production files:
myproject/
└── settings/
├── __init__.py
├── base.py
├── development.py
├── testing.py
└── production.py
3. Use Custom User Model from the Start
Even if you don't need custom user functionality yet, it's much easier to start with a custom user model:
# accounts/models.py
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
pass
Then in your settings:
AUTH_USER_MODEL = 'accounts.User'
4. Create a Core App for Project-Wide Functionality
A core app can contain shared functionality like custom template tags, middleware, etc.:
myproject/
├── core/
│ ├── __init__.py
│ ├── middleware.py
│ ├── templatetags/
│ │ ├── __init__.py
│ │ └── core_tags.py
│ └── utils.py
5. Group Related Apps in Packages
For large projects with many apps, group related apps in packages:
myproject/
├── accounts/
│ ├── __init__.py
│ ├── models.py
│ └── ...
├── blog/
│ ├── __init__.py
│ ├── models.py
│ └── ...
├── shop/
│ ├── __init__.py
│ ├── products/
│ │ ├── __init__.py
│ │ ├── models.py
│ │ └── ...
│ ├── orders/
│ │ ├── __init__.py
│ │ ├── models.py
│ │ └── ...
│ └── payments/
│ ├── __init__.py
│ ├── models.py
│ └── ...
Real-World Example: Blog Application
Let's look at a more comprehensive example of a blog application structure:
blog/
├── __init__.py
├── admin.py
├── apps.py
├── forms.py
├── managers.py
├── migrations/
├── models.py
├── services.py
├── static/
│ └── blog/
│ ├── css/
│ ├── js/
│ └── images/
├── templates/
│ └── blog/
│ ├── base.html
│ ├── includes/
│ │ ├── header.html
│ │ ├── footer.html
│ │ └── sidebar.html
│ ├── post_list.html
│ ├── post_detail.html
│ └── post_form.html
├── templatetags/
│ ├── __init__.py
│ └── blog_tags.py
├── tests/
│ ├── __init__.py
│ ├── test_models.py
│ ├── test_views.py
│ └── test_forms.py
├── urls.py
└── views/
├── __init__.py
├── post_views.py
└── comment_views.py
This structure includes:
- Separate modules for forms, managers, and services
- A dedicated directory for tests
- Split views by entity (posts and comments)
- Template includes for reusable components
- Custom template tags
Summary
Understanding Django's directory structure is crucial for organizing your code effectively. The default structure provides a solid foundation, but you'll want to extend it as your project grows.
Key points to remember:
- A Django project contains one or more applications
- Each application should focus on a specific functionality
- The default structure includes essential files like
models.py
,views.py
, andadmin.py
- As your project grows, add more organization with directories for templates, static files, and dedicated modules
- Follow best practices like separating settings for different environments and using a custom user model
By understanding and properly utilizing Django's directory structure, you'll be able to create more maintainable, scalable, and reusable code.
Additional Resources
- Django Official Documentation on Applications
- Django Official Documentation on Projects and Applications
- Two Scoops of Django - A book with excellent advice on Django project structure
- Cookiecutter Django - A framework for jumpstarting Django projects with good practices
Exercises
- Create a new Django project and add three applications:
users
,products
, andorders
. Set up the appropriate directory structure for each. - Take an existing single-app Django project and refactor it into multiple focused apps.
- Add a custom template tag to one of your Django applications.
- Create a custom settings structure with separate files for development, testing, and production environments.
- Implement a core app with shared functionality that other apps in your project can use.
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)