Project Structure Deep Dive
Running startproject generated a handful of files without much explanation of what
each one is for. Before adding TaskFlow's own code, it's worth slowing down and going through
every generated file, especially settings.py, whose variables you'll be coming back
to again and again for the rest of this track.
The Generated Layout
After running django-admin startproject taskflow_project ., your folder looks like
this:
taskflow/
├── manage.py
└── taskflow_project/
├── __init__.py
├── settings.py
├── urls.py
├── asgi.py
└── wsgi.py
| File / Folder | Purpose |
|---|---|
manage.py | The command-line entry point for this specific project — runs the server, migrations, and every other management command |
taskflow_project/ | The project's configuration package — not an app, just settings and wiring |
taskflow_project/__init__.py | An empty file that marks the folder as an importable Python package |
taskflow_project/settings.py | Every project-wide setting: installed apps, database connection, templates, static files, and more |
taskflow_project/urls.py | The project's root URL configuration — the starting point for routing every incoming request |
taskflow_project/wsgi.py | The entry point traditional (synchronous) production servers use to run TaskFlow |
taskflow_project/asgi.py | The entry point asynchronous-capable production servers use to run TaskFlow |
Touring settings.py: The Variables You'll Use Constantly
settings.py is a plain Python file — every "setting" is just a module-level
variable that Django reads at startup. A handful of these matter enough to understand right away:
import os
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent
DEBUG = True
ALLOWED_HOSTS = []
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
STATIC_URL = 'static/'
- DEBUG — when
True, Django shows detailed error pages with full tracebacks and configuration details whenever something goes wrong. Extremely useful while developing TaskFlow locally, and extremely dangerous if left on for a live site (more on this below). - ALLOWED_HOSTS — a list of hostnames/domains this Django project is allowed to serve. It's mostly ignored while
DEBUGisTrue, but Django enforces it strictly onceDEBUGisFalse, as a defense against certain HTTP header attacks. - INSTALLED_APPS — the list of every app Django should load for this project, including its own built-in apps (admin, auth, sessions) and, soon, TaskFlow's own
taskflowapp. We'll add it here in the next lesson. - DATABASES — the connection details for TaskFlow's database. By default this points at a local SQLite file, which is perfect for learning and small projects; we'll work with this in depth in Models & Migrations.
- TEMPLATES — configuration for how Django finds and renders the HTML template files that make up TaskFlow's pages, covered fully in Django Template Language.
- STATIC_URL — the URL prefix Django uses to serve CSS, JavaScript, and image files, expanded on in Static Files.
ROOT_URLCONF and the Project's urls.py
Another setting worth knowing about early is ROOT_URLCONF, which by default looks
like this:
ROOT_URLCONF = 'taskflow_project.urls'
This single line tells Django exactly where to start looking when a request comes in: at the
urlpatterns list inside taskflow_project/urls.py. Every URL TaskFlow
responds to — the task list, a project's detail page, the admin site — is ultimately
reachable because it's connected, directly or indirectly, from this one root file. We'll dig into
exactly how that works in URL Routing, a couple of lessons
from now.
wsgi.py and asgi.py: Talking to Production Servers
wsgi.py and asgi.py aren't files you'll edit often, but they matter once
TaskFlow needs to run somewhere other than your own machine. Both files expose a small
"application" object that a production web server (like Gunicorn or uWSGI for WSGI, or Daphne or
Uvicorn for ASGI) uses to actually talk to Django and hand it incoming requests. The development
server we've been using (python manage.py runserver) is a stand-in for this during
local development; a real production deployment swaps it out for one of these dedicated servers,
a process we'll cover fully in Deployment.
Why DEBUG = True Must Never Reach Production
It's worth calling this out clearly and early, because it's a genuine, well-documented security
risk rather than a stylistic preference. When DEBUG is True and an
unhandled error occurs, Django's error page shows a full Python traceback, the values of local
variables at the point of failure, your installed apps, and other internal configuration details
— all visible to whoever triggered the error. On a local development machine that's a
helpful debugging tool. On a live, public site, it can hand an attacker a detailed map of your
application's internals.
DEBUG
specifically as part of CSRF & Security and again when
preparing TaskFlow for a real server in Deployment. The safe
pattern, previewed here and covered in full in
Environment Configuration, is to load
DEBUG from an environment variable that defaults to False, rather than
hardcoding True directly in settings.py.
INSTALLED_APPS.