# Deploy Django

Django is detected from your dependencies and runs as a Python container on port `8000`. No Dockerfile needed - one is [generated](/platform/deployments/builds#dockerfiles-generated-or-your-own) unless the repo has its own.

## Serve it

Bind `0.0.0.0` on the routed [port](/create/build-settings#port) - `PORT` is set to it:

```bash
gunicorn myproject.wsgi --bind 0.0.0.0:$PORT
```

## Settings from the environment

Containers receive [environment variables](/platform/environment-variables#build-time-and-runtime) at runtime - read them in `settings.py`:

```python
import os

SECRET_KEY = os.environ["SECRET_KEY"]
DEBUG = os.environ.get("DEBUG", "false") == "true"
ALLOWED_HOSTS = ["*"]  # or the exact hosts you serve
```

## Database

Provision [managed PostgreSQL](/platform/databases) and read `DATABASE_URL` - `dj-database-url` turns it into the settings dict:

```python
import dj_database_url

DATABASES = {"default": dj_database_url.config(conn_max_age=60)}
```

Keep `sslmode=require` from the [connection string](/platform/databases/connect) as-is.

## Migrations

Run them where the database is reachable. The image build has no runtime variables, so the startup command is the natural place:

```bash
python manage.py migrate && gunicorn myproject.wsgi --bind 0.0.0.0:$PORT
```

Or run them from your laptop against the same `DATABASE_URL` - the [connection string works anywhere](/platform/databases/connect#connect-from-your-laptop).

## Static files

A container serves everything, static files included. The usual pattern is WhiteNoise: `collectstatic` during the build, WhiteNoise serving the result. Heavy asset traffic can move to its own [static site](/platform/frameworks#frontend) later.

## Related

- [Python](/platform/frameworks/python): Plain Python apps, and the runtime's defaults.
- [Connect an app](/platform/databases/connect): DATABASE_URL, TLS, per-environment databases.
- [Scaling](/create/scaling): Concurrency for CPU-heavy views, cold starts.
