Deployment: WSGI, Static & Settings
Deployment is the process of configuring and running your Django project on a production server safely, with debugging off, secrets in the environment, static files collected, and a real WSGI server handling requests.
Learn Deployment: WSGI, Static & Settings in our free Django course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a…
Part of the free Django course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
In this lesson you'll harden settings with DEBUG=False , ALLOWED_HOSTS , and an environment-driven SECRET_KEY , collect static files with collectstatic and WhiteNoise, serve the app through gunicorn and WSGI, parse a database URL, and run the deploy checklist.
The most important production change is turning DEBUG off and listing your real domains in ALLOWED_HOSTS . Secrets like SECRET_KEY must come from the environment, never from a file in your repository. You read them with os.environ at startup.
In production the dev server doesn't serve static files, so you run collectstatic to gather them into STATIC_ROOT and let WhiteNoise serve them. Your database connection arrives as a single DATABASE_URL , and you run the app through gunicorn , which loads your project's WSGI callable.
Django ships a built-in safety audit: python manage.py check --deploy . It inspects your settings and warns about anything unsafe for production — DEBUG left on, an empty ALLOWED_HOSTS , a weak SECRET_KEY , or missing SSL settings. Run it before every release.
Environment variables are strings, so "False" is truthy. Fill in the blank so DEBUG becomes the boolean False only when the variable is exactly "True" .
❌ DisallowedHost / Bad Request (400) after deploy
With DEBUG=False , Django rejects any host not listed in ALLOWED_HOSTS .
✅ Fix: add your domain(s) to ALLOWED_HOSTS , e.g. ["example.com", "www.example.com"] .
You never collected static files, or nothing is serving them.
✅ Fix: run collectstatic and add WhiteNoise middleware (or a CDN) to serve STATIC_ROOT .
A hard-coded SECRET_KEY in settings.py ends up in version control.
✅ Fix: read it from os.environ and store the value in your platform's secret manager.
Build a gate that loads settings from the environment, runs the production checklist, and only "deploys" when there are zero issues — otherwise it reports the blocking problems.
Lesson complete — you can ship to production!
You can harden settings with DEBUG=False , ALLOWED_HOSTS , and an env-driven SECRET_KEY , collect static files with collectstatic and WhiteNoise, run the app through gunicorn and WSGI, parse a database URL, and audit with check --deploy .
🚀 Up next: Checkpoint — Build a Django REST API — put pagination, auth, and caching together in one project.
Practice quiz
What must DEBUG be set to in production?
- True
- False
- 1
- 'on'
Answer: False. DEBUG=False hides tracebacks, enforces ALLOWED_HOSTS, and serves a generic 500 page.
Why is DEBUG=True dangerous in production?
- It makes the site slower only
- It disables the database
- It exposes code, settings, and environment in error pages
- It blocks all requests
Answer: It exposes code, settings, and environment in error pages. The debug error page leaks code, settings, and env vars to anyone who triggers an error.
What does collectstatic do?
- Compiles your Python code
- Gathers static files into STATIC_ROOT
- Minifies JavaScript only
- Starts the web server
Answer: Gathers static files into STATIC_ROOT. collectstatic gathers static files from all apps into the single STATIC_ROOT directory.
What is WSGI?
- A database driver
- A template engine
- A caching backend
- The standard interface between a Python web app and a server
Answer: The standard interface between a Python web app and a server. WSGI is the standard interface; project/wsgi.py exposes the 'application' callable.
Which command starts a production WSGI server for project/wsgi.py?
- gunicorn project.wsgi:application
- python manage.py runserver
- django-admin serve
- wsgi start project
Answer: gunicorn project.wsgi:application. gunicorn imports the WSGI application callable and serves it with worker processes.
What does WhiteNoise let you do?
- Encrypt the database
- Serve collected static files efficiently from the app server
- Run background tasks
- Manage migrations
Answer: Serve collected static files efficiently from the app server. WhiteNoise serves the collected static files with caching headers, the simplest production option without a CDN.
Why must ALLOWED_HOSTS be set when DEBUG=False?
- It speeds up rendering
- It configures static files
- Django rejects any host not listed, raising DisallowedHost
- It enables the admin
Answer: Django rejects any host not listed, raising DisallowedHost. With DEBUG off Django enforces ALLOWED_HOSTS and returns 400 for unlisted hosts.
How should SECRET_KEY be supplied in production?
- Hard-coded in settings.py
- Committed to the repository
- Generated fresh on every request
- Read from an environment variable, never committed
Answer: Read from an environment variable, never committed. Read SECRET_KEY from os.environ and keep it out of source control.
Which command audits settings for production safety?
- python manage.py check --deploy
- python manage.py audit
- python manage.py secure
- python manage.py validate
Answer: python manage.py check --deploy. check --deploy warns about DEBUG, empty ALLOWED_HOSTS, weak SECRET_KEY, and missing SSL settings.
Why compare an env var explicitly with == 'True' for DEBUG?
- It is faster than bool()
- Env vars are strings, so even 'False' is truthy
- Django requires the string form
- It avoids importing os
Answer: Env vars are strings, so even 'False' is truthy. Environment values arrive as strings; any non-empty string is truthy, so compare to 'True'.