From fd2e917ceb125b194854199edf8b280641e4ff05 Mon Sep 17 00:00:00 2001 From: Wan Liuyang Date: Tue, 6 Feb 2018 15:14:37 +0800 Subject: [PATCH 01/63] Use AWS IAM roles - Remove usage of AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY - Add instructions to set up IAM role --- docs/deployment-with-docker.rst | 7 +++++++ .../config/settings/production.py | 2 -- {{cookiecutter.project_slug}}/env.example | 2 -- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/deployment-with-docker.rst b/docs/deployment-with-docker.rst index fb383c3c5..2ded1286d 100644 --- a/docs/deployment-with-docker.rst +++ b/docs/deployment-with-docker.rst @@ -42,6 +42,13 @@ You will probably also need to setup the Mail backend, for example by adding a ` .. _sentry.io: https://sentry.io/welcome .. _Mailgun: https://mailgun.com +Create AWS IAM Role for EC2 instance +------------------------------------ +As a security best practice, we don't store `AWS_ACCESS_KEY_ID` AND `AWS_SECRET_ACCESS_KEY` on the server. In stead, in order to authorize Django to access your S3 bucket, you need to create an `IAM role`_ and `attach`_ it to the existing EC2 instance or create a new EC2 instance with that role. This role should assume a minimum permission of `AmazonS3FullAccess`. + +.. _IAM role: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html +.. _attach: https://aws.amazon.com/blogs/security/easily-replace-or-attach-an-iam-role-to-an-existing-ec2-instance-by-using-the-ec2-console/ + HTTPS is on by default ---------------------- diff --git a/{{cookiecutter.project_slug}}/config/settings/production.py b/{{cookiecutter.project_slug}}/config/settings/production.py index 33542fbf9..fc4eb76eb 100644 --- a/{{cookiecutter.project_slug}}/config/settings/production.py +++ b/{{cookiecutter.project_slug}}/config/settings/production.py @@ -94,8 +94,6 @@ INSTALLED_APPS += ['gunicorn', ] # See: http://django-storages.readthedocs.io/en/latest/index.html INSTALLED_APPS += ['storages', ] -AWS_ACCESS_KEY_ID = env('DJANGO_AWS_ACCESS_KEY_ID') -AWS_SECRET_ACCESS_KEY = env('DJANGO_AWS_SECRET_ACCESS_KEY') AWS_STORAGE_BUCKET_NAME = env('DJANGO_AWS_STORAGE_BUCKET_NAME') AWS_AUTO_CREATE_BUCKET = True AWS_QUERYSTRING_AUTH = False diff --git a/{{cookiecutter.project_slug}}/env.example b/{{cookiecutter.project_slug}}/env.example index 420ab4a5f..c83b3a83d 100644 --- a/{{cookiecutter.project_slug}}/env.example +++ b/{{cookiecutter.project_slug}}/env.example @@ -15,8 +15,6 @@ DJANGO_SECRET_KEY=CHANGEME!!! DJANGO_ALLOWED_HOSTS=.{{ cookiecutter.domain_name }} # AWS Settings -DJANGO_AWS_ACCESS_KEY_ID= -DJANGO_AWS_SECRET_ACCESS_KEY= DJANGO_AWS_STORAGE_BUCKET_NAME= # Used with email From 7aabfa0c36eab591e63654bc8b502db5c1e2542a Mon Sep 17 00:00:00 2001 From: Wan Liuyang Date: Tue, 6 Feb 2018 15:52:34 +0800 Subject: [PATCH 02/63] Fix typo and revert AWS environment variable --- docs/deployment-with-docker.rst | 2 +- {{cookiecutter.project_slug}}/config/settings/production.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/deployment-with-docker.rst b/docs/deployment-with-docker.rst index 2ded1286d..eeba285ae 100644 --- a/docs/deployment-with-docker.rst +++ b/docs/deployment-with-docker.rst @@ -44,7 +44,7 @@ You will probably also need to setup the Mail backend, for example by adding a ` Create AWS IAM Role for EC2 instance ------------------------------------ -As a security best practice, we don't store `AWS_ACCESS_KEY_ID` AND `AWS_SECRET_ACCESS_KEY` on the server. In stead, in order to authorize Django to access your S3 bucket, you need to create an `IAM role`_ and `attach`_ it to the existing EC2 instance or create a new EC2 instance with that role. This role should assume a minimum permission of `AmazonS3FullAccess`. +As a security best practice, we don't store `AWS_ACCESS_KEY_ID` AND `AWS_SECRET_ACCESS_KEY` on the server. Instead, in order to authorize Django to access your S3 bucket, you need to create an `IAM role`_ and `attach`_ it to the existing EC2 instance or create a new EC2 instance with that role. This role should assume a minimum permission of `AmazonS3FullAccess`. .. _IAM role: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html .. _attach: https://aws.amazon.com/blogs/security/easily-replace-or-attach-an-iam-role-to-an-existing-ec2-instance-by-using-the-ec2-console/ diff --git a/{{cookiecutter.project_slug}}/config/settings/production.py b/{{cookiecutter.project_slug}}/config/settings/production.py index fc4eb76eb..33542fbf9 100644 --- a/{{cookiecutter.project_slug}}/config/settings/production.py +++ b/{{cookiecutter.project_slug}}/config/settings/production.py @@ -94,6 +94,8 @@ INSTALLED_APPS += ['gunicorn', ] # See: http://django-storages.readthedocs.io/en/latest/index.html INSTALLED_APPS += ['storages', ] +AWS_ACCESS_KEY_ID = env('DJANGO_AWS_ACCESS_KEY_ID') +AWS_SECRET_ACCESS_KEY = env('DJANGO_AWS_SECRET_ACCESS_KEY') AWS_STORAGE_BUCKET_NAME = env('DJANGO_AWS_STORAGE_BUCKET_NAME') AWS_AUTO_CREATE_BUCKET = True AWS_QUERYSTRING_AUTH = False From 5e93bf954d2aacd9346e382345f8b105573995b5 Mon Sep 17 00:00:00 2001 From: Bruno Alla Date: Fri, 9 Feb 2018 13:00:20 +0000 Subject: [PATCH 03/63] Install psycopg2 with --no-binary option --- {{cookiecutter.project_slug}}/requirements/base.txt | 2 +- {{cookiecutter.project_slug}}/requirements/production.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/{{cookiecutter.project_slug}}/requirements/base.txt b/{{cookiecutter.project_slug}}/requirements/base.txt index 3d29fe16a..042423014 100644 --- a/{{cookiecutter.project_slug}}/requirements/base.txt +++ b/{{cookiecutter.project_slug}}/requirements/base.txt @@ -36,7 +36,7 @@ django-allauth==0.35.0 # from http://www.lfd.uci.edu/~gohlke/pythonlibs/#psycopg {% else %} # Python-PostgreSQL Database Adapter -psycopg2==2.7.4 +psycopg2==2.7.4 --no-binary psycopg2 {%- endif %} # Unicode slugification diff --git a/{{cookiecutter.project_slug}}/requirements/production.txt b/{{cookiecutter.project_slug}}/requirements/production.txt index 952ba4bd0..6739912d1 100644 --- a/{{cookiecutter.project_slug}}/requirements/production.txt +++ b/{{cookiecutter.project_slug}}/requirements/production.txt @@ -6,7 +6,7 @@ # Python-PostgreSQL Database Adapter # Assuming Windows is used locally, and *nix -- in production. # ------------------------------------------------------------ -psycopg2==2.7.4 +psycopg2==2.7.4 --no-binary psycopg2 {%- endif %} # WSGI Handler From 30dfbbd0aba298066a709bee78f14a448108b45d Mon Sep 17 00:00:00 2001 From: Wan Liuyang Date: Tue, 20 Feb 2018 16:04:16 +0800 Subject: [PATCH 04/63] Remove AWS S3 header bytes workaround --- {{cookiecutter.project_slug}}/config/settings/production.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/{{cookiecutter.project_slug}}/config/settings/production.py b/{{cookiecutter.project_slug}}/config/settings/production.py index f6f857876..3926f3db1 100644 --- a/{{cookiecutter.project_slug}}/config/settings/production.py +++ b/{{cookiecutter.project_slug}}/config/settings/production.py @@ -103,12 +103,8 @@ AWS_QUERYSTRING_AUTH = False # AWS cache settings, don't change unless you know what you're doing: AWS_EXPIRY = 60 * 60 * 24 * 7 -# TODO See: https://github.com/jschneier/django-storages/issues/47 -# Revert the following and use str after the above-mentioned bug is fixed in -# either django-storage-redux or boto -control = 'max-age=%d, s-maxage=%d, must-revalidate' % (AWS_EXPIRY, AWS_EXPIRY) AWS_S3_OBJECT_PARAMETERS = { - 'CacheControl': bytes(control, encoding='latin-1'), + 'CacheControl': 'max-age=%d, s-maxage=%d, must-revalidate' % (AWS_EXPIRY, AWS_EXPIRY), } # URL that handles the media served from MEDIA_ROOT, used for managing From c7238238f8804a0eeeb5b5ed6e7177c85c20a109 Mon Sep 17 00:00:00 2001 From: Bruno Alla Date: Fri, 16 Feb 2018 22:00:34 +0000 Subject: [PATCH 05/63] Update README, Changelog and setup.py after Django 2.0 upgrade --- CHANGELOG.md | 4 ++++ README.rst | 2 +- setup.py | 5 ++--- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 24f8d11cc..304732b9f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ All enhancements and patches to Cookiecutter Django will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## [2018-02-16] +### Changed +- Upgraded to Django 2.0 (@epicwhale) + ## [2018-01-15] ### Changed - Removed Elastic Beanstalk support (@pydanny) diff --git a/README.rst b/README.rst index b1dbe10d7..b856810f1 100644 --- a/README.rst +++ b/README.rst @@ -41,7 +41,7 @@ Features * For Django 2.0 * Works with Python 3.6 * Renders Django projects with 100% starting test coverage -* Twitter Bootstrap_ v4.0.0 - beta 1 (`maintained Foundation fork`_ also available) +* Twitter Bootstrap_ v4.0.0 (`maintained Foundation fork`_ also available) * 12-Factor_ based settings via django-environ_ * Secure by default. We believe in SSL. * Optimized development and production settings diff --git a/setup.py b/setup.py index 56306f92d..a7efb0a64 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ except ImportError: # Our version ALWAYS matches the version of Django we support # If Django has a new release, we branch, tag, then update this setting after the tag. -version = '1.11.9' +version = '2.0.2' if sys.argv[-1] == 'tag': os.system('git tag -a %s -m "version %s"' % (version, version)) @@ -34,7 +34,7 @@ setup( classifiers=[ 'Development Status :: 4 - Beta', 'Environment :: Console', - 'Framework :: Django :: 1.11', + 'Framework :: Django :: 2.0', 'Intended Audience :: Developers', 'Natural Language :: English', 'License :: OSI Approved :: BSD License', @@ -42,7 +42,6 @@ setup( 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: Implementation :: CPython', - 'Programming Language :: Python :: Implementation :: PyPy', 'Topic :: Software Development', ], keywords=( From 76334c086ec71a522e0aa4b5091fd0bd7b7d0cf4 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Tue, 20 Feb 2018 18:26:40 -0500 Subject: [PATCH 06/63] Update boto3 from 1.5.31 to 1.5.33 --- {{cookiecutter.project_slug}}/requirements/production.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/{{cookiecutter.project_slug}}/requirements/production.txt b/{{cookiecutter.project_slug}}/requirements/production.txt index 09151486d..75450eb92 100644 --- a/{{cookiecutter.project_slug}}/requirements/production.txt +++ b/{{cookiecutter.project_slug}}/requirements/production.txt @@ -16,7 +16,7 @@ gunicorn==19.7.1 # Static and Media Storage # ------------------------------------------------ -boto3==1.5.31 +boto3==1.5.33 django-storages==1.6.5 {% if cookiecutter.use_whitenoise != 'y' -%} Collectfast==0.6.0 From 3cfafcf347f035fb330ca1b6f3639d3ba2b50643 Mon Sep 17 00:00:00 2001 From: Daniel Roy Greenfeld Date: Wed, 21 Feb 2018 18:43:29 -0500 Subject: [PATCH 07/63] Update README.rst --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index b856810f1..939ad4a9a 100644 --- a/README.rst +++ b/README.rst @@ -111,7 +111,7 @@ Two Scoops of Django 1.11 :name: Two Scoops of Django 1.11 Cover :align: center :alt: Two Scoops of Django - :target: http://twoscoopspress.org/products/two-scoops-of-django-1-11 + :target: http://twoscoopspress.com/products/two-scoops-of-django-1-11 Two Scoops of Django is the best dessert-themed Django reference in the universe From f4cadeec97ef9f00652c27b7f8caff53e31e1ce9 Mon Sep 17 00:00:00 2001 From: Daniel Roy Greenfeld Date: Wed, 21 Feb 2018 18:54:03 -0500 Subject: [PATCH 08/63] Disallow backslashes in author name --- hooks/pre_gen_project.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hooks/pre_gen_project.py b/hooks/pre_gen_project.py index a65fedae8..c48ce0ad8 100644 --- a/hooks/pre_gen_project.py +++ b/hooks/pre_gen_project.py @@ -11,6 +11,9 @@ project_slug = '{{ cookiecutter.project_slug }}' if hasattr(project_slug, 'isidentifier'): assert project_slug.isidentifier(), "'{}' project slug is not a valid Python identifier.".format(project_slug) +assert "\\" not in "{{ cookiecutter.author_name }}", "Don't include backslashes in author name." + + using_docker = '{{ cookiecutter.use_docker }}'.lower() if using_docker == 'n': TERMINATOR = "\x1b[0m" From 0164c330b33d31aa9853a860eec6b412316f45e0 Mon Sep 17 00:00:00 2001 From: Bruno Alla Date: Thu, 22 Feb 2018 15:01:05 +0000 Subject: [PATCH 09/63] Move to the python:alpine docker image (#1482) * Move to the python:alpine docker image - Switch the base images for local and production to alpine - Install extra dependencies for psycopg2, Pillow and cffi - Change shebang for shell scripts to use sh instead of bash * Move to the python:alpine docker image - Migrate group and user creation to Alpine syntax * Move to the python:alpine docker image - Remove `function` keyword, unsupported in shell * Upgrade various places to the latest Python 3.6 * Test support for translations * Add gettext library, required for translations support * Add locale folder for translations support with README documenting it * Update Changelog * Tweak command to test translations support --- tests/test_docker.sh | 3 +++ .../compose/local/django/Dockerfile | 13 ++++++++++++- .../compose/local/django/celery/beat/start.sh | 2 +- .../compose/local/django/celery/worker/start.sh | 2 +- .../compose/local/django/start.sh | 2 +- .../compose/production/django/Dockerfile | 15 ++++++++++++--- .../production/django/celery/beat/start.sh | 2 +- .../production/django/celery/worker/start.sh | 2 +- .../compose/production/django/entrypoint.sh | 4 ++-- .../compose/production/django/gunicorn.sh | 2 +- {{cookiecutter.project_slug}}/locale/README.rst | 6 ++++++ 11 files changed, 41 insertions(+), 12 deletions(-) create mode 100644 {{cookiecutter.project_slug}}/locale/README.rst diff --git a/tests/test_docker.sh b/tests/test_docker.sh index 137694d7a..d80a091e4 100755 --- a/tests/test_docker.sh +++ b/tests/test_docker.sh @@ -19,3 +19,6 @@ docker-compose -f local.yml run django python manage.py test # return non-zero status code if there are migrations that have not been created docker-compose -f local.yml run django python manage.py makemigrations --dry-run --check || { echo "ERROR: there were changes in the models, but migration listed above have not been created and are not saved in version control"; exit 1; } + +# Test support for translations +docker-compose -f local.yml run --rm django python manage.py makemessages diff --git a/{{cookiecutter.project_slug}}/compose/local/django/Dockerfile b/{{cookiecutter.project_slug}}/compose/local/django/Dockerfile index b9ee34b76..383b15776 100644 --- a/{{cookiecutter.project_slug}}/compose/local/django/Dockerfile +++ b/{{cookiecutter.project_slug}}/compose/local/django/Dockerfile @@ -1,7 +1,18 @@ -FROM python:3.6 +FROM python:3.6-alpine ENV PYTHONUNBUFFERED 1 +RUN apk update \ + # psycopg2 dependencies + && apk add --virtual build-deps gcc python3-dev musl-dev \ + && apk add postgresql-dev \ + # Pillow dependencies + && apk add jpeg-dev zlib-dev freetype-dev lcms2-dev openjpeg-dev tiff-dev tk-dev tcl-dev \ + # CFFI dependencies + && apk add libffi-dev openssl-dev py-cffi \ + # Translations dependencies + && apk add gettext + # Requirements have to be pulled and installed here, otherwise caching won't work COPY ./requirements /requirements RUN pip install -r /requirements/local.txt diff --git a/{{cookiecutter.project_slug}}/compose/local/django/celery/beat/start.sh b/{{cookiecutter.project_slug}}/compose/local/django/celery/beat/start.sh index c26318b44..0ca8bb507 100644 --- a/{{cookiecutter.project_slug}}/compose/local/django/celery/beat/start.sh +++ b/{{cookiecutter.project_slug}}/compose/local/django/celery/beat/start.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/sh set -o errexit set -o pipefail diff --git a/{{cookiecutter.project_slug}}/compose/local/django/celery/worker/start.sh b/{{cookiecutter.project_slug}}/compose/local/django/celery/worker/start.sh index 8b50c8cfd..4335340de 100644 --- a/{{cookiecutter.project_slug}}/compose/local/django/celery/worker/start.sh +++ b/{{cookiecutter.project_slug}}/compose/local/django/celery/worker/start.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/sh set -o errexit set -o pipefail diff --git a/{{cookiecutter.project_slug}}/compose/local/django/start.sh b/{{cookiecutter.project_slug}}/compose/local/django/start.sh index cf4a41667..50227e19e 100644 --- a/{{cookiecutter.project_slug}}/compose/local/django/start.sh +++ b/{{cookiecutter.project_slug}}/compose/local/django/start.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/sh set -o errexit set -o pipefail diff --git a/{{cookiecutter.project_slug}}/compose/production/django/Dockerfile b/{{cookiecutter.project_slug}}/compose/production/django/Dockerfile index 48923c80b..2ded8253e 100644 --- a/{{cookiecutter.project_slug}}/compose/production/django/Dockerfile +++ b/{{cookiecutter.project_slug}}/compose/production/django/Dockerfile @@ -1,9 +1,18 @@ -FROM python:3.6 +FROM python:3.6-alpine ENV PYTHONUNBUFFERED 1 -RUN groupadd -r django \ - && useradd -r -g django django +RUN apk update \ + # psycopg2 dependencies + && apk add --virtual build-deps gcc python3-dev musl-dev \ + && apk add postgresql-dev \ + # Pillow dependencies + && apk add jpeg-dev zlib-dev freetype-dev lcms2-dev openjpeg-dev tiff-dev tk-dev tcl-dev \ + # CFFI dependencies + && apk add libffi-dev openssl-dev py-cffi + +RUN addgroup -S django \ + && adduser -S -G django django # Requirements have to be pulled and installed here, otherwise caching won't work COPY ./requirements /requirements diff --git a/{{cookiecutter.project_slug}}/compose/production/django/celery/beat/start.sh b/{{cookiecutter.project_slug}}/compose/production/django/celery/beat/start.sh index 845db0a3d..def83076c 100644 --- a/{{cookiecutter.project_slug}}/compose/production/django/celery/beat/start.sh +++ b/{{cookiecutter.project_slug}}/compose/production/django/celery/beat/start.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/sh set -o errexit set -o pipefail diff --git a/{{cookiecutter.project_slug}}/compose/production/django/celery/worker/start.sh b/{{cookiecutter.project_slug}}/compose/production/django/celery/worker/start.sh index 4529aad92..10f0d20c5 100644 --- a/{{cookiecutter.project_slug}}/compose/production/django/celery/worker/start.sh +++ b/{{cookiecutter.project_slug}}/compose/production/django/celery/worker/start.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/sh set -o errexit set -o pipefail diff --git a/{{cookiecutter.project_slug}}/compose/production/django/entrypoint.sh b/{{cookiecutter.project_slug}}/compose/production/django/entrypoint.sh index 3b83c7bb6..a40a2b7e4 100644 --- a/{{cookiecutter.project_slug}}/compose/production/django/entrypoint.sh +++ b/{{cookiecutter.project_slug}}/compose/production/django/entrypoint.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/sh set -o errexit set -o pipefail @@ -25,7 +25,7 @@ export DATABASE_URL=postgres://$POSTGRES_USER:$POSTGRES_PASSWORD@postgres:5432/$ export CELERY_BROKER_URL=$REDIS_URL/0 {% endif %} -function postgres_ready(){ +postgres_ready() { python << END import sys import psycopg2 diff --git a/{{cookiecutter.project_slug}}/compose/production/django/gunicorn.sh b/{{cookiecutter.project_slug}}/compose/production/django/gunicorn.sh index 25da06496..8846cafb2 100644 --- a/{{cookiecutter.project_slug}}/compose/production/django/gunicorn.sh +++ b/{{cookiecutter.project_slug}}/compose/production/django/gunicorn.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/sh set -o errexit set -o pipefail diff --git a/{{cookiecutter.project_slug}}/locale/README.rst b/{{cookiecutter.project_slug}}/locale/README.rst new file mode 100644 index 000000000..c2f1dcd6f --- /dev/null +++ b/{{cookiecutter.project_slug}}/locale/README.rst @@ -0,0 +1,6 @@ +Translations +============ + +Translations will be placed in this folder when running:: + + python manage.py makemessages From b3a4d0ca14de37217c50c827a214e8d397727fde Mon Sep 17 00:00:00 2001 From: "pyup.io bot" Date: Thu, 22 Feb 2018 16:03:06 +0100 Subject: [PATCH 10/63] Update django-extensions from 1.9.9 to 2.0.0 (#1526) --- {{cookiecutter.project_slug}}/requirements/local.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/{{cookiecutter.project_slug}}/requirements/local.txt b/{{cookiecutter.project_slug}}/requirements/local.txt index 697a40288..6004987d2 100644 --- a/{{cookiecutter.project_slug}}/requirements/local.txt +++ b/{{cookiecutter.project_slug}}/requirements/local.txt @@ -5,7 +5,7 @@ coverage==4.5.1 django-coverage-plugin==1.5.0 Sphinx==1.7.0 -django-extensions==1.9.9 +django-extensions==2.0.0 Werkzeug==0.14.1 django-test-plus==1.0.22 factory-boy==2.10.0 From a252830c3155eba27839a1b27bdd72f2ba02f3b3 Mon Sep 17 00:00:00 2001 From: "pyup.io bot" Date: Thu, 22 Feb 2018 16:03:25 +0100 Subject: [PATCH 11/63] Update pytest from 3.3.2 to 3.4.1 (#1523) --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 1790a0216..085d5a147 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,7 +4,7 @@ sh==1.12.14 binaryornot==0.4.4 # Testing -pytest==3.3.2 +pytest==3.4.1 pycodestyle==2.3.1 pyflakes==1.6.0 tox==2.9.1 From 01e598df795cdfda7c7909e7ed0468bc28278fae Mon Sep 17 00:00:00 2001 From: Bruno Alla Date: Sat, 24 Feb 2018 10:14:41 +0000 Subject: [PATCH 12/63] Link to unminified CSS if using django-compressor --- .../{{cookiecutter.project_slug}}/templates/base.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/base.html b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/base.html index a45de763c..c767cb3b9 100644 --- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/base.html +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/base.html @@ -22,7 +22,7 @@ {% endraw %}{% if cookiecutter.use_compressor == "y" %}{% raw %}{% compress css %}{% endraw %}{% endif %}{% raw %} - {% endraw %}{% if cookiecutter.js_task_runner == "Gulp" %}{% raw %} + {% endraw %}{% if cookiecutter.js_task_runner == "Gulp" and cookiecutter.use_compressor == "n" %}{% raw %} {% endraw %}{% else %}{% raw %} From 18509cb85b48c4e5c560318cc5d32d8e373fc78d Mon Sep 17 00:00:00 2001 From: "pyup.io bot" Date: Mon, 26 Feb 2018 14:34:51 +0100 Subject: [PATCH 13/63] Update sphinx from 1.7.0 to 1.7.1 (#1532) --- {{cookiecutter.project_slug}}/requirements/local.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/{{cookiecutter.project_slug}}/requirements/local.txt b/{{cookiecutter.project_slug}}/requirements/local.txt index 6004987d2..93e9f741d 100644 --- a/{{cookiecutter.project_slug}}/requirements/local.txt +++ b/{{cookiecutter.project_slug}}/requirements/local.txt @@ -4,7 +4,7 @@ coverage==4.5.1 django-coverage-plugin==1.5.0 -Sphinx==1.7.0 +Sphinx==1.7.1 django-extensions==2.0.0 Werkzeug==0.14.1 django-test-plus==1.0.22 From 48a6bf56a6a2e66d7a59b8a3b6bcea298d5c4f0f Mon Sep 17 00:00:00 2001 From: "pyup.io bot" Date: Mon, 26 Feb 2018 14:35:01 +0100 Subject: [PATCH 14/63] Update boto3 from 1.5.33 to 1.5.36 (#1531) --- {{cookiecutter.project_slug}}/requirements/production.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/{{cookiecutter.project_slug}}/requirements/production.txt b/{{cookiecutter.project_slug}}/requirements/production.txt index dff451337..7577c7462 100644 --- a/{{cookiecutter.project_slug}}/requirements/production.txt +++ b/{{cookiecutter.project_slug}}/requirements/production.txt @@ -16,7 +16,7 @@ gunicorn==19.7.1 # Static and Media Storage # ------------------------------------------------ -boto3==1.5.33 +boto3==1.5.36 django-storages==1.6.5 {% if cookiecutter.use_whitenoise != 'y' -%} Collectfast==0.6.0 From ff92210573a20032ac7e0034255994cbc7a61b71 Mon Sep 17 00:00:00 2001 From: Daniel Roy Greenfeld Date: Tue, 27 Feb 2018 17:03:02 -0500 Subject: [PATCH 15/63] Remove python_2_unicode_compatible Python 3.6 or go home! --- .../{{cookiecutter.project_slug}}/users/models.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/models.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/models.py index 9a831b48c..4b1a10d1e 100644 --- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/models.py +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/models.py @@ -1,11 +1,9 @@ from django.contrib.auth.models import AbstractUser from django.db import models from django.urls import reverse -from django.utils.encoding import python_2_unicode_compatible from django.utils.translation import ugettext_lazy as _ -@python_2_unicode_compatible class User(AbstractUser): # First Name and Last Name do not cover name patterns From 5f068dd972532f906dd4cfdbcf346a02f87a0056 Mon Sep 17 00:00:00 2001 From: Wan Liuyang Date: Wed, 28 Feb 2018 11:33:39 +0800 Subject: [PATCH 16/63] Revert environment variables and update docs --- docs/deployment-with-docker.rst | 4 ++-- {{cookiecutter.project_slug}}/env.example | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/deployment-with-docker.rst b/docs/deployment-with-docker.rst index eeba285ae..25ff7cb9f 100644 --- a/docs/deployment-with-docker.rst +++ b/docs/deployment-with-docker.rst @@ -42,9 +42,9 @@ You will probably also need to setup the Mail backend, for example by adding a ` .. _sentry.io: https://sentry.io/welcome .. _Mailgun: https://mailgun.com -Create AWS IAM Role for EC2 instance +Optional: Use AWS IAM Role for EC2 instance ------------------------------------ -As a security best practice, we don't store `AWS_ACCESS_KEY_ID` AND `AWS_SECRET_ACCESS_KEY` on the server. Instead, in order to authorize Django to access your S3 bucket, you need to create an `IAM role`_ and `attach`_ it to the existing EC2 instance or create a new EC2 instance with that role. This role should assume a minimum permission of `AmazonS3FullAccess`. +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 the `.env`. 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 a minimum permission of `AmazonS3FullAccess`. .. _IAM role: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html .. _attach: https://aws.amazon.com/blogs/security/easily-replace-or-attach-an-iam-role-to-an-existing-ec2-instance-by-using-the-ec2-console/ diff --git a/{{cookiecutter.project_slug}}/env.example b/{{cookiecutter.project_slug}}/env.example index 757c4ef00..1d28cb599 100644 --- a/{{cookiecutter.project_slug}}/env.example +++ b/{{cookiecutter.project_slug}}/env.example @@ -15,6 +15,8 @@ DJANGO_SECRET_KEY=!!!SET DJANGO_SECRET_KEY!!! DJANGO_ALLOWED_HOSTS=.{{ cookiecutter.domain_name }} # AWS Settings +DJANGO_AWS_ACCESS_KEY_ID= +DJANGO_AWS_SECRET_ACCESS_KEY= DJANGO_AWS_STORAGE_BUCKET_NAME= # Used with email From 496869164f42e4249a55a6ff67d2bf915884dbe0 Mon Sep 17 00:00:00 2001 From: "pyup.io bot" Date: Wed, 28 Feb 2018 12:42:47 +0100 Subject: [PATCH 17/63] Update boto3 from 1.5.36 to 1.6.1 (#1536) --- {{cookiecutter.project_slug}}/requirements/production.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/{{cookiecutter.project_slug}}/requirements/production.txt b/{{cookiecutter.project_slug}}/requirements/production.txt index 7577c7462..431f3e163 100644 --- a/{{cookiecutter.project_slug}}/requirements/production.txt +++ b/{{cookiecutter.project_slug}}/requirements/production.txt @@ -16,7 +16,7 @@ gunicorn==19.7.1 # Static and Media Storage # ------------------------------------------------ -boto3==1.5.36 +boto3==1.6.1 django-storages==1.6.5 {% if cookiecutter.use_whitenoise != 'y' -%} Collectfast==0.6.0 From a429a050c940862200d3b9ed3670dcadf55e1c6b Mon Sep 17 00:00:00 2001 From: "pyup.io bot" Date: Thu, 1 Mar 2018 11:59:59 +0100 Subject: [PATCH 18/63] Update boto3 to 1.6.2 (#1538) * Update boto3 from 1.6.1 to 1.6.2 * Update production.txt --- {{cookiecutter.project_slug}}/requirements/production.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/{{cookiecutter.project_slug}}/requirements/production.txt b/{{cookiecutter.project_slug}}/requirements/production.txt index 431f3e163..9b389a52b 100644 --- a/{{cookiecutter.project_slug}}/requirements/production.txt +++ b/{{cookiecutter.project_slug}}/requirements/production.txt @@ -16,7 +16,7 @@ gunicorn==19.7.1 # Static and Media Storage # ------------------------------------------------ -boto3==1.6.1 +boto3==1.6.2 # pyup: update minor django-storages==1.6.5 {% if cookiecutter.use_whitenoise != 'y' -%} Collectfast==0.6.0 From 3084d9d5c1d6870f3da118af1ae108316d788a60 Mon Sep 17 00:00:00 2001 From: "pyup.io bot" Date: Thu, 1 Mar 2018 12:20:08 +0100 Subject: [PATCH 19/63] Update django-redis from 4.8.0 to 4.9.0 (#1540) --- {{cookiecutter.project_slug}}/requirements/base.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/{{cookiecutter.project_slug}}/requirements/base.txt b/{{cookiecutter.project_slug}}/requirements/base.txt index c9f784327..85c45e993 100644 --- a/{{cookiecutter.project_slug}}/requirements/base.txt +++ b/{{cookiecutter.project_slug}}/requirements/base.txt @@ -46,7 +46,7 @@ awesome-slugify==1.6.5 pytz==2018.3 # Redis support -django-redis==4.8.0 +django-redis==4.9.0 redis>=2.10.5 {% if cookiecutter.use_celery == "y" %} From fbdc3c930f0336651f7e7e8e596ee2c0d3ed46a4 Mon Sep 17 00:00:00 2001 From: "pyup.io bot" Date: Thu, 1 Mar 2018 12:20:25 +0100 Subject: [PATCH 20/63] Update raven from 6.5.0 to 6.6.0 (#1539) --- {{cookiecutter.project_slug}}/requirements/production.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/{{cookiecutter.project_slug}}/requirements/production.txt b/{{cookiecutter.project_slug}}/requirements/production.txt index 9b389a52b..351c46cef 100644 --- a/{{cookiecutter.project_slug}}/requirements/production.txt +++ b/{{cookiecutter.project_slug}}/requirements/production.txt @@ -29,7 +29,7 @@ django-anymail==1.4 {% if cookiecutter.use_sentry_for_error_reporting == "y" -%} # Raven is the Sentry client # -------------------------- -raven==6.5.0 +raven==6.6.0 {%- endif %} {% if cookiecutter.use_opbeat == "y" -%} From 1afa2b44872e2e6eeaba2a8ef33f874af1f6c5ce Mon Sep 17 00:00:00 2001 From: Andy Woods Date: Thu, 1 Mar 2018 11:21:09 +0000 Subject: [PATCH 21/63] Update urls.py (#1537) Elsewise, named url 'detail' matches regex of 'update' --- .../{{cookiecutter.project_slug}}/users/urls.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/urls.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/urls.py index 7c83fab98..1e1618363 100644 --- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/urls.py +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/urls.py @@ -14,14 +14,14 @@ urlpatterns = [ view=views.UserRedirectView.as_view(), name='redirect' ), - url( - regex=r'^(?P[\w.@+-]+)/$', - view=views.UserDetailView.as_view(), - name='detail' - ), url( regex=r'^~update/$', view=views.UserUpdateView.as_view(), name='update' ), + url( + regex=r'^(?P[\w.@+-]+)/$', + view=views.UserDetailView.as_view(), + name='detail' + ), ] From f5341fcace5506eece98744e2a1462443d4e6a18 Mon Sep 17 00:00:00 2001 From: Bruno Alla Date: Thu, 1 Mar 2018 11:23:43 +0000 Subject: [PATCH 22/63] Use the default docker from Travis rather than installing a specific version (#1502) --- .travis.yml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index f6e18b521..8be8bc440 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,15 +13,6 @@ env: - TOX_ENV=py36 before_install: - - sudo sh -c 'echo "deb https://apt.dockerproject.org/repo ubuntu-precise main" > /etc/apt/sources.list.d/docker.list' - - sudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D - - sudo apt-get update - - sudo apt-key update - - sudo apt-get --force-yes -qqy -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install docker-engine=1.11.1-0~precise - - sudo rm /usr/local/bin/docker-compose - - curl -L https://github.com/docker/compose/releases/download/1.7.0/docker-compose-`uname -s`-`uname -m` > docker-compose - - chmod +x docker-compose - - sudo mv docker-compose /usr/local/bin - docker-compose -v - docker -v From ed2204ecbaed6e04a69fab03ff5fd5c68e890d1b Mon Sep 17 00:00:00 2001 From: adammsteele Date: Thu, 1 Mar 2018 11:25:33 +0000 Subject: [PATCH 23/63] Celery config - json serialization by default (#1535) * Use json serialization in celery by default * Added myself to CONTRIBUTORS.rst --- CONTRIBUTORS.rst | 2 ++ {{cookiecutter.project_slug}}/config/settings/base.py | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/CONTRIBUTORS.rst b/CONTRIBUTORS.rst index a9a857733..96c05d042 100644 --- a/CONTRIBUTORS.rst +++ b/CONTRIBUTORS.rst @@ -44,6 +44,7 @@ Listed in alphabetical order. Aaron Eikenberry `@aeikenberry`_ Adam BogdaƂ `@bogdal`_ Adam Dobrawy `@ad-m`_ + Adam Steele `@adammsteele` Agam Dua Alberto Sanchez `@alb3rto`_ Alex Tsai `@caffodian`_ @@ -159,6 +160,7 @@ Listed in alphabetical order. .. _@a7p: https://github.com/a7p .. _@ad-m: https://github.com/ad-m +.. _@adammsteele: https://github.com/adammsteele .. _@aeikenberry: https://github.com/aeikenberry .. _@alb3rto: https://github.com/alb3rto .. _@ameistad: https://github.com/ameistad diff --git a/{{cookiecutter.project_slug}}/config/settings/base.py b/{{cookiecutter.project_slug}}/config/settings/base.py index 2ce697677..9e16919ed 100644 --- a/{{cookiecutter.project_slug}}/config/settings/base.py +++ b/{{cookiecutter.project_slug}}/config/settings/base.py @@ -274,6 +274,10 @@ if CELERY_BROKER_URL == 'django://': CELERY_RESULT_BACKEND = 'redis://' else: CELERY_RESULT_BACKEND = CELERY_BROKER_URL +# default to json serialization only +CELERY_ACCEPT_CONTENT = ['json'] +CELERY_TASK_SERIALIZER = 'json' +CELERY_RESULT_SERIALIZER = 'json' ########## END CELERY {% endif %} From 69ff5515c9d42254201c2546513eb058de576254 Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Thu, 1 Mar 2018 22:43:00 +0300 Subject: [PATCH 24/63] Fix GPLv3 files not being removed --- hooks/post_gen_project.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py index 0e16ffb70..a00fd9b24 100644 --- a/hooks/post_gen_project.py +++ b/hooks/post_gen_project.py @@ -241,7 +241,7 @@ def main(): if '{{ cookiecutter.open_source_license }}' == 'Not open source': remove_open_source_project_only_files() - elif '{{ cookiecutter.open_source_license}}' != 'GPLv3': + if '{{ cookiecutter.open_source_license}}' != 'GPLv3': remove_gplv3_files() if '{{ cookiecutter.use_pycharm }}'.lower() == 'n': From 4a1cdb5d250a17b90145f7d6be832d4555ed8856 Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Sun, 4 Mar 2018 12:39:15 +0300 Subject: [PATCH 25/63] Drop support for PostgreSQL 9.2 Closes #1493. --- README.rst | 1 - cookiecutter.json | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 939ad4a9a..30abcdd70 100644 --- a/README.rst +++ b/README.rst @@ -176,7 +176,6 @@ Answer the prompts with your own desired options_. For example:: 3 - 9.5 4 - 9.4 5 - 9.3 - 6 - 9.2 Choose from 1, 2, 3, 4 [1]: 1 Select js_task_runner: 1 - Gulp diff --git a/cookiecutter.json b/cookiecutter.json index 933c3dfa0..4527a606c 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -17,7 +17,7 @@ "use_docker": "n", "use_heroku": "n", "use_compressor": "n", - "postgresql_version": ["10", "9.6", "9.5", "9.4", "9.3", "9.2"], + "postgresql_version": ["10", "9.6", "9.5", "9.4", "9.3"], "js_task_runner": ["Gulp", "Grunt", "None"], "custom_bootstrap_compilation": "n", "open_source_license": ["MIT", "BSD", "GPLv3", "Apache Software License 2.0", "Not open source"] From 281dde1d1df483cb7029cb98f73f149fb945f469 Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Sun, 4 Mar 2018 14:43:54 +0300 Subject: [PATCH 26/63] Simplify post hook --- hooks/post_gen_project.py | 15 +++------------ {{cookiecutter.project_slug}}/requirements.txt | 4 ++-- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py index a00fd9b24..796128566 100644 --- a/hooks/post_gen_project.py +++ b/hooks/post_gen_project.py @@ -72,22 +72,12 @@ def remove_heroku_files(): file_names = [ 'Procfile', 'runtime.txt', + 'requirements.txt', ] for file_name in file_names: remove_file(os.path.join(PROJECT_DIR_PATH, file_name)) -def remove_paas_files(): - none_paas_files_left = True - - if '{{ cookiecutter.use_heroku }}'.lower() == 'n': - remove_heroku_files() - none_paas_files_left &= True - else: - none_paas_files_left &= False - - if none_paas_files_left: - remove_file(os.path.join(PROJECT_DIR_PATH, 'requirements.txt')) def remove_grunt_files(): @@ -250,7 +240,8 @@ def main(): if '{{ cookiecutter.use_docker }}'.lower() == 'n': remove_docker_files() - remove_paas_files() + if '{{ cookiecutter.use_heroku }}'.lower() == 'n': + remove_heroku_files() if '{{ cookiecutter.js_task_runner}}'.lower() == 'gulp': remove_grunt_files() diff --git a/{{cookiecutter.project_slug}}/requirements.txt b/{{cookiecutter.project_slug}}/requirements.txt index d1197135e..c1b500c2b 100644 --- a/{{cookiecutter.project_slug}}/requirements.txt +++ b/{{cookiecutter.project_slug}}/requirements.txt @@ -1,3 +1,3 @@ -# This file is here because many Platforms as a Service look for -# requirements.txt in the root directory of a project. +# This file is expected by Heroku. + -r requirements/production.txt From 438ec0c101ab9cc5be4e68be85196a0b63eadf6a Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Sun, 4 Mar 2018 14:44:37 +0300 Subject: [PATCH 27/63] Remove .env when neither Docker nor Heroku are opted out for --- hooks/post_gen_project.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py index 796128566..aba19ae2b 100644 --- a/hooks/post_gen_project.py +++ b/hooks/post_gen_project.py @@ -78,6 +78,8 @@ def remove_heroku_files(): remove_file(os.path.join(PROJECT_DIR_PATH, file_name)) +def remove_dotenv_file(): + remove_file(os.path.join(PROJECT_DIR_PATH, '.env')) def remove_grunt_files(): @@ -243,6 +245,9 @@ def main(): if '{{ cookiecutter.use_heroku }}'.lower() == 'n': remove_heroku_files() + if '{{ cookiecutter.use_docker }}'.lower() == 'n' and '{{ cookiecutter.use_heroku }}'.lower() == 'n': + remove_dotenv_file() + if '{{ cookiecutter.js_task_runner}}'.lower() == 'gulp': remove_grunt_files() elif '{{ cookiecutter.js_task_runner}}'.lower() == 'grunt': From a40c9a22550eaa36dde5d8411d79c6aed152427f Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Sun, 4 Mar 2018 15:05:56 +0300 Subject: [PATCH 28/63] Prettify cookiecutter.json --- cookiecutter.json | 42 +++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/cookiecutter.json b/cookiecutter.json index 4527a606c..23e05b895 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -1,24 +1,40 @@ { - "project_name": "Project Name", + "project_name": "My Awesome Project", "project_slug": "{{ cookiecutter.project_name.lower()|replace(' ', '_')|replace('-', '_') }}", + "description": "Behold My Awesome Project!", "author_name": "Daniel Roy Greenfeld", - "email": "you@example.com", - "description": "A short description of the project.", + "email": "{{ cookiecutter.project_name.lower() }}@example.com", "domain_name": "example.com", "version": "0.1.0", + "open_source_license": [ + "MIT", + "BSD", + "GPLv3", + "Apache Software License 2.0", + "Not open source" + ], "timezone": "UTC", - "use_whitenoise": "y", + "windows": "n", + "use_pycharm": "n", + "use_docker": "n", + "postgresql_version": [ + "10", + "9.6", + "9.5", + "9.4", + "9.3" + ], + "js_task_runner": [ + "Gulp", + "Grunt", + "None" + ], + "custom_bootstrap_compilation": "n", + "use_compressor": "n", "use_celery": "n", "use_mailhog": "n", "use_sentry_for_error_reporting": "y", "use_opbeat": "n", - "use_pycharm": "n", - "windows": "n", - "use_docker": "n", - "use_heroku": "n", - "use_compressor": "n", - "postgresql_version": ["10", "9.6", "9.5", "9.4", "9.3"], - "js_task_runner": ["Gulp", "Grunt", "None"], - "custom_bootstrap_compilation": "n", - "open_source_license": ["MIT", "BSD", "GPLv3", "Apache Software License 2.0", "Not open source"] + "use_whitenoise": "y", + "use_heroku": "n" } From ccef0aaa89e6571d331443e39cbd02fa79306f3b Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Sun, 4 Mar 2018 15:06:50 +0300 Subject: [PATCH 29/63] Opt out of Celery by default --- cookiecutter.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cookiecutter.json b/cookiecutter.json index 23e05b895..f509953a3 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -33,7 +33,7 @@ "use_compressor": "n", "use_celery": "n", "use_mailhog": "n", - "use_sentry_for_error_reporting": "y", + "use_sentry_for_error_reporting": "n", "use_opbeat": "n", "use_whitenoise": "y", "use_heroku": "n" From 9f2f3b455f761d0559b9dc83707b9fa4285a82c5 Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Sun, 4 Mar 2018 15:07:05 +0300 Subject: [PATCH 30/63] Opt out of WhiteNoise by default --- cookiecutter.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cookiecutter.json b/cookiecutter.json index f509953a3..d32781947 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -35,6 +35,6 @@ "use_mailhog": "n", "use_sentry_for_error_reporting": "n", "use_opbeat": "n", - "use_whitenoise": "y", + "use_whitenoise": "n", "use_heroku": "n" } From afd3191038ef1501be4a1a4350da46914e14186e Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Sun, 4 Mar 2018 15:07:49 +0300 Subject: [PATCH 31/63] Get rid of remove_file() from post hook --- hooks/post_gen_project.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py index aba19ae2b..9d0c30a0d 100644 --- a/hooks/post_gen_project.py +++ b/hooks/post_gen_project.py @@ -25,11 +25,6 @@ except NotImplementedError: PROJECT_DIR_PATH = os.path.realpath(os.path.curdir) -def remove_file(file_path): - if os.path.exists(file_path): - os.remove(file_path) - - def remove_open_source_project_only_files(): file_names = [ 'CONTRIBUTORS.txt', @@ -75,11 +70,11 @@ def remove_heroku_files(): 'requirements.txt', ] for file_name in file_names: - remove_file(os.path.join(PROJECT_DIR_PATH, file_name)) + os.remove(os.path.join(PROJECT_DIR_PATH, file_name)) def remove_dotenv_file(): - remove_file(os.path.join(PROJECT_DIR_PATH, '.env')) + os.remove(os.path.join(PROJECT_DIR_PATH, '.env')) def remove_grunt_files(): From 0a69f194520b34070ef7a807d4041f42c4d08d50 Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Sun, 4 Mar 2018 15:11:54 +0300 Subject: [PATCH 32/63] Opt for .travis.yml Closes #1542. --- cookiecutter.json | 3 ++- hooks/post_gen_project.py | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/cookiecutter.json b/cookiecutter.json index d32781947..00b9372d2 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -36,5 +36,6 @@ "use_sentry_for_error_reporting": "n", "use_opbeat": "n", "use_whitenoise": "n", - "use_heroku": "n" + "use_heroku": "n", + "use_travisci": "n" } diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py index 9d0c30a0d..83e41eb89 100644 --- a/hooks/post_gen_project.py +++ b/hooks/post_gen_project.py @@ -105,6 +105,10 @@ def remove_celery_app(): shutil.rmtree(os.path.join(PROJECT_DIR_PATH, '{{ cookiecutter.project_slug }}', 'taskapp')) +def remove_dottravisyml_file(): + os.remove(os.path.join(PROJECT_DIR_PATH, '.travis.yml')) + + def append_to_project_gitignore(path): gitignore_file_path = os.path.join(PROJECT_DIR_PATH, '.gitignore') with open(gitignore_file_path, 'a') as gitignore_file: @@ -269,6 +273,9 @@ def main(): if '{{ cookiecutter.use_celery }}'.lower() == 'n': remove_celery_app() + if '{{ cookiecutter.use_travisci }}'.lower() == 'n': + remove_dottravisyml_file() + if __name__ == '__main__': main() From fe6fe1cc76681e9ceef6b06c866807a5b7559910 Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Sun, 4 Mar 2018 15:18:27 +0300 Subject: [PATCH 33/63] Fix test_docker.sh --- tests/test_docker.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_docker.sh b/tests/test_docker.sh index d80a091e4..c103b9833 100755 --- a/tests/test_docker.sh +++ b/tests/test_docker.sh @@ -12,7 +12,7 @@ cd .cache/docker # create the project using the default settings in cookiecutter.json cookiecutter ../../ --no-input --overwrite-if-exists use_docker=y js_task_runner=None -cd project_name +cd my_awesome_project # run the project's tests docker-compose -f local.yml run django python manage.py test From e3103d5f05b7125af4acd83ef764223d1fc5fa1e Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Sun, 4 Mar 2018 15:27:12 +0300 Subject: [PATCH 34/63] Fix default email --- cookiecutter.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cookiecutter.json b/cookiecutter.json index 00b9372d2..1338e6f74 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -3,7 +3,7 @@ "project_slug": "{{ cookiecutter.project_name.lower()|replace(' ', '_')|replace('-', '_') }}", "description": "Behold My Awesome Project!", "author_name": "Daniel Roy Greenfeld", - "email": "{{ cookiecutter.project_name.lower() }}@example.com", + "email": "{{ cookiecutter.project_slug }}@example.com", "domain_name": "example.com", "version": "0.1.0", "open_source_license": [ From 3132ce7ecfed28befde9e3f45d3ddaaaf194b9e7 Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Sun, 4 Mar 2018 15:31:48 +0300 Subject: [PATCH 35/63] Gitignore .pytest_cache/ --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 1f80de173..9e4496f1c 100644 --- a/.gitignore +++ b/.gitignore @@ -226,3 +226,5 @@ pip-selfcheck.json # to 'run' anything within it since any particular cookiecutter # is declarative by nature. .idea/ + +.pytest_cache/ From 0311732ce39076a3cc7ed15792a1f7891107da97 Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Sun, 4 Mar 2018 15:40:47 +0300 Subject: [PATCH 36/63] Temporarily opt for Sentry and WhiteNoise by default --- cookiecutter.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cookiecutter.json b/cookiecutter.json index 1338e6f74..7aaaa9438 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -33,9 +33,9 @@ "use_compressor": "n", "use_celery": "n", "use_mailhog": "n", - "use_sentry_for_error_reporting": "n", + "use_sentry_for_error_reporting": "y", "use_opbeat": "n", - "use_whitenoise": "n", + "use_whitenoise": "y", "use_heroku": "n", "use_travisci": "n" } From 6c26d39f65a66429ae1ec9a00d9676f29c408c45 Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Sun, 4 Mar 2018 17:24:06 +0300 Subject: [PATCH 37/63] Unconditionally connect to database from DATABASE_URL env when opting for Docker Closes #1541. --- {{cookiecutter.project_slug}}/config/settings/base.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/{{cookiecutter.project_slug}}/config/settings/base.py b/{{cookiecutter.project_slug}}/config/settings/base.py index 9e16919ed..9b14f5ac2 100644 --- a/{{cookiecutter.project_slug}}/config/settings/base.py +++ b/{{cookiecutter.project_slug}}/config/settings/base.py @@ -110,9 +110,15 @@ MANAGERS = ADMINS # See: https://docs.djangoproject.com/en/dev/ref/settings/#databases # Uses django-environ to accept uri format # See: https://django-environ.readthedocs.io/en/latest/#supported-types +{% if cookiecutter.use_docker == 'y' %} +DATABASES = { + 'default': env.db('DATABASE_URL'), +} +{% else %} DATABASES = { 'default': env.db('DATABASE_URL', default='postgres://{% if cookiecutter.windows == 'y' %}localhost{% endif %}/{{cookiecutter.project_slug}}'), } +{% endif %} DATABASES['default']['ATOMIC_REQUESTS'] = True From ea54bfe1756dc9f987c78c16f24757e5416064c1 Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Sun, 4 Mar 2018 17:28:42 +0300 Subject: [PATCH 38/63] Opt PostgreSQL for minor versions as well --- README.rst | 12 +++++++----- cookiecutter.json | 22 ++++++++++++---------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/README.rst b/README.rst index 30abcdd70..c5f9d06b3 100644 --- a/README.rst +++ b/README.rst @@ -171,11 +171,13 @@ Answer the prompts with your own desired options_. For example:: use_heroku [n]: y use_compressor [n]: y Select postgresql_version: - 1 - 10 - 2 - 9.6 - 3 - 9.5 - 4 - 9.4 - 5 - 9.3 + 1 - 10.3 + 2 - 10.2 + 3 - 10.1 + 4 - 9.6 + 5 - 9.5 + 6 - 9.4 + 7 - 9.3 Choose from 1, 2, 3, 4 [1]: 1 Select js_task_runner: 1 - Gulp diff --git a/cookiecutter.json b/cookiecutter.json index 7aaaa9438..9e5876e77 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -7,10 +7,10 @@ "domain_name": "example.com", "version": "0.1.0", "open_source_license": [ - "MIT", - "BSD", - "GPLv3", - "Apache Software License 2.0", + "MIT", + "BSD", + "GPLv3", + "Apache Software License 2.0", "Not open source" ], "timezone": "UTC", @@ -18,15 +18,17 @@ "use_pycharm": "n", "use_docker": "n", "postgresql_version": [ - "10", - "9.6", - "9.5", - "9.4", + "10.3", + "10.2", + "10.1", + "9.6", + "9.5", + "9.4", "9.3" ], "js_task_runner": [ - "Gulp", - "Grunt", + "Gulp", + "Grunt", "None" ], "custom_bootstrap_compilation": "n", From d0432316a8fd758371608f02b716282cf2e0a09a Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Sun, 4 Mar 2018 17:32:29 +0300 Subject: [PATCH 39/63] Opt for no js_task_runner by default --- cookiecutter.json | 82 +++++++++++++++++++++++------------------------ 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/cookiecutter.json b/cookiecutter.json index 9e5876e77..1eb56b784 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -1,43 +1,43 @@ { - "project_name": "My Awesome Project", - "project_slug": "{{ cookiecutter.project_name.lower()|replace(' ', '_')|replace('-', '_') }}", - "description": "Behold My Awesome Project!", - "author_name": "Daniel Roy Greenfeld", - "email": "{{ cookiecutter.project_slug }}@example.com", - "domain_name": "example.com", - "version": "0.1.0", - "open_source_license": [ - "MIT", - "BSD", - "GPLv3", - "Apache Software License 2.0", - "Not open source" - ], - "timezone": "UTC", - "windows": "n", - "use_pycharm": "n", - "use_docker": "n", - "postgresql_version": [ - "10.3", - "10.2", - "10.1", - "9.6", - "9.5", - "9.4", - "9.3" - ], - "js_task_runner": [ - "Gulp", - "Grunt", - "None" - ], - "custom_bootstrap_compilation": "n", - "use_compressor": "n", - "use_celery": "n", - "use_mailhog": "n", - "use_sentry_for_error_reporting": "y", - "use_opbeat": "n", - "use_whitenoise": "y", - "use_heroku": "n", - "use_travisci": "n" + "project_name": "My Awesome Project", + "project_slug": "{{ cookiecutter.project_name.lower()|replace(' ', '_')|replace('-', '_') }}", + "description": "Behold My Awesome Project!", + "author_name": "Daniel Roy Greenfeld", + "email": "{{ cookiecutter.project_slug }}@example.com", + "domain_name": "example.com", + "version": "0.1.0", + "open_source_license": [ + "MIT", + "BSD", + "GPLv3", + "Apache Software License 2.0", + "Not open source" + ], + "timezone": "UTC", + "windows": "n", + "use_pycharm": "n", + "use_docker": "n", + "postgresql_version": [ + "10.3", + "10.2", + "10.1", + "9.6", + "9.5", + "9.4", + "9.3" + ], + "js_task_runner": [ + "None", + "Gulp", + "Grunt" + ], + "custom_bootstrap_compilation": "n", + "use_compressor": "n", + "use_celery": "n", + "use_mailhog": "n", + "use_sentry_for_error_reporting": "y", + "use_opbeat": "n", + "use_whitenoise": "y", + "use_heroku": "n", + "use_travisci": "n" } From f4e217ed217f04ef6a2fa3c592849ae923d61f8a Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Sun, 4 Mar 2018 17:33:54 +0300 Subject: [PATCH 40/63] Simplify production databases section generation --- .../config/settings/production.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/{{cookiecutter.project_slug}}/config/settings/production.py b/{{cookiecutter.project_slug}}/config/settings/production.py index 3926f3db1..9947fc052 100644 --- a/{{cookiecutter.project_slug}}/config/settings/production.py +++ b/{{cookiecutter.project_slug}}/config/settings/production.py @@ -165,15 +165,12 @@ TEMPLATES[0]['OPTIONS']['loaders'] = [ ('django.template.loaders.cached.Loader', [ 'django.template.loaders.filesystem.Loader', 'django.template.loaders.app_directories.Loader', ]), ] -{% set _DEFAULT_CONN_MAX_AGE=60 %} + # DATABASE CONFIGURATION # ------------------------------------------------------------------------------ - -# Use the Heroku-style specification -# Raises ImproperlyConfigured exception if DATABASE_URL not in os.environ DATABASES['default'] = env.db('DATABASE_URL') -DATABASES['default']['CONN_MAX_AGE'] = env.int('CONN_MAX_AGE', default={{ _DEFAULT_CONN_MAX_AGE }}) DATABASES['default']['ATOMIC_REQUESTS'] = True +DATABASES['default']['CONN_MAX_AGE'] = env.int('CONN_MAX_AGE', default=60) # CACHING # ------------------------------------------------------------------------------ From 384f641ea5d30cf72d74b1d84ffc090a6b61ff6c Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Sun, 4 Mar 2018 17:35:11 +0300 Subject: [PATCH 41/63] Remove requirements_to_watch.txt Closes #1495. --- requirements_to_watch.txt | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 requirements_to_watch.txt diff --git a/requirements_to_watch.txt b/requirements_to_watch.txt deleted file mode 100644 index 91f0041bf..000000000 --- a/requirements_to_watch.txt +++ /dev/null @@ -1,2 +0,0 @@ -# These requirements prevented an upgrade to Django 1.11. -django-autoslug==1.9.3 From 64f25417436e3adceecacb0761d52077782d0a3a Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Sun, 4 Mar 2018 17:51:37 +0300 Subject: [PATCH 42/63] Set ALLOWED_HOSTS in config.settings.local --- {{cookiecutter.project_slug}}/config/settings/local.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/{{cookiecutter.project_slug}}/config/settings/local.py b/{{cookiecutter.project_slug}}/config/settings/local.py index c903795c7..18e5ba76a 100644 --- a/{{cookiecutter.project_slug}}/config/settings/local.py +++ b/{{cookiecutter.project_slug}}/config/settings/local.py @@ -15,6 +15,13 @@ Local settings for {{cookiecutter.project_name}} project. from .base import * # noqa +# SITE CONFIGURATION +# ------------------------------------------------------------------------------ +ALLOWED_HOSTS = [ + "localhost", + "0.0.0.0", +] + # DEBUG # ------------------------------------------------------------------------------ DEBUG = env.bool('DJANGO_DEBUG', default=True) From 8dd9e691b14458e521c3095ebecf90f39eb429c3 Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Sun, 4 Mar 2018 17:52:22 +0300 Subject: [PATCH 43/63] Group requirements from requirements.txt --- requirements.txt | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/requirements.txt b/requirements.txt index 085d5a147..6e16a2334 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,11 +1,19 @@ cookiecutter==1.6.0 -flake8==3.5.0 # pyup: != 2.6.0 + + +# Testing +# ------------------------------------------------------------------------------ sh==1.12.14 binaryornot==0.4.4 -# Testing +tox==2.9.1 + pytest==3.4.1 +pytest-cookies==0.3.0 + + +# Code quality +# ------------------------------------------------------------------------------ +flake8==3.5.0 pycodestyle==2.3.1 pyflakes==1.6.0 -tox==2.9.1 -pytest-cookies==0.3.0 From 00fbf6393965f4af2081679e43fe2269fbce928d Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Mon, 5 Mar 2018 13:12:33 +0300 Subject: [PATCH 44/63] Document use_travisci cookiecutter option --- docs/project-generation-options.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/project-generation-options.rst b/docs/project-generation-options.rst index d1d36324a..7c51cb050 100644 --- a/docs/project-generation-options.rst +++ b/docs/project-generation-options.rst @@ -86,9 +86,13 @@ open_source_license [1] 4. `Apache Software License 2.0`_ 5. Not open source +use_travisci [n] + Generate `Travis CI`_ configuration file. + **NOTE:** *If you choose to use Docker, selecting a JavaScript task runner is not supported out of the box.* + .. _WhiteNoise: https://github.com/evansd/whitenoise .. _Celery: https://github.com/celery/celery .. _MailHog: https://github.com/mailhog/MailHog @@ -106,3 +110,4 @@ not supported out of the box.* .. _BSD: https://opensource.org/licenses/BSD-3-Clause .. _GPLv3: https://www.gnu.org/licenses/gpl.html .. _Apache Software License 2.0: http://www.apache.org/licenses/LICENSE-2.0 +.. _Travis CI: https://travis-ci.org/ From f582aa1a84a7edf39045e972958ef0c9d587ccb1 Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Mon, 5 Mar 2018 13:53:38 +0300 Subject: [PATCH 45/63] Opt for personal email by default --- cookiecutter.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cookiecutter.json b/cookiecutter.json index 1eb56b784..27834a517 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -3,7 +3,7 @@ "project_slug": "{{ cookiecutter.project_name.lower()|replace(' ', '_')|replace('-', '_') }}", "description": "Behold My Awesome Project!", "author_name": "Daniel Roy Greenfeld", - "email": "{{ cookiecutter.project_slug }}@example.com", + "email": "{{ cookiecutter.author_name.lower()|replace(' ', '-') }}@example.com", "domain_name": "example.com", "version": "0.1.0", "open_source_license": [ From e4353a41ed78e5853f0b0760cd7bdc816d3643d6 Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Mon, 5 Mar 2018 13:54:35 +0300 Subject: [PATCH 46/63] Update project generation options docs --- docs/project-generation-options.rst | 158 +++++++++++++++------------- 1 file changed, 86 insertions(+), 72 deletions(-) diff --git a/docs/project-generation-options.rst b/docs/project-generation-options.rst index 7c51cb050..d5ebe07f2 100644 --- a/docs/project-generation-options.rst +++ b/docs/project-generation-options.rst @@ -1,69 +1,61 @@ Project Generation Options ========================== -project_name [project_name]: - Your human-readable project name, including any capitalization or spaces. +project_name [My Awesome Project]: + Your project's human-readable name, capitals and spaces allowed. -project_slug [project_name]: - The slug of your project, without dashes or spaces. Used to name your repo +project_slug [my_awesome_project]: + 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. -author_name [Your Name]: - You! This goes into places like the LICENSE file. +description [Behold My Awesome Project!] + Describes your project and gets used in places like `README.rst` and such. -email [Your email]: - Your email address. +author_name [Daniel Roy Greenfeld]: + This is you! The value goes into places like `LICENSE` and such. -description [A short description of the project.] - Used in the generated README.rst and other places. +email [daniel-roy-greenfeld@example.com]: + The email address you want to identify yourself in the project. domain_name [example.com] - Whatever domain name you plan to use for your project when it goes live. + The domain name you plan to use for your project ones it goes live. + Note that it can be safely changed later on whenever you need to. version [0.1.0] - The starting version number for your project. + The version of the project at its inception. + +open_source_license [1] + 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 [UTC] - Used in the base settings file for the `TIME_ZONE` value. - -use_whitenoise [y] - Whether to use WhiteNoise_ for static file serving. - -use_celery [n] - Whether to use Celery_. This gives you the ability to use distributed task - queues in your project. - -use_mailhog [n] - Whether to use MailHog_. MailHog is a tool that simulates email receiving - for development purposes. It runs a simple SMTP server which catches - any message sent to it. Messages are displayed in a web interface which - runs at ``http://localhost:8025/`` You need to download the MailHog - executable for your operating system, see the 'Developing Locally' docs - for instructions. - -use_sentry_for_error_reporting [n] - Whether to use Sentry_ to log errors from your project. - -use_opbeat [n] - Whether to use Opbeat_ for preformance monitoring and code optimization. - -use_pycharm [n] - Adds support for developing in PyCharm_ with a preconfigured .idea directory. + The value to be used for the `TIME_ZONE` setting of the project. windows [n] - Whether you'll be developing on Windows. + Indicates whether the project should be configured for development on Windows. + +use_pycharm [n] + Indicates whether the project should be configured for development with PyCharm_. use_docker [y] - Whether to use Docker_, separating the app and database into separate - containers. + Indicates whether the project should be configured to use Docker_ and `Docker Compose`_. -use_heroku [n] - Add configuration to deploy the application to a Heroku_ instance. +postgresql_version [1] + Select a PostgreSQL_ version to use. The choices are: -use_compressor [n] - Use `Django Compressor`_ to minify and combine rendered JavaScript and CSS - into cachable static resources. + 1. 10.3 + 2. 10.2 + 3. 10.1 + 4. 9.6 + 5. 9.5 + 6. 9.4 + 7. 9.3 js_task_runner [1] Select a JavaScript task runner. The choices are: @@ -73,41 +65,63 @@ js_task_runner [1] 3. None custom_bootstrap_compilation [n] - Scaffold out recompiling Bootstrap as as task, with Gulp_ or Grunt_. - Useful for letting you change Bootstrap variables in real time. - Consult project README for more details. + 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. -open_source_license [1] - Select a software license for the project. The choices are: +use_compressor [n] + Indicates whether the project should be configured to use `Django Compressor`_. - 1. MIT_ - 2. BSD_ - 3. GPLv3_ - 4. `Apache Software License 2.0`_ - 5. Not open source +use_celery [n] + Indicates whether the project should be configured to use Celery_. + +use_mailhog [n] + Indicates whether the project should be configured to use MailHog_. + +use_sentry_for_error_reporting [n] + Indicates whether the project should be configured to use Sentry_. + +use_opbeat [n] + Indicates whether the project should be configured to use Opbeat_. + +use_whitenoise [y] + Indicates whether the project should be configured to use WhiteNoise_. + +use_heroku [n] + Indicates whether the project should be configured so as to be deployable + to Heroku_. use_travisci [n] - Generate `Travis CI`_ configuration file. - -**NOTE:** *If you choose to use Docker, selecting a JavaScript task runner is -not supported out of the box.* + Indicates whether the project should be configured to use `Travis CI`_. -.. _WhiteNoise: https://github.com/evansd/whitenoise -.. _Celery: https://github.com/celery/celery -.. _MailHog: https://github.com/mailhog/MailHog -.. _Sentry: https://github.com/getsentry/sentry -.. _Opbeat: https://github.com/opbeat/opbeat_python -.. _PyCharm: https://www.jetbrains.com/pycharm/ -.. _Docker: https://github.com/docker/docker -.. _Heroku: https://github.com/heroku/heroku-buildpack-python -.. _Django Compressor: https://github.com/django-compressor/django-compressor -.. _Gulp: https://github.com/gulpjs/gulp -.. _Grunt: https://github.com/gruntjs/grunt -.. _Webpack: https://github.com/webpack/webpack -.. _Let's Encrypt: https://github.com/certbot/certbot .. _MIT: https://opensource.org/licenses/MIT .. _BSD: https://opensource.org/licenses/BSD-3-Clause .. _GPLv3: https://www.gnu.org/licenses/gpl.html .. _Apache Software License 2.0: http://www.apache.org/licenses/LICENSE-2.0 + +.. _PyCharm: https://www.jetbrains.com/pycharm/ + +.. _Docker: https://github.com/docker/docker +.. _Docker Compose: https://docs.docker.com/compose/ + +.. _PostgreSQL: https://www.postgresql.org/docs/ + +.. _Gulp: https://github.com/gulpjs/gulp +.. _Grunt: https://github.com/gruntjs/grunt + +.. _Django Compressor: https://github.com/django-compressor/django-compressor + +.. _Celery: https://github.com/celery/celery + +.. _MailHog: https://github.com/mailhog/MailHog + +.. _Sentry: https://github.com/getsentry/sentry + +.. _Opbeat: https://github.com/opbeat/opbeat_python + +.. _WhiteNoise: https://github.com/evansd/whitenoise + +.. _Heroku: https://github.com/heroku/heroku-buildpack-python + .. _Travis CI: https://travis-ci.org/ From d2964faa54303b84608439cf60c00bd62d3f60ac Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Mon, 5 Mar 2018 14:01:45 +0300 Subject: [PATCH 47/63] Re-order requirements.txt --- requirements.txt | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/requirements.txt b/requirements.txt index 6e16a2334..de0bc868d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,19 +1,18 @@ cookiecutter==1.6.0 - - -# Testing -# ------------------------------------------------------------------------------ sh==1.12.14 binaryornot==0.4.4 -tox==2.9.1 - -pytest==3.4.1 -pytest-cookies==0.3.0 - # Code quality # ------------------------------------------------------------------------------ flake8==3.5.0 pycodestyle==2.3.1 pyflakes==1.6.0 + + +# Testing +# ------------------------------------------------------------------------------ +tox==2.9.1 + +pytest==3.4.1 +pytest-cookies==0.3.0 From 70b56839c6605c68fa24b2f8a73a9bb082d7a059 Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Mon, 5 Mar 2018 14:25:51 +0300 Subject: [PATCH 48/63] Simplify tox.ini --- tox.ini | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tox.ini b/tox.ini index a16b80ed6..2399e24d5 100644 --- a/tox.ini +++ b/tox.ini @@ -3,10 +3,9 @@ skipsdist = true envlist = py36 [testenv] -passenv = LC_ALL, LANG, HOME deps = binaryornot flake8==2.5.5 pytest-cookies sh -commands = py.test {posargs:tests} +commands = pytest {posargs:./tests} From 20a43c2bc531ea118e0a579ab17f3b65522ea141 Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Mon, 5 Mar 2018 14:26:12 +0300 Subject: [PATCH 49/63] Simplify test_docker.sh --- tests/test_docker.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_docker.sh b/tests/test_docker.sh index c103b9833..384fdff2d 100755 --- a/tests/test_docker.sh +++ b/tests/test_docker.sh @@ -21,4 +21,4 @@ docker-compose -f local.yml run django python manage.py test docker-compose -f local.yml run django python manage.py makemigrations --dry-run --check || { echo "ERROR: there were changes in the models, but migration listed above have not been created and are not saved in version control"; exit 1; } # Test support for translations -docker-compose -f local.yml run --rm django python manage.py makemessages +docker-compose -f local.yml run django python manage.py makemessages From 52619563563c6347ff66b166abe0c9a01bf26a80 Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Mon, 5 Mar 2018 14:26:43 +0300 Subject: [PATCH 50/63] Refactor gunicorn -w to be set from WEB_CONCURRENCY env Closes #1480. --- .../compose/production/django/gunicorn.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/{{cookiecutter.project_slug}}/compose/production/django/gunicorn.sh b/{{cookiecutter.project_slug}}/compose/production/django/gunicorn.sh index 8846cafb2..39679f289 100644 --- a/{{cookiecutter.project_slug}}/compose/production/django/gunicorn.sh +++ b/{{cookiecutter.project_slug}}/compose/production/django/gunicorn.sh @@ -6,4 +6,4 @@ set -o nounset python /app/manage.py collectstatic --noinput -/usr/local/bin/gunicorn config.wsgi -w 4 -b 0.0.0.0:5000 --chdir=/app +/usr/local/bin/gunicorn config.wsgi -b 0.0.0.0:5000 --chdir=/app From baf08b2f5f14961d0c89876db68dd89c99e38b01 Mon Sep 17 00:00:00 2001 From: Bruno Alla Date: Mon, 5 Mar 2018 17:30:13 +0000 Subject: [PATCH 51/63] Document Gunicorn worker concurrency --- docs/deployment-on-heroku.rst | 1 + docs/deployment-on-pythonanywhere.rst | 1 + {{cookiecutter.project_slug}}/env.example | 3 +++ 3 files changed, 5 insertions(+) diff --git a/docs/deployment-on-heroku.rst b/docs/deployment-on-heroku.rst index b84edfa46..998c75b67 100644 --- a/docs/deployment-on-heroku.rst +++ b/docs/deployment-on-heroku.rst @@ -16,6 +16,7 @@ Run these commands to deploy the project to Heroku: heroku addons:create heroku-redis:hobby-dev heroku addons:create mailgun + heroku config:set WEB_CONCURRENCY=4 heroku config:set DJANGO_ADMIN_URL="$(openssl rand -base64 32)" heroku config:set DJANGO_SECRET_KEY="$(openssl rand -base64 64)" heroku config:set DJANGO_SETTINGS_MODULE='config.settings.production' diff --git a/docs/deployment-on-pythonanywhere.rst b/docs/deployment-on-pythonanywhere.rst index d70684bd9..cb23750c5 100644 --- a/docs/deployment-on-pythonanywhere.rst +++ b/docs/deployment-on-pythonanywhere.rst @@ -63,6 +63,7 @@ Add these exports .. code-block:: bash + export WEB_CONCURRENCY=4 export DJANGO_SETTINGS_MODULE='config.settings.production' export DJANGO_SECRET_KEY='' export DJANGO_ALLOWED_HOSTS='' diff --git a/{{cookiecutter.project_slug}}/env.example b/{{cookiecutter.project_slug}}/env.example index 1d28cb599..4030af32a 100644 --- a/{{cookiecutter.project_slug}}/env.example +++ b/{{cookiecutter.project_slug}}/env.example @@ -4,6 +4,9 @@ POSTGRES_PASSWORD=!!!SET POSTGRES_PASSWORD!!! POSTGRES_USER=!!!SET POSTGRES_USER!!! CONN_MAX_AGE= +# Gunicorn concurrency +WEB_CONCURRENCY=4 + # Domain name, used by caddy DOMAIN_NAME={{ cookiecutter.domain_name }} From 82dcd2d30c3ad358407ac5a4aa7c864ed5aec49a Mon Sep 17 00:00:00 2001 From: Bruno Alla Date: Mon, 5 Mar 2018 17:56:45 +0000 Subject: [PATCH 52/63] Simplify Mailgun settings When creating a Mailgun add-on on Heroku, the app gets some environment variables by default: MAILGUN_API_KEY MAILGUN_DOMAIN However, the cookiecutter names do not match and requires a manual step from the user deploying. It's used elsewhere but shouldn't harm the other deployment methods to rename these variables. While updating the docs I noticed a variable that appear unused DJANGO_MAILGUN_SERVER_NAME so this removes it from the documentation. --- docs/deployment-on-heroku.rst | 4 ---- docs/deployment-on-pythonanywhere.rst | 10 ++++------ docs/settings.rst | 5 ++--- .../config/settings/production.py | 4 ++-- {{cookiecutter.project_slug}}/env.example | 4 ++-- 5 files changed, 10 insertions(+), 17 deletions(-) diff --git a/docs/deployment-on-heroku.rst b/docs/deployment-on-heroku.rst index 998c75b67..f9abfa515 100644 --- a/docs/deployment-on-heroku.rst +++ b/docs/deployment-on-heroku.rst @@ -26,10 +26,6 @@ Run these commands to deploy the project to Heroku: heroku config:set DJANGO_AWS_SECRET_ACCESS_KEY=YOUR_AWS_SECRET_ACCESS_KEY_HERE heroku config:set DJANGO_AWS_STORAGE_BUCKET_NAME=YOUR_AWS_S3_BUCKET_NAME_HERE - heroku config:set DJANGO_MAILGUN_SERVER_NAME=YOUR_MALGUN_SERVER - heroku config:set DJANGO_MAILGUN_API_KEY=YOUR_MAILGUN_API_KEY - heroku config:set MAILGUN_SENDER_DOMAIN=YOUR_MAILGUN_SENDER_DOMAIN - heroku config:set PYTHONHASHSEED=random heroku config:set DJANGO_ADMIN_URL=\^somelocation/ diff --git a/docs/deployment-on-pythonanywhere.rst b/docs/deployment-on-pythonanywhere.rst index cb23750c5..995da7b03 100644 --- a/docs/deployment-on-pythonanywhere.rst +++ b/docs/deployment-on-pythonanywhere.rst @@ -68,9 +68,8 @@ Add these exports export DJANGO_SECRET_KEY='' export DJANGO_ALLOWED_HOSTS='' export DJANGO_ADMIN_URL='' - export DJANGO_MAILGUN_API_KEY='' - export DJANGO_MAILGUN_SERVER_NAME='' - export MAILGUN_SENDER_DOMAIN='' + export MAILGUN_API_KEY='' + export MAILGUN_DOMAIN='' export DJANGO_AWS_ACCESS_KEY_ID= export DJANGO_AWS_SECRET_ACCESS_KEY= export DJANGO_AWS_STORAGE_BUCKET_NAME= @@ -139,9 +138,8 @@ Click through to the **WSGI configuration file** link (near the top) and edit th os.environ['DJANGO_SECRET_KEY'] = '' os.environ['DJANGO_ALLOWED_HOSTS'] = '' os.environ['DJANGO_ADMIN_URL'] = '' - os.environ['DJANGO_MAILGUN_API_KEY'] = '' - os.environ['DJANGO_MAILGUN_SERVER_NAME'] = '' - os.environ['MAILGUN_SENDER_DOMAIN'] = '' + os.environ['MAILGUN_API_KEY'] = '' + os.environ['MAILGUN_DOMAIN'] = '' os.environ['DJANGO_AWS_ACCESS_KEY_ID'] = '' os.environ['DJANGO_AWS_SECRET_ACCESS_KEY'] = '' os.environ['DJANGO_AWS_STORAGE_BUCKET_NAME'] = '' diff --git a/docs/settings.rst b/docs/settings.rst index 20bf9e5e1..828b5de4b 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -47,9 +47,8 @@ DJANGO_AWS_STORAGE_BUCKET_NAME AWS_STORAGE_BUCKET_NAME n/a DJANGO_SENTRY_DSN SENTRY_DSN n/a raises error DJANGO_SENTRY_CLIENT SENTRY_CLIENT n/a raven.contrib.django.raven_compat.DjangoClient DJANGO_SENTRY_LOG_LEVEL SENTRY_LOG_LEVEL n/a logging.INFO -DJANGO_MAILGUN_API_KEY MAILGUN_ACCESS_KEY n/a raises error -DJANGO_MAILGUN_SERVER_NAME MAILGUN_SERVER_NAME n/a raises error -MAILGUN_SENDER_DOMAIN MAILGUN_SENDER_DOMAIN n/a raises error +MAILGUN_API_KEY MAILGUN_ACCESS_KEY n/a raises error +MAILGUN_DOMAIN MAILGUN_SENDER_DOMAIN n/a raises error NEW_RELIC_APP_NAME NEW_RELIC_APP_NAME n/a raises error NEW_RELIC_LICENSE_KEY NEW_RELIC_LICENSE_KEY n/a raises error DJANGO_OPBEAT_APP_ID OPBEAT['APP_ID'] n/a raises error diff --git a/{{cookiecutter.project_slug}}/config/settings/production.py b/{{cookiecutter.project_slug}}/config/settings/production.py index 9947fc052..09cd8ed9f 100644 --- a/{{cookiecutter.project_slug}}/config/settings/production.py +++ b/{{cookiecutter.project_slug}}/config/settings/production.py @@ -152,8 +152,8 @@ SERVER_EMAIL = env('DJANGO_SERVER_EMAIL', default=DEFAULT_FROM_EMAIL) # Anymail with Mailgun INSTALLED_APPS += ['anymail', ] ANYMAIL = { - 'MAILGUN_API_KEY': env('DJANGO_MAILGUN_API_KEY'), - 'MAILGUN_SENDER_DOMAIN': env('MAILGUN_SENDER_DOMAIN') + 'MAILGUN_API_KEY': env('MAILGUN_API_KEY'), + 'MAILGUN_SENDER_DOMAIN': env('MAILGUN_DOMAIN') } EMAIL_BACKEND = 'anymail.backends.mailgun.EmailBackend' diff --git a/{{cookiecutter.project_slug}}/env.example b/{{cookiecutter.project_slug}}/env.example index 4030af32a..1ea342045 100644 --- a/{{cookiecutter.project_slug}}/env.example +++ b/{{cookiecutter.project_slug}}/env.example @@ -23,9 +23,9 @@ DJANGO_AWS_SECRET_ACCESS_KEY= DJANGO_AWS_STORAGE_BUCKET_NAME= # Used with email -DJANGO_MAILGUN_API_KEY= +MAILGUN_API_KEY= DJANGO_SERVER_EMAIL= -MAILGUN_SENDER_DOMAIN= +MAILGUN_DOMAIN= # Security! Better to use DNS for this task, but you can use redirect DJANGO_SECURE_SSL_REDIRECT=False From 9fca6019ecb4b239ef41a2348343b1f28f9eae47 Mon Sep 17 00:00:00 2001 From: Melanie Crutchfield Date: Mon, 5 Mar 2018 14:55:15 -0800 Subject: [PATCH 53/63] Update project-generation-options.rst (#1547) Change small typo. "ones" should be "once". --- docs/project-generation-options.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/project-generation-options.rst b/docs/project-generation-options.rst index d5ebe07f2..3f7928c50 100644 --- a/docs/project-generation-options.rst +++ b/docs/project-generation-options.rst @@ -19,7 +19,7 @@ email [daniel-roy-greenfeld@example.com]: The email address you want to identify yourself in the project. domain_name [example.com] - The domain name you plan to use for your project ones it goes live. + 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 [0.1.0] From 93ad8e6125f8fc226432f92bf7118dccd3090ac1 Mon Sep 17 00:00:00 2001 From: "pyup.io bot" Date: Tue, 6 Mar 2018 07:13:20 +0100 Subject: [PATCH 54/63] Update django-crispy-forms from 1.7.0 to 1.7.1 (#1546) --- {{cookiecutter.project_slug}}/requirements/base.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/{{cookiecutter.project_slug}}/requirements/base.txt b/{{cookiecutter.project_slug}}/requirements/base.txt index 85c45e993..8bc63a5f6 100644 --- a/{{cookiecutter.project_slug}}/requirements/base.txt +++ b/{{cookiecutter.project_slug}}/requirements/base.txt @@ -16,7 +16,7 @@ whitenoise==3.3.1 # Forms -django-crispy-forms==1.7.0 +django-crispy-forms==1.7.1 # Models django-model-utils==3.1.1 From 5a20dce43125e31590b479afe1b330803f920e37 Mon Sep 17 00:00:00 2001 From: "pyup.io bot" Date: Tue, 6 Mar 2018 09:22:44 +0100 Subject: [PATCH 55/63] Update pytest from 3.4.1 to 3.4.2 (#1549) --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index de0bc868d..18cd5222a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,5 +14,5 @@ pyflakes==1.6.0 # ------------------------------------------------------------------------------ tox==2.9.1 -pytest==3.4.1 +pytest==3.4.2 pytest-cookies==0.3.0 From b4738d2ff35d487b3feb76f4fb3ee21840b6b88f Mon Sep 17 00:00:00 2001 From: Nicholas Date: Tue, 6 Mar 2018 17:44:44 +0800 Subject: [PATCH 56/63] Update Heroku deployment docs (#1548) * Update Heroku deployment Remove duplicate DJANGO_ADMIN_URL config, add SENTRY config * Update deployment-on-heroku.rst --- docs/deployment-on-heroku.rst | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/deployment-on-heroku.rst b/docs/deployment-on-heroku.rst index 998c75b67..bf9ac7458 100644 --- a/docs/deployment-on-heroku.rst +++ b/docs/deployment-on-heroku.rst @@ -17,7 +17,8 @@ Run these commands to deploy the project to Heroku: heroku addons:create mailgun heroku config:set WEB_CONCURRENCY=4 - heroku config:set DJANGO_ADMIN_URL="$(openssl rand -base64 32)" + # Generating a 32 character-long random string without any of the visually similiar characters "IOl01": + heroku config:set DJANGO_ADMIN_URL="^$(openssl rand -base64 4096 | tr -dc 'A-HJ-NP-Za-km-z2-9' | head -c 32)/" heroku config:set DJANGO_SECRET_KEY="$(openssl rand -base64 64)" heroku config:set DJANGO_SETTINGS_MODULE='config.settings.production' heroku config:set DJANGO_ALLOWED_HOSTS='.herokuapp.com' @@ -30,8 +31,10 @@ Run these commands to deploy the project to Heroku: heroku config:set DJANGO_MAILGUN_API_KEY=YOUR_MAILGUN_API_KEY heroku config:set MAILGUN_SENDER_DOMAIN=YOUR_MAILGUN_SENDER_DOMAIN + # This is to be set only if you're using Sentry: + heroku config:set DJANGO_SENTRY_DSN=YOUR_SENTRY_DSN + heroku config:set PYTHONHASHSEED=random - heroku config:set DJANGO_ADMIN_URL=\^somelocation/ git push heroku master heroku run python manage.py migrate From 538011718132346369ce5f36a0132c812637c525 Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Tue, 6 Mar 2018 14:27:13 +0300 Subject: [PATCH 57/63] Uninstall wheel Closes #1095. --- {{cookiecutter.project_slug}}/requirements/base.txt | 7 ------- 1 file changed, 7 deletions(-) diff --git a/{{cookiecutter.project_slug}}/requirements/base.txt b/{{cookiecutter.project_slug}}/requirements/base.txt index 8bc63a5f6..59ac7340f 100644 --- a/{{cookiecutter.project_slug}}/requirements/base.txt +++ b/{{cookiecutter.project_slug}}/requirements/base.txt @@ -1,10 +1,3 @@ -# Wheel 0.25+ needed to install certain packages on CPython 3.5+ -# like Pillow and psycopg2 -# See http://bitly.com/wheel-building-fails-CPython-35 -# Verified bug on Python 3.5.1 -wheel==0.30.0 - - # Conservative Django django==2.0.2 # pyup: < 2.1 From d2791b019a682b843233ae6ae4ee75ba7d8d865a Mon Sep 17 00:00:00 2001 From: Nikita Shupeyko Date: Tue, 6 Mar 2018 14:28:25 +0300 Subject: [PATCH 58/63] Prettify and re-order settings entries (#1550) * Prettify and re-order settings entries * Use old-style .format() for the time being * Remove redundant linebreaks at the settings files' beginning * Fix E303 too many blank lines * Remove a redundant linebreak from requirements.txt * Some linebreake juggling in config.settings.base --- requirements.txt | 1 - .../config/settings/base.py | 403 ++++++++---------- .../config/settings/local.py | 116 +++-- .../config/settings/production.py | 379 ++++++++-------- .../config/settings/test.py | 68 ++- 5 files changed, 463 insertions(+), 504 deletions(-) diff --git a/requirements.txt b/requirements.txt index 18cd5222a..d549c678a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -13,6 +13,5 @@ pyflakes==1.6.0 # Testing # ------------------------------------------------------------------------------ tox==2.9.1 - pytest==3.4.2 pytest-cookies==0.3.0 diff --git a/{{cookiecutter.project_slug}}/config/settings/base.py b/{{cookiecutter.project_slug}}/config/settings/base.py index 9b14f5ac2..3df643556 100644 --- a/{{cookiecutter.project_slug}}/config/settings/base.py +++ b/{{cookiecutter.project_slug}}/config/settings/base.py @@ -1,238 +1,119 @@ """ -Base settings for {{cookiecutter.project_name}} project. - -For more information on this file, see -https://docs.djangoproject.com/en/dev/topics/settings/ - -For the full list of settings and their values, see -https://docs.djangoproject.com/en/dev/ref/settings/ +Base settings to build other settings files upon. """ + import environ ROOT_DIR = environ.Path(__file__) - 3 # ({{ cookiecutter.project_slug }}/config/settings/base.py - 3 = {{ cookiecutter.project_slug }}/) APPS_DIR = ROOT_DIR.path('{{ cookiecutter.project_slug }}') -# Load operating system environment variables and then prepare to use them env = environ.Env() -# .env file, should load only in development environment READ_DOT_ENV_FILE = env.bool('DJANGO_READ_DOT_ENV_FILE', default=False) - if READ_DOT_ENV_FILE: - # Operating System Environment variables have precedence over variables defined in the .env file, - # that is to say variables from the .env files will only be used if not defined - # as environment variables. - env_file = str(ROOT_DIR.path('.env')) - print('Loading : {}'.format(env_file)) - env.read_env(env_file) - print('The .env file has been loaded. See base.py for more information') + # OS environment variables take precedence over variables from .env + env.read_env(str(ROOT_DIR.path('.env'))) -# APP CONFIGURATION +# GENERAL +# ------------------------------------------------------------------------------ +# https://docs.djangoproject.com/en/dev/ref/settings/#debug +DEBUG = env.bool('DJANGO_DEBUG', False) +# Local time zone. Choices are +# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name +# though not all of them may be available with every OS. +# In Windows, this must be set to your system time zone. +TIME_ZONE = '{{ cookiecutter.timezone }}' +# https://docs.djangoproject.com/en/dev/ref/settings/#language-code +LANGUAGE_CODE = 'en-us' +# https://docs.djangoproject.com/en/dev/ref/settings/#site-id +SITE_ID = 1 +# https://docs.djangoproject.com/en/dev/ref/settings/#use-i18n +USE_I18N = True +# https://docs.djangoproject.com/en/dev/ref/settings/#use-l10n +USE_L10N = True +# https://docs.djangoproject.com/en/dev/ref/settings/#use-tz +USE_TZ = True + +# DATABASES +# ------------------------------------------------------------------------------ +# https://docs.djangoproject.com/en/dev/ref/settings/#databases +{% if cookiecutter.use_docker == 'y' -%} +DATABASES = { + 'default': env.db('DATABASE_URL'), +} +{%- else %} +DATABASES = { + 'default': env.db('DATABASE_URL', default='postgres://{% if cookiecutter.windows == 'y' %}localhost{% endif %}/{{cookiecutter.project_slug}}'), +} +{%- endif %} +DATABASES['default']['ATOMIC_REQUESTS'] = True + +# URLS +# ------------------------------------------------------------------------------ +# https://docs.djangoproject.com/en/dev/ref/settings/#root-urlconf +ROOT_URLCONF = 'config.urls' +# https://docs.djangoproject.com/en/dev/ref/settings/#wsgi-application +WSGI_APPLICATION = 'config.wsgi.application' + +# APPS # ------------------------------------------------------------------------------ DJANGO_APPS = [ - # Default Django apps: 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.sites', 'django.contrib.messages', 'django.contrib.staticfiles', - - # Useful template tags: - # 'django.contrib.humanize', - - # Admin + # 'django.contrib.humanize', # Handy template tags 'django.contrib.admin', ] THIRD_PARTY_APPS = [ - 'crispy_forms', # Form layouts - 'allauth', # registration - 'allauth.account', # registration - 'allauth.socialaccount', # registration -] + 'crispy_forms', -# Apps specific for this project go here. + 'allauth', + 'allauth.account', + 'allauth.socialaccount', +] LOCAL_APPS = [ - # custom users app '{{ cookiecutter.project_slug }}.users.apps.UsersConfig', # Your stuff: custom apps go here ] - -# See: https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps +# https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS -# MIDDLEWARE CONFIGURATION -# ------------------------------------------------------------------------------ -MIDDLEWARE = [ - 'django.middleware.security.SecurityMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', -] - -# MIGRATIONS CONFIGURATION +# MIGRATIONS # ------------------------------------------------------------------------------ +# https://docs.djangoproject.com/en/dev/ref/settings/#migration-modules MIGRATION_MODULES = { 'sites': '{{ cookiecutter.project_slug }}.contrib.sites.migrations' } -# DEBUG +# AUTHENTICATION # ------------------------------------------------------------------------------ -# See: https://docs.djangoproject.com/en/dev/ref/settings/#debug -DEBUG = env.bool('DJANGO_DEBUG', False) - -# FIXTURE CONFIGURATION -# ------------------------------------------------------------------------------ -# See: https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-FIXTURE_DIRS -FIXTURE_DIRS = ( - str(APPS_DIR.path('fixtures')), -) - -# EMAIL CONFIGURATION -# ------------------------------------------------------------------------------ -EMAIL_BACKEND = env('DJANGO_EMAIL_BACKEND', default='django.core.mail.backends.smtp.EmailBackend') - -# MANAGER CONFIGURATION -# ------------------------------------------------------------------------------ -# See: https://docs.djangoproject.com/en/dev/ref/settings/#admins -ADMINS = [ - ("""{{cookiecutter.author_name}}""", '{{cookiecutter.email}}'), +# https://docs.djangoproject.com/en/dev/ref/settings/#authentication-backends +AUTHENTICATION_BACKENDS = [ + 'django.contrib.auth.backends.ModelBackend', + 'allauth.account.auth_backends.AuthenticationBackend', ] +# https://docs.djangoproject.com/en/dev/ref/settings/#auth-user-model +AUTH_USER_MODEL = 'users.User' +# https://docs.djangoproject.com/en/dev/ref/settings/#login-redirect-url +LOGIN_REDIRECT_URL = 'users:redirect' +# https://docs.djangoproject.com/en/dev/ref/settings/#login-url +LOGIN_URL = 'account_login' -# See: https://docs.djangoproject.com/en/dev/ref/settings/#managers -MANAGERS = ADMINS - -# DATABASE CONFIGURATION +# PASSWORDS # ------------------------------------------------------------------------------ -# See: https://docs.djangoproject.com/en/dev/ref/settings/#databases -# Uses django-environ to accept uri format -# See: https://django-environ.readthedocs.io/en/latest/#supported-types -{% if cookiecutter.use_docker == 'y' %} -DATABASES = { - 'default': env.db('DATABASE_URL'), -} -{% else %} -DATABASES = { - 'default': env.db('DATABASE_URL', default='postgres://{% if cookiecutter.windows == 'y' %}localhost{% endif %}/{{cookiecutter.project_slug}}'), -} -{% endif %} -DATABASES['default']['ATOMIC_REQUESTS'] = True - - -# GENERAL CONFIGURATION -# ------------------------------------------------------------------------------ -# Local time zone for this installation. Choices can be found here: -# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name -# although not all choices may be available on all operating systems. -# In a Windows environment this must be set to your system time zone. -TIME_ZONE = '{{ cookiecutter.timezone }}' - -# See: https://docs.djangoproject.com/en/dev/ref/settings/#language-code -LANGUAGE_CODE = 'en-us' - -# See: https://docs.djangoproject.com/en/dev/ref/settings/#site-id -SITE_ID = 1 - -# See: https://docs.djangoproject.com/en/dev/ref/settings/#use-i18n -USE_I18N = True - -# See: https://docs.djangoproject.com/en/dev/ref/settings/#use-l10n -USE_L10N = True - -# See: https://docs.djangoproject.com/en/dev/ref/settings/#use-tz -USE_TZ = True - -# TEMPLATE CONFIGURATION -# ------------------------------------------------------------------------------ -# See: https://docs.djangoproject.com/en/dev/ref/settings/#templates -TEMPLATES = [ - { - # See: https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-TEMPLATES-BACKEND - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - # See: https://docs.djangoproject.com/en/dev/ref/settings/#template-dirs - 'DIRS': [ - str(APPS_DIR.path('templates')), - ], - 'OPTIONS': { - # See: https://docs.djangoproject.com/en/dev/ref/settings/#template-debug - 'debug': DEBUG, - # See: https://docs.djangoproject.com/en/dev/ref/settings/#template-loaders - # https://docs.djangoproject.com/en/dev/ref/templates/api/#loader-types - 'loaders': [ - 'django.template.loaders.filesystem.Loader', - 'django.template.loaders.app_directories.Loader', - ], - # See: https://docs.djangoproject.com/en/dev/ref/settings/#template-context-processors - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.template.context_processors.i18n', - 'django.template.context_processors.media', - 'django.template.context_processors.static', - 'django.template.context_processors.tz', - 'django.contrib.messages.context_processors.messages', - # Your stuff: custom template context processors go here - ], - }, - }, -] - -# See: http://django-crispy-forms.readthedocs.io/en/latest/install.html#template-packs -CRISPY_TEMPLATE_PACK = 'bootstrap4' - -# STATIC FILE CONFIGURATION -# ------------------------------------------------------------------------------ -# See: https://docs.djangoproject.com/en/dev/ref/settings/#static-root -STATIC_ROOT = str(ROOT_DIR('staticfiles')) - -# See: https://docs.djangoproject.com/en/dev/ref/settings/#static-url -STATIC_URL = '/static/' - -# See: https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#std:setting-STATICFILES_DIRS -STATICFILES_DIRS = [ - str(APPS_DIR.path('static')), -] - -# See: https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#staticfiles-finders -STATICFILES_FINDERS = [ - 'django.contrib.staticfiles.finders.FileSystemFinder', - 'django.contrib.staticfiles.finders.AppDirectoriesFinder', -] - -# MEDIA CONFIGURATION -# ------------------------------------------------------------------------------ -# See: https://docs.djangoproject.com/en/dev/ref/settings/#media-root -MEDIA_ROOT = str(APPS_DIR('media')) - -# See: https://docs.djangoproject.com/en/dev/ref/settings/#media-url -MEDIA_URL = '/media/' - -# URL Configuration -# ------------------------------------------------------------------------------ -ROOT_URLCONF = 'config.urls' - -# See: https://docs.djangoproject.com/en/dev/ref/settings/#wsgi-application -WSGI_APPLICATION = 'config.wsgi.application' - -# PASSWORD STORAGE SETTINGS -# ------------------------------------------------------------------------------ -# See https://docs.djangoproject.com/en/dev/topics/auth/passwords/#using-argon2-with-django +# https://docs.djangoproject.com/en/dev/ref/settings/#password-hashers PASSWORD_HASHERS = [ + # https://docs.djangoproject.com/en/dev/topics/auth/passwords/#using-argon2-with-django 'django.contrib.auth.hashers.Argon2PasswordHasher', 'django.contrib.auth.hashers.PBKDF2PasswordHasher', 'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher', 'django.contrib.auth.hashers.BCryptSHA256PasswordHasher', 'django.contrib.auth.hashers.BCryptPasswordHasher', ] - -# PASSWORD VALIDATION # https://docs.djangoproject.com/en/dev/ref/settings/#auth-password-validators -# ------------------------------------------------------------------------------ - AUTH_PASSWORD_VALIDATORS = [ { 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', @@ -248,54 +129,142 @@ AUTH_PASSWORD_VALIDATORS = [ }, ] -# AUTHENTICATION CONFIGURATION +# MIDDLEWARE # ------------------------------------------------------------------------------ -AUTHENTICATION_BACKENDS = [ - 'django.contrib.auth.backends.ModelBackend', - 'allauth.account.auth_backends.AuthenticationBackend', +# https://docs.djangoproject.com/en/dev/ref/settings/#middleware +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] -# Some really nice defaults -ACCOUNT_AUTHENTICATION_METHOD = 'username' -ACCOUNT_EMAIL_REQUIRED = True -ACCOUNT_EMAIL_VERIFICATION = 'mandatory' +# STATIC +# ------------------------------------------------------------------------------ +# https://docs.djangoproject.com/en/dev/ref/settings/#static-root +STATIC_ROOT = str(ROOT_DIR('staticfiles')) +# https://docs.djangoproject.com/en/dev/ref/settings/#static-url +STATIC_URL = '/static/' +# https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#std:setting-STATICFILES_DIRS +STATICFILES_DIRS = [ + str(APPS_DIR.path('static')), +] +# https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#staticfiles-finders +STATICFILES_FINDERS = [ + 'django.contrib.staticfiles.finders.FileSystemFinder', + 'django.contrib.staticfiles.finders.AppDirectoriesFinder', +] -ACCOUNT_ALLOW_REGISTRATION = env.bool('DJANGO_ACCOUNT_ALLOW_REGISTRATION', True) -ACCOUNT_ADAPTER = '{{cookiecutter.project_slug}}.users.adapters.AccountAdapter' -SOCIALACCOUNT_ADAPTER = '{{cookiecutter.project_slug}}.users.adapters.SocialAccountAdapter' +# MEDIA +# ------------------------------------------------------------------------------ +# https://docs.djangoproject.com/en/dev/ref/settings/#media-root +MEDIA_ROOT = str(APPS_DIR('media')) +# https://docs.djangoproject.com/en/dev/ref/settings/#media-url +MEDIA_URL = '/media/' -# Custom user app defaults -# Select the correct user model -AUTH_USER_MODEL = 'users.User' -LOGIN_REDIRECT_URL = 'users:redirect' -LOGIN_URL = 'account_login' +# TEMPLATES +# ------------------------------------------------------------------------------ +# https://docs.djangoproject.com/en/dev/ref/settings/#templates +TEMPLATES = [ + { + # https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-TEMPLATES-BACKEND + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + # https://docs.djangoproject.com/en/dev/ref/settings/#template-dirs + 'DIRS': [ + str(APPS_DIR.path('templates')), + ], + 'OPTIONS': { + # https://docs.djangoproject.com/en/dev/ref/settings/#template-debug + 'debug': DEBUG, + # https://docs.djangoproject.com/en/dev/ref/settings/#template-loaders + # https://docs.djangoproject.com/en/dev/ref/templates/api/#loader-types + 'loaders': [ + 'django.template.loaders.filesystem.Loader', + 'django.template.loaders.app_directories.Loader', + ], + # https://docs.djangoproject.com/en/dev/ref/settings/#template-context-processors + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.template.context_processors.i18n', + 'django.template.context_processors.media', + 'django.template.context_processors.static', + 'django.template.context_processors.tz', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] +# http://django-crispy-forms.readthedocs.io/en/latest/install.html#template-packs +CRISPY_TEMPLATE_PACK = 'bootstrap4' -# SLUGLIFIER -AUTOSLUG_SLUGIFY_FUNCTION = 'slugify.slugify' -{% if cookiecutter.use_celery == 'y' %} -########## CELERY +# FIXTURES +# ------------------------------------------------------------------------------ +# https://docs.djangoproject.com/en/dev/ref/settings/#fixture-dirs +FIXTURE_DIRS = ( + str(APPS_DIR.path('fixtures')), +) + +# EMAIL +# ------------------------------------------------------------------------------ +# https://docs.djangoproject.com/en/dev/ref/settings/#email-backend +EMAIL_BACKEND = env('DJANGO_EMAIL_BACKEND', default='django.core.mail.backends.smtp.EmailBackend') + +# ADMIN +# ------------------------------------------------------------------------------ +# Django Admin URL regex. +ADMIN_URL = r'^admin/' +# https://docs.djangoproject.com/en/dev/ref/settings/#admins +ADMINS = [ + ("""{{cookiecutter.author_name}}""", '{{cookiecutter.email}}'), +] +# https://docs.djangoproject.com/en/dev/ref/settings/#managers +MANAGERS = ADMINS + +{% if cookiecutter.use_celery == 'y' -%} +# Celery +# ------------------------------------------------------------------------------ INSTALLED_APPS += ['{{cookiecutter.project_slug}}.taskapp.celery.CeleryConfig'] +# http://docs.celeryproject.org/en/latest/userguide/configuration.html#std:setting-broker_url CELERY_BROKER_URL = env('CELERY_BROKER_URL', default='django://') +# http://docs.celeryproject.org/en/latest/userguide/configuration.html#std:setting-result_backend if CELERY_BROKER_URL == 'django://': CELERY_RESULT_BACKEND = 'redis://' else: CELERY_RESULT_BACKEND = CELERY_BROKER_URL -# default to json serialization only +# http://docs.celeryproject.org/en/latest/userguide/configuration.html#std:setting-accept_content CELERY_ACCEPT_CONTENT = ['json'] +# http://docs.celeryproject.org/en/latest/userguide/configuration.html#std:setting-task_serializer CELERY_TASK_SERIALIZER = 'json' +# http://docs.celeryproject.org/en/latest/userguide/configuration.html#std:setting-result_serializer CELERY_RESULT_SERIALIZER = 'json' -########## END CELERY -{% endif %} -{%- if cookiecutter.use_compressor == 'y'-%} +{%- endif %} +# django-allauth +# ------------------------------------------------------------------------------ +ACCOUNT_ALLOW_REGISTRATION = env.bool('DJANGO_ACCOUNT_ALLOW_REGISTRATION', True) +# https://django-allauth.readthedocs.io/en/latest/configuration.html +ACCOUNT_AUTHENTICATION_METHOD = 'username' +# https://django-allauth.readthedocs.io/en/latest/configuration.html +ACCOUNT_EMAIL_REQUIRED = True +# https://django-allauth.readthedocs.io/en/latest/configuration.html +ACCOUNT_EMAIL_VERIFICATION = 'mandatory' +# https://django-allauth.readthedocs.io/en/latest/configuration.html +ACCOUNT_ADAPTER = '{{cookiecutter.project_slug}}.users.adapters.AccountAdapter' +# https://django-allauth.readthedocs.io/en/latest/configuration.html +SOCIALACCOUNT_ADAPTER = '{{cookiecutter.project_slug}}.users.adapters.SocialAccountAdapter' + +{% if cookiecutter.use_compressor == 'y' -%} # django-compressor # ------------------------------------------------------------------------------ +# https://django-compressor.readthedocs.io/en/latest/quickstart/#installation INSTALLED_APPS += ['compressor'] STATICFILES_FINDERS += ['compressor.finders.CompressorFinder'] + {%- endif %} - -# Location of root django.contrib.admin URL, use {% raw %}{% url 'admin:index' %}{% endraw %} -ADMIN_URL = r'^admin/' - -# Your common stuff: Below this line define 3rd party library settings +# Your stuff... # ------------------------------------------------------------------------------ diff --git a/{{cookiecutter.project_slug}}/config/settings/local.py b/{{cookiecutter.project_slug}}/config/settings/local.py index 18e5ba76a..1029f9f45 100644 --- a/{{cookiecutter.project_slug}}/config/settings/local.py +++ b/{{cookiecutter.project_slug}}/config/settings/local.py @@ -1,54 +1,20 @@ -""" -Local settings for {{cookiecutter.project_name}} project. - -- Run in Debug mode -{% if cookiecutter.use_mailhog == 'y' and cookiecutter.use_docker == 'y' %} -- Use mailhog for emails via Docker -{% elif cookiecutter.use_mailhog == 'y' and cookiecutter.use_docker == 'n' %} -- Use mailhog for emails -{% else %} -- Use console backend for emails -{% endif %} -- Add Django Debug Toolbar -- Add django-extensions as app -""" - from .base import * # noqa -# SITE CONFIGURATION +# GENERAL # ------------------------------------------------------------------------------ +# https://docs.djangoproject.com/en/dev/ref/settings/#debug +DEBUG = env.bool('DJANGO_DEBUG', default=True) +# https://docs.djangoproject.com/en/dev/ref/settings/#secret-key +SECRET_KEY = env('DJANGO_SECRET_KEY', default='!!!SET DJANGO_SECRET_KEY!!!') +# https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts ALLOWED_HOSTS = [ "localhost", "0.0.0.0", ] -# DEBUG -# ------------------------------------------------------------------------------ -DEBUG = env.bool('DJANGO_DEBUG', default=True) -TEMPLATES[0]['OPTIONS']['debug'] = DEBUG - -# SECRET CONFIGURATION -# ------------------------------------------------------------------------------ -# See: https://docs.djangoproject.com/en/dev/ref/settings/#secret-key -# Note: This key only used for development and testing. -SECRET_KEY = env('DJANGO_SECRET_KEY', default='!!!SET DJANGO_SECRET_KEY!!!') - -# Mail settings -# ------------------------------------------------------------------------------ - -EMAIL_PORT = 1025 -{% if cookiecutter.use_mailhog == 'y' and cookiecutter.use_docker == 'y' %} -EMAIL_HOST = env('EMAIL_HOST', default='mailhog') -{% elif cookiecutter.use_mailhog == 'y' and cookiecutter.use_docker == 'n' %} -EMAIL_HOST = 'localhost' -{% else %} -EMAIL_HOST = 'localhost' -EMAIL_BACKEND = env('DJANGO_EMAIL_BACKEND', - default='django.core.mail.backends.console.EmailBackend') -{% endif %} - -# CACHING +# CACHES # ------------------------------------------------------------------------------ +# https://docs.djangoproject.com/en/dev/ref/settings/#caches CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', @@ -56,40 +22,62 @@ CACHES = { } } +# TEMPLATES +# ------------------------------------------------------------------------------ +# https://docs.djangoproject.com/en/dev/ref/settings/#templates +TEMPLATES[0]['OPTIONS']['debug'] = DEBUG + +# EMAIL +# ------------------------------------------------------------------------------ +{% if cookiecutter.use_mailhog == 'y' and cookiecutter.use_docker == 'y' -%} +# https://docs.djangoproject.com/en/dev/ref/settings/#email-host +EMAIL_HOST = env('EMAIL_HOST', default='mailhog') +{%- elif cookiecutter.use_mailhog == 'y' and cookiecutter.use_docker == 'n' -%} +# https://docs.djangoproject.com/en/dev/ref/settings/#email-host +EMAIL_HOST = 'localhost' +{%- else -%} +# https://docs.djangoproject.com/en/dev/ref/settings/#email-backend +EMAIL_BACKEND = env('DJANGO_EMAIL_BACKEND', default='django.core.mail.backends.console.EmailBackend') +# https://docs.djangoproject.com/en/dev/ref/settings/#email-host +EMAIL_HOST = 'localhost' +{%- endif %} +# https://docs.djangoproject.com/en/dev/ref/settings/#email-port +EMAIL_PORT = 1025 + # django-debug-toolbar # ------------------------------------------------------------------------------ -MIDDLEWARE += ['debug_toolbar.middleware.DebugToolbarMiddleware', ] -INSTALLED_APPS += ['debug_toolbar', ] - -INTERNAL_IPS = ['127.0.0.1', '10.0.2.2', ] -{% if cookiecutter.use_docker == 'y' %} -{# [cookiecutter-django] This is a workaround to flake8 "imported but unused" errors #} -import socket -import os -# tricks to have debug toolbar when developing with docker -if os.environ.get('USE_DOCKER') == 'yes': - ip = socket.gethostbyname(socket.gethostname()) - INTERNAL_IPS += [ip[:-1] + '1'] -{% endif %} +# https://django-debug-toolbar.readthedocs.io/en/latest/installation.html#prerequisites +INSTALLED_APPS += ['debug_toolbar'] +# https://django-debug-toolbar.readthedocs.io/en/latest/installation.html#middleware +MIDDLEWARE += ['debug_toolbar.middleware.DebugToolbarMiddleware'] +# https://django-debug-toolbar.readthedocs.io/en/latest/configuration.html#debug-toolbar-config DEBUG_TOOLBAR_CONFIG = { 'DISABLE_PANELS': [ 'debug_toolbar.panels.redirects.RedirectsPanel', ], 'SHOW_TEMPLATE_CONTEXT': True, } +# https://django-debug-toolbar.readthedocs.io/en/latest/installation.html#internal-ips +INTERNAL_IPS = ['127.0.0.1', '10.0.2.2'] +{% if cookiecutter.use_docker == 'y' -%} +import socket +import os +if os.environ.get('USE_DOCKER') == 'yes': + ip = socket.gethostbyname(socket.gethostname()) + INTERNAL_IPS += [ip[:-1] + '1'] +{%- endif %} # django-extensions # ------------------------------------------------------------------------------ -INSTALLED_APPS += ['django_extensions', ] +# https://django-extensions.readthedocs.io/en/latest/installation_instructions.html#configuration +INSTALLED_APPS += ['django_extensions'] +{% if cookiecutter.use_celery == 'y' -%} -# TESTING +# Celery # ------------------------------------------------------------------------------ -TEST_RUNNER = 'django.test.runner.DiscoverRunner' -{% if cookiecutter.use_celery == 'y' %} -########## CELERY -# In development, all tasks will be executed locally by blocking until the task returns +# http://docs.celeryproject.org/en/latest/userguide/configuration.html#std:setting-task_always_eager CELERY_ALWAYS_EAGER = True -########## END CELERY -{% endif %} -# Your local stuff: Below this line define 3rd party library settings + +{%- endif %} +# Your stuff... # ------------------------------------------------------------------------------ diff --git a/{{cookiecutter.project_slug}}/config/settings/production.py b/{{cookiecutter.project_slug}}/config/settings/production.py index 09cd8ed9f..e3c695f3e 100644 --- a/{{cookiecutter.project_slug}}/config/settings/production.py +++ b/{{cookiecutter.project_slug}}/config/settings/production.py @@ -1,196 +1,189 @@ -""" -Production settings for {{cookiecutter.project_name}} project. - -{% if cookiecutter.use_whitenoise == 'y' -%} -- Use WhiteNoise for serving static files{% endif %} -- Use Amazon's S3 for storing {% if cookiecutter.use_whitenoise == 'n' -%}static files and {% endif %}uploaded media -- Use mailgun to send emails -- Use Redis for cache -{% if cookiecutter.use_sentry_for_error_reporting == 'y' %} -- Use sentry for error logging -{% endif %} -{% if cookiecutter.use_opbeat == 'y' %} -- Use opbeat for error reporting -{% endif %} -""" - -{% if cookiecutter.use_sentry_for_error_reporting == 'y' %} import logging -{% endif %} from .base import * # noqa -# SECRET CONFIGURATION +# GENERAL # ------------------------------------------------------------------------------ -# See: https://docs.djangoproject.com/en/dev/ref/settings/#secret-key -# Raises ImproperlyConfigured exception if DJANGO_SECRET_KEY not in os.environ +# https://docs.djangoproject.com/en/dev/ref/settings/#secret-key SECRET_KEY = env('DJANGO_SECRET_KEY') +# https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts +ALLOWED_HOSTS = env.list('DJANGO_ALLOWED_HOSTS', default=['{{ cookiecutter.domain_name }}']) - -# This ensures that Django will be able to detect a secure connection -# properly on Heroku. -SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') - -{%- if cookiecutter.use_sentry_for_error_reporting == 'y' %} -# raven sentry client -# See https://docs.sentry.io/clients/python/integrations/django/ -INSTALLED_APPS += ['raven.contrib.django.raven_compat', ] -{% endif %} -{%- if cookiecutter.use_whitenoise == 'y' %} -# Use Whitenoise to serve static files -# See: https://whitenoise.readthedocs.io/ -WHITENOISE_MIDDLEWARE = ['whitenoise.middleware.WhiteNoiseMiddleware', ] -MIDDLEWARE = WHITENOISE_MIDDLEWARE + MIDDLEWARE -{% endif %} -{%- if cookiecutter.use_sentry_for_error_reporting == 'y' -%} -RAVEN_MIDDLEWARE = ['raven.contrib.django.raven_compat.middleware.SentryResponseErrorIdMiddleware'] -MIDDLEWARE = RAVEN_MIDDLEWARE + MIDDLEWARE -{% endif %} -{%- if cookiecutter.use_opbeat == 'y' -%} -# opbeat integration -# See https://opbeat.com/languages/django/ -INSTALLED_APPS += ['opbeat.contrib.django', ] -OPBEAT = { - 'ORGANIZATION_ID': env('DJANGO_OPBEAT_ORGANIZATION_ID'), - 'APP_ID': env('DJANGO_OPBEAT_APP_ID'), - 'SECRET_TOKEN': env('DJANGO_OPBEAT_SECRET_TOKEN') -} -MIDDLEWARE = ['opbeat.contrib.django.middleware.OpbeatAPMMiddleware', ] + MIDDLEWARE -{% endif %} - -# SECURITY CONFIGURATION -# ------------------------------------------------------------------------------ -# See https://docs.djangoproject.com/en/dev/ref/middleware/#module-django.middleware.security -# and https://docs.djangoproject.com/en/dev/howto/deployment/checklist/#run-manage-py-check-deploy - -# set this to 60 seconds and then to 518400 when you can prove it works -SECURE_HSTS_SECONDS = 60 -SECURE_HSTS_INCLUDE_SUBDOMAINS = env.bool( - 'DJANGO_SECURE_HSTS_INCLUDE_SUBDOMAINS', default=True) -SECURE_CONTENT_TYPE_NOSNIFF = env.bool( - 'DJANGO_SECURE_CONTENT_TYPE_NOSNIFF', default=True) -SECURE_BROWSER_XSS_FILTER = True -SESSION_COOKIE_SECURE = True -SESSION_COOKIE_HTTPONLY = True -SECURE_SSL_REDIRECT = env.bool('DJANGO_SECURE_SSL_REDIRECT', default=True) -CSRF_COOKIE_SECURE = True -CSRF_COOKIE_HTTPONLY = True -X_FRAME_OPTIONS = 'DENY' - -# SITE CONFIGURATION -# ------------------------------------------------------------------------------ -# Hosts/domain names that are valid for this site -# See https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts -ALLOWED_HOSTS = env.list('DJANGO_ALLOWED_HOSTS', default=['{{cookiecutter.domain_name}}', ]) -# END SITE CONFIGURATION - -INSTALLED_APPS += ['gunicorn', ] - - -# STORAGE CONFIGURATION -# ------------------------------------------------------------------------------ -# Uploaded Media Files -# ------------------------ -# See: http://django-storages.readthedocs.io/en/latest/index.html -INSTALLED_APPS += ['storages', ] - -AWS_ACCESS_KEY_ID = env('DJANGO_AWS_ACCESS_KEY_ID') -AWS_SECRET_ACCESS_KEY = env('DJANGO_AWS_SECRET_ACCESS_KEY') -AWS_STORAGE_BUCKET_NAME = env('DJANGO_AWS_STORAGE_BUCKET_NAME') -AWS_AUTO_CREATE_BUCKET = True -AWS_QUERYSTRING_AUTH = False - -# AWS cache settings, don't change unless you know what you're doing: -AWS_EXPIRY = 60 * 60 * 24 * 7 - -AWS_S3_OBJECT_PARAMETERS = { - 'CacheControl': 'max-age=%d, s-maxage=%d, must-revalidate' % (AWS_EXPIRY, AWS_EXPIRY), -} - -# URL that handles the media served from MEDIA_ROOT, used for managing -# stored files. -{% if cookiecutter.use_whitenoise == 'y' -%} -MEDIA_URL = 'https://s3.amazonaws.com/%s/' % AWS_STORAGE_BUCKET_NAME -DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage' -{% else %} -# See:http://stackoverflow.com/questions/10390244/ -from storages.backends.s3boto3 import S3Boto3Storage -StaticRootS3BotoStorage = lambda: S3Boto3Storage(location='static') # noqa -MediaRootS3BotoStorage = lambda: S3Boto3Storage(location='media', file_overwrite=False) # noqa -DEFAULT_FILE_STORAGE = 'config.settings.production.MediaRootS3BotoStorage' - -MEDIA_URL = 'https://s3.amazonaws.com/%s/media/' % AWS_STORAGE_BUCKET_NAME -{%- endif %} - -# Static Assets -# ------------------------ -{% if cookiecutter.use_whitenoise == 'y' -%} -STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage' -{% else %} -STATIC_URL = 'https://s3.amazonaws.com/%s/static/' % AWS_STORAGE_BUCKET_NAME -STATICFILES_STORAGE = 'config.settings.production.StaticRootS3BotoStorage' -# See: https://github.com/antonagestam/collectfast -# For Django 1.7+, 'collectfast' should come before -# 'django.contrib.staticfiles' -AWS_PRELOAD_METADATA = True -INSTALLED_APPS = ['collectfast', ] + INSTALLED_APPS -{%- endif %} -{% if cookiecutter.use_compressor == 'y'-%} -# COMPRESSOR -# ------------------------------------------------------------------------------ -COMPRESS_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage' -COMPRESS_URL = STATIC_URL -COMPRESS_ENABLED = env.bool('COMPRESS_ENABLED', default=True) -{%- endif %} -# EMAIL -# ------------------------------------------------------------------------------ -DEFAULT_FROM_EMAIL = env('DJANGO_DEFAULT_FROM_EMAIL', - default='{{cookiecutter.project_name}} ') -EMAIL_SUBJECT_PREFIX = env('DJANGO_EMAIL_SUBJECT_PREFIX', default='[{{cookiecutter.project_name}}]') -SERVER_EMAIL = env('DJANGO_SERVER_EMAIL', default=DEFAULT_FROM_EMAIL) - -# Anymail with Mailgun -INSTALLED_APPS += ['anymail', ] -ANYMAIL = { - 'MAILGUN_API_KEY': env('MAILGUN_API_KEY'), - 'MAILGUN_SENDER_DOMAIN': env('MAILGUN_DOMAIN') -} -EMAIL_BACKEND = 'anymail.backends.mailgun.EmailBackend' - -# TEMPLATE CONFIGURATION -# ------------------------------------------------------------------------------ -# See: -# https://docs.djangoproject.com/en/dev/ref/templates/api/#django.template.loaders.cached.Loader -TEMPLATES[0]['OPTIONS']['loaders'] = [ - ('django.template.loaders.cached.Loader', [ - 'django.template.loaders.filesystem.Loader', 'django.template.loaders.app_directories.Loader', ]), -] - -# DATABASE CONFIGURATION +# DATABASES # ------------------------------------------------------------------------------ DATABASES['default'] = env.db('DATABASE_URL') DATABASES['default']['ATOMIC_REQUESTS'] = True DATABASES['default']['CONN_MAX_AGE'] = env.int('CONN_MAX_AGE', default=60) -# CACHING +# CACHES # ------------------------------------------------------------------------------ -REDIS_LOCATION = '{0}/{1}'.format(env('REDIS_URL', default='redis://127.0.0.1:6379'), 0) - -# Heroku URL does not pass the DB number, so we parse it in CACHES = { 'default': { 'BACKEND': 'django_redis.cache.RedisCache', - 'LOCATION': REDIS_LOCATION, + 'LOCATION': "{}/0".format(env('REDIS_URL', default='redis://127.0.0.1:6379')), 'OPTIONS': { 'CLIENT_CLASS': 'django_redis.client.DefaultClient', - 'IGNORE_EXCEPTIONS': True, # mimics memcache behavior. - # http://niwinz.github.io/django-redis/latest/#_memcached_exceptions_behavior + # Mimicing memcache behavior. + # http://niwinz.github.io/django-redis/latest/#_memcached_exceptions_behavior + 'IGNORE_EXCEPTIONS': True, } } } -{% if cookiecutter.use_sentry_for_error_reporting == 'y' %} -# Sentry Configuration +# SECURITY +# ------------------------------------------------------------------------------ +# https://docs.djangoproject.com/en/dev/ref/settings/#secure-proxy-ssl-header +SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') +# https://docs.djangoproject.com/en/dev/ref/settings/#secure-ssl-redirect +SECURE_SSL_REDIRECT = env.bool('DJANGO_SECURE_SSL_REDIRECT', default=True) +# https://docs.djangoproject.com/en/dev/ref/settings/#session-cookie-secure +SESSION_COOKIE_SECURE = True +# https://docs.djangoproject.com/en/dev/ref/settings/#session-cookie-httponly +SESSION_COOKIE_HTTPONLY = True +# https://docs.djangoproject.com/en/dev/ref/settings/#csrf-cookie-secure +CSRF_COOKIE_SECURE = True +# https://docs.djangoproject.com/en/dev/ref/settings/#csrf-cookie-httponly +CSRF_COOKIE_HTTPONLY = True +# https://docs.djangoproject.com/en/dev/topics/security/#ssl-https +# https://docs.djangoproject.com/en/dev/ref/settings/#secure-hsts-seconds +# TODO: set this to 60 seconds first and then to 518400 once you prove the former works +SECURE_HSTS_SECONDS = 60 +# https://docs.djangoproject.com/en/dev/ref/settings/#secure-hsts-include-subdomains +SECURE_HSTS_INCLUDE_SUBDOMAINS = env.bool('DJANGO_SECURE_HSTS_INCLUDE_SUBDOMAINS', default=True) +# https://docs.djangoproject.com/en/dev/ref/settings/#secure-hsts-preload +SECURE_HSTS_PRELOAD = env.bool('DJANGO_SECURE_HSTS_PRELOAD', default=True) +# https://docs.djangoproject.com/en/dev/ref/middleware/#x-content-type-options-nosniff +SECURE_CONTENT_TYPE_NOSNIFF = env.bool('DJANGO_SECURE_CONTENT_TYPE_NOSNIFF', default=True) +# https://docs.djangoproject.com/en/dev/ref/settings/#secure-browser-xss-filter +SECURE_BROWSER_XSS_FILTER = True +# https://docs.djangoproject.com/en/dev/ref/settings/#x-frame-options +X_FRAME_OPTIONS = 'DENY' + +# STORAGES +# ------------------------------------------------------------------------------ +# https://django-storages.readthedocs.io/en/latest/#installation +INSTALLED_APPS += ['storages'] +# https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#settings +AWS_ACCESS_KEY_ID = env('DJANGO_AWS_ACCESS_KEY_ID') +# https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#settings +AWS_SECRET_ACCESS_KEY = env('DJANGO_AWS_SECRET_ACCESS_KEY') +# https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#settings +AWS_STORAGE_BUCKET_NAME = env('DJANGO_AWS_STORAGE_BUCKET_NAME') +# https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#settings +AWS_AUTO_CREATE_BUCKET = True +# https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#settings +AWS_QUERYSTRING_AUTH = False +# DO NOT change these unless you know what you're doing. +_AWS_EXPIRY = 60 * 60 * 24 * 7 +# https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#settings +AWS_S3_OBJECT_PARAMETERS = { + 'CacheControl': 'max-age=%d, s-maxage=%d, must-revalidate' % (_AWS_EXPIRY, _AWS_EXPIRY), +} + +# STATIC +# ------------------------ +{% if cookiecutter.use_whitenoise == 'y' -%} +STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage' +{%- else %} +STATICFILES_STORAGE = 'config.settings.production.StaticRootS3BotoStorage' +STATIC_URL = 'https://s3.amazonaws.com/%s/static/' % AWS_STORAGE_BUCKET_NAME +{%- endif %} + +# MEDIA +# ------------------------------------------------------------------------------ +{% if cookiecutter.use_whitenoise == 'y' -%} +DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage' +MEDIA_URL = 'https://s3.amazonaws.com/%s/' % AWS_STORAGE_BUCKET_NAME +{%- else %} +# region http://stackoverflow.com/questions/10390244/ +from storages.backends.s3boto3 import S3Boto3Storage +StaticRootS3BotoStorage = lambda: S3Boto3Storage(location='static') # noqa +MediaRootS3BotoStorage = lambda: S3Boto3Storage(location='media', file_overwrite=False) # noqa +# endregion +DEFAULT_FILE_STORAGE = 'config.settings.production.MediaRootS3BotoStorage' +MEDIA_URL = 'https://s3.amazonaws.com/%s/media/' % AWS_STORAGE_BUCKET_NAME +{%- endif %} + +# TEMPLATES +# ------------------------------------------------------------------------------ +# https://docs.djangoproject.com/en/dev/ref/settings/#templates +TEMPLATES[0]['OPTIONS']['loaders'] = [ + ( + 'django.template.loaders.cached.Loader', + [ + 'django.template.loaders.filesystem.Loader', + 'django.template.loaders.app_directories.Loader', + ] + ), +] + +# EMAIL +# ------------------------------------------------------------------------------ +# https://docs.djangoproject.com/en/dev/ref/settings/#default-from-email +DEFAULT_FROM_EMAIL = env( + 'DJANGO_DEFAULT_FROM_EMAIL', + default='{{cookiecutter.project_name}} ' +) +# https://docs.djangoproject.com/en/dev/ref/settings/#server-email +SERVER_EMAIL = env('DJANGO_SERVER_EMAIL', default=DEFAULT_FROM_EMAIL) +# https://docs.djangoproject.com/en/dev/ref/settings/#email-subject-prefix +EMAIL_SUBJECT_PREFIX = env('DJANGO_EMAIL_SUBJECT_PREFIX', default='[{{cookiecutter.project_name}}]') + +# ADMIN +# ------------------------------------------------------------------------------ +# Django Admin URL regex. +ADMIN_URL = env('DJANGO_ADMIN_URL') + +# Anymail (Mailgun) +# ------------------------------------------------------------------------------ +# https://anymail.readthedocs.io/en/stable/installation/#installing-anymail +INSTALLED_APPS += ['anymail'] +EMAIL_BACKEND = 'anymail.backends.mailgun.EmailBackend' +# https://anymail.readthedocs.io/en/stable/installation/#anymail-settings-reference +ANYMAIL = { + 'MAILGUN_API_KEY': env('MAILGUN_API_KEY'), + 'MAILGUN_SENDER_DOMAIN': env('MAILGUN_DOMAIN') +} + +# Gunicorn +# ------------------------------------------------------------------------------ +INSTALLED_APPS += ['gunicorn'] + +{% if cookiecutter.use_whitenoise == 'y' -%} +# WhiteNoise +# ------------------------------------------------------------------------------ +# http://whitenoise.evans.io/en/latest/django.html#enable-whitenoise +MIDDLEWARE = ['whitenoise.middleware.WhiteNoiseMiddleware'] + MIDDLEWARE + +{%- endif %} +{% if cookiecutter.use_compressor == 'y' -%} +# django-compressor +# ------------------------------------------------------------------------------ +# https://django-compressor.readthedocs.io/en/latest/settings/#django.conf.settings.COMPRESS_ENABLED +COMPRESS_ENABLED = env.bool('COMPRESS_ENABLED', default=True) +# https://django-compressor.readthedocs.io/en/latest/settings/#django.conf.settings.COMPRESS_STORAGE +COMPRESS_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage' +# https://django-compressor.readthedocs.io/en/latest/settings/#django.conf.settings.COMPRESS_URL +COMPRESS_URL = STATIC_URL + +{%- endif %} +{% if cookiecutter.use_whitenoise == 'n' -%} +# Collectfast +# ------------------------------------------------------------------------------ +# https://github.com/antonagestam/collectfast#installation +INSTALLED_APPS = ['collectfast'] + INSTALLED_APPS +AWS_PRELOAD_METADATA = True + +{%- endif %} +{% if cookiecutter.use_sentry_for_error_reporting == 'y' -%} +# raven +# ------------------------------------------------------------------------------ +# https://docs.sentry.io/clients/python/integrations/django/ +INSTALLED_APPS += ['raven.contrib.django.raven_compat'] +MIDDLEWARE = ['raven.contrib.django.raven_compat.middleware.SentryResponseErrorIdMiddleware'] + MIDDLEWARE + +# Sentry +# ------------------------------------------------------------------------------ SENTRY_DSN = env('DJANGO_SENTRY_DSN') SENTRY_CLIENT = env('DJANGO_SENTRY_CLIENT', default='raven.contrib.django.raven_compat.DjangoClient') LOGGING = { @@ -198,7 +191,7 @@ LOGGING = { 'disable_existing_loggers': True, 'root': { 'level': 'WARNING', - 'handlers': ['sentry', ], + 'handlers': ['sentry'], }, 'formatters': { 'verbose': { @@ -220,38 +213,39 @@ LOGGING = { 'loggers': { 'django.db.backends': { 'level': 'ERROR', - 'handlers': ['console', ], + 'handlers': ['console'], 'propagate': False, }, 'raven': { 'level': 'DEBUG', - 'handlers': ['console', ], + 'handlers': ['console'], 'propagate': False, }, 'sentry.errors': { 'level': 'DEBUG', - 'handlers': ['console', ], + 'handlers': ['console'], 'propagate': False, }, 'django.security.DisallowedHost': { 'level': 'ERROR', - 'handlers': ['console', 'sentry', ], + 'handlers': ['console', 'sentry'], 'propagate': False, }, }, } + SENTRY_CELERY_LOGLEVEL = env.int('DJANGO_SENTRY_LOG_LEVEL', logging.INFO) RAVEN_CONFIG = { 'CELERY_LOGLEVEL': env.int('DJANGO_SENTRY_LOG_LEVEL', logging.INFO), 'DSN': SENTRY_DSN } -{% elif cookiecutter.use_sentry_for_error_reporting == 'n' %} -# LOGGING CONFIGURATION +{%- else %} +# LOGGING # ------------------------------------------------------------------------------ # See: https://docs.djangoproject.com/en/dev/ref/settings/#logging # A sample logging configuration. The only tangible logging # performed by this configuration is to send an email to -# the site admins on every HTTP 500 error when DEBUG=False. +# the site admins bon every HTTP 500 error when DEBUG=False. # See https://docs.djangoproject.com/en/dev/topics/logging for # more details on how to customize your logging configuration. LOGGING = { @@ -271,7 +265,7 @@ LOGGING = { 'handlers': { 'mail_admins': { 'level': 'ERROR', - 'filters': ['require_debug_false', ], + 'filters': ['require_debug_false'], 'class': 'django.utils.log.AdminEmailHandler' }, 'console': { @@ -282,20 +276,33 @@ LOGGING = { }, 'loggers': { 'django.request': { - 'handlers': ['mail_admins', ], + 'handlers': ['mail_admins'], 'level': 'ERROR', 'propagate': True }, 'django.security.DisallowedHost': { 'level': 'ERROR', - 'handlers': ['console', 'mail_admins', ], + 'handlers': ['console', 'mail_admins'], 'propagate': True } } } -{% endif %} -# Custom Admin URL, use {% raw %}{% url 'admin:index' %}{% endraw %} -ADMIN_URL = env('DJANGO_ADMIN_URL') -# Your production stuff: Below this line define 3rd party library settings +{%- endif %} +{% if cookiecutter.use_opbeat == 'y' -%} +# opbeat +# ------------------------------------------------------------------------------ +# https://opbeat.com/docs/articles/get-started-with-django/#setup +INSTALLED_APPS += ['opbeat.contrib.django'] +# https://opbeat.com/docs/articles/get-started-with-django/#setup +OPBEAT = { + 'ORGANIZATION_ID': env('DJANGO_OPBEAT_ORGANIZATION_ID'), + 'APP_ID': env('DJANGO_OPBEAT_APP_ID'), + 'SECRET_TOKEN': env('DJANGO_OPBEAT_SECRET_TOKEN') +} +# https://opbeat.com/docs/articles/get-started-with-django/#performance-metrics +MIDDLEWARE = ['opbeat.contrib.django.middleware.OpbeatAPMMiddleware'] + MIDDLEWARE + +{%- endif %} +# Your stuff... # ------------------------------------------------------------------------------ diff --git a/{{cookiecutter.project_slug}}/config/settings/test.py b/{{cookiecutter.project_slug}}/config/settings/test.py index 01a412791..b46b8e423 100644 --- a/{{cookiecutter.project_slug}}/config/settings/test.py +++ b/{{cookiecutter.project_slug}}/config/settings/test.py @@ -1,36 +1,21 @@ """ -Test settings for {{cookiecutter.project_name}} project. - -- Used to run tests fast on the continuous integration server and locally +With these settings, tests run faster. """ from .base import * # noqa - -# DEBUG +# GENERAL # ------------------------------------------------------------------------------ -# Turn debug off so tests run faster +# https://docs.djangoproject.com/en/dev/ref/settings/#debug DEBUG = False -TEMPLATES[0]['OPTIONS']['debug'] = False - -# SECRET CONFIGURATION -# ------------------------------------------------------------------------------ -# See: https://docs.djangoproject.com/en/dev/ref/settings/#secret-key -# Note: This key only used for development and testing. +# https://docs.djangoproject.com/en/dev/ref/settings/#secret-key SECRET_KEY = env('DJANGO_SECRET_KEY', default='!!!SET DJANGO_SECRET_KEY!!!') +# https://docs.djangoproject.com/en/dev/ref/settings/#test-runner +TEST_RUNNER = 'django.test.runner.DiscoverRunner' -# Mail settings +# CACHES # ------------------------------------------------------------------------------ -EMAIL_HOST = 'localhost' -EMAIL_PORT = 1025 - -# In-memory email backend stores messages in django.core.mail.outbox -# for unit testing purposes -EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend' - -# CACHING -# ------------------------------------------------------------------------------ -# Speed advantages of in-memory caching without having to run Memcached +# https://docs.djangoproject.com/en/dev/ref/settings/#caches CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', @@ -38,24 +23,35 @@ CACHES = { } } -# TESTING +# PASSWORDS # ------------------------------------------------------------------------------ -TEST_RUNNER = 'django.test.runner.DiscoverRunner' - - -# PASSWORD HASHING -# ------------------------------------------------------------------------------ -# Use fast password hasher so tests run faster +# https://docs.djangoproject.com/en/dev/ref/settings/#password-hashers PASSWORD_HASHERS = [ 'django.contrib.auth.hashers.MD5PasswordHasher', ] -# TEMPLATE LOADERS +# TEMPLATES # ------------------------------------------------------------------------------ -# Keep templates in memory so tests run faster +# https://docs.djangoproject.com/en/dev/ref/settings/#templates +TEMPLATES[0]['OPTIONS']['debug'] = DEBUG TEMPLATES[0]['OPTIONS']['loaders'] = [ - ['django.template.loaders.cached.Loader', [ - 'django.template.loaders.filesystem.Loader', - 'django.template.loaders.app_directories.Loader', - ], ], + ( + 'django.template.loaders.cached.Loader', + [ + 'django.template.loaders.filesystem.Loader', + 'django.template.loaders.app_directories.Loader', + ], + ), ] + +# EMAIL +# ------------------------------------------------------------------------------ +# https://docs.djangoproject.com/en/dev/ref/settings/#email-backend +EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend' +# https://docs.djangoproject.com/en/dev/ref/settings/#email-host +EMAIL_HOST = 'localhost' +# https://docs.djangoproject.com/en/dev/ref/settings/#email-port +EMAIL_PORT = 1025 + +# Your stuff... +# ------------------------------------------------------------------------------ From 7bc5d1408c1b91e20e4d5681d8dbdbeb1d84ba42 Mon Sep 17 00:00:00 2001 From: Daniel Roy Greenfeld Date: Tue, 6 Mar 2018 10:52:45 -0500 Subject: [PATCH 59/63] Make registration of signals easier for users --- .../{{cookiecutter.project_slug}}/users/apps.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/apps.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/apps.py index 8f5bb1d44..90e68eb83 100644 --- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/apps.py +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/apps.py @@ -10,4 +10,7 @@ class UsersConfig(AppConfig): Users system checks Users signal registration """ - pass + try: + import users.signals + except ImportError: + pass From 218a79e16adef60e1d3c5ddce53f5cc66d120b42 Mon Sep 17 00:00:00 2001 From: "pyup.io bot" Date: Tue, 6 Mar 2018 17:44:43 +0100 Subject: [PATCH 60/63] Update django from 2.0.2 to 2.0.3 (#1551) --- {{cookiecutter.project_slug}}/requirements/base.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/{{cookiecutter.project_slug}}/requirements/base.txt b/{{cookiecutter.project_slug}}/requirements/base.txt index 59ac7340f..9cd9f30f1 100644 --- a/{{cookiecutter.project_slug}}/requirements/base.txt +++ b/{{cookiecutter.project_slug}}/requirements/base.txt @@ -1,5 +1,5 @@ # Conservative Django -django==2.0.2 # pyup: < 2.1 +django==2.0.3 # pyup: < 2.1 # Configuration django-environ==0.4.4 From f67f37a4635b1ae1682b8084085a8409cfbaef68 Mon Sep 17 00:00:00 2001 From: Eric Groom Date: Tue, 6 Mar 2018 08:46:21 -0800 Subject: [PATCH 61/63] update grunt-sass to latest version (#1544) * update grunt-sass * add to contributors * update gulp deps * update grunt deps * add convenience run script to grunt and gulp configurations --- CONTRIBUTORS.rst | 1 + docs/live-reloading-and-sass-compilation.rst | 2 +- {{cookiecutter.project_slug}}/Gruntfile.js | 2 +- {{cookiecutter.project_slug}}/package.json | 34 ++++++++++++-------- 4 files changed, 24 insertions(+), 15 deletions(-) diff --git a/CONTRIBUTORS.rst b/CONTRIBUTORS.rst index 96c05d042..e1c3cad4e 100644 --- a/CONTRIBUTORS.rst +++ b/CONTRIBUTORS.rst @@ -89,6 +89,7 @@ Listed in alphabetical order. Dong Huynh `@trungdong`_ Emanuel Calso `@bloodpet`_ @bloodpet Eraldo Energy `@eraldo`_ + Eric Groom `@ericgroom`_ Eyad Al Sibai `@eyadsibai`_ Felipe Arruda `@arruda`_ Garry Cairns `@garry-cairns`_ diff --git a/docs/live-reloading-and-sass-compilation.rst b/docs/live-reloading-and-sass-compilation.rst index 7f978ede5..a456b81af 100644 --- a/docs/live-reloading-and-sass-compilation.rst +++ b/docs/live-reloading-and-sass-compilation.rst @@ -15,7 +15,7 @@ If you don't already have it, install `compass` (doesn't hurt if you run this co Now you just need:: - $ grunt serve + $ npm run dev The base app will now run as it would with the usual ``manage.py runserver`` but with live reloading and Sass compilation enabled. diff --git a/{{cookiecutter.project_slug}}/Gruntfile.js b/{{cookiecutter.project_slug}}/Gruntfile.js index 15384c67b..b225266c3 100644 --- a/{{cookiecutter.project_slug}}/Gruntfile.js +++ b/{{cookiecutter.project_slug}}/Gruntfile.js @@ -92,7 +92,7 @@ module.exports = function (grunt) { processors: [ require('pixrem')(), // add fallbacks for rem units - require('autoprefixer-core')({browsers: [ + require('autoprefixer')({browsers: [ 'Android 2.3', 'Android >= 4', 'Chrome >= 20', diff --git a/{{cookiecutter.project_slug}}/package.json b/{{cookiecutter.project_slug}}/package.json index a37d73bf5..acaae12ab 100644 --- a/{{cookiecutter.project_slug}}/package.json +++ b/{{cookiecutter.project_slug}}/package.json @@ -4,22 +4,22 @@ "dependencies": {}, "devDependencies": { {% if cookiecutter.js_task_runner == 'Grunt' %} - "autoprefixer-core": "~5.2.1", + "autoprefixer": "~8.1.0", {% if cookiecutter.custom_bootstrap_compilation == 'y' %} "bootstrap": "^4.0.0", {% endif %} - "connect-livereload": "~0.3.2", - "cssnano": "~2.1.0", - "grunt": "~0.4.5", + "connect-livereload": "~0.6.0", + "cssnano": "~3.10.0", + "grunt": "~1.0.2", "grunt-bg-shell": "~2.3.1", - "grunt-contrib-watch": "~0.6.1", - "grunt-postcss": "~0.5.5", - "grunt-sass": "~1.0.0", + "grunt-contrib-watch": "~1.0.0", + "grunt-postcss": "~0.9.0", + "grunt-sass": "~2.1.0", {% if cookiecutter.custom_bootstrap_compilation == 'y' %} "jquery": "^3.2.1-slim", {% endif %} "load-grunt-tasks": "~3.2.0", - "pixrem": "~1.3.1", + "pixrem": "~4.0.1", {% if cookiecutter.custom_bootstrap_compilation == 'y' %} "popper.js": "^1.12.3", {% endif %} @@ -31,26 +31,34 @@ "browser-sync": "^2.14.0", "del": "^2.2.2", "gulp": "^3.9.1", - "gulp-autoprefixer": "^3.1.1", + "gulp-autoprefixer": "^5.0.0", {% if cookiecutter.custom_bootstrap_compilation == 'y' %} "gulp-concat": "^2.6.1", {% endif %} "gulp-cssnano": "^2.1.2", - "gulp-imagemin": "^3.0.3", + "gulp-imagemin": "^4.1.0", "gulp-pixrem": "^1.0.0", "gulp-plumber": "^1.1.0", "gulp-rename": "^1.2.2", - "gulp-sass": "^2.3.2", - "gulp-uglify": "^2.0.0", + "gulp-sass": "^3.1.0", + "gulp-uglify": "^3.0.0", "gulp-util": "^3.0.7", {% if cookiecutter.custom_bootstrap_compilation == 'y' %} "jquery": "^3.2.1-slim", "popper.js": "^1.12.3", {% endif %} - "run-sequence": "^1.2.2" + "run-sequence": "^2.1.1" {% endif %} }, "engines": { "node": ">=0.8.0" + }, + "scripts": { + {% if cookiecutter.js_task_runner == 'Grunt' %} + "dev": "grunt serve" + {% elif cookiecutter.js_task_runner == 'Gulp' %} + "dev": "gulp" + {% endif %} + } } From ee04c5cf09f59cc93153c345d172b932ee608c00 Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Tue, 6 Mar 2018 19:54:20 +0300 Subject: [PATCH 62/63] noqa F401 in users apps.py --- .../{{cookiecutter.project_slug}}/users/apps.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/apps.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/apps.py index 90e68eb83..24c319df3 100644 --- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/apps.py +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/apps.py @@ -11,6 +11,6 @@ class UsersConfig(AppConfig): Users signal registration """ try: - import users.signals + import users.signals # noqa F401 except ImportError: pass From 9cb7e50b8eba3864dff41849b6fec3b0657dd28f Mon Sep 17 00:00:00 2001 From: Wan Liuyang Date: Wed, 7 Mar 2018 00:56:27 +0800 Subject: [PATCH 63/63] Convert old-styled string formatting to f-string (#1528) * Convert old-styled string formatting to f-string * Update flake8 explicit version to 3.5.0 * Make tox.ini in sync with requirements.txt * Fix annoying flake8 F405 --- tox.ini | 6 +--- .../config/settings/local.py | 9 +++--- .../config/settings/production.py | 31 ++++++++++--------- .../config/settings/test.py | 5 +-- .../taskapp/celery.py | 4 +-- .../users/tests/factories.py | 4 +-- 6 files changed, 29 insertions(+), 30 deletions(-) diff --git a/tox.ini b/tox.ini index 2399e24d5..040c8a41c 100644 --- a/tox.ini +++ b/tox.ini @@ -3,9 +3,5 @@ skipsdist = true envlist = py36 [testenv] -deps = - binaryornot - flake8==2.5.5 - pytest-cookies - sh +deps = -rrequirements.txt commands = pytest {posargs:./tests} diff --git a/{{cookiecutter.project_slug}}/config/settings/local.py b/{{cookiecutter.project_slug}}/config/settings/local.py index 1029f9f45..2b1b9ddf5 100644 --- a/{{cookiecutter.project_slug}}/config/settings/local.py +++ b/{{cookiecutter.project_slug}}/config/settings/local.py @@ -1,4 +1,5 @@ from .base import * # noqa +from .base import env # GENERAL # ------------------------------------------------------------------------------ @@ -25,7 +26,7 @@ CACHES = { # TEMPLATES # ------------------------------------------------------------------------------ # https://docs.djangoproject.com/en/dev/ref/settings/#templates -TEMPLATES[0]['OPTIONS']['debug'] = DEBUG +TEMPLATES[0]['OPTIONS']['debug'] = DEBUG # noqa F405 # EMAIL # ------------------------------------------------------------------------------ @@ -47,9 +48,9 @@ EMAIL_PORT = 1025 # django-debug-toolbar # ------------------------------------------------------------------------------ # https://django-debug-toolbar.readthedocs.io/en/latest/installation.html#prerequisites -INSTALLED_APPS += ['debug_toolbar'] +INSTALLED_APPS += ['debug_toolbar'] # noqa F405 # https://django-debug-toolbar.readthedocs.io/en/latest/installation.html#middleware -MIDDLEWARE += ['debug_toolbar.middleware.DebugToolbarMiddleware'] +MIDDLEWARE += ['debug_toolbar.middleware.DebugToolbarMiddleware'] # noqa F405 # https://django-debug-toolbar.readthedocs.io/en/latest/configuration.html#debug-toolbar-config DEBUG_TOOLBAR_CONFIG = { 'DISABLE_PANELS': [ @@ -70,7 +71,7 @@ if os.environ.get('USE_DOCKER') == 'yes': # django-extensions # ------------------------------------------------------------------------------ # https://django-extensions.readthedocs.io/en/latest/installation_instructions.html#configuration -INSTALLED_APPS += ['django_extensions'] +INSTALLED_APPS += ['django_extensions'] # noqa F405 {% if cookiecutter.use_celery == 'y' -%} # Celery diff --git a/{{cookiecutter.project_slug}}/config/settings/production.py b/{{cookiecutter.project_slug}}/config/settings/production.py index e3c695f3e..b29a22b06 100644 --- a/{{cookiecutter.project_slug}}/config/settings/production.py +++ b/{{cookiecutter.project_slug}}/config/settings/production.py @@ -1,6 +1,7 @@ import logging from .base import * # noqa +from .base import env # GENERAL # ------------------------------------------------------------------------------ @@ -11,16 +12,16 @@ ALLOWED_HOSTS = env.list('DJANGO_ALLOWED_HOSTS', default=['{{ cookiecutter.domai # DATABASES # ------------------------------------------------------------------------------ -DATABASES['default'] = env.db('DATABASE_URL') -DATABASES['default']['ATOMIC_REQUESTS'] = True -DATABASES['default']['CONN_MAX_AGE'] = env.int('CONN_MAX_AGE', default=60) +DATABASES['default'] = env.db('DATABASE_URL') # noqa F405 +DATABASES['default']['ATOMIC_REQUESTS'] = True # noqa F405 +DATABASES['default']['CONN_MAX_AGE'] = env.int('CONN_MAX_AGE', default=60) # noqa F405 # CACHES # ------------------------------------------------------------------------------ CACHES = { 'default': { 'BACKEND': 'django_redis.cache.RedisCache', - 'LOCATION': "{}/0".format(env('REDIS_URL', default='redis://127.0.0.1:6379')), + 'LOCATION': f'{env("REDIS_URL", default="redis://127.0.0.1:6379")}/{0}', 'OPTIONS': { 'CLIENT_CLASS': 'django_redis.client.DefaultClient', # Mimicing memcache behavior. @@ -62,7 +63,7 @@ X_FRAME_OPTIONS = 'DENY' # STORAGES # ------------------------------------------------------------------------------ # https://django-storages.readthedocs.io/en/latest/#installation -INSTALLED_APPS += ['storages'] +INSTALLED_APPS += ['storages'] # noqa F405 # https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#settings AWS_ACCESS_KEY_ID = env('DJANGO_AWS_ACCESS_KEY_ID') # https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#settings @@ -77,7 +78,7 @@ AWS_QUERYSTRING_AUTH = False _AWS_EXPIRY = 60 * 60 * 24 * 7 # https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#settings AWS_S3_OBJECT_PARAMETERS = { - 'CacheControl': 'max-age=%d, s-maxage=%d, must-revalidate' % (_AWS_EXPIRY, _AWS_EXPIRY), + 'CacheControl': f'max-age={_AWS_EXPIRY}, s-maxage={_AWS_EXPIRY}, must-revalidate', } # STATIC @@ -93,7 +94,7 @@ STATIC_URL = 'https://s3.amazonaws.com/%s/static/' % AWS_STORAGE_BUCKET_NAME # ------------------------------------------------------------------------------ {% if cookiecutter.use_whitenoise == 'y' -%} DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage' -MEDIA_URL = 'https://s3.amazonaws.com/%s/' % AWS_STORAGE_BUCKET_NAME +MEDIA_URL = f'https://s3.amazonaws.com/{AWS_STORAGE_BUCKET_NAME}/' {%- else %} # region http://stackoverflow.com/questions/10390244/ from storages.backends.s3boto3 import S3Boto3Storage @@ -101,13 +102,13 @@ StaticRootS3BotoStorage = lambda: S3Boto3Storage(location='static') # noqa MediaRootS3BotoStorage = lambda: S3Boto3Storage(location='media', file_overwrite=False) # noqa # endregion DEFAULT_FILE_STORAGE = 'config.settings.production.MediaRootS3BotoStorage' -MEDIA_URL = 'https://s3.amazonaws.com/%s/media/' % AWS_STORAGE_BUCKET_NAME +MEDIA_URL = f'https://s3.amazonaws.com/{AWS_STORAGE_BUCKET_NAME}/media/' {%- endif %} # TEMPLATES # ------------------------------------------------------------------------------ # https://docs.djangoproject.com/en/dev/ref/settings/#templates -TEMPLATES[0]['OPTIONS']['loaders'] = [ +TEMPLATES[0]['OPTIONS']['loaders'] = [ # noqa F405 ( 'django.template.loaders.cached.Loader', [ @@ -137,7 +138,7 @@ ADMIN_URL = env('DJANGO_ADMIN_URL') # Anymail (Mailgun) # ------------------------------------------------------------------------------ # https://anymail.readthedocs.io/en/stable/installation/#installing-anymail -INSTALLED_APPS += ['anymail'] +INSTALLED_APPS += ['anymail'] # noqa F405 EMAIL_BACKEND = 'anymail.backends.mailgun.EmailBackend' # https://anymail.readthedocs.io/en/stable/installation/#anymail-settings-reference ANYMAIL = { @@ -147,13 +148,13 @@ ANYMAIL = { # Gunicorn # ------------------------------------------------------------------------------ -INSTALLED_APPS += ['gunicorn'] +INSTALLED_APPS += ['gunicorn'] # noqa F405 {% if cookiecutter.use_whitenoise == 'y' -%} # WhiteNoise # ------------------------------------------------------------------------------ # http://whitenoise.evans.io/en/latest/django.html#enable-whitenoise -MIDDLEWARE = ['whitenoise.middleware.WhiteNoiseMiddleware'] + MIDDLEWARE +MIDDLEWARE = ['whitenoise.middleware.WhiteNoiseMiddleware'] + MIDDLEWARE # noqa F405 {%- endif %} {% if cookiecutter.use_compressor == 'y' -%} @@ -171,7 +172,7 @@ COMPRESS_URL = STATIC_URL # Collectfast # ------------------------------------------------------------------------------ # https://github.com/antonagestam/collectfast#installation -INSTALLED_APPS = ['collectfast'] + INSTALLED_APPS +INSTALLED_APPS = ['collectfast'] + INSTALLED_APPS # noqa F405 AWS_PRELOAD_METADATA = True {%- endif %} @@ -179,7 +180,7 @@ AWS_PRELOAD_METADATA = True # raven # ------------------------------------------------------------------------------ # https://docs.sentry.io/clients/python/integrations/django/ -INSTALLED_APPS += ['raven.contrib.django.raven_compat'] +INSTALLED_APPS += ['raven.contrib.django.raven_compat'] # noqa F405 MIDDLEWARE = ['raven.contrib.django.raven_compat.middleware.SentryResponseErrorIdMiddleware'] + MIDDLEWARE # Sentry @@ -293,7 +294,7 @@ LOGGING = { # opbeat # ------------------------------------------------------------------------------ # https://opbeat.com/docs/articles/get-started-with-django/#setup -INSTALLED_APPS += ['opbeat.contrib.django'] +INSTALLED_APPS += ['opbeat.contrib.django'] # noqa F405 # https://opbeat.com/docs/articles/get-started-with-django/#setup OPBEAT = { 'ORGANIZATION_ID': env('DJANGO_OPBEAT_ORGANIZATION_ID'), diff --git a/{{cookiecutter.project_slug}}/config/settings/test.py b/{{cookiecutter.project_slug}}/config/settings/test.py index b46b8e423..e206c2f5f 100644 --- a/{{cookiecutter.project_slug}}/config/settings/test.py +++ b/{{cookiecutter.project_slug}}/config/settings/test.py @@ -3,6 +3,7 @@ With these settings, tests run faster. """ from .base import * # noqa +from .base import env # GENERAL # ------------------------------------------------------------------------------ @@ -33,8 +34,8 @@ PASSWORD_HASHERS = [ # TEMPLATES # ------------------------------------------------------------------------------ # https://docs.djangoproject.com/en/dev/ref/settings/#templates -TEMPLATES[0]['OPTIONS']['debug'] = DEBUG -TEMPLATES[0]['OPTIONS']['loaders'] = [ +TEMPLATES[0]['OPTIONS']['debug'] = DEBUG # noqa F405 +TEMPLATES[0]['OPTIONS']['loaders'] = [ # noqa F405 ( 'django.template.loaders.cached.Loader', [ diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/taskapp/celery.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/taskapp/celery.py index 72513ed38..9827fa02a 100644 --- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/taskapp/celery.py +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/taskapp/celery.py @@ -66,7 +66,7 @@ class CeleryConfig(AppConfig): try: opbeat_register_signal(opbeat_client) except Exception as e: - opbeat_logger.exception('Failed installing celery hook: %s' % e) + opbeat_logger.exception(f'Failed installing celery hook: {e}') if 'opbeat.contrib.django' in settings.INSTALLED_APPS: opbeat_register_handlers() @@ -75,7 +75,7 @@ class CeleryConfig(AppConfig): @app.task(bind=True) def debug_task(self): - print('Request: {0!r}'.format(self.request)) # pragma: no cover + print(f'Request: {self.request!r}') # pragma: no cover {% else %} # Use this as a starting point for your project with celery. # If you are not using celery, you can remove this app diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/factories.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/factories.py index e2c967de7..a777ae9e5 100644 --- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/factories.py +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/factories.py @@ -2,8 +2,8 @@ import factory class UserFactory(factory.django.DjangoModelFactory): - username = factory.Sequence(lambda n: 'user-{0}'.format(n)) - email = factory.Sequence(lambda n: 'user-{0}@example.com'.format(n)) + username = factory.Sequence(lambda n: f'user-{n}') + email = factory.Sequence(lambda n: f'user-{n}@example.com') password = factory.PostGenerationMethodCall('set_password', 'password') class Meta: