Deploying Django
Preparation
Complete the .env
file with additional variables
If your .env
file doesn’t exist yet, create one and use a tool to load the variables. My choice is environs
pip install environs
In the case of using dj-database-url
to connect to postgres database, the .env
file already includes at least one variable DATABASE_URL
.
Consider adding the following variables to the .env
file before deploying: SECRET_KEY
, DEBUG
, and other data or passwords, as well as API keys that you don’t want to share in production.
For generating secret key use this command:
python -c 'import secrets;print(secrets.token_hex(32))'
Set DEBUG
to true in development mode, and to false by default.
# config/settings.py
from environs import Env
# Load the environment variables
env = Env()
env.read_env()
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = env.str('SECRET_KEY')
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = env.bool('DEBUG', default=False)
After deploying you might have to set these variables in your choosen service or cloud platform as well.
Git, GitHub
Create Git repository locally
Download Git: https://git-scm.com/downloads
Install Git on your system
Check if the installation is succesful
git --version
Initalize a Git repository in your project directory
cd <project path>
git init
Create a GitHub account if you haven’t got yet: https://github.com/
Create a new repository Repository/new
, name the new repo, set to private or keep it public
Create a .gitignore
file and add the names of the files to it that should be ignored while pushing to GitHub.
Typically, the .env
file, virtual environment, and other non-public data, is placed in this file.
If you use React as well, copy the content of frontend/.gitignore
(related to React) to the new .gitignore
file in the project directory.
Delete frontend/.gitignore
Create your README.md
file and delete frontend/README.md
(if you don’t need it)
Connect the local Git repository to the remote GitHub repo
git remote add origin <copy the path from github>
Add all files that are not ignored by .gitignore
git add .
Make the first inital commit
git commit -m 'init'
Push it to the GitHub
git push -u origin main
Collect staticfiles
Add STATIC_ROOT
to config/settings.py
Set STATIC_ROOT
to point to other destination than STATICFILES_DIRS
Install whitenoise
pipenv install whitenoise
MIDDLEWARE = [
# ...
"django.middleware.security.SecurityMiddleware",
"whitenoise.middleware.WhiteNoiseMiddleware",
# ...
]
Collect static files before deploying
python manage.py collectstatic --noinput
Update config/settings.py
Add the URL to the ALLOWED_HOSTS
- myappname.up.railway.app or myappname.herokuapp.com for example - or set to ‘*’ temporarily.
Gunicorn
https://pypi.org/project/gunicorn/
pipenv install gunicorn
Procfile
web: gunicorn config.wsgi --log-file -
requirements.txt
Create a text file for listing dependencies
pip freeze > requirements.txt
Deploying to Railway
Create an account on Railway
Open Railway Dashboard
Add New Project
Add Postgres as database \ Select Deploy PostgreSQL option
Create +, then select the GitHub repo to deploy
Set VariablesSECRET_KEY
from your .env
file and DATABASE_URL
from Railway (you have to copy the DATABASE_PUBLIC_URL from the Postgres variables)
Go to Settings Generate or add a custom URL: Networking\Public Networking
Go to Deploy\Custom Start Command and add the gunicorn command
gunicorn config.wsgi --log-file -
Update config/settings.py
Add the domain to ALLOWED_HOSTS
Add the URL to CSRF_TRUSTED_ORIGINS
If you want to deploy a JS front-end library with NodeJS (ReactJS e.g.) as well, then create a nixpacks.toml
file
providers = ["node", "python"]
Finally, deploy the project using the button on the dashboard.
Deploying to Heroku
Create an account on Heroku
Install Heroku CLI
cd <project-name>
Login to Heroku
heroku login
Open Heroku Dashboard
Create New Project in Heroku
Environment variables
Overview > heroku postgres > settings > database credentials. Then copy URI to DATABASE_URL
variable in config vars.
Add SECRET_KEY
and DISABLE_COLLECTSTATIC
and setting to 1, if needed.
If you want to deploy a JS front-end library with NodeJS (ReactJS e.g.) as well
A Node.js app on Heroku requires a ‘package.json’ at the root of the directory structure. If you are trying to deploy a Node.js application, ensure that this file is present at the top level directory.
Since the package.json
is dependent on the other React related files, copy the entire contents of the frontend
directory into the root directory!
If you are using Vite to create React project, don’t forget the build:OutDir to modify to ‘./static’ in the vite.config.js
!
Add heroku/nodejs Buildpack
Complete the process on your system
If heroku does not support the python version which you would like to use in runtime.txt
then ignore it - .slugignore
- and use the default on the platform. Files and directories listing in slugignore will be ignored by Heroku.
Add your heroku domain to the ALLOWED_HOSTS
in config/settings.py
Using git to start deployment process
heroku git:remote <project-name>
git add .
git commit -m 'deploying'
Finally,
git push heroku main
heroku run python manage.py migrate
Docker
Sign up/in Docker Hub: https://app.docker.com/signup
Download and install Docker Desktop: https://docs.docker.com/desktop/install/windows-install/
Check if the installation is successful, then run the ‘hello world’ image.
docker --version
docker run hello-world
Create a requirements text file, if you haven’t created one yet, that will be used by the Dockerfile to install the dependencies in the container.
pip freeze > requirements.txt
Dockerfile
# Pull base image
FROM python:3.11-slim-bullseye
# Set environment variables
ENV PIP_DISABLE_PIP_VERSION_CHECK 1
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
# Set work directory
WORKDIR /code
# Install dependencies
COPY ./requirements.txt .
RUN pip install -r requirements.txt
# Copy project
COPY . /code/
docker-compose.yml
services:
backend:
build: .
container_name: my_helloworld
command: python manage.py runserver 0.0.0.0:8000
volumes:
- .:/code
ports:
- 8000:8000
depends_on:
- db
environment:
- "SECRET_KEY=${SECRET_KEY}" # .env
- "DEBUG=True"
- "DATABASE_URL=postgres://postgres:postgres@db:5432/postgres"
- "SSL_REQUIRED=False"
db:
image: postgres:16.2
container_name: my_helloworld_db
ports:
- '5432:5432'
volumes:
- postgres_data:/var/lib/postgresql/data/
environment:
- "POSTGRES_HOST_AUTH_METHOD=trust"
volumes:
postgres_data:
According to the content of compose yaml file, generate secret key and add to the .env
file.
python -c 'import secrets;print(secrets.token_hex(32))'
# .env
SECRET_KEY="<generated with the command above>"
DEBUG=True # Set the `DEBUG` variable as well
Modify secret key and the debug in the config/settings.py
# config/settings.py
SECRET_KEY = env.str('SECRET_KEY')
DEBUG = env.bool('DEBUG', default=False)
Build docker-compose
docker-compose build
Use Django commands to migrate data and create superuser
docker-compose exec backend python manage.py migrate
docker-compose exec backend python manage.py createsuperuser
Start services based on docker-compose.yml
docker-compose up -d
Open the application in the web-browser
http://localhost:8000/
To turn off the services
docker-compose down
To run any Django commands
docker-compose exec <django_service_name> python manage.py <command>
Use this repo’s README for more information about the Dockerfile and docker-compose.yml.
https://github.com/grbeno/django-postgres-docker