Project setup
Django is a batteries-included web framework: routing, an ORM, templates, forms, an admin and a security layer come in the box. This lesson gets a project running the way a team would actually start one.
Install into a virtual environment
Django 5.1 runs on Python 3.10 to 3.13. Always use a virtual environment so each project keeps its own versions.
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install "django~=5.1" mysqlclient python-dotenv
django-admin startproject config .
python manage.py startapp shop
python manage.py migrate
python manage.py runserver
The trailing dot in startproject config . matters: it puts manage.py in the current folder instead of nesting
another directory. Freeze what you installed with pip freeze > requirements.txt before you write any code.
What you just created
manage.py # command-line entry point
config/
settings.py # all configuration
urls.py # the project-wide URL map
wsgi.py / asgi.py # the server entry points
shop/
models.py # data
views.py # logic
admin.py # admin registration
migrations/ # generated schema changes
Django calls its pattern MTV: Models hold data, Templates render HTML, Views contain the logic that joins them. The URL map decides which view handles which request.
Wire the app in
In config/settings.py add your app and a project-level templates folder:
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"shop",
]
TEMPLATES[0]["DIRS"] = [BASE_DIR / "templates"]
TIME_ZONE = "Asia/Kolkata"
USE_TZ = True
Keeping USE_TZ = True stores timestamps in UTC and renders them in IST — do not turn it off to "fix" times.
Settings that differ per machine
Never commit a secret. Read anything environment-specific from the environment:
import os
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent
SECRET_KEY = os.environ["DJANGO_SECRET_KEY"]
DEBUG = os.environ.get("DJANGO_DEBUG", "0") == "1"
ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS", "").split(",")
DATABASES = {
"default": {
"ENGINE": "django.db.backends.mysql",
"NAME": os.environ.get("DB_NAME", "shopdb"),
"USER": os.environ.get("DB_USER", "root"),
"PASSWORD": os.environ.get("DB_PASSWORD", ""),
"HOST": os.environ.get("DB_HOST", "127.0.0.1"),
"PORT": "3306",
"OPTIONS": {"charset": "utf8mb4"},
}
}
Use utf8mb4 so Hindi, Tamil and emoji all store correctly. Keep a .env file locally, add it to .gitignore, and
load it with python-dotenv in manage.py.
One more decision to take on day one: if you might ever customise the user model, do it now with a custom user app. Changing it after the first migration is painful.
The commands you will use daily
| Command | What it does |
|---|---|
runserver |
Development server with auto-reload (never in production) |
makemigrations |
Turn model changes into migration files |
migrate |
Apply migrations to the database |
createsuperuser |
Make an admin login |
shell |
A Python shell with Django loaded |
check --deploy |
Audit production settings |
test |
Run the test suite |
Common mistakes
- Forgetting to activate the virtual environment, then installing into the system Python.
- Leaving
SECRET_KEYand database passwords insettings.pyand pushing to GitHub. - Omitting the app from
INSTALLED_APPSand wondering why migrations are empty. - Running
runserverin production.
Practice
Create a project called config with an app called billing, point it at a MySQL database through environment
variables, and confirm python manage.py check passes with DJANGO_DEBUG=0 and a real ALLOWED_HOSTS value set.