Skip to main content

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:

bash
pip install django

Now, let's create a new project:

bash
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:

bash
# 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:

python
# 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:

python
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:

bash
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:

python
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.

python
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):

python
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:

python
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:

python
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:

python
# 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:

python
# 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:

python
# 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:

python
# accounts/models.py
from django.contrib.auth.models import AbstractUser

class User(AbstractUser):
pass

Then in your settings:

python
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

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:

  1. Separate modules for forms, managers, and services
  2. A dedicated directory for tests
  3. Split views by entity (posts and comments)
  4. Template includes for reusable components
  5. 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, and admin.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

Exercises

  1. Create a new Django project and add three applications: users, products, and orders. Set up the appropriate directory structure for each.
  2. Take an existing single-app Django project and refactor it into multiple focused apps.
  3. Add a custom template tag to one of your Django applications.
  4. Create a custom settings structure with separate files for development, testing, and production environments.
  5. 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! :)