Django starter
Start a Django project with django-admin, then add gunicorn, WhiteNoise, settings from variables and a small tanzahost.json to run it on Tanzahost.
Updated 17 Oct 20264 min read
Start with django-admin startproject, then add four packages, change a few lines of settings.py so it reads its secrets from variables, and add a tanzahost.json that collects static files and runs migrations. With gunicorn in your requirements, we start your app with it by ourselves.
1. Make the project with django-admin
Django 6.1 needs Python 3.12 or newer. As Django's own tutorial shows:
python -m pip install Django
django-admin startproject mysite djangotutorial
cd djangotutorialThat makes a folder djangotutorial with manage.py and a project called mysite. We read manage.py to find mysite, and start gunicorn mysite.wsgi:application on the port in PORT.
2. List your packages
Add requirements.txt at the top of the folder:
Django>=6.1,<6.2
gunicorn
whitenoise
psycopg[binary]gunicorn serves your app, WhiteNoise serves its static files, and psycopg talks to PostgreSQL. Add a file .python-version with the version to build with:
3.133. Read settings from variables
In mysite/settings.py, add import os at the top, then replace the lines for SECRET_KEY, DEBUG, ALLOWED_HOSTS and DATABASES with these:
DEBUG = os.environ.get("DEBUG") == "1"
SECRET_KEY = os.environ["SECRET_KEY"] if not DEBUG else os.environ.get("SECRET_KEY", "django-insecure-local-only")
ALLOWED_HOSTS = os.environ.get("ALLOWED_HOSTS", "localhost,127.0.0.1").split(",")
# Visitors arrive over https through Tanzahost's front door.
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
if os.environ.get("DB_HOST"):
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"HOST": os.environ["DB_HOST"],
"PORT": os.environ["DB_PORT"],
"NAME": os.environ["DB_DATABASE"],
"USER": os.environ["DB_USERNAME"],
"PASSWORD": os.environ["DB_PASSWORD"],
# The connection pool works one transaction at a time.
"DISABLE_SERVER_SIDE_CURSORS": True,
}
}
else:
DATABASES = {"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": BASE_DIR / "db.sqlite3"}}Then add WhiteNoise, as its own guide shows. In MIDDLEWARE, right after SecurityMiddleware:
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"whitenoise.middleware.WhiteNoiseMiddleware",
# the rest as it was
]And at the bottom of the file:
STATIC_ROOT = BASE_DIR / "staticfiles"
STORAGES = {
"default": {"BACKEND": "django.core.files.storage.FileSystemStorage"},
"staticfiles": {"BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage"},
}On your computer, run it with DEBUG=1 python manage.py runserver.
4. Add tanzahost.json
This tells us the two commands Django needs, and an address to check before visitors arrive. Put it at the top of the folder, next to manage.py:
{
"build": "python manage.py collectstatic --noinput",
"release": "python manage.py migrate --noinput",
"health": "/admin/login/"
}build gathers your static files into
staticfiles, once, while we build the app.release is the "before going live" command: migrations run once per deploy, before the switch. If they fail, the version before keeps serving.
health is the page a new version must answer before it gets visitors. A new project has no page at
/, so we check Django's admin login.
5. Push it to GitHub
Add a .gitignore with db.sqlite3, staticfiles/, __pycache__/ and .env, then:
git init
git add .
git commit -m "First version"
git branch -M main
git remote add origin https://github.com/asha/duka-api.git
git push -u origin main6. Add it as an app, with its database
On your project's page, in the Add a service card, choose App.
Give it an App name, like
api.Under Where's your code?, choose GitHub, then your repository and the branch
main, and choose Deploy.
This first build stops, because the app has no secret key yet. Nothing was live, so nothing broke. Now give it a database:
In Add a service, choose Database, then PostgreSQL.
Leave Add its connection details to your app's variables ticked, and add it.
Your app gets DB_HOST, DB_PORT, DB_DATABASE, DB_USERNAME and DB_PASSWORD, through connection pooling. Then make a secret key on your computer:
python -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())"Open the project's Variables tab, choose your app, then Paste a .env file, and paste these, with your own key:
SECRET_KEY=…
ALLOWED_HOSTS=*Last, on the app's Code card, choose Build again. The build installs your packages with pip and collects the static files, the migrations run, and the app goes live on its free address once /admin/login/ answers. Every push to main then deploys by itself, without downtime.
Django checks the host of each request, to stop requests meant for another site. Our front door already does that: it sends your app only the visits for its own addresses. Our health check calls your app by its private address, which no list of host names would hold, so * is what lets it through. To keep a list of your addresses instead, give the health check a path of its own: DisallowedHost shows how, and Deploy Django does it that way.
What's next
Make an admin user in the browser's terminal: open your app, choose Terminal, and run
python manage.py createsuperuser.Run Celery or another queue as a worker, in the app's Processes: Processes.
Read Deploy Django for the whole walkthrough, and PostgreSQL for the pool and the direct address.