Django Project Structure Explained

Abstract generated cover for Django Project Structure Explained.

Django projects can look confusing at first because the word "project" and the word "app" both have specific meanings. A Django project is the whole website or backend. A Django app is a smaller module inside that project. For example, an ecommerce site might be one Django project with several apps:

  • catalogue
  • accounts
  • checkout
  • orders
  • dashboard Understanding that difference makes the folder structure much easier to read.

The Mental Model

Think of the Django project as the container. It holds global configuration:

  • settings
  • root URLs
  • ASGI and WSGI entry points
  • installed apps
  • middleware
  • database configuration Think of Django apps as feature modules. They hold domain code:
  • models
  • views
  • forms
  • templates
  • admin configuration
  • migrations
  • tests The project wires everything together. The apps do the actual work.

A Basic Django Layout

A simple Django project might look like this: ```plain text mysite/ manage.py mysite/ init.py settings.py urls.py asgi.py wsgi.py blog/ init.py admin.py apps.py models.py views.py urls.py migrations/ init.py templates/ blog/ post_detail.html tests.py

The repeated name is normal.
The outer \`my_site/\` is the repository or project folder.
The inner \`my_site/\` is the Django configuration package.
The \`blog/\` folder is a Django app.
## \`manage.py\`
\`manage.py\` is the command line entry point for many Django tasks.
Common commands:
```bash
python manage.py runserver
python manage.py migrate
python manage.py makemigrations
python manage.py createsuperuser
python manage.py shell
python manage.py test

You run these commands from the folder containing `manage.py`. For local development, `manage.py` is one of the files you interact with most.

Settings

`settings.py` contains the project configuration. This includes things like:

  • installed apps
  • middleware
  • database connection
  • templates
  • static files
  • timezone
  • security settings For small projects, one `settings.py` file may be enough. For larger projects, settings are often split: ```plain text settings/ init.py base.py development.py production.py
This helps keep local development settings separate from production settings.
The important rule is to keep secrets out of Git. Use environment variables for private values.
## URLs
The project-level \`urls.py\` is the root router.
Example:
```python
from django.urls import include, path

urlpatterns = [
    path("blog/", include("blog.urls")),
]

The app-level `blog/urls.py` handles routes for that feature:

from django.urls import path
from . import views

urlpatterns = [
    path("", views.post_list, name="post_list"),
    path("<slug:slug>/", views.post_detail, name="post_detail"),
]

This keeps routing organized. The project decides which app handles a URL prefix. The app decides what happens inside that feature.

Models, Views, and Templates

Django's common pattern is:

  • models describe data
  • views handle requests
  • templates render HTML A model:
from django.db import models

class Post(models.Model):
    title = models.CharField(max_length=200)
    slug = models.SlugField(unique=True)
    body = models.TextField()

A view:

from django.shortcuts import render
from .models import Post

def post_list(request):
    posts = Post.objects.all()
    return render(request, "blog/post_list.html", {"posts": posts})

A template:

{% for post in posts %}
  <h2>{{ post.title }}</h2>
{% endfor %}

Each layer has a job.

Migrations

Migrations track database schema changes. When you change models, you usually create migrations:

python manage.py makemigrations

Then apply them:

python manage.py migrate

Migrations should usually be committed. They are the project's record of how the database schema changes over time.

Common Mistakes

Mistake 1: Putting all code in one app

One app is fine at the beginning. But if one app starts handling accounts, checkout, reporting, blog posts, and admin tools, it becomes hard to reason about. Split apps around real domain boundaries.

Mistake 2: Committing secrets in settings

Never commit production secrets into `settings.py`. Read them from environment variables.

Mistake 3: Ignoring migrations

If model changes are committed without migrations, other machines may not be able to update their database correctly. Migrations are part of the codebase.

Where This Shows Up in Real Projects

Django structure matters when projects grow. An ecommerce backend needs clear places for catalogue data, basket behavior, checkout, orders, and admin workflows. A content site may need apps for blog posts, pages, media, and search. If the project and app boundaries are clear, the code is easier to change without breaking unrelated features.

Key Takeaways

  • A Django project is the whole site or backend.
  • A Django app is a feature module inside that project.
  • `manage.py` runs common development commands.
  • Project URLs can include app URLs.
  • Migrations should be committed and treated as part of the code.

    Related Articles

  • Python Virtual Environments Explained

  • How to Structure a Python Project
  • Getting Started With Django Oscar

← Back to Blog Index