Bootstraping a production-ready django project
If you have some experience with django and feel that the django django-admin startproject command is too light for you, then cookiecuter-django might be just what you are looking for.
Through this guide, we will see how to start a new django project using a cookiecutter. This guide is intended for beginners and intermediate level devs who already have experience with django and want a ready to use production grade setup for their django projects. I'm promoting cookiecutter-django here, but it's not the only one available in town, a quick search for django cookiecutter on the django packages website or GitHub will give you a ton of options.
If you are wondering what I mean by production-ready, here is a non-exhaustive list of what I expect :
- settings oriented towards the highest level of security
- basic deployment requirements included
- logging and monitoring set up
- postgresql requirements included
- linters and formatters already set up
- pytest set up
- etc
And for convenience, cookiecutter-django makes it easy to set up via the prompt common django packages that solve common issues such as :
- Task queue manager (celery)
- Mail services (amazon SES, Sendgrid, etc.) etc.
- CI / CD pipeline (GitHub, gitlab, etc)
If you are already convinced at this point, just run the two commands below, and you are done 😀.
pip install "cookiecutter>=1.7.0"
cookiecutter https://github.com/cookiecutter/cookiecutter-django
Read on for a closer look at all the options available and why you might want to ignore some of them to simplify the initial project generated a bit.
So what is a cookiecutter anyway ?
The cookiecutter project was initiated by Audrey Feldroy, the co-author of the excellent Two Scoops of Django. It is a command-line utility that creates projects from cookiecutters (project templates). There are a multitude of cookiecutters for various frameworks, django, flask, etc.
Generate a project using cookiecutter-django
The default values are in brackets, if you see a blank line, then I used the default value by pressing the Enter key. Throughout the article I have included many links to other articles to help understand what I can't go into here, but don't feel obligated to follow each link every time, or you may never get through it 😅. I suggest you read the entire article at least once, then revisit it by following the links that interest you.
Installation
pip install "cookiecutter>=1.7.0"
cookiecutter https://github.com/cookiecutter/cookiecutter-django
Project metadata
This section is for basic project information such as name, description, authors, etc.
project_name [My Awesome Project]: Ushopify
project_slug [ushopify]:
description [Behold My Awesome Project!]: My amazing ecommerce platform.
author_name [Daniel Roy Greenfeld]: John Doe
domain_name [example.com]: ushopify.com
email [john-doe@example.com]: doe@ushopify.com
version [0.1.0]:
Select open_source_license:
1 - MIT
2 - BSD
3 - GPLv3
4 - Apache Software License 2.0
5 - Not open source
Choose from 1, 2, 3, 4, 5 [1]: 1
A source code license is a legal text that tells people what they may do with the source code, for example, edit it, use it, share it with others freely, etc. More information about software licensing here.
timezone [UTC]: US/Pacific
I chose a completely random location. You can get the full list of timezones or open your python shell (ever heard of bpython?) and type this code:
from pytz import all_timezones
for tz in all_timezones:
print(tz)
Editor and OS
I'm on linux, so n for me.
windows [n]:
use_pycharm [n]: y
If you are using pycharm, the cookiecutter will create runserver
, migrate
and more run configurations automatically for you, neat 😎.
Docker
use_docker [n]: n
Docker is an open source platform for developing, shipping, and running applications. Docker enables you to separate your applications from your infrastructure, so you can deliver software quickly. Enter y and the cookiecutter will automatically create docker and docker-compose files to help you run your project locally and even deploy it with less effort. It's a great start to help you deploy your project, but I think it is necessary to have a minimum of experience with docker to understand how to correctly use the generated files. If you want more information about docker, read this.
Select postgresql_version:
1 - 14
2 - 13
3 - 12
4 - 11
5 - 10
Choose from 1, 2, 3, 4, 5 [1]:
Set the version of postgresql to use in the Dockerfile for production. This only matters if you enter y at the use_docker option. As I don't often use the docker and docker compose configuration provided by the cookiecutter (I create my own files), it doesn't really matter to me.
Cloud services
Select cloud_provider:
1 - AWS
2 - GCP
3 - None
Choose from 1, 2, 3 [1]:
This is about static (HTML, CSS, static images like background images) and media files (file upload by you or your users like profile picture for example) storages. If you choose AWS (amazon web service) or GCP (google cloud provider), your project will be configured for these providers to handle static and media files in production. If you choose None, then media files will not work by default (you will have to set it up yourself) in production and static files will work only if you choose y on the option use_whitenoise. For a step-by-step guide on how to configure static and media files serving yourself using AWS, watch this.
Select mail_service:
1 - Mailgun
2 - Amazon SES
3 - Mailjet
4 - Mandrill
5 - Postmark
6 - Sendgrid
7 - SendinBlue
8 - SparkPost
9 - Other SMTP
Choose from 1, 2, 3, 4, 5, 6, 7, 8, 9 [1]: 2
I usually go with amazon SES because it is the easiest to set up for me, but do what you want based on your experience. For a simple setup based on SMTP settings, choose 9.
Async django
use_async [n]:
Indicates whether the project should use web sockets with Uvicorn + Gunicorn.
This statement is from the cookiecutter-django official documentation. If you are not sure what it means, there is a high chance you don't need it, skip it. If you want to know more about websocket in django, read this.
Django rest framework
use_drf [n]:
In case you are building a json based API, then choose y. More info on Dango Rest framework here. DRF is the go-to framework to build json-based APIs with django. What I call a json-based API here most people would call it a REST API, but here's why they're wrong.
Frontend
Select frontend_pipeline:
1 - None
2 - Django Compressor
3 - Gulp
Choose from 1, 2, 3 [1]:
The tools suggested here are for minification, transpilation, etc of static assets (CSS, JS, etc). I don't use any of them, so my answer is always the default, None. If you want to know more about these tools, check out their official documentation:
Celery
use_celery [n]:
Celery is an open source asynchronous task queue or job queue which is based on distributed message passing. While it supports scheduling, its focus is on operations in real time. That was the wikipedia definition 😅. Celery is used to handle asynchronous tasks (background tasks) and scheduled tasks (things that should happen in the future). I don't use celery that much, I find it a bit too complex for most of my use cases. You can read my article on Handling background tasks in django to see how I handle this kind of stuff in my projects.
Local email server setup
use_mailhog [n]: y
MailHog is an email testing tool for developers. The django console backend is set up for local development if you choose n but mailhog gives you a nice graphical user interface (GUI) when you test your email delivery locally.
Sentry - production error tracking
use_sentry [n]: y
Sentry is an error monitoring and tracking system. I recommend you always choose y if you know your app is going in production, it will avoid you the hassle of always switching your DEBUG environment variable value to see errors when they happened in production. It is very easy to set up, just follow the official guide If you want to configure it manually. If you choose y the only thing you need is a Sentry DSN key that you can get by creating a django app on the official web platform.
Whitenoise
use_whitenoise [n]: y
Whitenoise serves your static files in production and locally if you want it to. I usually choose y because having the same setup for production and local development can help mitigate surprises on your production environment.
Heroku
use_heroku [n]: y
Heroku is a hosting platform for web applications. The cookiecutter will add the necessary requirements for your project to work on heroku, these requirements being:
- A requirements.txt file with all your project production requirements
- A Procfile If you are using a similar deployment method based on a procfile like dokku type y if not then n.
Continuous Integration (CI)
Select ci_tool:
1 - None
2 - Travis
3 - Gitlab
4 - Github
Choose from 1, 2, 3, 4 [1]:
Select an option other than the default if you are planning to set up a CI/CD pipeline for your project. More info on how to set up CI/CD for a django project here.
Environment variables
keep_local_envs_in_vcs [y]:
If you typed y on the use_docker or use_heroku option, then your project will have a .envs
folder with .local
and .production
subdirectories.
If on the current option you type n, both folder will be kept out of your version control system (VCS), if you choose the default value your `.local will be tracked by your VCS.
Cookiecutter debug
debug [n]:
This option is only for Cookiecutter Django developers only, choose the default value.
If all went well, you will get this message.
[SUCCESS]: Project initialized, keep up the good work!
Structures of the project
Let's take a quick look at the generated project. I use tree to get a two-level tree view generated project.
cd ushopify
tree -L 2
├── CONTRIBUTORS.txt
├── LICENSE
├── README.md
├── config
│ ├── __init__.py
│ ├── settings
│ ├── urls.py
│ └── wsgi.py
├── docs
│ ├── Makefile
│ ├── __init__.py
│ ├── conf.py
│ ├── howto.rst
│ ├── index.rst
│ ├── make.bat
│ ├── pycharm
│ └── users.rst
├── locale
│ └── README.rst
├── manage.py
├── pytest.ini
├── requirements
│ ├── base.txt
│ ├── local.txt
│ └── production.txt
├── setup.cfg
├── ushopify
│ ├── __init__.py
│ ├── conftest.py
│ ├── contrib
│ ├── static
│ ├── templates
│ ├── users
│ └── utils
└── utility
├── install_os_dependencies.sh
├── install_python_dependencies.sh
├── requirements-bionic.apt
├── requirements-bullseye.apt
├── requirements-buster.apt
├── requirements-focal.apt
├── requirements-jessie.apt
├── requirements-stretch.apt
├── requirements-trusty.apt
└── requirements-xenial.apt
13 directories, 32 files
At the root of your project should have these directories:
config
: store all your project settings and configurations. In thesettings
subdirectory, you have abase.py
setting file for common settings, alocal.py
and aproduction.py
file respectively for development and production specific settings. In the root of this directory, you have your classicurl.py
(your project level urls configurations) and yourwsgi.py
file.docs
: if you need to write a documentation for your project, it is configured to use sphinx documentation generatorlocale
: this folder is there to store translationsrequirements
: this folder contains all your project's requirements, thebase.txt
file contains all requirements common to your dev and prod environments, thelocal.txt
file for your development environment andproduction.txt
for your production environment.ushopify
: this folder contains all your templates and statics files, it also contains ausers
app created by the cookiecutter. This app use the excellent allauth package to offers your project full user management system, login, logout, reset password, change password, change email, email verification and much more. Theusers
app contains atests
directory with test files structured like this:test_{module}.py
. This test structure is the one defined in theushopify/conftest.py
file. Follow it when writing your tests, or update theconftest.py
file to match your needs. In this folder, you also have autils
subdirectory that contains acontext_processors.py
file. Read this short article for more information on context processors.Utility
: this folder contains some bash scripts that help you install system and project requirements, useful only if you are planning on deploying on a linux server and set up the server yourself.
Beside those directories, you have the classic manage.py
file to run your commands, a Procfile
if you choose to deploy using Heroku, a pytest.ini
file because the project is configured to use pytest for testing.
Run your project
Running your project works like for any other django project, you create a virtual environment, you install the requirements, create a database, then run your migrations. You can find detailed instructions here.
I know it was a lot to digest and the project generated can seem very complex the first time, but you get used to it with time. If you feel like some of the generated defaults don't work for you, want to use poetry instead of a virtualenv, don't like the exact folder structure, etc, I encourage you to build your own cookiecutter or create a simpler version with the django project template system. If you have any comments, feel free to leave them in the comment section below and subscribe to keep up to date with my findings 😃.