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