How to set up a Django project for production in 2024

Published 3/29/2024 12:36:42 PM
Filed under Python

Django is a great framework for building Python based web applications both for REST endpoints and regular websites. However, I've found that the default template lacks a few things that I like in my Python projects. In this article I'll show you how you can change the layout of your Django projects for the better.

Get a project management tool before you start

One of my worst nightmares is a Python project that doesn't use a virtual environment. It will break your Python installation. Python allows you to have just one version of a package installed per Python environment. This causes problems when you're working on multiple projects since the methods and properties of various packages change between versions. The solution is simple though, get a project management tool like Rye or Poetry.

Tools like Poetry and Rye help you solve the problem of managing packages in a project. When you add a package through one of these project management tools you automatically get the latest version and the package information is recorded in the project metadata. When you download the project on a different machine you can rebuild the environment automatically using the project management tool saving you a lot of time.

I prefer to use Rye these days because it's the fastest around. And it is less intrusive than Poetry. But whatever you use is great. It's better than breaking your Python installation.

Both Rye and Poetry assume you're building Python packages with a single root directory. This is a good assumption for many cases but not for Django. Django projects contain multiple packages and associated directories.

It's a bit harder to use a project management tool for Django projects but I still recommend using one. For Rye you can set up a new Django project environment like so:

rye init --virtual

This initializes a new project without a root package directory. You can still use Rye as normal. For a Django project you can run the following command to add the Django package:

rye add django
rye sync

The first command resolves the latest Django package and add it to my project manifest. The second command downloads the right Python version and syncs the Django project into my project virtual environment.

With that out of the way, let's look at how to set up a Django project.

Setting up a new Django project

Python projects with virtual environments require a bit more work to get going. To create a new Django web project, run the following command to activate the project environment on Linux/Mac:

source .venv/bin/activate

For Windows with Powershell you can run . .venv\scripts\activate Next, run the following command to start the new project:

django-admin startproject mywebsite .

This command adds the necessary project files for a new Django web project to the current directory. You can now run the website using the following command:

python manage.py migrate
python manage.py runserver

The first command migrates the database to the latest version. The second command starts the webserver to make the website available on http://localhost:8000/. This website isn't ready for production just yet. Let's cover how to manage settings for production next.

Managing settings for different environments

In the previous section we covered how to start a new Django project. The settings are stored in package named mywebsite if you followed the instructions from the previous section. There's just one version of the settings, but you'll need different combinations of settings for test and production.

The best way I've found to split settings per environment is to introduce a folder called settings and move the settings.py file into settings/base.py. Next, you need to create a new file called settings/development.py that will contain the development settings. The file should look like this:

from mywebsite.settings.base import * # noqa

SECRET_KEY = "<your-secret-key>"
DEBUG = True

ALLOWED_HOSTS = []

Repeat the process for the production settings by creating a settings/production.py file with the following content:

import os
from mywebsite.settings.base import * # noqa

SECRET_KEY = os.getenv("SECRET_KEY", "")
DEBUG = False

ALLOWED_HOSTS = ["your-production-domain.org"]

The secret key in production should not be stored in code. Instead you want to read this value from an environment variable. That way you can be sure that your secret key is not available to hackers breaking your GIT repo. If you're running a secret server, you can consider loading the secret key from there. Also, on production you don't want debug settings and you want to make sure you have a domain name specified.

To use the new settings pattern you'll want to modify the mywebsite/asgi.py, mywebsite/wsgi.py and manage.py files so they load the correct settings file for the active environment. Each of the mentioned files contains a line like this:

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mywebsite.settings")

Replace the line with the following two lines of code:

environment_name = os.getenv("APP_ENVIRONMENT", "development")
os.environ.setdefault("DJANGO_SETTINGS_MODULE", f"mywebsite.settings.{environment_name}")

The first line, resolves the environment from an environment variable. The second line loads the settings from the right module. Make sure to set the correct environment variable in production and you're up and going.

Adding the finishing touch with a core module

The settings pattern makes Django work a lot better in production. This next step will make things more sane for you as the developer of the website.

Django websites are modular. You need to create a new module for each functional area in your web project. In Django they call functional modules apps. You can create a new app with the following command:

python manage.py startapp customers

You can replace customers in this command with the name of your functional area. When you execute the command you end up with a directory that contains all the code needed to implement the new app/functional area.

Remember, we had the mywebsite directory that contains the core settings for the web project. Now I personally don't like it to be called mywebsite. It's weird. Honestly, it drives me insane.

If you want to stay sane, move the mywebsite directory to core and then modify the core/settings/base.py so that the variable ROOT_URLCONF refers to core.urls. There's also a setting called WSGI_APPLICATION in the base settings file. This setting should point to core.wsgi.application.

Make sure you also modify the core/asgi.py, core/wsgi.py and manage.py files so that you load the settings module from core.settings.{environment_name}.

Summary

Setting up Django projects for production is a bit of work. You will need to invest time to learn a project management tool and you'll want to restructure things a bit. But it's worth the effort.

I hope you liked this one!