🛠️ Setting Up a Django Project
Time to go from theory to a running server. In this lesson you'll build a clean, isolated environment, install Django 5, generate your first project, and open it in a browser — the exact ritual professional Django developers repeat at the start of every project.
🎯 Learning Objectives
By the end of this lesson, you will be able to:
- Create and activate a Python virtual environment and explain why it matters
- Install Django and verify the version from the command line
- Use
startprojectand identify the purpose of every generated file - Configure key settings — database, apps, templates, time zone, and security
- Run migrations, create a superuser, and launch the development server
Estimated Time: 35–45 minutes • Difficulty: Beginner
Hands-on: Build a working blogsite project end to end and log into its admin.
In This Lesson
Prerequisites
Setting up cleanly is like laying out your ingredients before you start cooking — it prevents mid-recipe scrambles. Confirm you have these ready:
| Tool | Why | Check it |
|---|---|---|
| Python 3.10+ | Django 5 requires it. | python --version |
| pip | Installs Python packages; ships with Python. | pip --version |
| An editor | VS Code, PyCharm, or similar. | — |
| A terminal | PowerShell/Command Prompt on Windows, Terminal on macOS/Linux. | — |
⚠️ python vs. python3
On macOS and many Linux distros, python may point at an old Python 2 or nothing at all — use python3 (and pip3) there. On Windows the command is usually just python. If in doubt, run the version check first.
The Virtual Environment
A virtual environment is an isolated, per-project Python installation. Packages you install inside it stay inside it, so Project A's Django 5.0 never collides with Project B's Django 4.2, and nothing pollutes your system Python.
🧰 Analogy: A virtual environment is a separate toolbox for each project. You never accidentally grab Project A's wrench while working on Project B, and each toolbox can hold a different version of the same tool without conflict.
Create and activate
# Windows (PowerShell)
python -m venv venv
venv\Scripts\activate
# macOS / Linux
python3 -m venv venv
source venv/bin/activate
When it's active, your prompt gains a (venv) prefix. Every pip install now lands in this isolated folder. When you're done for the day:
deactivate
💡 Naming tip
Calling the folder venv (or .venv) is a widely followed convention — editors auto-detect it, and it's the first thing you add to .gitignore so the environment never gets committed.
Installing Django
With the environment active, install Django from PyPI:
# Latest stable release
pip install django
# Or pin a specific version (recommended for teams)
pip install "django==5.1.*"
Confirm it worked:
python -m django --version
Expected output:
5.1.4
Immediately record what you installed so a teammate (or future you) can rebuild the exact environment:
pip freeze > requirements.txt
Anyone can then reproduce it with pip install -r requirements.txt. Think of requirements.txt as the recipe card for your project's dependencies.
Creating the Project
Django ships a command-line tool, django-admin, that scaffolds a new project:
django-admin startproject myproject
That creates a myproject/ folder containing another myproject/ folder — a nesting that trips up beginners. To avoid the double folder, add a trailing dot to build the project in the current directory:
# Common in real projects — no extra wrapper folder
mkdir blogsite && cd blogsite
django-admin startproject config .
Here the inner package is named config, a popular convention that makes "the settings package" obvious. For the rest of this lesson we'll use the default myproject name to match what startproject myproject produces.
What you get
myproject/
├── manage.py
└── myproject/
├── __init__.py
├── asgi.py
├── settings.py
├── urls.py
└── wsgi.py
🏗️ Analogy: startproject pours the foundation and frames the walls. The house is empty, but it is structurally complete and ready for you to move features in.
Understanding the Files
Every file has a job. Learn them once and the project layout stops feeling mysterious.
| File | Role |
|---|---|
manage.py | Your project's control panel — run the server, migrations, shell, and more. |
__init__.py | Marks the folder as a Python package. Usually empty. |
settings.py | All configuration: apps, database, templates, security, locale. |
urls.py | The site's URL routing table — the "table of contents". |
wsgi.py | Entry point for traditional (synchronous) production servers. |
asgi.py | Entry point for async-capable servers (WebSockets, etc.). |
manage.py — the control panel
You will type python manage.py … hundreds of times. It's a thin wrapper that points Django at your settings and forwards commands:
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
def main():
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myproject.settings")
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH? Did you forget to activate "
"a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == "__main__":
main()
urls.py — the routing table
A fresh project routes only the admin site. You'll add your own patterns here (usually with include()) as you build apps:
from django.contrib import admin
from django.urls import path
urlpatterns = [
path("admin/", admin.site.urls),
]
💁 Analogy: urls.py is the receptionist. When a request walks in, the receptionist reads the requested path and directs it to the right department (view).
Configuring settings.py
The settings.py file is your project's control center. Here are the settings you'll touch most often.
Installed apps & middleware
Every project starts with Django's own apps enabled. You'll append your apps to this list later:
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
# Your apps go here, e.g.:
# "blog",
]
Database
SQLite is the zero-config default — perfect for learning. For production you'll switch to PostgreSQL:
# Default: SQLite (development)
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "db.sqlite3",
}
}
# Production: PostgreSQL
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": "blogsite",
"USER": "blog_user",
"PASSWORD": os.environ["DB_PASSWORD"],
"HOST": "localhost",
"PORT": "5432",
}
}
Templates, static files, and locale
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [BASE_DIR / "templates"], # project-level templates
"APP_DIRS": True, # each app's templates/ folder
"OPTIONS": {
"context_processors": [
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
],
},
},
]
STATIC_URL = "static/"
STATICFILES_DIRS = [BASE_DIR / "static"]
TIME_ZONE = "America/New_York"
LANGUAGE_CODE = "en-us"
USE_TZ = True
Security: DEBUG, SECRET_KEY, ALLOWED_HOSTS
These three settings behave differently in development and production. The safest pattern is to read them from environment variables:
import os
# Never hard-code the real key or commit it — read from the environment.
SECRET_KEY = os.environ.get("DJANGO_SECRET_KEY", "dev-only-insecure-key")
# True locally; MUST be False in production.
DEBUG = os.environ.get("DJANGO_DEBUG", "True") == "True"
ALLOWED_HOSTS = [] if DEBUG else ["example.com", "www.example.com"]
🚨 Two rules you must never break
- Never ship
DEBUG = Trueto production — it leaks your settings and stack traces to the public. - Never commit your real
SECRET_KEYto version control. Keep it in an environment variable or a secrets manager.
Running the Server
From the folder that contains manage.py, start Django's built-in development server:
python manage.py runserver
# Or on a different port
python manage.py runserver 8080
Visit http://127.0.0.1:8000/ and you'll meet Django's launch page:
DEBUG = True and no URLs are configured.The server auto-reloads when you save a file, so you rarely restart it manually.
⚠️ Development only
runserver is built for convenience, not for the public internet. It lacks the performance and hardening of production servers like Gunicorn or uWSGI. Never use it to serve real traffic.
Migrations & the Superuser
Django's built-in apps (auth, sessions, admin) need database tables. The migrate command creates them:
python manage.py migrate
Now create an administrator account so you can log into the admin site:
python manage.py createsuperuser
You'll be prompted for a username, email, and password. Then restart the server (if needed), visit http://127.0.0.1:8000/admin/, and log in. You get a full data-management interface for free.
💡 Order matters
Run migrate before createsuperuser — the superuser is stored in a table that migrations create. If you see "no such table: auth_user", you skipped migrate.
Commands you'll use constantly
| Command | What it does |
|---|---|
runserver | Start the development server. |
makemigrations | Generate migration files from model changes. |
migrate | Apply migrations to the database. |
createsuperuser | Create an admin account. |
startapp | Scaffold a new app inside the project. |
shell | Open a Python shell with Django loaded. |
test | Run your test suite. |
Hands-on Exercise
🏋️ Build the "blogsite" Project
Objective: Go from an empty folder to a running Django project you can log into — the full setup ritual, start to finish.
Instructions:
- Create and activate a virtual environment named
venv. - Install Django and save a
requirements.txt. - Create a project called
blogsite(use the trailing dot to avoid a wrapper folder). - Set
TIME_ZONEto your own locale insettings.py. - Run
migrate, then create a superuser. - Start the server and log into
/admin/.
💡 Hint
If python manage.py runserver says the command isn't found or Django can't be imported, your virtual environment probably isn't active — re-run the activate step and confirm the (venv) prefix is in your prompt.
✅ Solution (the full command sequence)
# 1. Environment
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
# 2. Install + record
pip install django
pip freeze > requirements.txt
# 3. Create the project
mkdir blogsite && cd blogsite
django-admin startproject config .
# 4. Edit config/settings.py -> TIME_ZONE = "America/New_York"
# 5. Database + admin user
python manage.py migrate
python manage.py createsuperuser
# 6. Run it
python manage.py runserver
# Open http://127.0.0.1:8000/admin/ and log in
🎯 Quick Quiz
Question 1: Why should each Django project have its own virtual environment?
Question 2: Which file is your day-to-day "control panel" for running the server, migrations, and other commands?
Question 3: What must be true before deploying a Django project to production?
Summary & Quiz
🎉 Key Takeaways
- Always work inside a virtual environment and record dependencies in
requirements.txt. django-admin startprojectscaffolds the project; the trailing dot avoids a redundant wrapper folder.manage.pyis your control panel;settings.pyis the control center;urls.pyis the routing table.- Run
migratebeforecreatesuperuser, then start the server withrunserver. - For production:
DEBUG = False, secrets in environment variables, and a real database + server.
📚 Further Reading
- Django tutorial, part 1 — writing your first app
- Django settings reference
- Deployment checklist
- Python venv documentation
🚀 What's Next?
Your project is running, but it doesn't do anything yet. In the next lesson, Django Applications Structure, you'll create your first app and learn how projects and apps fit together.
🎉 You have a running Django project!
The scaffolding is up. Next we start building rooms inside it.