Welcome to Cookiecutter Django’s documentation!

A Cookiecutter template for Django.

Contents:

Project Generation Options

project_name:
Your project’s human-readable name, capitals and spaces allowed.
project_slug:
Your project’s slug without dashes or spaces. Used to name your repo and in other places where a Python-importable version of your project name is needed.
description:
Describes your project and gets used in places like README.rst and such.
author_name:
This is you! The value goes into places like LICENSE and such.
email:
The email address you want to identify yourself in the project.
domain_name:
The domain name you plan to use for your project once it goes live. Note that it can be safely changed later on whenever you need to.
version:
The version of the project at its inception.
open_source_license:

A software license for the project. The choices are:

  1. MIT
  2. BSD
  3. GPLv3
  4. Apache Software License 2.0
  5. Not open source
timezone:
The value to be used for the TIME_ZONE setting of the project.
windows:
Indicates whether the project should be configured for development on Windows.
use_pycharm:
Indicates whether the project should be configured for development with PyCharm.
use_docker:
Indicates whether the project should be configured to use Docker and Docker Compose.
postgresql_version:

Select a PostgreSQL version to use. The choices are:

  1. 11.3
  2. 10.8
  3. 9.6
  4. 9.5
  5. 9.4
js_task_runner:

Select a JavaScript task runner. The choices are:

  1. None
  2. Gulp
cloud_provider:

Select a cloud provider for static & media files. The choices are:

  1. AWS
  2. GCP
  3. None

Note that if you choose no cloud provider, media files won’t work.

mail_service:

Select an email service that Django-Anymail provides

  1. Mailgun
  2. Amazon SES
  3. Mailjet
  4. Mandrill
  5. Postmark
  6. SendGrid
  7. SendinBlue
  8. SparkPost
  9. Other SMTP
use_drf:
Indicates whether the project should be configured to use Django Rest Framework.
custom_bootstrap_compilation:
Indicates whether the project should support Bootstrap recompilation via the selected JavaScript task runner’s task. This can be useful for real-time Bootstrap variable alteration.
use_compressor:
Indicates whether the project should be configured to use Django Compressor.
use_celery:
Indicates whether the project should be configured to use Celery.
use_mailhog:
Indicates whether the project should be configured to use MailHog.
use_sentry:
Indicates whether the project should be configured to use Sentry.
use_whitenoise:
Indicates whether the project should be configured to use WhiteNoise.
use_heroku:
Indicates whether the project should be configured so as to be deployable to Heroku.
ci_tool:

Select a CI tool for running tests. The choices are:

  1. None
  2. Travis CI
  3. Gitlab CI
keep_local_envs_in_vcs:
Indicates whether the project’s .envs/.local/ should be kept in VCS (comes in handy when working in teams where local environment reproducibility is strongly encouraged). Note: .env(s) are only utilized when Docker Compose and/or Heroku support is enabled.
debug:
Indicates whether the project should be configured for debugging. This option is relevant for Cookiecutter Django developers only.

Getting Up and Running Locally

Setting Up Development Environment

Make sure to have the following on your host:

First things first.

  1. Create a virtualenv:

    $ python3.7 -m venv <virtual env path>
    
  2. Activate the virtualenv you have just created:

    $ source <virtual env path>/bin/activate
    
  3. Install development requirements:

    $ pip install -r requirements/local.txt
    $ pre-commit install
    
     .. note::
    
        the `pre-commit` exists in the generated project as default.
        for the details of `pre-commit`, follow the [site of pre-commit](https://pre-commit.com/).
    
  4. Create a new PostgreSQL database using createdb:

    $ createdb <what you have entered as the project_slug at setup stage> -U postgres --password <password>
    

    Note

    if this is the first time a database is created on your machine you might need an initial PostgreSQL set up to allow local connections & set a password for the postgres user. The postgres documentation explains the syntax of the config file that you need to change.

  5. Set the environment variables for your database(s):

    $ export DATABASE_URL=postgres://postgres:<password>@127.0.0.1:5432/<DB name given to createdb>
    # Optional: set broker URL if using Celery
    $ export CELERY_BROKER_URL=redis://localhost:6379/0
    

    Note

    Check out the Settings page for a comprehensive list of the environments variables.

    See also

    To help setting up your environment variables, you have a few options:

    • create an .env file in the root of your project and define all the variables you need in it. Then you just need to have DJANGO_READ_DOT_ENV_FILE=True in your machine and all the variables will be read.
    • Use a local environment manager like direnv
  6. Apply migrations:

    $ python manage.py migrate
    
  7. See the application being served through Django development server:

    $ python manage.py runserver 0.0.0.0:8000
    

Setup Email Backend

MailHog

Note

In order for the project to support MailHog it must have been bootstrapped with use_mailhog set to y.

MailHog is used to receive emails during development, it is written in Go and has no external dependencies.

For instance, one of the packages we depend upon, django-allauth sends verification emails to new users signing up as well as to the existing ones who have not yet verified themselves.

  1. Download the latest MailHog release for your OS.

  2. Rename the build to MailHog.

  3. Copy the file to the project root.

  4. Make it executable:

    $ chmod +x MailHog
    
  5. Spin up another terminal window and start it there:

    ./MailHog
    
  6. Check out http://127.0.0.1:8025/ to see how it goes.

Now you have your own mail server running locally, ready to receive whatever you send it.

Console

Note

If you have generated your project with use_mailhog set to n this will be a default setup.

Alternatively, deliver emails over console via EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'.

In production, we have Mailgun configured to have your back!

Celery

If the project is configured to use Celery as a task scheduler then by default tasks are set to run on the main thread when developing locally. If you have the appropriate setup on your local machine then set the following in config/settings/local.py:

CELERY_TASK_ALWAYS_EAGER = False

Sass Compilation & Live Reloading

If you’d like to take advantage of live reloading and Sass compilation you can do so with a little bit of preparation, see Sass Compilation & Live Reloading.

Summary

Congratulations, you have made it! Keep on reading to unleash full potential of Cookiecutter Django.

Getting Up and Running Locally With Docker

The steps below will get you up and running with a local development environment. All of these commands assume you are in the root of your generated project.

Note

If you’re new to Docker, please be aware that some resources are cached system-wide and might reappear if you generate a project multiple times with the same name (e.g. this issue with Postgres).

Prerequisites

Build the Stack

This can take a while, especially the first time you run this particular command on your development system:

$ docker-compose -f local.yml build

Generally, if you want to emulate production environment use production.yml instead. And this is true for any other actions you might need to perform: whenever a switch is required, just do it!

Run the Stack

This brings up both Django and PostgreSQL. The first time it is run it might take a while to get started, but subsequent runs will occur quickly.

Open a terminal at the project root and run the following for local development:

$ docker-compose -f local.yml up

You can also set the environment variable COMPOSE_FILE pointing to local.yml like this:

$ export COMPOSE_FILE=local.yml

And then run:

$ docker-compose up

To run in a detached (background) mode, just:

$ docker-compose up -d

Execute Management Commands

As with any shell command that we wish to run in our container, this is done using the docker-compose -f local.yml run --rm command:

$ docker-compose -f local.yml run --rm django python manage.py migrate
$ docker-compose -f local.yml run --rm django python manage.py createsuperuser

Here, django is the target service we are executing the commands against.

(Optionally) Designate your Docker Development Server IP

When DEBUG is set to True, the host is validated against ['localhost', '127.0.0.1', '[::1]']. This is adequate when running a virtualenv. For Docker, in the config.settings.local, add your host development server IP to INTERNAL_IPS or ALLOWED_HOSTS if the variable exists.

Configuring the Environment

This is the excerpt from your project’s local.yml:

# ...

postgres:
  build:
    context: .
    dockerfile: ./compose/production/postgres/Dockerfile
  volumes:
    - local_postgres_data:/var/lib/postgresql/data
    - local_postgres_data_backups:/backups
  env_file:
    - ./.envs/.local/.postgres

# ...

The most important thing for us here now is env_file section enlisting ./.envs/.local/.postgres. Generally, the stack’s behavior is governed by a number of environment variables (env(s), for short) residing in envs/, for instance, this is what we generate for you:

.envs
├── .local
│   ├── .django
│   └── .postgres
└── .production
    ├── .django
    └── .postgres

By convention, for any service sI in environment e (you know someenv is an environment when there is a someenv.yml file in the project root), given sI requires configuration, a .envs/.e/.sI service configuration file exists.

Consider the aforementioned .envs/.local/.postgres:

# PostgreSQL
# ------------------------------------------------------------------------------
POSTGRES_HOST=postgres
POSTGRES_DB=<your project slug>
POSTGRES_USER=XgOWtQtJecsAbaIyslwGvFvPawftNaqO
POSTGRES_PASSWORD=jSljDz4whHuwO3aJIgVBrqEml5Ycbghorep4uVJ4xjDYQu0LfuTZdctj7y0YcCLu

The three envs we are presented with here are POSTGRES_DB, POSTGRES_USER, and POSTGRES_PASSWORD (by the way, their values have also been generated for you). You might have figured out already where these definitions will end up; it’s all the same with django service container envs.

One final touch: should you ever need to merge .envs/production/* in a single .env run the merge_production_dotenvs_in_dotenv.py:

$ python merge_production_dotenvs_in_dotenv.py

The .env file will then be created, with all your production envs residing beside each other.

Tips & Tricks

Activate a Docker Machine

This tells our computer that all future commands are specifically for the dev1 machine. Using the eval command we can switch machines as needed.:

$ eval "$(docker-machine env dev1)"

Debugging

ipdb

If you are using the following within your code to debug:

import ipdb; ipdb.set_trace()

Then you may need to run the following for it to work as desired:

$ docker-compose -f local.yml run --rm --service-ports django
django-debug-toolbar

In order for django-debug-toolbar to work designate your Docker Machine IP with INTERNAL_IPS in local.py.

Mailhog

When developing locally you can go with MailHog for email testing provided use_mailhog was set to y on setup. To proceed,

  1. make sure mailhog container is up and running;
  2. open up http://127.0.0.1:8025.

Celery tasks in local development

When not using docker Celery tasks are set to run in Eager mode, so that a full stack is not needed. When using docker the task scheduler will be used by default.

If you need tasks to be executed on the main thread during development set CELERY_TASK_ALWAYS_EAGER = True in config/settings/local.py.

Possible uses could be for testing, or ease of profiling with DJDT.

Celery Flower

Flower is a “real-time monitor and web admin for Celery distributed task queue”.

Prerequisites:

  • use_docker was set to y on project initialization;
  • use_celery was set to y on project initialization.

By default, it’s enabled both in local and production environments (local.yml and production.yml Docker Compose configs, respectively) through a flower service. For added security, flower requires its clients to provide authentication credentials specified as the corresponding environments’ .envs/.local/.django and .envs/.production/.django CELERY_FLOWER_USER and CELERY_FLOWER_PASSWORD environment variables. Check out localhost:5555 and see for yourself.

Settings

This project relies extensively on environment settings which will not work with Apache/mod_wsgi setups. It has been deployed successfully with both Gunicorn/Nginx and even uWSGI/Nginx.

For configuration purposes, the following table maps environment variables to their Django setting and project settings:

Environment Variable Django Setting Development Default Production Default
DJANGO_READ_DOT_ENV_FILE READ_DOT_ENV_FILE False False
Environment Variable Django Setting Development Default Production Default
DATABASE_URL DATABASES auto w/ Docker; postgres://project_slug w/o raises error
DJANGO_ADMIN_URL n/a ‘admin/’ raises error
DJANGO_DEBUG DEBUG True False
DJANGO_SECRET_KEY SECRET_KEY auto-generated raises error
DJANGO_SECURE_BROWSER_XSS_FILTER SECURE_BROWSER_XSS_FILTER n/a True
DJANGO_SECURE_SSL_REDIRECT SECURE_SSL_REDIRECT n/a True
DJANGO_SECURE_CONTENT_TYPE_NOSNIFF SECURE_CONTENT_TYPE_NOSNIFF n/a True
DJANGO_SECURE_FRAME_DENY SECURE_FRAME_DENY n/a True
DJANGO_SECURE_HSTS_INCLUDE_SUBDOMAINS HSTS_INCLUDE_SUBDOMAINS n/a True
DJANGO_SESSION_COOKIE_HTTPONLY SESSION_COOKIE_HTTPONLY n/a True
DJANGO_SESSION_COOKIE_SECURE SESSION_COOKIE_SECURE n/a False
DJANGO_DEFAULT_FROM_EMAIL DEFAULT_FROM_EMAIL n/a “your_project_name <noreply@your_domain_name>”
DJANGO_SERVER_EMAIL SERVER_EMAIL n/a “your_project_name <noreply@your_domain_name>”
DJANGO_EMAIL_SUBJECT_PREFIX EMAIL_SUBJECT_PREFIX n/a “[your_project_name] “
DJANGO_ALLOWED_HOSTS ALLOWED_HOSTS [‘*’] [‘your_domain_name’]

The following table lists settings and their defaults for third-party applications, which may or may not be part of your project:

Environment Variable Django Setting Development Default Production Default
CELERY_BROKER_URL CELERY_BROKER_URL auto w/ Docker; raises error w/o raises error
DJANGO_AWS_ACCESS_KEY_ID AWS_ACCESS_KEY_ID n/a raises error
DJANGO_AWS_SECRET_ACCESS_KEY AWS_SECRET_ACCESS_KEY n/a raises error
DJANGO_AWS_STORAGE_BUCKET_NAME AWS_STORAGE_BUCKET_NAME n/a raises error
DJANGO_AWS_S3_REGION_NAME AWS_S3_REGION_NAME n/a None
DJANGO_GCP_STORAGE_BUCKET_NAME GS_BUCKET_NAME n/a raises error
GOOGLE_APPLICATION_CREDENTIALS n/a n/a raises error
SENTRY_DSN SENTRY_DSN n/a raises error
DJANGO_SENTRY_LOG_LEVEL SENTRY_LOG_LEVEL n/a logging.INFO
MAILGUN_API_KEY MAILGUN_API_KEY n/a raises error
MAILGUN_DOMAIN MAILGUN_SENDER_DOMAIN n/a raises error
MAILGUN_API_URL n/a n/a https://api.mailgun.net/v3
MAILJET_API_KEY MAILJET_API_KEY n/a raises error
MAILJET_SECRET_KEY MAILJET_SECRET_KEY n/a raises error
MAILJET_API_URL n/a n/a https://api.mailjet.com/v3
MANDRILL_API_KEY MANDRILL_API_KEY n/a raises error
MANDRILL_API_URL n/a n/a https://mandrillapp.com/api/1.0
POSTMARK_SERVER_TOKEN POSTMARK_SERVER_TOKEN n/a raises error
POSTMARK_API_URL n/a n/a https://api.postmarkapp.com/
SENDGRID_API_KEY SENDGRID_API_KEY n/a raises error
SENDGRID_GENERATE_MESSAGE_ID True n/a raises error
SENDGRID_MERGE_FIELD_FORMAT None n/a raises error
SENDGRID_API_URL n/a n/a https://api.sendgrid.com/v3/
SENDINBLUE_API_KEY SENDINBLUE_API_KEY n/a raises error
SENDINBLUE_API_URL n/a n/a https://api.sendinblue.com/v3/
SPARKPOST_API_KEY SPARKPOST_API_KEY n/a raises error
SPARKPOST_API_URL n/a n/a https://api.sparkpost.com/api/v1

Other Environment Settings

DJANGO_ACCOUNT_ALLOW_REGISTRATION (=True)
Allow enable or disable user registration through django-allauth without disabling other characteristics like authentication and account management. (Django Setting: ACCOUNT_ALLOW_REGISTRATION)

Linters

flake8

To run flake8:

$ flake8

The config for flake8 is located in setup.cfg. It specifies:

  • Set max line length to 120 chars
  • Exclude .tox,.git,*/migrations/*,*/static/CACHE/*,docs,node_modules

pylint

This is included in flake8’s checks, but you can also run it separately to see a more detailed report:

$ pylint <python files that you wish to lint>

The config for pylint is located in .pylintrc. It specifies:

  • Use the pylint_django plugin. If using Celery, also use pylint_celery.
  • Set max line length to 120 chars
  • Disable linting messages for missing docstring and invalid name
  • max-parents=13

pycodestyle

This is included in flake8’s checks, but you can also run it separately to see a more detailed report:

$ pycodestyle <python files that you wish to lint>

The config for pycodestyle is located in setup.cfg. It specifies:

  • Set max line length to 120 chars
  • Exclude .tox,.git,*/migrations/*,*/static/CACHE/*,docs,node_modules

Testing

We encourage users to build application tests. As best practice, this should be done immediately after documentation of the application being built, before starting on any coding.

Pytest

This project uses the Pytest, a framework for easily building simple and scalable tests. After you have set up to develop locally, run the following commands to make sure the testing environment is ready:

$ pytest

You will get a readout of the users app that has already been set up with tests. If you do not want to run the pytest on the entire project, you can target a particular app by typing in its location:

$ pytest <path-to-app-in-project/app>

If you set up your project to develop locally with docker, run the following command:

$ docker-compose -f local.yml run --rm django pytest

Targeting particular apps for testing in docker follows a similar pattern as previously shown above.

Coverage

You should build your tests to provide the highest level of code coverage. You can run the pytest with code coverage by typing in the following command:

$ docker-compose -f local.yml run --rm django coverage run -m pytest

Once the tests are complete, in order to see the code coverage, run the following command:

$ docker-compose -f local.yml run --rm django coverage report

Note

At the root of the project folder, you will find the pytest.ini file. You can use this to customize the pytest to your liking.

There is also the .coveragerc. This is the configuration file for the coverage tool. You can find out more about configuring coverage.

See also

For unit tests, run:

$ python manage.py test

Since this is a fresh install, and there are no tests built using the Python unittest library yet, you should get feedback that says there were no tests carried out.

Document

This project uses Sphinx documentation generator. After you have set up to develop locally, run the following commands to generate the HTML documentation:

$ sphinx-build docs/ docs/_build/html/

If you set up your project to develop locally with docker, run the following command:

$ docker-compose -f local.yml run --rm django sphinx-build docs/ docs/_build/html/

Generate API documentation

Sphinx can automatically generate documentation from docstrings, to enable this feature, follow these steps:

  1. Add Sphinx extension in docs/conf.py file, like below:

    extensions = [
        'sphinx.ext.autodoc',
    ]
    
  2. Uncomment the following lines in the docs/conf.py file:

    # import django
    # sys.path.insert(0, os.path.abspath('..'))
    # os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.local")
    # django.setup()
    
  3. Run the following command:

    $ sphinx-apidoc -f -o ./docs/modules/ ./tpub/ migrations/*
    

    If you set up your project to develop locally with docker, run the following command:

    $ docker-compose -f local.yml run --rm django sphinx-apidoc -f -o ./docs/modules ./tpub/ migrations/*
    
  4. Regenerate HTML documentation as written above.

Deployment on PythonAnywhere

Overview

Full instructions follow, but here’s a high-level view.

First time config:

  1. Pull your code down to PythonAnywhere using a Bash console and setup a virtualenv
  2. Set your config variables in the postactivate script
  3. Run the manage.py migrate and collectstatic commands
  4. Add an entry to the PythonAnywhere Web tab
  5. Set your config variables in the PythonAnywhere WSGI config file

Once you’ve been through this one-off config, future deployments are much simpler: just git pull and then hit the “Reload” button :)

Getting your code and dependencies installed on PythonAnywhere

Make sure your project is fully committed and pushed up to Bitbucket or Github or wherever it may be. Then, log into your PythonAnywhere account, open up a Bash console, clone your repo, and create a virtualenv:

git clone <my-repo-url>  # you can also use hg
cd my-project-name
mkvirtualenv --python=/usr/bin/python3.7 my-project-name
pip install -r requirements/production.txt  # may take a few minutes

Setting environment variables in the console

Generate a secret key for yourself, eg like this:

python -c 'import random;import string; print("".join(random.SystemRandom().choice(string.digits + string.ascii_letters + string.punctuation) for _ in range(50)))'

Make a note of it, since we’ll need it here in the console and later on in the web app config tab.

Set environment variables via the virtualenv “postactivate” script (this will set them every time you use the virtualenv in a console):

vi $VIRTUAL_ENV/bin/postactivate

TIP: If you don’t like vi, you can also edit this file via the PythonAnywhere “Files” menu; look in the “.virtualenvs” folder.

Add these exports

export WEB_CONCURRENCY=4
export DJANGO_SETTINGS_MODULE='config.settings.production'
export DJANGO_SECRET_KEY='<secret key goes here>'
export DJANGO_ALLOWED_HOSTS='<www.your-domain.com>'
export DJANGO_ADMIN_URL='<not admin/>'
export MAILGUN_API_KEY='<mailgun key>'
export MAILGUN_DOMAIN='<mailgun sender domain (e.g. mg.yourdomain.com)>'
export DJANGO_AWS_ACCESS_KEY_ID=
export DJANGO_AWS_SECRET_ACCESS_KEY=
export DJANGO_AWS_STORAGE_BUCKET_NAME=
export DATABASE_URL='<see below>'

NOTE: The AWS details are not required if you’re using whitenoise or the built-in pythonanywhere static files service, but you do need to set them to blank, as above.

Database setup:

Go to the PythonAnywhere Databases tab and configure your database.

  • For Postgres, setup your superuser password, then open a Postgres console and run a CREATE DATABASE my-db-name. You should probably also set up a specific role and permissions for your app, rather than using the superuser credentials. Make a note of the address and port of your postgres server.
  • For MySQL, set the password and create a database. More info here: https://help.pythonanywhere.com/pages/UsingMySQL
  • You can also use sqlite if you like! Not recommended for anything beyond toy projects though.

Now go back to the postactivate script and set the DATABASE_URL environment variable:

export DATABASE_URL='postgres://<postgres-username>:<postgres-password>@<postgres-address>:<postgres-port>/<database-name>'
# or
export DATABASE_URL='mysql://<pythonanywhere-username>:<mysql-password>@<mysql-address>/<database-name>'
# or
export DATABASE_URL='sqlite:////home/yourusername/path/to/db.sqlite'

If you’re using MySQL, you may need to run pip install mysqlclient, and maybe add mysqlclient to requirements/production.txt too.

Now run the migration, and collectstatic:

source $VIRTUAL_ENV/bin/postactivate
python manage.py migrate
python manage.py collectstatic
# and, optionally
python manage.py createsuperuser

Configure the PythonAnywhere Web Tab

Go to the PythonAnywhere Web tab, hit Add new web app, and choose Manual Config, and then the version of Python you used for your virtualenv.

NOTE: If you’re using a custom domain (not on *.pythonanywhere.com), then you’ll need to set up a CNAME with your domain registrar.

When you’re redirected back to the web app config screen, set the path to your virtualenv. If you used virtualenvwrapper as above, you can just enter its name.

Click through to the WSGI configuration file link (near the top) and edit the wsgi file. Make it look something like this, repeating the environment variables you used earlier:

import os
import sys
path = '/home/<your-username>/<your-project-directory>'
if path not in sys.path:
    sys.path.append(path)

os.environ['DJANGO_SETTINGS_MODULE'] = 'config.settings.production'
os.environ['DJANGO_SECRET_KEY'] = '<as above>'
os.environ['DJANGO_ALLOWED_HOSTS'] = '<as above>'
os.environ['DJANGO_ADMIN_URL'] = '<as above>'
os.environ['MAILGUN_API_KEY'] = '<as above>'
os.environ['MAILGUN_DOMAIN'] = '<as above>'
os.environ['DJANGO_AWS_ACCESS_KEY_ID'] = ''
os.environ['DJANGO_AWS_SECRET_ACCESS_KEY'] = ''
os.environ['DJANGO_AWS_STORAGE_BUCKET_NAME'] = ''
os.environ['DATABASE_URL'] = '<as above>'

from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()

Back on the Web tab, hit Reload, and your app should be live!

NOTE: you may see security warnings until you set up your SSL certificates. If you want to suppress them temporarily, set DJANGO_SECURE_SSL_REDIRECT to blank. Follow the instructions here to get SSL set up: https://help.pythonanywhere.com/pages/SSLOwnDomains/

Optional: static files

If you want to use the PythonAnywhere static files service instead of using whitenoise or S3, you’ll find its configuration section on the Web tab. Essentially you’ll need an entry to match your STATIC_URL and STATIC_ROOT settings. There’s more info here: https://help.pythonanywhere.com/pages/DjangoStaticFiles

Future deployments

For subsequent deployments, the procedure is much simpler. In a Bash console:

workon my-virtualenv-name
cd project-directory
git pull
python manage.py migrate
python manage.py collectstatic

And then go to the Web tab and hit Reload

TIP: if you’re really keen, you can set up git-push based deployments: https://blog.pythonanywhere.com/87/

Deployment on Heroku

Commands to run

Run these commands to deploy the project to Heroku:

heroku create --buildpack https://github.com/heroku/heroku-buildpack-python

heroku addons:create heroku-postgresql:hobby-dev
# On Windows use double quotes for the time zone, e.g.
# heroku pg:backups schedule --at "02:00 America/Los_Angeles" DATABASE_URL
heroku pg:backups schedule --at '02:00 America/Los_Angeles' DATABASE_URL
heroku pg:promote DATABASE_URL

heroku addons:create heroku-redis:hobby-dev

heroku addons:create mailgun:starter

heroku config:set PYTHONHASHSEED=random

heroku config:set WEB_CONCURRENCY=4

heroku config:set DJANGO_DEBUG=False
heroku config:set DJANGO_SETTINGS_MODULE=config.settings.production
heroku config:set DJANGO_SECRET_KEY="$(openssl rand -base64 64)"

# Generating a 32 character-long random string without any of the visually similar characters "IOl01":
heroku config:set DJANGO_ADMIN_URL="$(openssl rand -base64 4096 | tr -dc 'A-HJ-NP-Za-km-z2-9' | head -c 32)/"

# Set this to your Heroku app url, e.g. 'bionic-beaver-28392.herokuapp.com'
heroku config:set DJANGO_ALLOWED_HOSTS=

# Assign with AWS_ACCESS_KEY_ID
heroku config:set DJANGO_AWS_ACCESS_KEY_ID=

# Assign with AWS_SECRET_ACCESS_KEY
heroku config:set DJANGO_AWS_SECRET_ACCESS_KEY=

# Assign with AWS_STORAGE_BUCKET_NAME
heroku config:set DJANGO_AWS_STORAGE_BUCKET_NAME=

git push heroku master

heroku run python manage.py createsuperuser

heroku run python manage.py check --deploy

heroku open

Warning

If your email server used to send email isn’t configured properly (Mailgun by default), attempting to send an email will cause an Internal Server Error.

By default, django-allauth is setup to have emails verifications mandatory, which means it’ll send a verification email when an unverified user tries to log-in or when someone tries to sign-up.

This may happen just after you’ve setup your Mailgun account, which is running in a sandbox subdomain by default. Either add your email to the list of authorized recipients or verify your domain.

Optional actions

Celery

Celery requires a few extra environment variables to be ready operational. Also, the worker is created, it’s in the Procfile, but is turned off by default:

# Set the broker URL to Redis
heroku config:set CELERY_BROKER_URL=`heroku config:get REDIS_URL`
# Scale dyno to 1 instance
heroku ps:scale worker=1

Sentry

If you’re opted for Sentry error tracking, you can either install it through the Sentry add-on:

heroku addons:create sentry:f1

Or add the DSN for your account, if you already have one:

heroku config:set SENTRY_DSN=https://xxxx@sentry.io/12345

Gulp & Bootstrap compilation

If you’ve opted for a custom bootstrap build, you’ll most likely need to setup your app to use multiple buildpacks: one for Python & one for Node.js:

heroku buildpacks:add --index 1 heroku/nodejs

At time of writing, this should do the trick: during deployment, the Heroku should run npm install and then npm build, which runs Gulp in cookiecutter-django.

If things don’t work, please refer to the Heroku docs.

About Heroku & Docker

Although Heroku has some sort of Docker support, it’s not supported by cookiecutter-django. We invite you to follow Heroku documentation about it.

Deployment with Docker

Prerequisites

  • Docker 17.05+.
  • Docker Compose 1.17+

Understanding the Docker Compose Setup

Before you begin, check out the production.yml file in the root of this project. Keep note of how it provides configuration for the following services:

  • django: your application running behind Gunicorn;
  • postgres: PostgreSQL database with the application’s relational data;
  • redis: Redis instance for caching;
  • traefik: Traefik reverse proxy with HTTPS on by default.

Provided you have opted for Celery (via setting use_celery to y) there are three more services:

  • celeryworker running a Celery worker process;
  • celerybeat running a Celery beat process;
  • flower running Flower.

The flower service is served by Traefik over HTTPS, through the port 5555. For more information about Flower and its login credentials, check out Celery Flower instructions for local environment.

Configuring the Stack

The majority of services above are configured through the use of environment variables. Just check out Configuring the Environment and you will know the drill.

To obtain logs and information about crashes in a production setup, make sure that you have access to an external Sentry instance (e.g. by creating an account with sentry.io), and set the SENTRY_DSN variable. Logs of level logging.ERROR are sent as Sentry events. Therefore, in order to send a Sentry event use:

import logging
logging.error("This event is sent to Sentry", extra={"<example_key>": "<example_value>"})

The extra parameter allows you to send additional information about the context of this error.

You will probably also need to setup the Mail backend, for example by adding a Mailgun API key and a Mailgun sender domain, otherwise, the account creation view will crash and result in a 500 error when the backend attempts to send an email to the account owner.

Warning

If your email server used to send email isn’t configured properly (Mailgun by default), attempting to send an email will cause an Internal Server Error.

By default, django-allauth is setup to have emails verifications mandatory, which means it’ll send a verification email when an unverified user tries to log-in or when someone tries to sign-up.

This may happen just after you’ve setup your Mailgun account, which is running in a sandbox subdomain by default. Either add your email to the list of authorized recipients or verify your domain.

Optional: Use AWS IAM Role for EC2 instance

If you are deploying to AWS, you can use the IAM role to substitute AWS credentials, after which it’s safe to remove the AWS_ACCESS_KEY_ID AND AWS_SECRET_ACCESS_KEY from .envs/.production/.django. To do it, create an IAM role and attach it to the existing EC2 instance or create a new EC2 instance with that role. The role should assume, at minimum, the AmazonS3FullAccess permission.

HTTPS is On by Default

SSL (Secure Sockets Layer) is a standard security technology for establishing an encrypted link between a server and a client, typically in this case, a web server (website) and a browser. Not having HTTPS means that malicious network users can sniff authentication credentials between your website and end users’ browser.

It is always better to deploy a site behind HTTPS and will become crucial as the web services extend to the IoT (Internet of Things). For this reason, we have set up a number of security defaults to help make your website secure:

  • If you are not using a subdomain of the domain name set in the project, then remember to put your staging/production IP address in the DJANGO_ALLOWED_HOSTS environment variable (see Settings) before you deploy your website. Failure to do this will mean you will not have access to your website through the HTTP protocol.
  • Access to the Django admin is set up by default to require HTTPS in production or once live.

The Traefik reverse proxy used in the default configuration will get you a valid certificate from Lets Encrypt and update it automatically. All you need to do to enable this is to make sure that your DNS records are pointing to the server Traefik runs on.

You can read more about this feature and how to configure it, at Automatic HTTPS in the Traefik docs.

(Optional) Postgres Data Volume Modifications

Postgres is saving its database files to the production_postgres_data volume by default. Change that if you want something else and make sure to make backups since this is not done automatically.

Building & Running Production Stack

You will need to build the stack first. To do that, run:

docker-compose -f production.yml build

Once this is ready, you can run it with:

docker-compose -f production.yml up

To run the stack and detach the containers, run:

docker-compose -f production.yml up -d

To run a migration, open up a second terminal and run:

docker-compose -f production.yml run --rm django python manage.py migrate

To create a superuser, run:

docker-compose -f production.yml run --rm django python manage.py createsuperuser

If you need a shell, run:

docker-compose -f production.yml run --rm django python manage.py shell

To check the logs out, run:

docker-compose -f production.yml logs

If you want to scale your application, run:

docker-compose -f production.yml scale django=4
docker-compose -f production.yml scale celeryworker=2

Warning

don’t try to scale postgres, celerybeat, or traefik.

To see how your containers are doing run:

docker-compose -f production.yml ps

Example: Supervisor

Once you are ready with your initial setup, you want to make sure that your application is run by a process manager to survive reboots and auto restarts in case of an error. You can use the process manager you are most familiar with. All it needs to do is to run docker-compose -f production.yml up in your projects root directory.

If you are using supervisor, you can use this file as a starting point:

[program:{{cookiecutter.project_slug}}]
command=docker-compose -f production.yml up
directory=/path/to/{{cookiecutter.project_slug}}
redirect_stderr=true
autostart=true
autorestart=true
priority=10

Move it to /etc/supervisor/conf.d/{{cookiecutter.project_slug}}.conf and run:

supervisorctl reread
supervisorctl update
supervisorctl start {{cookiecutter.project_slug}}

For status check, run:

supervisorctl status

PostgreSQL Backups with Docker

Note

For brevity it is assumed that you will be running the below commands against local environment, however, this is by no means mandatory so feel free to switch to production.yml when needed.

Prerequisites

  1. the project was generated with use_docker set to y;
  2. the stack is up and running: docker-compose -f local.yml up -d postgres.

Creating a Backup

To create a backup, run:

$ docker-compose -f local.yml exec postgres backup

Assuming your project’s database is named my_project here is what you will see:

Backing up the 'my_project' database...
SUCCESS: 'my_project' database backup 'backup_2018_03_13T09_05_07.sql.gz' has been created and placed in '/backups'.

Keep in mind that /backups is the postgres container directory.

Viewing the Existing Backups

To list existing backups,

$ docker-compose -f local.yml exec postgres backups

These are the sample contents of /backups:

These are the backups you have got:
total 24K
-rw-r--r-- 1 root root 5.2K Mar 13 09:05 backup_2018_03_13T09_05_07.sql.gz
-rw-r--r-- 1 root root 5.2K Mar 12 21:13 backup_2018_03_12T21_13_03.sql.gz
-rw-r--r-- 1 root root 5.2K Mar 12 21:12 backup_2018_03_12T21_12_58.sql.gz

Copying Backups Locally

If you want to copy backups from your postgres container locally, docker cp command will help you on that.

For example, given 9c5c3f055843 is the container ID copying all the backups over to a local directory is as simple as

$ docker cp 9c5c3f055843:/backups ./backups

With a single backup file copied to . that would be

$ docker cp 9c5c3f055843:/backups/backup_2018_03_13T09_05_07.sql.gz .

Restoring from the Existing Backup

To restore from one of the backups you have already got (take the backup_2018_03_13T09_05_07.sql.gz for example),

$ docker-compose -f local.yml exec postgres restore backup_2018_03_13T09_05_07.sql.gz

You will see something like

Restoring the 'my_project' database from the '/backups/backup_2018_03_13T09_05_07.sql.gz' backup...
INFO: Dropping the database...
INFO: Creating a new database...
INFO: Applying the backup to the new database...
SET
SET
SET
SET
SET
 set_config
------------

(1 row)

SET
# ...
ALTER TABLE
SUCCESS: The 'my_project' database has been restored from the '/backups/backup_2018_03_13T09_05_07.sql.gz' backup.

Backup to Amazon S3

For uploading your backups to Amazon S3 you can use the aws cli container. There is an upload command for uploading the postgres /backups directory recursively and there is a download command for downloading a specific backup. The default S3 environment variables are used.

$ docker-compose -f production.yml run --rm awscli upload
$ docker-compose -f production.yml run --rm awscli download backup_2018_03_13T09_05_07.sql.gz

FAQ

Why is there a django.contrib.sites directory in Cookiecutter Django?

It is there to add a migration so you don’t have to manually change the sites.Site record from example.com to whatever your domain is. Instead, your {{cookiecutter.domain_name}} and {{cookiecutter.project_name}} value is placed by Cookiecutter in the domain and name fields respectively.

See 0003_set_site_domain_and_name.py.

Why aren’t you using just one configuration file (12-Factor App)

TODO .. TODO

Why doesn’t this follow the layout from Two Scoops of Django?

You may notice that some elements of this project do not exactly match what we describe in chapter 3 of Two Scoops of Django 1.11. The reason for that is this project, amongst other things, serves as a test bed for trying out new ideas and concepts. Sometimes they work, sometimes they don’t, but the end result is that it won’t necessarily match precisely what is described in the book I co-authored.

Troubleshooting

This page contains some advice about errors and problems commonly encountered during the development of Cookiecutter Django applications.

Server Error on sign-up/log-in

Make sure you have configured the mail backend (e.g. Mailgun) by adding the API key and sender domain

If your email server used to send email isn’t configured properly (Mailgun by default), attempting to send an email will cause an Internal Server Error.

By default, django-allauth is setup to have emails verifications mandatory, which means it’ll send a verification email when an unverified user tries to log-in or when someone tries to sign-up.

This may happen just after you’ve setup your Mailgun account, which is running in a sandbox subdomain by default. Either add your email to the list of authorized recipients or verify your domain.

Docker: Postgres authentication failed

Examples of logs:

postgres_1      | 2018-06-07 19:11:23.963 UTC [81] FATAL:  password authentication failed for user "pydanny"
postgres_1      | 2018-06-07 19:11:23.963 UTC [81] DETAIL:  Password does not match for user "pydanny".
postgres_1      |   Connection matched pg_hba.conf line 95: "host all all all md5"

If you recreate the project multiple times with the same name, Docker would preserve the volumes for the postgres container between projects. Here is what happens:

  1. You generate the project the first time. The .env postgres file is populated with the random password
  2. You run the docker-compose and the containers are created. The postgres container creates the database based on the .env file credentials
  3. You “regenerate” the project with the same name, so the postgres .env file is populated with a new random password
  4. You run docker-compose. Since the names of the containers are the same, docker will try to start them (not create them from scratch i.e. it won’t execute the Dockerfile to recreate the database). When this happens, it tries to start the database based on the new credentials which do not match the ones that the database was created with, and you get the error message above.

To fix this, you can either:

  • Clear your project-related Docker cache with docker-compose -f local.yml down --volumes --rmi all.
  • Use the Docker volume sub-commands to find volumes (ls) and remove them (rm).
  • Use the prune command to clear system-wide (use with care!).

Others

  1. project_slug must be a valid Python module name or you will have issues on imports.
  2. jinja2.exceptions.TemplateSyntaxError: Encountered unknown tag 'now'.: please upgrade your cookiecutter version to >= 1.4 (see #528)
  3. New apps not getting created in project root: This is the expected behavior, because cookiecutter-django does not change the way that django startapp works, you’ll have to fix this manually (see #1725)

Indices and tables