1) Create a clean Python environment
A clean environment isolates your project’s dependencies (Django version, libraries) from other projects on your machine. This prevents “works on my machine” issues and makes your backend reproducible.
Step-by-step: create and activate a virtual environment
- Create a project folder (example:
first_backend/) and enter it. - Create a virtual environment named
.venv(a common convention). - Activate it.
- Install Django.
# macOS/Linux (bash/zsh) example commands
mkdir first_backend
cd first_backend
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
pip install django
# Windows (PowerShell) example commands
mkdir first_backend
cd first_backend
py -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
pip install djangoVerify Django is available inside the environment:
python -m django --version2) Create a new Django project
A Django “project” is the container for settings and configuration. Inside it, you’ll create one or more “apps” that hold features (e.g., accounts, blog, payments).
Step-by-step: start a project
Run django-admin to generate the project scaffold. The trailing dot (.) tells Django to create files in the current directory (keeps the folder structure tidy).
django-admin startproject config .You should now see a structure similar to:
Continue in our app.
You can listen to the audiobook with the screen off, receive a free certificate for this course, and also have access to 5,000 other free online courses.
Or continue reading below...Download the app
first_backend/
manage.py
config/
__init__.py
settings.py
urls.py
asgi.py
wsgi.py3) Understand manage.py and core project files
manage.py: your project command runner
manage.py is a small script that sets the correct Django settings module and then delegates to Django’s command-line system. You use it for tasks like running the dev server, creating apps, running migrations, opening a Django shell, and more.
Examples of commands you’ll commonly run:
python manage.py runserver(start development server)python manage.py startapp core(create an app)python manage.py check(validate configuration)
config/settings.py: configuration for this project
This file defines settings such as installed apps, middleware, templates, database configuration, static files, and security-related options. In development you’ll tweak settings frequently; in production you’ll typically split settings or use environment variables.
config/urls.py: the URL entry point
This file is the top-level URL router. It maps URL paths to views (or includes other URL modules). As your project grows, you’ll usually keep this file small and delegate routing to each app.
config/wsgi.py and config/asgi.py: deployment entry points
wsgi.pyis used by WSGI servers (traditional synchronous deployments).asgi.pyis used by ASGI servers (async-capable deployments, websockets, etc.).
You typically don’t edit these often early on, but it’s important to know they exist for deployment.
4) Run the development server
Step-by-step: start the server
python manage.py runserverBy default, Django serves on http://127.0.0.1:8000/. Visit that URL in your browser. If everything is set up correctly, you’ll see Django’s default success page.
What the dev server is (and isn’t)
- It’s a convenience server for local development: auto-reload, helpful error pages, quick iteration.
- It is not intended for production traffic or hardened security.
5) Trace the request/response cycle (high level)
When you request a URL in Django, the flow looks like this:
- Browser/client sends an HTTP request to the server (e.g.,
GET /hello/). - Django receives the request through the server interface (dev server now; WSGI/ASGI in deployment).
- Middleware runs (a chain of components that can modify the request/response, handle sessions, authentication, security headers, etc.).
- URL routing matches a path in
config/urls.py(and included app URL modules). - A view runs (a Python function or class) and returns an
HttpResponse(HTML, JSON, redirect, 404, etc.). - Django builds the final response (middleware can modify it on the way out).
- Server sends the HTTP response back to the client.
For a backend API, the “view returns JSON” is a common pattern; for a server-rendered site, the view often renders a template into HTML.
6) Create your first app and wire it in
An “app” is a self-contained feature unit: it can have its own URLs, views, models, templates, tests, and admin configuration. Even for small projects, using apps helps keep code organized.
Step-by-step: create an app
python manage.py startapp coreThis creates:
core/
__init__.py
admin.py
apps.py
migrations/
__init__.py
models.py
tests.py
views.pyRegister the app in INSTALLED_APPS
Open config/settings.py and add the app config to INSTALLED_APPS:
# config/settings.py
INSTALLED_APPS = [
# ... default Django apps ...
'core.apps.CoreConfig',
]This tells Django to include the app in project discovery (models, migrations, admin, etc.).
7) Add a simple URL route and view
To confirm everything is wired correctly, you’ll create a minimal view and map it to a URL.
Create a view
Edit core/views.py:
# core/views.py
from django.http import HttpResponse
def hello(request):
return HttpResponse("Hello from Django!")Create app-level URLs
Create a new file core/urls.py:
# core/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('hello/', views.hello, name='hello'),
]Include the app URLs in the project URLs
Edit config/urls.py:
# config/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('core.urls')),
]Now run the server (or let it auto-reload) and visit:
http://127.0.0.1:8000/hello/You should see: Hello from Django!
8) Use Django’s debugging error pages effectively
In development, Django’s debug pages are designed to help you locate errors quickly. They show stack traces, local variables, and the exact line that failed.
Trigger a controlled error to see the debug page
Temporarily change the view to raise an exception:
# core/views.py
from django.http import HttpResponse
def hello(request):
1 / 0
return HttpResponse("Hello from Django!")Reload /hello/. You’ll see a detailed error page with:
- Exception type (e.g.,
ZeroDivisionError) - Traceback showing the call stack
- Source code context around the failing line
- Request information (path, method, headers)
Undo the error after confirming the debug page works.
Understand when debug pages appear
- They appear when
DEBUG = Trueinconfig/settings.py. - When
DEBUG = False, Django shows generic error pages (and you must configure allowed hosts, logging, and proper error handling).
Common “first setup” errors and what they mean
| Symptom | Likely cause | Where to look |
|---|---|---|
404 Not Found on /hello/ | URL not included or path mismatch | config/urls.py, core/urls.py |
ModuleNotFoundError for core | App not created, wrong name, or not on path | Folder name, INSTALLED_APPS |
| Server won’t start, settings error | Syntax error or misconfiguration | config/settings.py, terminal output |
9) Conventions for organizing code as the project grows
Early structure decisions make a big difference later. The goal is to keep responsibilities clear: project configuration in the project package, feature code in apps.
Keep project URLs thin; route by app
As you add apps, include each app’s URL module:
# config/urls.py
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('core.urls')),
path('accounts/', include('accounts.urls')),
path('api/', include('api.urls')),
]Use consistent app naming
- Prefer short, descriptive app names:
core,accounts,billing,inventory. - Avoid generic names like
utilsfor large mixed responsibilities; if you need shared helpers, keep them small and well-scoped.
Introduce a predictable layout inside each app
Django creates a minimal layout, but you can expand it as complexity increases. A common pattern is to split large files into modules:
core/
views/
__init__.py
health.py
pages.py
urls.py
services/
__init__.py
greeting.py
templates/
core/
home.htmlThis keeps views.py from becoming a “mega-file” and encourages separation between HTTP handling (views) and business logic (services).
Adopt a “thin views” mindset
As you move beyond a hello-world response, keep views focused on HTTP concerns (parsing input, returning responses) and move business rules into dedicated functions/classes. This improves testability and readability.
Use explicit imports and clear boundaries
- Views import from
servicesormodelsrather than duplicating logic. - Apps should avoid circular dependencies; if two apps need shared logic, consider a small, dedicated app (e.g.,
common) with a narrow purpose.