From 9661ecaf8feb7c9a615199f044f8d469df2c3340 Mon Sep 17 00:00:00 2001 From: Sander van Leeuwen Date: Wed, 25 Oct 2017 14:11:36 +0200 Subject: [PATCH 001/166] Remove boto related settings that aren't used Since upgrade to boto3 in commit 12db5176d6c4c we don't need AWS_HEADERS anymore --- .../config/settings/production.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/{{cookiecutter.project_slug}}/config/settings/production.py b/{{cookiecutter.project_slug}}/config/settings/production.py index cc518644..b332c776 100644 --- a/{{cookiecutter.project_slug}}/config/settings/production.py +++ b/{{cookiecutter.project_slug}}/config/settings/production.py @@ -100,17 +100,6 @@ 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 - -# 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_HEADERS = { - 'Cache-Control': bytes(control, encoding='latin-1') -} - # URL that handles the media served from MEDIA_ROOT, used for managing # stored files. {% if cookiecutter.use_whitenoise == 'y' -%} From 8bfe18b52ad1a48abe5ae0346b19a96a596aec64 Mon Sep 17 00:00:00 2001 From: Dayson Pais Date: Sat, 30 Dec 2017 12:16:19 +0530 Subject: [PATCH 002/166] Update django from 1.11.8 to 2.0 - Refactor django.core.urlresolvers module import to django.urls. Resolves: The django.core.urlresolvers module is removed in favor of its new location, django.urls. - Add an app namespace to urls in user app. Resolves: Support for setting a URL instance namespace without an application namespace is removed. --- {{cookiecutter.project_slug}}/requirements/base.txt | 2 +- .../{{cookiecutter.project_slug}}/users/models.py | 2 +- .../{{cookiecutter.project_slug}}/users/tests/test_urls.py | 2 +- .../{{cookiecutter.project_slug}}/users/urls.py | 1 + .../{{cookiecutter.project_slug}}/users/views.py | 2 +- 5 files changed, 5 insertions(+), 4 deletions(-) diff --git a/{{cookiecutter.project_slug}}/requirements/base.txt b/{{cookiecutter.project_slug}}/requirements/base.txt index 369d8464..3eb0ae55 100644 --- a/{{cookiecutter.project_slug}}/requirements/base.txt +++ b/{{cookiecutter.project_slug}}/requirements/base.txt @@ -6,7 +6,7 @@ wheel==0.30.0 # Conservative Django -django==1.11.8 # pyup: <2.0 +django==2.0 # pyup: <2.0 # Configuration django-environ==0.4.4 diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/models.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/models.py index c06f15da..91582365 100644 --- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/models.py +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/models.py @@ -1,5 +1,5 @@ from django.contrib.auth.models import AbstractUser -from django.core.urlresolvers import reverse +from django.urls import reverse from django.db import models from django.utils.encoding import python_2_unicode_compatible from django.utils.translation import ugettext_lazy as _ diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_urls.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_urls.py index 6e181cc8..4935b0f3 100644 --- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_urls.py +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_urls.py @@ -1,4 +1,4 @@ -from django.core.urlresolvers import reverse, resolve +from django.urls import reverse, resolve from test_plus.test import TestCase diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/urls.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/urls.py index 600ccfbd..7c83fab9 100644 --- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/urls.py +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/urls.py @@ -2,6 +2,7 @@ from django.conf.urls import url from . import views +app_name = 'users' urlpatterns = [ url( regex=r'^$', diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/views.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/views.py index 777f42b7..7fa94c23 100644 --- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/views.py +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/views.py @@ -1,4 +1,4 @@ -from django.core.urlresolvers import reverse +from django.urls import reverse from django.views.generic import DetailView, ListView, RedirectView, UpdateView from django.contrib.auth.mixins import LoginRequiredMixin From 9ca98e02d48bbf81d5b67904702aef1c04ea7d48 Mon Sep 17 00:00:00 2001 From: Dayson Pais Date: Thu, 25 Jan 2018 10:36:06 +0100 Subject: [PATCH 003/166] Update base.txt --- {{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 3eb0ae55..eff48586 100644 --- a/{{cookiecutter.project_slug}}/requirements/base.txt +++ b/{{cookiecutter.project_slug}}/requirements/base.txt @@ -6,7 +6,7 @@ wheel==0.30.0 # Conservative Django -django==2.0 # pyup: <2.0 +django==2.0 # Configuration django-environ==0.4.4 From d4420e3dd663fcaf2e0813008977aebfe7b6b0ae Mon Sep 17 00:00:00 2001 From: Dayson Pais Date: Mon, 5 Feb 2018 10:23:10 +0000 Subject: [PATCH 004/166] Update base.txt --- {{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 eff48586..b7de5975 100644 --- a/{{cookiecutter.project_slug}}/requirements/base.txt +++ b/{{cookiecutter.project_slug}}/requirements/base.txt @@ -6,7 +6,7 @@ wheel==0.30.0 # Conservative Django -django==2.0 +django==2.0 # pyup: < 2.1 # Configuration django-environ==0.4.4 From d133026968aca97d39000295433642d8a30de91a Mon Sep 17 00:00:00 2001 From: Dayson Pais Date: Mon, 5 Feb 2018 23:29:36 +0000 Subject: [PATCH 005/166] Update 0001_initial.py Increase max length of User.last_name to 150 characters. --- .../users/migrations/0001_initial.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/migrations/0001_initial.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/migrations/0001_initial.py index b2cfca39..7cc96f62 100644 --- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/migrations/0001_initial.py +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/migrations/0001_initial.py @@ -22,7 +22,7 @@ class Migration(migrations.Migration): ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')), ('first_name', models.CharField(blank=True, max_length=30, verbose_name='first name')), - ('last_name', models.CharField(blank=True, max_length=30, verbose_name='last name')), + ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')), ('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')), ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')), From fd2e917ceb125b194854199edf8b280641e4ff05 Mon Sep 17 00:00:00 2001 From: Wan Liuyang Date: Tue, 6 Feb 2018 15:14:37 +0800 Subject: [PATCH 006/166] 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 fb383c3c..2ded1286 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 33542fbf..fc4eb76e 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 420ab4a5..c83b3a83 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 007/166] 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 2ded1286..eeba285a 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 fc4eb76e..33542fbf 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 8941e4a81d3c8428477cdf1a2350df711cb098f4 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Fri, 9 Feb 2018 02:46:23 -0800 Subject: [PATCH 008/166] Update pytz from 2017.3 to 2018.3 --- {{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 3d29fe16..56a44833 100644 --- a/{{cookiecutter.project_slug}}/requirements/base.txt +++ b/{{cookiecutter.project_slug}}/requirements/base.txt @@ -43,7 +43,7 @@ psycopg2==2.7.4 awesome-slugify==1.6.5 # Time zones support -pytz==2017.3 +pytz==2018.3 # Redis support django-redis==4.8.0 From 5e93bf954d2aacd9346e382345f8b105573995b5 Mon Sep 17 00:00:00 2001 From: Bruno Alla Date: Fri, 9 Feb 2018 13:00:20 +0000 Subject: [PATCH 009/166] 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 3d29fe16..04242301 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 952ba4bd..6739912d 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 e7a47c6f9b823081b24a16f4c0cd2fcaf393f255 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Sun, 11 Feb 2018 02:06:17 -0500 Subject: [PATCH 010/166] Update coverage from 4.5 to 4.5.1 --- {{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 63ec8a53..cfd0b99c 100644 --- a/{{cookiecutter.project_slug}}/requirements/local.txt +++ b/{{cookiecutter.project_slug}}/requirements/local.txt @@ -1,7 +1,7 @@ # Local development dependencies go here -r base.txt -coverage==4.5 +coverage==4.5.1 django-coverage-plugin==1.5.0 Sphinx==1.6.7 From 7d291e886305a3510f431aed015d4b0df595d943 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Sun, 11 Feb 2018 02:06:18 -0500 Subject: [PATCH 011/166] Update coverage from 4.5 to 4.5.1 --- {{cookiecutter.project_slug}}/requirements/test.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/{{cookiecutter.project_slug}}/requirements/test.txt b/{{cookiecutter.project_slug}}/requirements/test.txt index 8e8969c7..2a6ed87f 100644 --- a/{{cookiecutter.project_slug}}/requirements/test.txt +++ b/{{cookiecutter.project_slug}}/requirements/test.txt @@ -7,7 +7,7 @@ psycopg2==2.7.4 {%- endif %} -coverage==4.5 +coverage==4.5.1 flake8==3.5.0 # pyup: != 2.6.0 django-test-plus==1.0.22 factory-boy==2.10.0 From c0bcf3d22ec3f086d5c1b902598ea5e6fadc6b36 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Mon, 12 Feb 2018 11:00:24 -0500 Subject: [PATCH 012/166] Update sphinx from 1.6.7 to 1.7.0 --- {{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 63ec8a53..113d01cf 100644 --- a/{{cookiecutter.project_slug}}/requirements/local.txt +++ b/{{cookiecutter.project_slug}}/requirements/local.txt @@ -4,7 +4,7 @@ coverage==4.5 django-coverage-plugin==1.5.0 -Sphinx==1.6.7 +Sphinx==1.7.0 django-extensions==1.9.9 Werkzeug==0.14.1 django-test-plus==1.0.22 From 26e35a5c79ef7faf1cab468577c9d1cb34aa8eda Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Mon, 12 Feb 2018 21:26:27 -0500 Subject: [PATCH 013/166] Update boto3 from 1.5.25 to 1.5.27 --- {{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 952ba4bd..3bc011b6 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.25 +boto3==1.5.27 django-storages==1.6.5 {% if cookiecutter.use_whitenoise != 'y' -%} Collectfast==0.6.0 From d783367a8644cbdaa05af2d35470ef16666f4f03 Mon Sep 17 00:00:00 2001 From: Bruno Alla Date: Tue, 13 Feb 2018 14:37:40 +0000 Subject: [PATCH 014/166] Prevent pyup to Update Celery automatically --- {{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 56a44833..a568ab56 100644 --- a/{{cookiecutter.project_slug}}/requirements/base.txt +++ b/{{cookiecutter.project_slug}}/requirements/base.txt @@ -50,7 +50,7 @@ django-redis==4.8.0 redis>=2.10.5 {% if cookiecutter.use_celery == "y" %} -celery==3.1.25 +celery==3.1.25 # pyup: <4.0 {% endif %} {% if cookiecutter.use_compressor == "y" %} From bef1bb856e8434984ef4201b9ba28ee0936ce5c0 Mon Sep 17 00:00:00 2001 From: Sander van Leeuwen Date: Tue, 13 Feb 2018 16:04:43 +0100 Subject: [PATCH 015/166] Add cache control via AWS_S3_OBJECT_PARAMETERS setting Previously covered by AWS_HEADERS --- .../config/settings/production.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/{{cookiecutter.project_slug}}/config/settings/production.py b/{{cookiecutter.project_slug}}/config/settings/production.py index b332c776..32739837 100644 --- a/{{cookiecutter.project_slug}}/config/settings/production.py +++ b/{{cookiecutter.project_slug}}/config/settings/production.py @@ -100,6 +100,17 @@ 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 + +# 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'), +} + # URL that handles the media served from MEDIA_ROOT, used for managing # stored files. {% if cookiecutter.use_whitenoise == 'y' -%} From e8ca2dd8ea6396b8a9714ad270d0d56c4e847d01 Mon Sep 17 00:00:00 2001 From: Hashim Muqtadir Date: Fri, 16 Feb 2018 20:15:50 +0500 Subject: [PATCH 016/166] Add atomic requests setting to production.py (#1513) Since config/production.py sets a new value for `DATABASES['default']`, the `DATABASES['default']['ATOMIC_REQUESTS'] = True` setting from base gets overridden. So it's probably a good idea to add it back. --- {{cookiecutter.project_slug}}/config/settings/production.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/{{cookiecutter.project_slug}}/config/settings/production.py b/{{cookiecutter.project_slug}}/config/settings/production.py index 33542fbf..cb0b8021 100644 --- a/{{cookiecutter.project_slug}}/config/settings/production.py +++ b/{{cookiecutter.project_slug}}/config/settings/production.py @@ -177,7 +177,7 @@ TEMPLATES[0]['OPTIONS']['loaders'] = [ # 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 # CACHING # ------------------------------------------------------------------------------ From 07d7482dbe5a247d317c4033d0e15b6747a91609 Mon Sep 17 00:00:00 2001 From: "pyup.io bot" Date: Fri, 16 Feb 2018 16:16:09 +0100 Subject: [PATCH 017/166] Update boto3 from 1.5.27 to 1.5.30 (#1512) --- {{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 3bc011b6..5b5a7d84 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.27 +boto3==1.5.30 django-storages==1.6.5 {% if cookiecutter.use_whitenoise != 'y' -%} Collectfast==0.6.0 From 68ae00e028b27d080ece89b64e75ded6e55446fe Mon Sep 17 00:00:00 2001 From: "pyup.io bot" Date: Fri, 16 Feb 2018 16:16:23 +0100 Subject: [PATCH 018/166] Update ipdb from 0.10.3 to 0.11 (#1511) --- {{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 e5624830..697a4028 100644 --- a/{{cookiecutter.project_slug}}/requirements/local.txt +++ b/{{cookiecutter.project_slug}}/requirements/local.txt @@ -13,7 +13,7 @@ factory-boy==2.10.0 django-debug-toolbar==1.9.1 # improved REPL -ipdb==0.10.3 +ipdb==0.11 pytest-django==3.1.2 pytest-sugar==0.9.1 From 97f0ca6fa782c8d886a9a62327e2601873e48b53 Mon Sep 17 00:00:00 2001 From: "pyup.io bot" Date: Fri, 16 Feb 2018 22:42:20 +0100 Subject: [PATCH 019/166] Update django from 2.0 to 2.0.2 (#1514) --- {{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 9d57acd6..5bbeb5ec 100644 --- a/{{cookiecutter.project_slug}}/requirements/base.txt +++ b/{{cookiecutter.project_slug}}/requirements/base.txt @@ -6,7 +6,7 @@ wheel==0.30.0 # Conservative Django -django==2.0 # pyup: < 2.1 +django==2.0.2 # pyup: < 2.1 # Configuration django-environ==0.4.4 From cbd44dc4b94fe327bd2ad77eb1066b0eacbf9ec3 Mon Sep 17 00:00:00 2001 From: jose Gabriel Guzman Lopez Date: Sun, 18 Feb 2018 11:20:15 -0500 Subject: [PATCH 020/166] Update README.rst (#1518) --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 6536ab7e..b1dbe10d 100644 --- a/README.rst +++ b/README.rst @@ -38,7 +38,7 @@ production-ready Django projects quickly. Features --------- -* For Django 1.11 +* 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) From 1452fe6ecd707a0ec72775b8a0ab4bb93039e286 Mon Sep 17 00:00:00 2001 From: "pyup.io bot" Date: Sun, 18 Feb 2018 17:20:27 +0100 Subject: [PATCH 021/166] Update boto3 from 1.5.30 to 1.5.31 (#1517) --- {{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 5b5a7d84..09151486 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.30 +boto3==1.5.31 django-storages==1.6.5 {% if cookiecutter.use_whitenoise != 'y' -%} Collectfast==0.6.0 From 30dfbbd0aba298066a709bee78f14a448108b45d Mon Sep 17 00:00:00 2001 From: Wan Liuyang Date: Tue, 20 Feb 2018 16:04:16 +0800 Subject: [PATCH 022/166] 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 f6f85787..3926f3db 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 023/166] 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 24f8d11c..304732b9 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 b1dbe10d..b856810f 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 56306f92..a7efb0a6 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 024/166] 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 09151486..75450eb9 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 025/166] Update README.rst --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index b856810f..939ad4a9 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 026/166] 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 a65fedae..c48ce0ad 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 027/166] 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 137694d7..d80a091e 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 b9ee34b7..383b1577 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 c26318b4..0ca8bb50 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 8b50c8cf..4335340d 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 cf4a4166..50227e19 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 48923c80..2ded8253 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 845db0a3..def83076 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 4529aad9..10f0d20c 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 3b83c7bb..a40a2b7e 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 25da0649..8846cafb 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 00000000..c2f1dcd6 --- /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 028/166] 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 697a4028..6004987d 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 029/166] 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 1790a021..085d5a14 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 030/166] 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 a45de763..c767cb3b 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 031/166] 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 6004987d..93e9f741 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 032/166] 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 dff45133..7577c746 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 033/166] 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 9a831b48..4b1a10d1 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 034/166] 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 eeba285a..25ff7cb9 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 757c4ef0..1d28cb59 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 035/166] 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 7577c746..431f3e16 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 036/166] 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 431f3e16..9b389a52 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 037/166] 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 c9f78432..85c45e99 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 038/166] 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 9b389a52..351c46ce 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 039/166] 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 7c83fab9..1e161836 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 040/166] 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 f6e18b52..8be8bc44 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 041/166] 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 a9a85773..96c05d04 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 2ce69767..9e16919e 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 042/166] 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 0e16ffb7..a00fd9b2 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 043/166] 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 939ad4a9..30abcdd7 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 933c3dfa..4527a606 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 044/166] 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 a00fd9b2..79612856 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 d1197135..c1b500c2 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 045/166] 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 79612856..aba19ae2 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 046/166] Prettify cookiecutter.json --- cookiecutter.json | 42 +++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/cookiecutter.json b/cookiecutter.json index 4527a606..23e05b89 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 047/166] 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 23e05b89..f509953a 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 048/166] 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 f509953a..d3278194 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 049/166] 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 aba19ae2..9d0c30a0 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 050/166] 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 d3278194..00b9372d 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 9d0c30a0..83e41eb8 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 051/166] 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 d80a091e..c103b983 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 052/166] Fix default email --- cookiecutter.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cookiecutter.json b/cookiecutter.json index 00b9372d..1338e6f7 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 053/166] Gitignore .pytest_cache/ --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 1f80de17..9e4496f1 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 054/166] 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 1338e6f7..7aaaa943 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 055/166] 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 9e16919e..9b14f5ac 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 056/166] 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 30abcdd7..c5f9d06b 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 7aaaa943..9e5876e7 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 057/166] 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 9e5876e7..1eb56b78 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 058/166] 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 3926f3db..9947fc05 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 059/166] 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 91f0041b..00000000 --- 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 060/166] 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 c903795c..18e5ba76 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 061/166] Group requirements from requirements.txt --- requirements.txt | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/requirements.txt b/requirements.txt index 085d5a14..6e16a233 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 062/166] 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 d1d36324..7c51cb05 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 063/166] 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 1eb56b78..27834a51 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 064/166] 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 7c51cb05..d5ebe07f 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 065/166] Re-order requirements.txt --- requirements.txt | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/requirements.txt b/requirements.txt index 6e16a233..de0bc868 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 066/166] Simplify tox.ini --- tox.ini | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tox.ini b/tox.ini index a16b80ed..2399e24d 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 067/166] 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 c103b983..384fdff2 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 068/166] 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 8846cafb..39679f28 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 069/166] 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 b84edfa4..998c75b6 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 d70684bd..cb23750c 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 1d28cb59..4030af32 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 070/166] 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 998c75b6..f9abfa51 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 cb23750c..995da7b0 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 20bf9e5e..828b5de4 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 9947fc05..09cd8ed9 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 4030af32..1ea34204 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 071/166] 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 d5ebe07f..3f7928c5 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 072/166] 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 85c45e99..8bc63a5f 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 073/166] 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 de0bc868..18cd5222 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 074/166] 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 998c75b6..bf9ac745 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 075/166] 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 8bc63a5f..59ac7340 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 076/166] 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 18cd5222..d549c678 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 9b14f5ac..3df64355 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 18e5ba76..1029f9f4 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 09cd8ed9..e3c695f3 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 01a41279..b46b8e42 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 077/166] 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 8f5bb1d4..90e68eb8 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 078/166] 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 59ac7340..9cd9f30f 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 079/166] 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 96c05d04..e1c3cad4 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 7f978ede..a456b81a 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 15384c67..b225266c 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 a37d73bf..acaae12a 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 080/166] 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 90e68eb8..24c319df 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 081/166] 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 2399e24d..040c8a41 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 1029f9f4..2b1b9ddf 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 e3c695f3..b29a22b0 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 b46b8e42..e206c2f5 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 72513ed3..9827fa02 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 e2c967de..a777ae9e 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: From 6574abb1411d23335e1a342eb2603016997de7ad Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Wed, 7 Mar 2018 17:06:29 +0300 Subject: [PATCH 082/166] Clean up requirements.txt --- requirements.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index d549c678..7c4c5feb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,14 +2,12 @@ cookiecutter==1.6.0 sh==1.12.14 binaryornot==0.4.4 - # Code quality # ------------------------------------------------------------------------------ flake8==3.5.0 pycodestyle==2.3.1 pyflakes==1.6.0 - # Testing # ------------------------------------------------------------------------------ tox==2.9.1 From 0bd019deb0fb04d98f3acfc26efb248a4ef753fd Mon Sep 17 00:00:00 2001 From: "pyup.io bot" Date: Wed, 7 Mar 2018 15:15:15 +0100 Subject: [PATCH 083/166] Update django-extensions from 2.0.0 to 2.0.2 (#1556) --- {{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 93e9f741..29cfd58e 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.1 -django-extensions==2.0.0 +django-extensions==2.0.2 Werkzeug==0.14.1 django-test-plus==1.0.22 factory-boy==2.10.0 From 6c8538abfe2e37b2ec2114a5770e90852f4732d0 Mon Sep 17 00:00:00 2001 From: Malik S Date: Thu, 8 Mar 2018 18:54:24 +0600 Subject: [PATCH 084/166] Add all internal IPs for multiple docker networks (#1520) * Add all internal IPs for multiple docker networks When developing with modified docker-compose.yml that contains multiple network definitions, all networks gateways of the created container should be added to INTERNAL_IPS, otherwise Django-Debug-Toolbar will not work. * Add @flyudvik to contributors --- CONTRIBUTORS.rst | 2 ++ {{cookiecutter.project_slug}}/config/settings/local.py | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTORS.rst b/CONTRIBUTORS.rst index e1c3cad4..713e72cb 100644 --- a/CONTRIBUTORS.rst +++ b/CONTRIBUTORS.rst @@ -116,6 +116,7 @@ Listed in alphabetical order. Luis Nell `@originell`_ Lukas Klein Lyla Fischer + Malik Sulaimanov `@flyudvik`_ @flyudvik Martin Blech Mathijs Hoogland `@MathijsHoogland`_ Matt Braymer-Hayes `@mattayes`_ @mattayes @@ -196,6 +197,7 @@ Listed in alphabetical order. .. _@eraldo: https://github.com/eraldo .. _@eriol: https://github.com/eriol .. _@eyadsibai: https://github.com/eyadsibai +.. _@flyudvik: https://github.com/flyudvik .. _@garry-cairns: https://github.com/garry-cairns .. _@garrypolley: https://github.com/garrypolley .. _@goldhand: https://github.com/goldhand diff --git a/{{cookiecutter.project_slug}}/config/settings/local.py b/{{cookiecutter.project_slug}}/config/settings/local.py index 2b1b9ddf..6dc27de4 100644 --- a/{{cookiecutter.project_slug}}/config/settings/local.py +++ b/{{cookiecutter.project_slug}}/config/settings/local.py @@ -64,8 +64,8 @@ INTERNAL_IPS = ['127.0.0.1', '10.0.2.2'] import socket import os if os.environ.get('USE_DOCKER') == 'yes': - ip = socket.gethostbyname(socket.gethostname()) - INTERNAL_IPS += [ip[:-1] + '1'] + hostname, _, ips = socket.gethostbyname_ex(socket.gethostname()) + INTERNAL_IPS += [ip[:-1] + '1' for ip in ips] {%- endif %} # django-extensions From 3f8aa26d0f27de28c0b65c7fef91f6dff973a475 Mon Sep 17 00:00:00 2001 From: Nikita Shupeyko Date: Thu, 8 Mar 2018 15:56:15 +0300 Subject: [PATCH 085/166] Group environment variables by the corresponding directories (#1295) * Update generated project's .gitignore * Post-gen gitignore .env/ and .env * Fix linesep between gitignored entries * Persist `.env/**/*` files into cookiecutter-django's VCS * Rename .env/ to .envs/ * Reference the newly created .envs/**/.* files in local.yml * Reference the newly created .envs/**/.* files in production.yml * Delete .env.example * Refactor post-gen-project.py Closes #1299. * Implement production-dotenv-files-to-dotenv-file merge script * Create shared PyCharm Run Configuration for the automation script * Randomize POSTGRES_PASSWORD in ./envs/(.local|.production)/.postgres * Default POSTGRES_PASSWORD and POSTGRES_USER to random values * Fix jinja linebreaks in local.yml * Spaces in production.yml * Fix post-merge leftovers & set DJANGO_ADMIN_URL automatically * Prettify here and there * Fix FileNotFoundError * Leave a TODO in post_gen_hook.py * Introduce keep_local_envs_in_vcs option * Remove envs when not opted for * Inline pre_gen_project.py if-condition * Get rid of PROJECT_DIR_PATH in post_gen_project.py * Clean up the docs * Match copyright notices * Document envs ins and outs --- LICENSE | 2 +- README.rst | 3 +- cookiecutter.json | 3 +- docs/conf.py | 2 +- docs/deployment-on-pythonanywhere.rst | 2 +- docs/deployment-with-docker.rst | 14 +- docs/developing-locally-docker.rst | 160 ++++++++--------- docs/docker-postgres-backups.rst | 8 +- docs/faq.rst | 12 +- docs/project-generation-options.rst | 11 +- docs/troubleshooting.rst | 5 +- hooks/post_gen_project.py | 161 +++++++++++------- hooks/pre_gen_project.py | 33 ++-- .../.envs/.local/.django | 3 + .../.envs/.local/.postgres | 4 + .../.envs/.production/.caddy | 3 + .../.envs/.production/.django | 43 +++++ .../.envs/.production/.postgres | 4 + {{cookiecutter.project_slug}}/.gitignore | 19 --- .../merge_production_dotenvs_in_dotenv.xml | 21 +++ {{cookiecutter.project_slug}}/env.example | 46 ----- {{cookiecutter.project_slug}}/local.yml | 37 ++-- .../merge_production_dotenvs_in_dotenv.py | 69 ++++++++ {{cookiecutter.project_slug}}/production.yml | 20 ++- 24 files changed, 415 insertions(+), 270 deletions(-) create mode 100644 {{cookiecutter.project_slug}}/.envs/.local/.django create mode 100644 {{cookiecutter.project_slug}}/.envs/.local/.postgres create mode 100644 {{cookiecutter.project_slug}}/.envs/.production/.caddy create mode 100644 {{cookiecutter.project_slug}}/.envs/.production/.django create mode 100644 {{cookiecutter.project_slug}}/.envs/.production/.postgres create mode 100644 {{cookiecutter.project_slug}}/.idea/runConfigurations/merge_production_dotenvs_in_dotenv.xml delete mode 100644 {{cookiecutter.project_slug}}/env.example create mode 100644 {{cookiecutter.project_slug}}/merge_production_dotenvs_in_dotenv.py diff --git a/LICENSE b/LICENSE index da2bbe30..28466d40 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2013-2018, Daniel Greenfeld +Copyright (c) 2013-2018, Daniel Roy Greenfeld All rights reserved. Redistribution and use in source and binary forms, with or without modification, diff --git a/README.rst b/README.rst index c5f9d06b..e2c24f5b 100644 --- a/README.rst +++ b/README.rst @@ -129,7 +129,7 @@ Pyup brings you automated security and dependency updates used by Google and oth Usage ------ -Let's pretend you want to create a Django project called "redditclone". Rather than using `startproject` +Let's pretend you want to create a Django project called "redditclone". Rather than using ``startproject`` and then editing the results to include your name, email, and various configuration issues that always get forgotten until the worst possible moment, get cookiecutter_ to do all the work. First, get Cookiecutter. Trust me, it's awesome:: @@ -192,6 +192,7 @@ Answer the prompts with your own desired options_. For example:: 4 - Apache Software License 2.0 5 - Not open source Choose from 1, 2, 3, 4, 5 [1]: 1 + keep_local_envs_in_vcs [y]: y Enter the project and take a look around:: diff --git a/cookiecutter.json b/cookiecutter.json index 27834a51..aa341801 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -39,5 +39,6 @@ "use_opbeat": "n", "use_whitenoise": "y", "use_heroku": "n", - "use_travisci": "n" + "use_travisci": "n", + "keep_local_envs_in_vcs": "y" } diff --git a/docs/conf.py b/docs/conf.py index f8810ca7..aa023b74 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -42,7 +42,7 @@ master_doc = 'index' # General information about the project. project = 'Cookiecutter Django' -copyright = "2013-2016, Daniel Roy Greenfeld".format(now.year) +copyright = "2013-2018, Daniel Roy Greenfeld".format(now.year) # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the diff --git a/docs/deployment-on-pythonanywhere.rst b/docs/deployment-on-pythonanywhere.rst index 995da7b0..ea25b3ae 100644 --- a/docs/deployment-on-pythonanywhere.rst +++ b/docs/deployment-on-pythonanywhere.rst @@ -83,7 +83,7 @@ Database setup: Go to the PythonAnywhere **Databases tab** and configure your database. -* For Postgres, setup your superuser password, then open a Postgres console and run a `CREATE DATABASE my-db-name`. You should probably also set up a specific role and permissions for your app, rather than using the superuser credentials. Make a note of the address and port of your postgres server. +* For Postgres, setup your superuser password, then open a Postgres console and run a ``CREATE DATABASE my-db-name``. You should probably also set up a specific role and permissions for your app, rather than using the superuser credentials. Make a note of the address and port of your postgres server. * For MySQL, set the password and create a database. More info here: https://help.pythonanywhere.com/pages/UsingMySQL diff --git a/docs/deployment-with-docker.rst b/docs/deployment-with-docker.rst index 25ff7cb9..9e9d635e 100644 --- a/docs/deployment-with-docker.rst +++ b/docs/deployment-with-docker.rst @@ -1,5 +1,5 @@ Deployment with Docker -======================= +====================== .. index:: Docker, deployment @@ -10,7 +10,7 @@ Prerequisites * Docker Compose (at least 1.6) Understand the Compose Setup --------------------------------- +---------------------------- Before you start, check out the `production.yml` file in the root of this project. This is where each component of this application gets its configuration from. Notice how it provides configuration for these services: @@ -73,12 +73,12 @@ You can read more about this here at `Automatic HTTPS`_ in the Caddy docs. .. _Automatic HTTPS: https://caddyserver.com/docs/automatic-https -Optional: Postgres Data Volume Modifications +(Optional) Postgres Data Volume Modifications --------------------------------------------- Postgres is saving its database files to the `postgres_data` volume by default. Change that if you want something else and make sure to make backups since this is not done automatically. -Run your app with docker-compose +Run your app with Docker Compose -------------------------------- To get started, pull your code from source control (don't forget the `.env` file) and change to your projects root @@ -94,15 +94,15 @@ Once this is ready, you can run it with:: To run a migration, open up a second terminal and run:: - docker-compose -f production.yml run django python manage.py migrate + docker-compose -f production.yml run --rm django python manage.py migrate To create a superuser, run:: - docker-compose -f production.yml run django python manage.py createsuperuser + docker-compose -f production.yml run --rm django python manage.py createsuperuser If you need a shell, run:: - docker-compose -f production.yml run django python manage.py shell + docker-compose -f production.yml run --rm django python manage.py shell To get an output of all running containers. diff --git a/docs/developing-locally-docker.rst b/docs/developing-locally-docker.rst index 99622c3c..4dd6a443 100644 --- a/docs/developing-locally-docker.rst +++ b/docs/developing-locally-docker.rst @@ -6,23 +6,19 @@ Getting Up and Running Locally With Docker The steps below will get you up and running with a local development environment. All of these commands assume you are in the root of your generated project. + Prerequisites ------------- -You'll need at least Docker 1.10. +* Docker; if you don't have it yet, follow the `installation instructions`_; +* Docker Compose; refer to the official documentation for the `installation guide`_. -If you don't already have it installed, follow the instructions for your OS: +.. _`installation instructions`: https://docs.docker.com/install/#supported-platforms +.. _`installation guide`: https://docs.docker.com/compose/install/ - - On Mac OS X, you'll need `Docker for Mac`_ - - On Windows, you'll need `Docker for Windows`_ - - On Linux, you'll need `docker-engine`_ -.. _`Docker for Mac`: https://docs.docker.com/engine/installation/mac/ -.. _`Docker for Windows`: https://docs.docker.com/engine/installation/windows/ -.. _`docker-engine`: https://docs.docker.com/engine/installation/ - -Attention Windows users ------------------------ +Attention, Windows Users +------------------------ Currently PostgreSQL (``psycopg2`` python package) is not installed inside Docker containers for Windows users, while it is required by the generated Django project. To fix this, add ``psycopg2`` to the list of requirements inside ``requirements/base.txt``:: @@ -31,23 +27,21 @@ Currently PostgreSQL (``psycopg2`` python package) is not installed inside Docke Doing this will prevent the project from being installed in an Windows-only environment (thus without usage of Docker). If you want to use this project without Docker, make sure to remove ``psycopg2`` from the requirements again. + Build the Stack --------------- -This can take a while, especially the first time you run this particular command -on your development system:: +This can take a while, especially the first time you run this particular command on your development system:: $ docker-compose -f local.yml build -If you want to build the production environment you use ``production.yml`` as -f argument (``docker-compose.yml`` or ``docker-compose.yaml`` are the defaults). +Generally, if you want to emulate production environment use ``production.yml`` instead. And this is true for any other actions you might need to perform: whenever a switch is required, just do it! -Boot the System ---------------- -This brings up both Django and PostgreSQL. +Run the Stack +------------- -The first time it is run it might take a while to get started, but subsequent -runs will occur quickly. +This brings up both Django and PostgreSQL. The first time it is run it might take a while to get started, but subsequent runs will occur quickly. Open a terminal at the project root and run the following for local development:: @@ -61,98 +55,108 @@ And then run:: $ docker-compose up -Running management commands -~~~~~~~~~~~~~~~~~~~~~~~~~~~ +To run in a detached (background) mode, just:: -As with any shell command that we wish to run in our container, this is done -using the ``docker-compose -f local.yml run`` command. + $ docker-compose up -d -To migrate your app and to create a superuser, run:: - $ docker-compose -f local.yml run django python manage.py migrate - $ docker-compose -f local.yml run django python manage.py createsuperuser +Execute Management Commands +--------------------------- -Here we specify the ``django`` container as the location to run our management commands. +As with any shell command that we wish to run in our container, this is done using the ``docker-compose -f local.yml run --rm`` command: :: -Add your Docker development server IP -------------------------------------- + $ docker-compose -f local.yml run --rm django python manage.py migrate + $ docker-compose -f local.yml run --rm django python manage.py createsuperuser -When ``DEBUG`` is set to `True`, the host is validated against ``['localhost', '127.0.0.1', '[::1]']``. This is adequate when running a ``virtualenv``. For Docker, in the ``config.settings.local``, add your host development server IP to ``INTERNAL_IPS`` or ``ALLOWED_HOSTS`` if the variable exists. +Here, ``django`` is the target service we are executing the commands against. -Production Mode -~~~~~~~~~~~~~~~ -Instead of using `local.yml`, you would use `production.yml`. +(Optionally) Designate your Docker Development Server IP +-------------------------------------------------------- -Other Useful Tips ------------------ +When ``DEBUG`` is set to ``True``, the host is validated against ``['localhost', '127.0.0.1', '[::1]']``. This is adequate when running a ``virtualenv``. For Docker, in the ``config.settings.local``, add your host development server IP to ``INTERNAL_IPS`` or ``ALLOWED_HOSTS`` if the variable exists. -Make a machine the active unit -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -This tells our computer that all future commands are specifically for the dev1 machine. -Using the ``eval`` command we can switch machines as needed. +Configuring the Environment +--------------------------- -:: +This is the excerpt from your project's ``local.yml``: :: + + # ... + + postgres: + build: + context: . + dockerfile: ./compose/production/postgres/Dockerfile + volumes: + - postgres_data_local:/var/lib/postgresql/data + - postgres_backup_local:/backups + env_file: + - ./.envs/.local/.postgres + + # ... + +The most important thing for us here now is ``env_file`` section enlisting ``./.envs/.local/.postgres``. Generally, the stack's behavior is governed by a number of environment variables (`env(s)`, for short) residing in ``envs/``, for instance, this is what we generate for you: :: + + .envs + ├── .local + │   ├── .django + │   └── .postgres + └── .production + ├── .caddy + ├── .django + └── .postgres + +By convention, for any service ``sI`` in environment ``e`` (you know ``someenv`` is an environment when there is a ``someenv.yml`` file in the project root), given ``sI`` requires configuration, a ``.envs/.e/.sI`` `service configuration` file exists. + +Consider the aforementioned ``.envs/.local/.postgres``: :: + + # PostgreSQL + # ------------------------------------------------------------------------------ + POSTGRES_USER=XgOWtQtJecsAbaIyslwGvFvPawftNaqO + POSTGRES_PASSWORD=jSljDz4whHuwO3aJIgVBrqEml5Ycbghorep4uVJ4xjDYQu0LfuTZdctj7y0YcCLu + +The two envs we are presented with here are ``POSTGRES_USER``, and ``POSTGRES_PASSWORD`` (by the way, their values have also been generated for you). You might have figured out already where these definitions will end up; it's all the same with ``django`` and ``caddy`` service container envs. + + +Tips & Tricks +------------- + +Activate a Docker Machine +~~~~~~~~~~~~~~~~~~~~~~~~~ + +This tells our computer that all future commands are specifically for the dev1 machine. Using the ``eval`` command we can switch machines as needed.:: $ eval "$(docker-machine env dev1)" -Detached Mode -~~~~~~~~~~~~~ - -If you want to run the stack in detached mode (in the background), use the ``-d`` argument: - -:: - - $ docker-compose -f local.yml up -d - Debugging -~~~~~~~~~~~~~ +~~~~~~~~~ ipdb """"" -If you are using the following within your code to debug: - -:: +If you are using the following within your code to debug: :: import ipdb; ipdb.set_trace() -Then you may need to run the following for it to work as desired: +Then you may need to run the following for it to work as desired: :: -:: - - $ docker-compose -f local.yml run --service-ports django + $ docker-compose -f local.yml run --rm --service-ports django django-debug-toolbar """""""""""""""""""" -In order for django-debug-toolbar to work with docker you need to add your docker-machine ip address to ``INTERNAL_IPS`` in ``local.py`` +In order for ``django-debug-toolbar`` to work designate your Docker Machine IP with ``INTERNAL_IPS`` in ``local.py``. -.. May be a better place to put this, as it is not Docker specific. +Mailhog +~~~~~~~ -You may need to add the following to your css in order for the django-debug-toolbar to be visible (this applies whether Docker is being used or not): +When developing locally you can go with MailHog_ for email testing provided ``use_mailhog`` was set to ``y`` on setup. To proceed, -.. code-block:: css +#. make sure ``mailhog`` container is up and running; - /* Override Bootstrap 4 styling on Django Debug Toolbar */ - #djDebug[hidden], #djDebug [hidden] { - display: block !important; - } - - #djDebug [hidden][style='display: none;'] { - display: none !important; - } - - -Using the Mailhog Docker Container -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -In development you can (optionally) use MailHog_ for email testing. If you selected `use_docker`, MailHog is added as a Docker container. To use MailHog: - -1. Make sure, that ``mailhog`` docker container is up and running -2. Open your browser and go to ``http://127.0.0.1:8025`` +#. open up ``http://127.0.0.1:8025``. .. _Mailhog: https://github.com/mailhog/MailHog/ diff --git a/docs/docker-postgres-backups.rst b/docs/docker-postgres-backups.rst index d3c7ca1d..d0ad1a52 100644 --- a/docs/docker-postgres-backups.rst +++ b/docs/docker-postgres-backups.rst @@ -2,7 +2,7 @@ Database Backups with Docker ============================ -The database has to be running to create/restore a backup. These examples show local examples. If you want to use it on a remote server, remove ``-f local.yml`` from each example. +The database has to be running to create/restore a backup. These examples show local examples. If you want to use it on a remote server, use ``-f production.yml`` instead. Running Backups ================ @@ -11,17 +11,17 @@ Run the app with `docker-compose -f local.yml up`. To create a backup, run:: - docker-compose -f local.yml run postgres backup + docker-compose -f local.yml run --rm postgres backup To list backups, run:: - docker-compose -f local.yml run postgres list-backups + docker-compose -f local.yml run --rm postgres list-backups To restore a backup, run:: - docker-compose -f local.yml run postgres restore filename.sql + docker-compose -f local.yml run --rm postgres restore filename.sql Where is the ID of the Postgres container. To get it, run:: diff --git a/docs/faq.rst b/docs/faq.rst index def4ba1f..1481a8ba 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -1,5 +1,5 @@ FAQ -==== +=== .. index:: FAQ, 12-Factor App @@ -17,11 +17,11 @@ Why aren't you using just one configuration file (12-Factor App) ---------------------------------------------------------------------- TODO +.. TODO -Why doesn't this follow the layout from Two Scoops of Django 1.8? ----------------------------------------------------------------------- +Why doesn't this follow the layout from Two Scoops of Django? +------------------------------------------------------------- -You may notice that some elements of this project do not exactly match what we describe in chapter 3 of `Two Scoops of Django`_. The reason for that is this project, amongst other things, serves as a test bed for trying out new ideas and concepts. Sometimes they work, sometimes they don't, but the end result is that it won't necessarily match precisely what is described in the book I co-authored. +You may notice that some elements of this project do not exactly match what we describe in chapter 3 of `Two Scoops of Django 1.11`_. The reason for that is this project, amongst other things, serves as a test bed for trying out new ideas and concepts. Sometimes they work, sometimes they don't, but the end result is that it won't necessarily match precisely what is described in the book I co-authored. - -.. _`Two Scoops of Django`: http://twoscoopspress.com/products/two-scoops-of-django-1-8 +.. _Two Scoops of Django 1.11: https://www.twoscoopspress.com/collections/django/products/two-scoops-of-django-1-11 diff --git a/docs/project-generation-options.rst b/docs/project-generation-options.rst index 3f7928c5..2ca2872c 100644 --- a/docs/project-generation-options.rst +++ b/docs/project-generation-options.rst @@ -10,10 +10,10 @@ project_slug [my_awesome_project]: is needed. description [Behold My Awesome Project!] - Describes your project and gets used in places like `README.rst` and such. + Describes your project and gets used in places like ``README.rst`` and such. author_name [Daniel Roy Greenfeld]: - This is you! The value goes into places like `LICENSE` and such. + This is you! The value goes into places like ``LICENSE`` and such. email [daniel-roy-greenfeld@example.com]: The email address you want to identify yourself in the project. @@ -35,7 +35,7 @@ open_source_license [1] 5. Not open source timezone [UTC] - The value to be used for the `TIME_ZONE` setting of the project. + The value to be used for the ``TIME_ZONE`` setting of the project. windows [n] Indicates whether the project should be configured for development on Windows. @@ -94,6 +94,11 @@ use_heroku [n] use_travisci [n] Indicates whether the project should be configured to use `Travis CI`_. +keep_local_envs_in_vcs [y] + Indicates whether the project's ``.envs/.local/`` should be kept in VCS + (comes in handy when working in teams where local environment reproducibility + is strongly encouraged). + .. _MIT: https://opensource.org/licenses/MIT .. _BSD: https://opensource.org/licenses/BSD-3-Clause diff --git a/docs/troubleshooting.rst b/docs/troubleshooting.rst index fe121b9c..4a682ac2 100644 --- a/docs/troubleshooting.rst +++ b/docs/troubleshooting.rst @@ -3,7 +3,8 @@ Troubleshooting This page contains some advice about errors and problems commonly encountered during the development of Cookiecutter Django applications. -#. If you get the error ``jinja2.exceptions.TemplateSyntaxError: Encountered unknown tag 'now'.`` , please upgrade your cookiecutter version to >= 1.4 (see issue # 528_ ) #. ``project_slug`` must be a valid Python module name or you will have issues on imports. -.. _528: https://github.com/pydanny/cookiecutter-django/issues/528#issuecomment-212650373 \ No newline at end of file +#. ``jinja2.exceptions.TemplateSyntaxError: Encountered unknown tag 'now'.``: please upgrade your cookiecutter version to >= 1.4 (see # 528_) + +.. _528: https://github.com/pydanny/cookiecutter-django/issues/528#issuecomment-212650373 diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py index 83e41eb8..af813e7d 100644 --- a/hooks/post_gen_project.py +++ b/hooks/post_gen_project.py @@ -7,12 +7,12 @@ NOTE: TODO: ? restrict Cookiecutter Django project initialization to Python 3.x environments only """ +from __future__ import print_function import os import random import shutil import string -import sys try: # Inspired by @@ -22,15 +22,19 @@ try: except NotImplementedError: using_sysrandom = False -PROJECT_DIR_PATH = os.path.realpath(os.path.curdir) +TERMINATOR = "\x1b[0m" +WARNING = "\x1b[1;33m [WARNING]: " +INFO = "\x1b[1;33m [INFO]: " +HINT = "\x1b[3;33m" +SUCCESS = "\x1b[1;32m [SUCCESS]: " -def remove_open_source_project_only_files(): +def remove_open_source_files(): file_names = [ 'CONTRIBUTORS.txt', ] for file_name in file_names: - os.remove(os.path.join(PROJECT_DIR_PATH, file_name)) + os.remove(file_name) def remove_gplv3_files(): @@ -38,21 +42,21 @@ def remove_gplv3_files(): 'COPYING', ] for file_name in file_names: - os.remove(os.path.join(PROJECT_DIR_PATH, file_name)) + os.remove(file_name) def remove_pycharm_files(): - idea_dir_path = os.path.join(PROJECT_DIR_PATH, '.idea') + idea_dir_path = '.idea' if os.path.exists(idea_dir_path): shutil.rmtree(idea_dir_path) - docs_dir_path = os.path.join(PROJECT_DIR_PATH, 'docs', 'pycharm') + docs_dir_path = os.path.join('docs', 'pycharm') if os.path.exists(docs_dir_path): shutil.rmtree(docs_dir_path) def remove_docker_files(): - shutil.rmtree(os.path.join(PROJECT_DIR_PATH, 'compose')) + shutil.rmtree('compose') file_names = [ 'local.yml', @@ -60,7 +64,7 @@ def remove_docker_files(): '.dockerignore', ] for file_name in file_names: - os.remove(os.path.join(PROJECT_DIR_PATH, file_name)) + os.remove(file_name) def remove_heroku_files(): @@ -70,11 +74,7 @@ def remove_heroku_files(): 'requirements.txt', ] for file_name in file_names: - os.remove(os.path.join(PROJECT_DIR_PATH, file_name)) - - -def remove_dotenv_file(): - os.remove(os.path.join(PROJECT_DIR_PATH, '.env')) + os.remove(file_name) def remove_grunt_files(): @@ -82,7 +82,7 @@ def remove_grunt_files(): 'Gruntfile.js', ] for file_name in file_names: - os.remove(os.path.join(PROJECT_DIR_PATH, file_name)) + os.remove(file_name) def remove_gulp_files(): @@ -90,7 +90,7 @@ def remove_gulp_files(): 'gulpfile.js', ] for file_name in file_names: - os.remove(os.path.join(PROJECT_DIR_PATH, file_name)) + os.remove(file_name) def remove_packagejson_file(): @@ -98,19 +98,19 @@ def remove_packagejson_file(): 'package.json', ] for file_name in file_names: - os.remove(os.path.join(PROJECT_DIR_PATH, file_name)) + os.remove(file_name) def remove_celery_app(): - shutil.rmtree(os.path.join(PROJECT_DIR_PATH, '{{ cookiecutter.project_slug }}', 'taskapp')) + shutil.rmtree(os.path.join('{{ cookiecutter.project_slug }}', 'taskapp')) def remove_dottravisyml_file(): - os.remove(os.path.join(PROJECT_DIR_PATH, '.travis.yml')) + os.remove('.travis.yml') def append_to_project_gitignore(path): - gitignore_file_path = os.path.join(PROJECT_DIR_PATH, '.gitignore') + gitignore_file_path = '.gitignore' with open(gitignore_file_path, 'a') as gitignore_file: gitignore_file.write(path) gitignore_file.write(os.linesep) @@ -144,17 +144,19 @@ def generate_random_string(length, def set_flag(file_path, flag, value=None, + formatted=None, *args, **kwargs): if value is None: random_string = generate_random_string(*args, **kwargs) if random_string is None: - import sys - sys.stdout.write( + print( "We couldn't find a secure pseudo-random number generator on your system. " "Please, make sure to manually {} later.".format(flag) ) random_string = flag + if formatted is not None: + random_string = formatted.format(random_string) value = random_string with open(file_path, 'r+') as f: @@ -170,21 +172,38 @@ def set_django_secret_key(file_path): django_secret_key = set_flag( file_path, '!!!SET DJANGO_SECRET_KEY!!!', - length=50, + length=64, using_digits=True, using_ascii_letters=True ) return django_secret_key +def set_django_admin_url(file_path): + django_admin_url = set_flag( + file_path, + '!!!SET DJANGO_ADMIN_URL!!!', + formatted='^{}/', + length=32, + using_digits=True, + using_ascii_letters=True + ) + return django_admin_url + + +def generate_postgres_user(): + return generate_random_string( + length=32, + using_ascii_letters=True + ) + + def set_postgres_user(file_path, value=None): postgres_user = set_flag( file_path, '!!!SET POSTGRES_USER!!!', - value=value, - length=8, - using_ascii_letters=True + value=value or generate_postgres_user() ) return postgres_user @@ -193,45 +212,50 @@ def set_postgres_password(file_path): postgres_password = set_flag( file_path, '!!!SET POSTGRES_PASSWORD!!!', - length=42, + length=64, using_digits=True, using_ascii_letters=True ) return postgres_password -def initialize_dotenv(postgres_user): - # Initializing `env.example` first. - envexample_file_path = os.path.join(PROJECT_DIR_PATH, 'env.example') - set_django_secret_key(envexample_file_path) - set_postgres_user(envexample_file_path, value=postgres_user) - set_postgres_password(envexample_file_path) - # Renaming `env.example` to `.env`. - dotenv_file_path = os.path.join(PROJECT_DIR_PATH, '.env') - shutil.move(envexample_file_path, dotenv_file_path) +def append_to_gitignore_file(s): + with open('.gitignore', 'a') as gitignore_file: + gitignore_file.write(s) + gitignore_file.write(os.linesep) -def initialize_localyml(postgres_user): - set_postgres_user(os.path.join(PROJECT_DIR_PATH, 'local.yml'), value=postgres_user) +def set_flags_in_envs(postgres_user): + local_postgres_envs_path = os.path.join('.envs', '.local', '.postgres') + set_postgres_user(local_postgres_envs_path, value=postgres_user) + set_postgres_password(local_postgres_envs_path) + + production_django_envs_path = os.path.join('.envs', '.production', '.django') + set_django_secret_key(production_django_envs_path) + set_django_admin_url(production_django_envs_path) + + production_postgres_envs_path = os.path.join('.envs', '.production', '.postgres') + set_postgres_user(production_postgres_envs_path, value=postgres_user) + set_postgres_password(production_postgres_envs_path) -def initialize_local_settings(): - set_django_secret_key(os.path.join(PROJECT_DIR_PATH, 'config', 'settings', 'local.py')) +def set_flags_in_settings_files(): + set_django_secret_key(os.path.join('config', 'settings', 'local.py')) + set_django_secret_key(os.path.join('config', 'settings', 'test.py')) -def initialize_test_settings(): - set_django_secret_key(os.path.join(PROJECT_DIR_PATH, 'config', 'settings', 'test.py')) +def remove_envs_and_associated_files(): + shutil.rmtree('.envs') + os.remove('merge_production_dotenvs_in_dotenv.py') def main(): - postgres_user = generate_random_string(length=16, using_ascii_letters=True) - initialize_dotenv(postgres_user) - initialize_localyml(postgres_user) - initialize_local_settings() - initialize_test_settings() + postgres_user = generate_postgres_user() + set_flags_in_envs(postgres_user) + set_flags_in_settings_files() if '{{ cookiecutter.open_source_license }}' == 'Not open source': - remove_open_source_project_only_files() + remove_open_source_files() if '{{ cookiecutter.open_source_license}}' != 'GPLv3': remove_gplv3_files() @@ -245,7 +269,20 @@ def main(): remove_heroku_files() if '{{ cookiecutter.use_docker }}'.lower() == 'n' and '{{ cookiecutter.use_heroku }}'.lower() == 'n': - remove_dotenv_file() + if '{{ cookiecutter.keep_local_envs_in_vcs }}'.lower() == 'y': + print( + INFO + + ".env(s) are only utilized when Docker Compose and/or " + "Heroku support is enabled so keeping them does not " + "make sense given your current setup." + + TERMINATOR + ) + remove_envs_and_associated_files() + else: + append_to_gitignore_file('.env') + append_to_gitignore_file('.envs' + '/**/*') + if '{{ cookiecutter.keep_local_envs_in_vcs }}'.lower() == 'y': + append_to_gitignore_file('!.envs/.local/') if '{{ cookiecutter.js_task_runner}}'.lower() == 'gulp': remove_grunt_files() @@ -255,18 +292,20 @@ def main(): remove_gulp_files() remove_grunt_files() remove_packagejson_file() - if '{{ cookiecutter.js_task_runner }}'.lower() in ['grunt', 'gulp'] \ and '{{ cookiecutter.use_docker }}'.lower() == 'y': - TERMINATOR = "\x1b[0m" - INFO = "\x1b[1;33m [INFO]: " - sys.stdout.write( - INFO + - "Docker and {} JS task runner ".format('{{ cookiecutter.js_task_runner }}'.lower().capitalize()) + + print( + WARNING + + "Docker and {} JS task runner ".format( + '{{ cookiecutter.js_task_runner }}' + .lower() + .capitalize() + ) + "working together not supported yet. " - "You can continue using the generated project like you normally would, " - "however you would need to add a JS task runner service " - "to your Docker Compose configuration manually." + + "You can continue using the generated project like you " + "normally would, however you would need to add a JS " + "task runner service to your Docker Compose configuration " + "manually." + TERMINATOR ) @@ -276,6 +315,12 @@ def main(): if '{{ cookiecutter.use_travisci }}'.lower() == 'n': remove_dottravisyml_file() + print( + SUCCESS + + "Project initialized, keep up the good work!" + + TERMINATOR + ) + if __name__ == '__main__': main() diff --git a/hooks/pre_gen_project.py b/hooks/pre_gen_project.py index c48ce0ad..ed2bef18 100644 --- a/hooks/pre_gen_project.py +++ b/hooks/pre_gen_project.py @@ -6,6 +6,15 @@ NOTE: TODO: ? restrict Cookiecutter Django project initialization to Python 3.x environments only """ +from __future__ import print_function + +import sys + +TERMINATOR = "\x1b[0m" +WARNING = "\x1b[1;33m [WARNING]: " +INFO = "\x1b[1;33m [INFO]: " +HINT = "\x1b[3;33m" +SUCCESS = "\x1b[1;32m [SUCCESS]: " project_slug = '{{ cookiecutter.project_slug }}' if hasattr(project_slug, 'isidentifier'): @@ -13,20 +22,10 @@ if hasattr(project_slug, 'isidentifier'): 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" - WARNING = "\x1b[1;33m [WARNING]: " - INFO = "\x1b[1;33m [INFO]: " - HINT = "\x1b[3;33m" - SUCCESS = "\x1b[1;32m [SUCCESS]: " - - import sys - +if '{{ cookiecutter.use_docker }}'.lower() == 'n': python_major_version = sys.version_info[0] if python_major_version == 2: - sys.stdout.write( + print( WARNING + "Cookiecutter Django does not support Python 2. " "Stability is guaranteed with Python 3.6+ only, " @@ -39,14 +38,14 @@ if using_docker == 'n': if choice in yes_options: break elif choice in no_options: - sys.stdout.write( + print( INFO + "Generation process stopped as requested." + TERMINATOR ) sys.exit(1) else: - sys.stdout.write( + print( HINT + "Please respond with {} or {}: ".format( ', '.join(["'{}'".format(o) for o in yes_options if not o == '']), @@ -54,9 +53,3 @@ if using_docker == 'n': ) + TERMINATOR ) - - sys.stdout.write( - SUCCESS + - "Project initialized, keep up the good work!" + - TERMINATOR - ) diff --git a/{{cookiecutter.project_slug}}/.envs/.local/.django b/{{cookiecutter.project_slug}}/.envs/.local/.django new file mode 100644 index 00000000..630aa890 --- /dev/null +++ b/{{cookiecutter.project_slug}}/.envs/.local/.django @@ -0,0 +1,3 @@ +# General +# ------------------------------------------------------------------------------ +USE_DOCKER=yes diff --git a/{{cookiecutter.project_slug}}/.envs/.local/.postgres b/{{cookiecutter.project_slug}}/.envs/.local/.postgres new file mode 100644 index 00000000..b3da9842 --- /dev/null +++ b/{{cookiecutter.project_slug}}/.envs/.local/.postgres @@ -0,0 +1,4 @@ +# PostgreSQL +# ------------------------------------------------------------------------------ +POSTGRES_USER=!!!SET POSTGRES_USER!!! +POSTGRES_PASSWORD=!!!SET POSTGRES_PASSWORD!!! diff --git a/{{cookiecutter.project_slug}}/.envs/.production/.caddy b/{{cookiecutter.project_slug}}/.envs/.production/.caddy new file mode 100644 index 00000000..83d7fc7a --- /dev/null +++ b/{{cookiecutter.project_slug}}/.envs/.production/.caddy @@ -0,0 +1,3 @@ +# Caddy +# ------------------------------------------------------------------------------ +DOMAIN_NAME={{ cookiecutter.domain_name }} diff --git a/{{cookiecutter.project_slug}}/.envs/.production/.django b/{{cookiecutter.project_slug}}/.envs/.production/.django new file mode 100644 index 00000000..c6def565 --- /dev/null +++ b/{{cookiecutter.project_slug}}/.envs/.production/.django @@ -0,0 +1,43 @@ +# General +# ------------------------------------------------------------------------------ +# DJANGO_READ_DOT_ENV_FILE=True +DJANGO_SETTINGS_MODULE=config.settings.production +DJANGO_SECRET_KEY=!!!SET DJANGO_SECRET_KEY!!! +DJANGO_ADMIN_URL=!!!SET DJANGO_ADMIN_URL!!! +DJANGO_ALLOWED_HOSTS=.{{ cookiecutter.domain_name }} + +# Security +# ------------------------------------------------------------------------------ +# TIP: better off using DNS, however, redirect is OK too +DJANGO_SECURE_SSL_REDIRECT=False + +# Email +# ------------------------------------------------------------------------------ +MAILGUN_API_KEY= +DJANGO_SERVER_EMAIL= +MAILGUN_DOMAIN= + +# AWS +# ------------------------------------------------------------------------------ +DJANGO_AWS_ACCESS_KEY_ID= +DJANGO_AWS_SECRET_ACCESS_KEY= +DJANGO_AWS_STORAGE_BUCKET_NAME= + +# django-allauth +# ------------------------------------------------------------------------------ +DJANGO_ACCOUNT_ALLOW_REGISTRATION=True +{% if cookiecutter.use_compressor == 'y' %} +# django-compressor +# ------------------------------------------------------------------------------ +COMPRESS_ENABLED= +{% endif %}{% if cookiecutter.use_sentry_for_error_reporting == 'y' %} +# Sentry +# ------------------------------------------------------------------------------ +DJANGO_SENTRY_DSN= +{% endif %}{% if cookiecutter.use_opbeat == 'y' %} +# opbeat +# ------------------------------------------------------------------------------ +DJANGO_OPBEAT_ORGANIZATION_ID= +DJANGO_OPBEAT_APP_ID= +DJANGO_OPBEAT_SECRET_TOKEN= +{% endif %} diff --git a/{{cookiecutter.project_slug}}/.envs/.production/.postgres b/{{cookiecutter.project_slug}}/.envs/.production/.postgres new file mode 100644 index 00000000..b3da9842 --- /dev/null +++ b/{{cookiecutter.project_slug}}/.envs/.production/.postgres @@ -0,0 +1,4 @@ +# PostgreSQL +# ------------------------------------------------------------------------------ +POSTGRES_USER=!!!SET POSTGRES_USER!!! +POSTGRES_PASSWORD=!!!SET POSTGRES_PASSWORD!!! diff --git a/{{cookiecutter.project_slug}}/.gitignore b/{{cookiecutter.project_slug}}/.gitignore index 65feea00..207d2044 100644 --- a/{{cookiecutter.project_slug}}/.gitignore +++ b/{{cookiecutter.project_slug}}/.gitignore @@ -53,42 +53,23 @@ coverage.xml # Django stuff: staticfiles/ -# Flask stuff: -instance/ -.webassets-cache - -# Scrapy stuff: -.scrapy - # Sphinx documentation docs/_build/ # PyBuilder target/ -# Jupyter Notebook -.ipynb_checkpoints - # pyenv .python-version # celery beat schedule file celerybeat-schedule -# SageMath parsed files -*.sage.py - # Environments -.env .venv -env/ venv/ ENV/ -# Spyder project settings -.spyderproject -.spyproject - # Rope project settings .ropeproject diff --git a/{{cookiecutter.project_slug}}/.idea/runConfigurations/merge_production_dotenvs_in_dotenv.xml b/{{cookiecutter.project_slug}}/.idea/runConfigurations/merge_production_dotenvs_in_dotenv.xml new file mode 100644 index 00000000..18f8365a --- /dev/null +++ b/{{cookiecutter.project_slug}}/.idea/runConfigurations/merge_production_dotenvs_in_dotenv.xml @@ -0,0 +1,21 @@ + + + + diff --git a/{{cookiecutter.project_slug}}/env.example b/{{cookiecutter.project_slug}}/env.example deleted file mode 100644 index 1ea34204..00000000 --- a/{{cookiecutter.project_slug}}/env.example +++ /dev/null @@ -1,46 +0,0 @@ - -# PostgreSQL -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 }} - -# General settings -# DJANGO_READ_DOT_ENV_FILE=True -DJANGO_ADMIN_URL= -DJANGO_SETTINGS_MODULE=config.settings.production -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 -MAILGUN_API_KEY= -DJANGO_SERVER_EMAIL= -MAILGUN_DOMAIN= - -# Security! Better to use DNS for this task, but you can use redirect -DJANGO_SECURE_SSL_REDIRECT=False - -# django-allauth -DJANGO_ACCOUNT_ALLOW_REGISTRATION=True -{% if cookiecutter.use_sentry_for_error_reporting == 'y' -%} -# Sentry -DJANGO_SENTRY_DSN= -{% endif %} -{% if cookiecutter.use_opbeat == 'y' -%} -DJANGO_OPBEAT_ORGANIZATION_ID= -DJANGO_OPBEAT_APP_ID= -DJANGO_OPBEAT_SECRET_TOKEN= -{% endif %} -{% if cookiecutter.use_compressor == 'y' -%} -COMPRESS_ENABLED= -{% endif %} diff --git a/{{cookiecutter.project_slug}}/local.yml b/{{cookiecutter.project_slug}}/local.yml index b030e617..8376c4a5 100644 --- a/{{cookiecutter.project_slug}}/local.yml +++ b/{{cookiecutter.project_slug}}/local.yml @@ -10,13 +10,15 @@ services: context: . dockerfile: ./compose/local/django/Dockerfile depends_on: - - postgres{% if cookiecutter.use_mailhog == 'y' %} - - mailhog{% endif %} + - postgres + {% if cookiecutter.use_mailhog == 'y' -%} + - mailhog + {%- endif %} volumes: - .:/app - environment: - - POSTGRES_USER=!!!SET POSTGRES_USER!!! - - USE_DOCKER=yes + env_file: + - ./.envs/.local/.django + - ./.envs/.local/.postgres ports: - "8000:8000" command: /start.sh @@ -28,35 +30,36 @@ services: volumes: - postgres_data_local:/var/lib/postgresql/data - postgres_backup_local:/backups - environment: - - POSTGRES_USER=!!!SET POSTGRES_USER!!! -{% if cookiecutter.use_mailhog == 'y' %} + env_file: + - ./.envs/.local/.postgres + {% if cookiecutter.use_mailhog == 'y' %} mailhog: image: mailhog/mailhog:v1.0.0 ports: - "8025:8025" -{% endif %} -{% if cookiecutter.use_celery == 'y' %} + {% endif %}{% if cookiecutter.use_celery == 'y' %} redis: image: redis:3.0 celeryworker: - # https://github.com/docker/compose/issues/3220 <<: *django depends_on: - redis - - postgres{% if cookiecutter.use_mailhog == 'y' %} - - mailhog{% endif %} + - postgres + {% if cookiecutter.use_mailhog == 'y' -%} + - mailhog + {%- endif %} ports: [] command: /start-celeryworker.sh celerybeat: - # https://github.com/docker/compose/issues/3220 <<: *django depends_on: - redis - - postgres{% if cookiecutter.use_mailhog == 'y' %} - - mailhog{% endif %} + - postgres + {% if cookiecutter.use_mailhog == 'y' -%} + - mailhog + {%- endif %} ports: [] command: /start-celerybeat.sh -{% endif %} + {% endif %} diff --git a/{{cookiecutter.project_slug}}/merge_production_dotenvs_in_dotenv.py b/{{cookiecutter.project_slug}}/merge_production_dotenvs_in_dotenv.py new file mode 100644 index 00000000..c1bfe30a --- /dev/null +++ b/{{cookiecutter.project_slug}}/merge_production_dotenvs_in_dotenv.py @@ -0,0 +1,69 @@ +import os +from typing import Sequence + +import pytest + +ROOT_DIR_PATH = os.path.dirname(os.path.realpath(__file__)) +PRODUCTION_DOTENVS_DIR_PATH = os.path.join(ROOT_DIR_PATH, '.envs', '.production') +PRODUCTION_DOTENV_FILE_PATHS = [ + os.path.join(PRODUCTION_DOTENVS_DIR_PATH, '.django'), + os.path.join(PRODUCTION_DOTENVS_DIR_PATH, '.postgres'), + os.path.join(PRODUCTION_DOTENVS_DIR_PATH, '.caddy'), +] +DOTENV_FILE_PATH = os.path.join(ROOT_DIR_PATH, '.env') + + +def merge(output_file_path: str, + merged_file_paths: Sequence[str], + append_linesep: bool = True) -> None: + with open(output_file_path, 'w') as output_file: + for merged_file_path in merged_file_paths: + with open(merged_file_path, 'r') as merged_file: + merged_file_content = merged_file.read() + output_file.write(merged_file_content) + if append_linesep: + output_file.write(os.linesep) + + +def main(): + merge(DOTENV_FILE_PATH, PRODUCTION_DOTENV_FILE_PATHS) + + +@pytest.mark.parametrize('merged_file_count', range(3)) +@pytest.mark.parametrize('append_linesep', [True, False]) +def test_merge(tmpdir_factory, + merged_file_count: int, + append_linesep: bool): + tmp_dir_path = str(tmpdir_factory.getbasetemp()) + + output_file_path = os.path.join(tmp_dir_path, '.env') + + expected_output_file_content = '' + merged_file_paths = [] + for i in range(merged_file_count): + merged_file_ord = i + 1 + + merged_filename = '.service{}'.format(merged_file_ord) + merged_file_path = os.path.join(tmp_dir_path, merged_filename) + + merged_file_content = merged_filename * merged_file_ord + + with open(merged_file_path, 'w+') as file: + file.write(merged_file_content) + + expected_output_file_content += merged_file_content + if append_linesep: + expected_output_file_content += os.linesep + + merged_file_paths.append(merged_file_path) + + merge(output_file_path, merged_file_paths, append_linesep) + + with open(output_file_path, 'r') as output_file: + actual_output_file_content = output_file.read() + + assert actual_output_file_content == expected_output_file_content + + +if __name__ == '__main__': + main() diff --git a/{{cookiecutter.project_slug}}/production.yml b/{{cookiecutter.project_slug}}/production.yml index ef9163e5..469903d9 100644 --- a/{{cookiecutter.project_slug}}/production.yml +++ b/{{cookiecutter.project_slug}}/production.yml @@ -13,7 +13,9 @@ services: depends_on: - postgres - redis - env_file: .env + env_file: + - ./.envs/.production/.django + - ./.envs/.production/.postgres command: /gunicorn.sh postgres: @@ -23,7 +25,8 @@ services: volumes: - postgres_data:/var/lib/postgresql/data - postgres_backup:/backups - env_file: .env + env_file: + - ./.envs/.production/.postgres caddy: build: @@ -33,19 +36,23 @@ services: - django volumes: - caddy:/root/.caddy - env_file: .env + env_file: + - ./.envs/.production/.caddy ports: - "0.0.0.0:80:80" - "0.0.0.0:443:443" redis: image: redis:3.0 -{% if cookiecutter.use_celery == 'y' %} + {% if cookiecutter.use_celery == 'y' %} celeryworker: <<: *django depends_on: - postgres - redis + env_file: + - ./.envs/.production/.django + - ./.envs/.production/.postgres command: /start-celeryworker.sh celerybeat: @@ -53,5 +60,8 @@ services: depends_on: - postgres - redis + env_file: + - ./.envs/.production/.django + - ./.envs/.production/.postgres command: /start-celerybeat.sh -{% endif %} + {% endif %} From dd0a73a9854c4c00ae45854ff432d77952f29fed Mon Sep 17 00:00:00 2001 From: "pyup.io bot" Date: Thu, 8 Mar 2018 17:03:18 +0100 Subject: [PATCH 086/166] Update django-extensions from 2.0.2 to 2.0.3 (#1561) --- {{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 29cfd58e..3fb728fa 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.1 -django-extensions==2.0.2 +django-extensions==2.0.3 Werkzeug==0.14.1 django-test-plus==1.0.22 factory-boy==2.10.0 From 5543359382e928873a9bead3c090d9ea4e6da9dc Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Thu, 8 Mar 2018 16:59:41 +0300 Subject: [PATCH 087/166] Distinguish between POSTGRES_DB and POSTGRES_USER Closes #1301. --- docs/developing-locally-docker.rst | 3 +- .../.envs/.local/.postgres | 1 + .../.envs/.production/.postgres | 1 + .../compose/production/django/entrypoint.sh | 36 ++++++++++--------- 4 files changed, 23 insertions(+), 18 deletions(-) diff --git a/docs/developing-locally-docker.rst b/docs/developing-locally-docker.rst index 4dd6a443..f83baf81 100644 --- a/docs/developing-locally-docker.rst +++ b/docs/developing-locally-docker.rst @@ -113,10 +113,11 @@ Consider the aforementioned ``.envs/.local/.postgres``: :: # PostgreSQL # ------------------------------------------------------------------------------ + POSTGRES_DB= POSTGRES_USER=XgOWtQtJecsAbaIyslwGvFvPawftNaqO POSTGRES_PASSWORD=jSljDz4whHuwO3aJIgVBrqEml5Ycbghorep4uVJ4xjDYQu0LfuTZdctj7y0YcCLu -The two envs we are presented with here are ``POSTGRES_USER``, and ``POSTGRES_PASSWORD`` (by the way, their values have also been generated for you). You might have figured out already where these definitions will end up; it's all the same with ``django`` and ``caddy`` service container envs. +The three envs we are presented with here are ``POSTGRES_DB``, ``POSTGRES_USER``, and ``POSTGRES_PASSWORD`` (by the way, their values have also been generated for you). You might have figured out already where these definitions will end up; it's all the same with ``django`` and ``caddy`` service container envs. Tips & Tricks diff --git a/{{cookiecutter.project_slug}}/.envs/.local/.postgres b/{{cookiecutter.project_slug}}/.envs/.local/.postgres index b3da9842..87203da0 100644 --- a/{{cookiecutter.project_slug}}/.envs/.local/.postgres +++ b/{{cookiecutter.project_slug}}/.envs/.local/.postgres @@ -1,4 +1,5 @@ # PostgreSQL # ------------------------------------------------------------------------------ +POSTGRES_DB={{ cookiecutter.project_slug }} POSTGRES_USER=!!!SET POSTGRES_USER!!! POSTGRES_PASSWORD=!!!SET POSTGRES_PASSWORD!!! diff --git a/{{cookiecutter.project_slug}}/.envs/.production/.postgres b/{{cookiecutter.project_slug}}/.envs/.production/.postgres index b3da9842..87203da0 100644 --- a/{{cookiecutter.project_slug}}/.envs/.production/.postgres +++ b/{{cookiecutter.project_slug}}/.envs/.production/.postgres @@ -1,4 +1,5 @@ # PostgreSQL # ------------------------------------------------------------------------------ +POSTGRES_DB={{ cookiecutter.project_slug }} POSTGRES_USER=!!!SET POSTGRES_USER!!! POSTGRES_PASSWORD=!!!SET POSTGRES_PASSWORD!!! diff --git a/{{cookiecutter.project_slug}}/compose/production/django/entrypoint.sh b/{{cookiecutter.project_slug}}/compose/production/django/entrypoint.sh index a40a2b7e..b31581de 100644 --- a/{{cookiecutter.project_slug}}/compose/production/django/entrypoint.sh +++ b/{{cookiecutter.project_slug}}/compose/production/django/entrypoint.sh @@ -2,45 +2,47 @@ set -o errexit set -o pipefail - -# todo: turn on after #1295 -# set -o nounset +set -o nounset cmd="$@" -# This entrypoint is used to play nicely with the current cookiecutter configuration. -# Since docker-compose relies heavily on environment variables itself for configuration, we'd have to define multiple -# environment variables just to support cookiecutter out of the box. That makes no sense, so this little entrypoint -# does all this for us. export REDIS_URL=redis://redis:6379 +{%- if cookiecutter.use_celery == 'y' %} +export CELERY_BROKER_URL="${REDIS_URL}/0" +{%- endif %} -# the official postgres image uses 'postgres' as default user if not set explictly. -if [ -z "$POSTGRES_USER" ]; then +if [ -z "${POSTGRES_USER}" ]; then + # the official postgres image uses 'postgres' as default user if not set explictly. export POSTGRES_USER=postgres fi - -export DATABASE_URL=postgres://$POSTGRES_USER:$POSTGRES_PASSWORD@postgres:5432/$POSTGRES_USER -{% if cookiecutter.use_celery == 'y' %} -export CELERY_BROKER_URL=$REDIS_URL/0 -{% endif %} +export DATABASE_URL="postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}" postgres_ready() { python << END import sys + import psycopg2 + try: - conn = psycopg2.connect(dbname="$POSTGRES_USER", user="$POSTGRES_USER", password="$POSTGRES_PASSWORD", host="postgres") + psycopg2.connect( + dbname="${POSTGRES_DB}", + user="${POSTGRES_USER}", + password="${POSTGRES_PASSWORD}", + host="postgres" + ) except psycopg2.OperationalError: sys.exit(-1) sys.exit(0) + END } until postgres_ready; do - >&2 echo "Postgres is unavailable - sleeping" + >&2 echo 'PostgreSQL is unavailable (sleeping)...' sleep 1 done ->&2 echo "Postgres is up - continuing..." +>&2 echo 'PostgreSQL is up - continuing...' + exec $cmd From 03ee6c78d61d78e2e77e06376a14389856ef2b84 Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Thu, 8 Mar 2018 18:10:38 +0300 Subject: [PATCH 088/166] Fix CELERY_BROKER_URL overriden in entrypoint.sh Closes #1235. --- hooks/post_gen_project.py | 7 +++++++ .../.envs/.local/.celery | 3 +++ .../.envs/.production/.celery | 3 +++ .../compose/production/django/entrypoint.sh | 5 ----- {{cookiecutter.project_slug}}/local.yml | 20 +++++++++++++++---- .../merge_production_dotenvs_in_dotenv.py | 3 +++ {{cookiecutter.project_slug}}/production.yml | 15 ++++++++------ 7 files changed, 41 insertions(+), 15 deletions(-) create mode 100644 {{cookiecutter.project_slug}}/.envs/.local/.celery create mode 100644 {{cookiecutter.project_slug}}/.envs/.production/.celery diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py index af813e7d..0cd1a541 100644 --- a/hooks/post_gen_project.py +++ b/hooks/post_gen_project.py @@ -249,6 +249,11 @@ def remove_envs_and_associated_files(): os.remove('merge_production_dotenvs_in_dotenv.py') +def remove_celery_envs(): + os.remove(os.path.join('.envs', '.local', '.celery')) + os.remove(os.path.join('.envs', '.production', '.celery')) + + def main(): postgres_user = generate_postgres_user() set_flags_in_envs(postgres_user) @@ -311,6 +316,8 @@ def main(): if '{{ cookiecutter.use_celery }}'.lower() == 'n': remove_celery_app() + if '{{ cookiecutter.use_docker }}'.lower() == 'y': + remove_celery_envs() if '{{ cookiecutter.use_travisci }}'.lower() == 'n': remove_dottravisyml_file() diff --git a/{{cookiecutter.project_slug}}/.envs/.local/.celery b/{{cookiecutter.project_slug}}/.envs/.local/.celery new file mode 100644 index 00000000..f779a430 --- /dev/null +++ b/{{cookiecutter.project_slug}}/.envs/.local/.celery @@ -0,0 +1,3 @@ +# Celery +# ------------------------------------------------------------------------------ +CELERY_BROKER_URL=redis://redis:6379/0 diff --git a/{{cookiecutter.project_slug}}/.envs/.production/.celery b/{{cookiecutter.project_slug}}/.envs/.production/.celery new file mode 100644 index 00000000..f779a430 --- /dev/null +++ b/{{cookiecutter.project_slug}}/.envs/.production/.celery @@ -0,0 +1,3 @@ +# Celery +# ------------------------------------------------------------------------------ +CELERY_BROKER_URL=redis://redis:6379/0 diff --git a/{{cookiecutter.project_slug}}/compose/production/django/entrypoint.sh b/{{cookiecutter.project_slug}}/compose/production/django/entrypoint.sh index b31581de..19d2ad7b 100644 --- a/{{cookiecutter.project_slug}}/compose/production/django/entrypoint.sh +++ b/{{cookiecutter.project_slug}}/compose/production/django/entrypoint.sh @@ -7,11 +7,6 @@ set -o nounset cmd="$@" -export REDIS_URL=redis://redis:6379 -{%- if cookiecutter.use_celery == 'y' %} -export CELERY_BROKER_URL="${REDIS_URL}/0" -{%- endif %} - if [ -z "${POSTGRES_USER}" ]; then # the official postgres image uses 'postgres' as default user if not set explictly. export POSTGRES_USER=postgres diff --git a/{{cookiecutter.project_slug}}/local.yml b/{{cookiecutter.project_slug}}/local.yml index 8376c4a5..8c0e2e89 100644 --- a/{{cookiecutter.project_slug}}/local.yml +++ b/{{cookiecutter.project_slug}}/local.yml @@ -11,7 +11,7 @@ services: dockerfile: ./compose/local/django/Dockerfile depends_on: - postgres - {% if cookiecutter.use_mailhog == 'y' -%} + {%- if cookiecutter.use_mailhog == 'y' %} - mailhog {%- endif %} volumes: @@ -19,6 +19,9 @@ services: env_file: - ./.envs/.local/.django - ./.envs/.local/.postgres + {%- if cookiecutter.use_celery == 'y' %} + - ./.envs/.local/.celery + {%- endif %} ports: - "8000:8000" command: /start.sh @@ -32,12 +35,16 @@ services: - postgres_backup_local:/backups env_file: - ./.envs/.local/.postgres - {% if cookiecutter.use_mailhog == 'y' %} + {%- if cookiecutter.use_mailhog == 'y' %} + mailhog: image: mailhog/mailhog:v1.0.0 ports: - "8025:8025" - {% endif %}{% if cookiecutter.use_celery == 'y' %} + + {%- endif %} + {%- if cookiecutter.use_celery == 'y' %} + redis: image: redis:3.0 @@ -49,6 +56,8 @@ services: {% if cookiecutter.use_mailhog == 'y' -%} - mailhog {%- endif %} + env_file: + - ./.envs/.local/.celery ports: [] command: /start-celeryworker.sh @@ -60,6 +69,9 @@ services: {% if cookiecutter.use_mailhog == 'y' -%} - mailhog {%- endif %} + env_file: + - ./.envs/.local/.celery ports: [] command: /start-celerybeat.sh - {% endif %} + + {%- endif %} diff --git a/{{cookiecutter.project_slug}}/merge_production_dotenvs_in_dotenv.py b/{{cookiecutter.project_slug}}/merge_production_dotenvs_in_dotenv.py index c1bfe30a..fe4560ad 100644 --- a/{{cookiecutter.project_slug}}/merge_production_dotenvs_in_dotenv.py +++ b/{{cookiecutter.project_slug}}/merge_production_dotenvs_in_dotenv.py @@ -8,6 +8,9 @@ PRODUCTION_DOTENVS_DIR_PATH = os.path.join(ROOT_DIR_PATH, '.envs', '.production' PRODUCTION_DOTENV_FILE_PATHS = [ os.path.join(PRODUCTION_DOTENVS_DIR_PATH, '.django'), os.path.join(PRODUCTION_DOTENVS_DIR_PATH, '.postgres'), + {%- if cookiecutter.use_celery == 'y' %} + os.path.join(PRODUCTION_DOTENVS_DIR_PATH, '.celery'), + {%- endif %} os.path.join(PRODUCTION_DOTENVS_DIR_PATH, '.caddy'), ] DOTENV_FILE_PATH = os.path.join(ROOT_DIR_PATH, '.env') diff --git a/{{cookiecutter.project_slug}}/production.yml b/{{cookiecutter.project_slug}}/production.yml index 469903d9..c2b6fccf 100644 --- a/{{cookiecutter.project_slug}}/production.yml +++ b/{{cookiecutter.project_slug}}/production.yml @@ -16,6 +16,9 @@ services: env_file: - ./.envs/.production/.django - ./.envs/.production/.postgres + {%- if cookiecutter.use_celery == 'y' %} + - ./.envs/.production/.celery + {%- endif %} command: /gunicorn.sh postgres: @@ -44,15 +47,15 @@ services: redis: image: redis:3.0 - {% if cookiecutter.use_celery == 'y' %} + {%- if cookiecutter.use_celery == 'y' %} + celeryworker: <<: *django depends_on: - postgres - redis env_file: - - ./.envs/.production/.django - - ./.envs/.production/.postgres + - ./.envs/.production/.celery command: /start-celeryworker.sh celerybeat: @@ -61,7 +64,7 @@ services: - postgres - redis env_file: - - ./.envs/.production/.django - - ./.envs/.production/.postgres + - ./.envs/.production/.celery command: /start-celerybeat.sh - {% endif %} + + {%- endif %} From b15b63b67d8f68a9068cb7d47152c120d41f7c4f Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Thu, 8 Mar 2018 21:45:16 +0300 Subject: [PATCH 089/166] Put @webyneter's first and last names in the proper order --- CONTRIBUTORS.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTORS.rst b/CONTRIBUTORS.rst index 713e72cb..f0fcec39 100644 --- a/CONTRIBUTORS.rst +++ b/CONTRIBUTORS.rst @@ -16,7 +16,7 @@ Fábio C. Barrionuevo da Luz `@luzfcb`_ @luzfcb Saurabh Kumar `@theskumar`_ @_theskumar Jannis Gebauer `@jayfk`_ Burhan Khalid `@burhan`_ @burhan -Shupeyko Nikita `@webyneter`_ @webyneter +Nikita Shupeyko `@webyneter`_ @webyneter Bruno Alla               `@browniebroke`_ @_BrunoAlla =========================== ================ =========== From a72383a85123b2d35ce9419733c55ccba2bc846d Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Thu, 8 Mar 2018 22:40:22 +0300 Subject: [PATCH 090/166] FIx WEB_CONCURRENCY environment variable missing Fixes #1562. --- {{cookiecutter.project_slug}}/.envs/.production/.django | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/{{cookiecutter.project_slug}}/.envs/.production/.django b/{{cookiecutter.project_slug}}/.envs/.production/.django index c6def565..39bbaae4 100644 --- a/{{cookiecutter.project_slug}}/.envs/.production/.django +++ b/{{cookiecutter.project_slug}}/.envs/.production/.django @@ -30,7 +30,11 @@ DJANGO_ACCOUNT_ALLOW_REGISTRATION=True # django-compressor # ------------------------------------------------------------------------------ COMPRESS_ENABLED= -{% endif %}{% if cookiecutter.use_sentry_for_error_reporting == 'y' %} +{% endif %} +# Gunicorn +# ------------------------------------------------------------------------------ +WEB_CONCURRENCY=4 +{% if cookiecutter.use_sentry_for_error_reporting == 'y' %} # Sentry # ------------------------------------------------------------------------------ DJANGO_SENTRY_DSN= From f3dc7898e912a17c1db1556e34d66832c2c4e94b Mon Sep 17 00:00:00 2001 From: "pyup.io bot" Date: Fri, 9 Mar 2018 08:54:56 +0100 Subject: [PATCH 091/166] Update django-anymail from 1.4 to 2.0 (#1564) --- {{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 351c46ce..41649167 100644 --- a/{{cookiecutter.project_slug}}/requirements/production.txt +++ b/{{cookiecutter.project_slug}}/requirements/production.txt @@ -24,7 +24,7 @@ Collectfast==0.6.0 # Email backends for Mailgun, Postmark, SendGrid and more # ------------------------------------------------------- -django-anymail==1.4 +django-anymail==2.0 {% if cookiecutter.use_sentry_for_error_reporting == "y" -%} # Raven is the Sentry client From e1bce92ad98a10efdb542cb811ee08a611d78db0 Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Fri, 9 Mar 2018 11:40:52 +0300 Subject: [PATCH 092/166] apk add postgresql-client with django Dockerfile --- {{cookiecutter.project_slug}}/compose/local/django/Dockerfile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/{{cookiecutter.project_slug}}/compose/local/django/Dockerfile b/{{cookiecutter.project_slug}}/compose/local/django/Dockerfile index 383b1577..c4338109 100644 --- a/{{cookiecutter.project_slug}}/compose/local/django/Dockerfile +++ b/{{cookiecutter.project_slug}}/compose/local/django/Dockerfile @@ -11,7 +11,9 @@ RUN apk update \ # CFFI dependencies && apk add libffi-dev openssl-dev py-cffi \ # Translations dependencies - && apk add gettext + && apk add gettext \ + # https://docs.djangoproject.com/en/2.0/ref/django-admin/#dbshell + && apk add postgresql-client # Requirements have to be pulled and installed here, otherwise caching won't work COPY ./requirements /requirements From b2a6b9a511979448a3a86d4ec83f17518846e268 Mon Sep 17 00:00:00 2001 From: Nikita Shupeyko Date: Fri, 9 Mar 2018 12:57:32 +0300 Subject: [PATCH 093/166] Prettify generated project requirements (#1557) * Prettify base.txt * Prettify local.txt * Get rid of test.txt Rationale: it effectively a duplicate of what's in local.txt * Prettify production.txt --- .../requirements/base.txt | 79 +++++++------------ .../requirements/local.txt | 34 ++++---- .../requirements/production.txt | 50 ++++-------- .../requirements/test.txt | 18 ----- .../utility/install_python_dependencies.sh | 1 - 5 files changed, 64 insertions(+), 118 deletions(-) delete mode 100644 {{cookiecutter.project_slug}}/requirements/test.txt diff --git a/{{cookiecutter.project_slug}}/requirements/base.txt b/{{cookiecutter.project_slug}}/requirements/base.txt index 9cd9f30f..1f091295 100644 --- a/{{cookiecutter.project_slug}}/requirements/base.txt +++ b/{{cookiecutter.project_slug}}/requirements/base.txt @@ -1,54 +1,31 @@ -# Conservative Django -django==2.0.3 # pyup: < 2.1 - -# Configuration -django-environ==0.4.4 -{% if cookiecutter.use_whitenoise == 'y' -%} -whitenoise==3.3.1 +pytz==2018.3 # https://github.com/stub42/pytz +awesome-slugify==1.6.5 # https://github.com/dimka665/awesome-slugify +Pillow==5.0.0 # https://github.com/python-pillow/Pillow +{%- if cookiecutter.use_compressor == "y" %} +rcssmin==1.0.6{% if cookiecutter.windows == 'y' %} --install-option="--without-c-extensions"{% endif %} # https://github.com/ndparker/rcssmin +{%- endif %} +argon2-cffi==18.1.0 # https://github.com/hynek/argon2_cffi +{%- if cookiecutter.use_whitenoise == 'y' %} +whitenoise==3.3.1 # https://github.com/evansd/whitenoise +{%- endif %} +{%- if cookiecutter.windows == 'y' %} +# TODO: On Windows, install psycopg2 manually from http://www.lfd.uci.edu/~gohlke/pythonlibs/#psycopg +{%- else %} +psycopg2==2.7.4 --no-binary psycopg2 # https://github.com/psycopg/psycopg2 +{%- endif %} +redis>=2.10.5 # https://github.com/antirez/redis +{%- if cookiecutter.use_celery == "y" %} +celery==3.1.25 # pyup: <4.0 # https://github.com/celery/celery {%- endif %} - -# Forms -django-crispy-forms==1.7.1 - -# Models -django-model-utils==3.1.1 - -# Images -Pillow==5.0.0 - -# Password storage -argon2-cffi==18.1.0 - -# For user registration, either via email or social -# Well-built with regular release cycles! -django-allauth==0.35.0 - -{% if cookiecutter.windows == 'y' -%} -# On Windows, you must download/install psycopg2 manually -# from http://www.lfd.uci.edu/~gohlke/pythonlibs/#psycopg -{% else %} -# Python-PostgreSQL Database Adapter -psycopg2==2.7.4 --no-binary psycopg2 +# Django +# ------------------------------------------------------------------------------ +django==2.0.3 # pyup: < 2.1 # https://www.djangoproject.com/ +django-environ==0.4.4 # https://github.com/joke2k/django-environ +django-model-utils==3.1.1 # https://github.com/jazzband/django-model-utils +django-allauth==0.35.0 # https://github.com/pennersr/django-allauth +django-crispy-forms==1.7.1 # https://github.com/django-crispy-forms/django-crispy-forms +{%- if cookiecutter.use_compressor == "y" %} +django-compressor==2.2 # https://github.com/django-compressor/django-compressor {%- endif %} - -# Unicode slugification -awesome-slugify==1.6.5 - -# Time zones support -pytz==2018.3 - -# Redis support -django-redis==4.9.0 -redis>=2.10.5 - -{% if cookiecutter.use_celery == "y" %} -celery==3.1.25 # pyup: <4.0 -{% endif %} - -{% if cookiecutter.use_compressor == "y" %} -rcssmin==1.0.6 {% if cookiecutter.windows == 'y' %}--install-option="--without-c-extensions"{% endif %} -django-compressor==2.2 -{% endif %} - -# Your custom requirements go here +django-redis==4.9.0 # https://github.com/niwinz/django-redis diff --git a/{{cookiecutter.project_slug}}/requirements/local.txt b/{{cookiecutter.project_slug}}/requirements/local.txt index 3fb728fa..a40da042 100644 --- a/{{cookiecutter.project_slug}}/requirements/local.txt +++ b/{{cookiecutter.project_slug}}/requirements/local.txt @@ -1,19 +1,25 @@ -# Local development dependencies go here --r base.txt +-r ./base.txt -coverage==4.5.1 -django-coverage-plugin==1.5.0 +Werkzeug==0.14.1 # https://github.com/pallets/werkzeug +ipdb==0.11 # https://github.com/gotcha/ipdb +Sphinx==1.7.1 # https://github.com/sphinx-doc/sphinx -Sphinx==1.7.1 -django-extensions==2.0.3 -Werkzeug==0.14.1 -django-test-plus==1.0.22 -factory-boy==2.10.0 +# Testing +# ------------------------------------------------------------------------------ +pytest==3.4.2 # https://github.com/pytest-dev/pytest +pytest-sugar==0.9.1 # https://github.com/Frozenball/pytest-sugar -django-debug-toolbar==1.9.1 +# Code quality +# ------------------------------------------------------------------------------ +flake8==3.5.0 # https://github.com/PyCQA/flake8 +coverage==4.5.1 # https://github.com/nedbat/coveragepy -# improved REPL -ipdb==0.11 +# Django +# ------------------------------------------------------------------------------ +factory-boy==2.10.0 # https://github.com/FactoryBoy/factory_boy +django-test-plus==1.0.22 # https://github.com/revsys/django-test-plus -pytest-django==3.1.2 -pytest-sugar==0.9.1 +django-debug-toolbar==1.9.1 # https://github.com/jazzband/django-debug-toolbar +django-extensions==2.0.3 # https://github.com/django-extensions/django-extensions +django-coverage-plugin==1.5.0 # https://github.com/nedbat/django_coverage_plugin +pytest-django==3.1.2 # https://github.com/pytest-dev/pytest-django diff --git a/{{cookiecutter.project_slug}}/requirements/production.txt b/{{cookiecutter.project_slug}}/requirements/production.txt index 41649167..e605e220 100644 --- a/{{cookiecutter.project_slug}}/requirements/production.txt +++ b/{{cookiecutter.project_slug}}/requirements/production.txt @@ -1,39 +1,21 @@ -# Pro-tip: Try not to put anything here. Avoid dependencies in -# production that aren't in development. +# PRECAUTION: avoid production dependencies that aren't in development + -r base.txt -{% if cookiecutter.windows == 'y' -%} -# Python-PostgreSQL Database Adapter -# Assuming Windows is used locally, and *nix -- in production. -# ------------------------------------------------------------ -psycopg2==2.7.4 --no-binary psycopg2 -{%- endif %} - -# WSGI Handler -# ------------------------------------------------ gevent==1.2.2 -gunicorn==19.7.1 - -# Static and Media Storage -# ------------------------------------------------ -boto3==1.6.2 # pyup: update minor -django-storages==1.6.5 -{% if cookiecutter.use_whitenoise != 'y' -%} -Collectfast==0.6.0 +gunicorn==19.7.1 # https://github.com/benoitc/gunicorn +boto3==1.6.2 # pyup: update minor # https://github.com/boto/boto3 +{%- if cookiecutter.use_whitenoise == 'n' %} +Collectfast==0.6.0 # https://github.com/antonagestam/collectfast +{%- endif %} +{%- if cookiecutter.use_sentry_for_error_reporting == "y" %} +raven==6.6.0 # https://github.com/getsentry/raven-python +{%- endif %} +{%- if cookiecutter.use_opbeat == "y" %} +opbeat==3.6.1 # https://github.com/opbeat/opbeat_python {%- endif %} -# Email backends for Mailgun, Postmark, SendGrid and more -# ------------------------------------------------------- -django-anymail==2.0 - -{% if cookiecutter.use_sentry_for_error_reporting == "y" -%} -# Raven is the Sentry client -# -------------------------- -raven==6.6.0 -{%- endif %} - -{% if cookiecutter.use_opbeat == "y" -%} -# Opbeat agent for performance monitoring -# ----------------------------------------- -opbeat==3.6.1 -{%- endif %} +# Django +# ------------------------------------------------------------------------------ +django-storages==1.6.5 # https://github.com/jschneier/django-storages +django-anymail==2.0 # https://github.com/anymail/django-anymail diff --git a/{{cookiecutter.project_slug}}/requirements/test.txt b/{{cookiecutter.project_slug}}/requirements/test.txt deleted file mode 100644 index 2a6ed87f..00000000 --- a/{{cookiecutter.project_slug}}/requirements/test.txt +++ /dev/null @@ -1,18 +0,0 @@ -# Test dependencies go here. --r base.txt - -{% if cookiecutter.windows == 'y' -%} -# Python-PostgreSQL Database Adapter -# If using Win for dev, this assumes Unix in test/prod -psycopg2==2.7.4 -{%- endif %} - -coverage==4.5.1 -flake8==3.5.0 # pyup: != 2.6.0 -django-test-plus==1.0.22 -factory-boy==2.10.0 -django-coverage-plugin==1.5.0 - -# pytest -pytest-django==3.1.2 -pytest-sugar==0.9.1 diff --git a/{{cookiecutter.project_slug}}/utility/install_python_dependencies.sh b/{{cookiecutter.project_slug}}/utility/install_python_dependencies.sh index c28b5b89..51793484 100755 --- a/{{cookiecutter.project_slug}}/utility/install_python_dependencies.sh +++ b/{{cookiecutter.project_slug}}/utility/install_python_dependencies.sh @@ -35,7 +35,6 @@ if [ -z "$VIRTUAL_ENV" ]; then else pip install -r $PROJECT_DIR/requirements/local.txt - pip install -r $PROJECT_DIR/requirements/test.txt {% if cookiecutter.use_heroku == "y" -%} pip install -r $PROJECT_DIR/requirements.txt {%- endif %} From 3e2bf3f701d4becba4383303c910434bb98f0d02 Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Fri, 9 Mar 2018 13:06:45 +0300 Subject: [PATCH 094/166] Prettify template's pytest.ini --- {{cookiecutter.project_slug}}/pytest.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/{{cookiecutter.project_slug}}/pytest.ini b/{{cookiecutter.project_slug}}/pytest.ini index 89c5e63f..690c78f1 100644 --- a/{{cookiecutter.project_slug}}/pytest.ini +++ b/{{cookiecutter.project_slug}}/pytest.ini @@ -1,5 +1,5 @@ [pytest] DJANGO_SETTINGS_MODULE=config.settings.test -{% if cookiecutter.js_task_runner != 'None' %} +{%- if cookiecutter.js_task_runner != 'None' %} norecursedirs = node_modules -{% endif %} +{%- endif %} From 9cd0ee0272f99e2e2619d98c1cb975a74a557400 Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Fri, 9 Mar 2018 13:16:47 +0300 Subject: [PATCH 095/166] Document merge_production_dotenvs_in_dotenv.py usage --- docs/developing-locally-docker.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/developing-locally-docker.rst b/docs/developing-locally-docker.rst index f83baf81..7cbf9ae9 100644 --- a/docs/developing-locally-docker.rst +++ b/docs/developing-locally-docker.rst @@ -119,6 +119,12 @@ Consider the aforementioned ``.envs/.local/.postgres``: :: The three envs we are presented with here are ``POSTGRES_DB``, ``POSTGRES_USER``, and ``POSTGRES_PASSWORD`` (by the way, their values have also been generated for you). You might have figured out already where these definitions will end up; it's all the same with ``django`` and ``caddy`` service container envs. +One final touch: should you ever need to merge ``.envs/production/*`` in a single ``.env`` run the ``merge_production_dotenvs_in_dotenv.py``: :: + + $ python merge_production_dotenvs_in_dotenv.py + +The ``.env`` file will then be created, with all your production envs residing beside each other. + Tips & Tricks ------------- From 57761e77b3638eb2245816ea0940f14ae21bd3d0 Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Fri, 9 Mar 2018 17:36:11 +0300 Subject: [PATCH 096/166] Fix .envs in template's .gitignore Fix #1565. --- 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 0cd1a541..4c987cd1 100644 --- a/hooks/post_gen_project.py +++ b/hooks/post_gen_project.py @@ -285,7 +285,7 @@ def main(): remove_envs_and_associated_files() else: append_to_gitignore_file('.env') - append_to_gitignore_file('.envs' + '/**/*') + append_to_gitignore_file('.envs/*') if '{{ cookiecutter.keep_local_envs_in_vcs }}'.lower() == 'y': append_to_gitignore_file('!.envs/.local/') From 05e97777e23f9fdb0bb55892a8bcb8ac05ac4434 Mon Sep 17 00:00:00 2001 From: "pyup.io bot" Date: Fri, 9 Mar 2018 17:21:40 +0100 Subject: [PATCH 097/166] Update django-crispy-forms from 1.7.1 to 1.7.2 (#1567) --- {{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 1f091295..4b2ac77f 100644 --- a/{{cookiecutter.project_slug}}/requirements/base.txt +++ b/{{cookiecutter.project_slug}}/requirements/base.txt @@ -24,7 +24,7 @@ django==2.0.3 # pyup: < 2.1 # https://www.djangoproject.com/ django-environ==0.4.4 # https://github.com/joke2k/django-environ django-model-utils==3.1.1 # https://github.com/jazzband/django-model-utils django-allauth==0.35.0 # https://github.com/pennersr/django-allauth -django-crispy-forms==1.7.1 # https://github.com/django-crispy-forms/django-crispy-forms +django-crispy-forms==1.7.2 # https://github.com/django-crispy-forms/django-crispy-forms {%- if cookiecutter.use_compressor == "y" %} django-compressor==2.2 # https://github.com/django-compressor/django-compressor {%- endif %} From a31f5090d1e7fa2d3c7c34d00a92ea14cb2167dd Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Fri, 9 Mar 2018 21:17:56 +0300 Subject: [PATCH 098/166] Update the docs --- docs/deployment-with-docker.rst | 88 ++++++++-------- docs/developing-locally-docker.rst | 2 + docs/developing-locally.rst | 100 ++++++++++++------- docs/live-reloading-and-sass-compilation.rst | 4 +- 4 files changed, 105 insertions(+), 89 deletions(-) diff --git a/docs/deployment-with-docker.rst b/docs/deployment-with-docker.rst index 9e9d635e..90f2fa5c 100644 --- a/docs/deployment-with-docker.rst +++ b/docs/deployment-with-docker.rst @@ -1,72 +1,66 @@ Deployment with Docker ====================== -.. index:: Docker, deployment +.. index:: deployment, docker, docker-compose, compose + Prerequisites ------------- -* Docker (at least 1.10) -* Docker Compose (at least 1.6) +* Docker 1.10+. +* Docker Compose 1.6+ -Understand the Compose Setup ----------------------------- -Before you start, check out the `production.yml` file in the root of this project. This is where each component -of this application gets its configuration from. Notice how it provides configuration for these services: +Understanding the Docker Compose Setup +-------------------------------------- -* `postgres` service that runs the database -* `redis` for caching -* `caddy` as webserver -* `django` is the Django project run by gunicorn +Before you begin, check out the ``production.yml`` file in the root of this project. Keep note of how it provides configuration for the following services: -If you chose the `use_celery` option, there are two more services: +* ``django``: your application running behind ``Gunicorn``; +* ``postgres``: PostgreSQL database with the application's relational data; +* ``redis``: Redis instance for caching; +* ``caddy``: Caddy web server with HTTPS on by default. -* `celeryworker` which runs the celery worker process -* `celerybeat` which runs the celery beat process +Provided you have opted for Celery (via setting ``use_celery`` to ``y``) there are two more services: -Populate .env With Your Environment Variables ---------------------------------------------- +* ``celeryworker`` running a Celery worker process; +* ``celerybeat`` running a Celery beat process. -Some of these services rely on environment variables set by you. There is an `env.example` file in the -root directory of this project as a starting point. Add your own variables to the file and rename it to `.env`. This -file won't be tracked by git by default so you'll have to make sure to use some other mechanism to copy your secret if -you are relying solely on git. -It is **highly recommended** that before you build your production application, you set your POSTGRES_USER value here. This will create a non-default user for the postgres image. If you do not set this user before building the application, the default user 'postgres' will be created, and this user will not be able to create or restore backups. +Configuring the Stack +--------------------- -To obtain logs and information about crashes in a production setup, make sure that you have access to an external Sentry instance (e.g. by creating an account with `sentry.io`_), and set the `DJANGO_SENTRY_DSN` variable. This should be enough to report crashes to Sentry. +The majority of services above are configured through the use of environment variables. Just check out :ref:`envs` and you will know the drill. + +To obtain logs and information about crashes in a production setup, make sure that you have access to an external Sentry instance (e.g. by creating an account with `sentry.io`_), and set the ``DJANGO_SENTRY_DSN`` variable. You will probably also need to setup the Mail backend, for example by adding a `Mailgun`_ API key and a `Mailgun`_ sender domain, otherwise, the account creation view will crash and result in a 500 error when the backend attempts to send an email to the account owner. .. _sentry.io: https://sentry.io/welcome .. _Mailgun: https://mailgun.com + Optional: Use AWS IAM Role for EC2 instance ------------------------------------- -If you are deploying to AWS, you can use the IAM role to substitute AWS credentials, after which it's safe to remove the `AWS_ACCESS_KEY_ID` AND `AWS_SECRET_ACCESS_KEY` from 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`. +------------------------------------------- + +If you are deploying to AWS, you can use the IAM role to substitute AWS credentials, after which it's safe to remove the ``AWS_ACCESS_KEY_ID`` AND ``AWS_SECRET_ACCESS_KEY`` from ``.envs/.production/.django``. To do it, create an `IAM role`_ and `attach`_ it to the existing EC2 instance or create a new EC2 instance with that role. The role should assume, at minimum, the ``AmazonS3FullAccess`` permission. .. _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 + +HTTPS is On by Default ---------------------- SSL (Secure Sockets Layer) is a standard security technology for establishing an encrypted link between a server and a client, typically in this case, a web server (website) and a browser. Not having HTTPS means that malicious network users can sniff authentication credentials between your website and end users' browser. It is always better to deploy a site behind HTTPS and will become crucial as the web services extend to the IoT (Internet of Things). For this reason, we have set up a number of security defaults to help make your website secure: -* In the `.env.example`, we have made it simpler for you to change the default `Django Admin` into a custom name through an environmental variable. This should make it harder to guess the access to the admin panel. - -* If you are not using a subdomain of the domain name set in the project, then remember to put the your staging/production IP address in the :code:`DJANGO_ALLOWED_HOSTS` environment variable (see :ref:`settings`) before you deploy your website. Failure to do this will mean you will not have access to your website through the HTTP protocol. +* If you are not using a subdomain of the domain name set in the project, then remember to put the your staging/production IP address in the ``DJANGO_ALLOWED_HOSTS`` environment variable (see :ref:`settings`) before you deploy your website. Failure to do this will mean you will not have access to your website through the HTTP protocol. * Access to the Django admin is set up by default to require HTTPS in production or once *live*. - -HTTPS is configured by default ------------------------------- - -The Caddy webserver used in the default configuration will get you a valid certificate from Lets Encrypt and update it automatically. All you need to do to enable this is to make sure that your DNS records are pointing to the server Caddy runs on. +The Caddy web server used in the default configuration will get you a valid certificate from Lets Encrypt and update it automatically. All you need to do to enable this is to make sure that your DNS records are pointing to the server Caddy runs on. You can read more about this here at `Automatic HTTPS`_ in the Caddy docs. @@ -76,15 +70,13 @@ You can read more about this here at `Automatic HTTPS`_ in the Caddy docs. (Optional) Postgres Data Volume Modifications --------------------------------------------- -Postgres is saving its database files to the `postgres_data` volume by default. Change that if you want something else and make sure to make backups since this is not done automatically. +Postgres is saving its database files to the ``postgres_data`` volume by default. Change that if you want something else and make sure to make backups since this is not done automatically. -Run your app with Docker Compose --------------------------------- -To get started, pull your code from source control (don't forget the `.env` file) and change to your projects root -directory. +Building & Running Production Stack +----------------------------------- -You'll need to build the stack first. To do that, run:: +You will need to build the stack first. To do that, run:: docker-compose -f production.yml build @@ -104,9 +96,7 @@ If you need a shell, run:: docker-compose -f production.yml run --rm django python manage.py shell -To get an output of all running containers. - -To check your logs, run:: +To check the logs out, run:: docker-compose -f production.yml logs @@ -115,21 +105,21 @@ If you want to scale your application, run:: docker-compose -f production.yml scale django=4 docker-compose -f production.yml scale celeryworker=2 -.. warning:: Don't run the scale command on postgres, celerybeat, or caddy. +.. warning:: don't try to scale ``postgres``, ``celerybeat``, or ``caddy``. -If you have errors, you can always check your stack with `docker-compose`. Switch to your projects root directory and run:: +To see how your containers are doing run:: docker-compose -f production.yml ps -Supervisor Example +Example: Supervisor ------------------- Once you are ready with your initial setup, you want to make sure that your application is run by a process manager to survive reboots and auto restarts in case of an error. You can use the process manager you are most familiar with. All -it needs to do is to run `docker-compose -f production.yml up` in your projects root directory. +it needs to do is to run ``docker-compose -f production.yml up`` in your projects root directory. -If you are using `supervisor`, you can use this file as a starting point:: +If you are using ``supervisor``, you can use this file as a starting point:: [program:{{cookiecutter.project_slug}}] command=docker-compose -f production.yml up @@ -139,11 +129,11 @@ If you are using `supervisor`, you can use this file as a starting point:: autorestart=true priority=10 -Place it in `/etc/supervisor/conf.d/{{cookiecutter.project_slug}}.conf` and run:: +Move it to ``/etc/supervisor/conf.d/{{cookiecutter.project_slug}}.conf`` and run:: supervisorctl reread supervisorctl start {{cookiecutter.project_slug}} -To get the status, run:: +For status check, run:: supervisorctl status diff --git a/docs/developing-locally-docker.rst b/docs/developing-locally-docker.rst index 7cbf9ae9..86808bfd 100644 --- a/docs/developing-locally-docker.rst +++ b/docs/developing-locally-docker.rst @@ -77,6 +77,8 @@ Here, ``django`` is the target service we are executing the commands against. When ``DEBUG`` is set to ``True``, the host is validated against ``['localhost', '127.0.0.1', '[::1]']``. This is adequate when running a ``virtualenv``. For Docker, in the ``config.settings.local``, add your host development server IP to ``INTERNAL_IPS`` or ``ALLOWED_HOSTS`` if the variable exists. +.. _envs: + Configuring the Environment --------------------------- diff --git a/docs/developing-locally.rst b/docs/developing-locally.rst index 8aae8f0b..7885f45e 100644 --- a/docs/developing-locally.rst +++ b/docs/developing-locally.rst @@ -3,74 +3,98 @@ Getting Up and Running Locally .. index:: pip, virtualenv, PostgreSQL -The steps below will get you up and running with a local development environment. We assume you have the following installed: -* pip -* virtualenv -* PostgreSQL +Setting Up Development Environment +---------------------------------- -First make sure to create and activate a virtualenv_. +Make sure to have the following on your host: -.. _virtualenv: http://docs.python-guide.org/en/latest/dev/virtualenvs/ +* virtualenv_; +* pip; +* PostgreSQL. -Then install the requirements for your local development:: +First things first. + +#. `Create a virtualenv`_. + +#. Activate the virtualenv you have just created. + +#. Install development requirements: :: $ pip install -r requirements/local.txt -Then, create a PostgreSQL database with the following command, where `[project_slug]` is what value you entered for your project's `project_slug`:: +#. Create a new PostgreSQL database (note: if this is the first time a database is created on your machine you might need to alter a localhost-related entry in your ``pg_hba.conf`` so as to utilize ``trust`` policy): :: - $ createdb [project_slug] + $ createdb -You can now run the usual Django ``migrate`` and ``runserver`` commands:: +#. Apply migrations: :: $ python manage.py migrate - $ python manage.py runserver -At this point you can take a break from setup and start getting to know the files in the project. +#. See the application being served through Django development server: :: -But if you want to go further with setup, read on. + $ python manage.py runserver 0.0.0.0:8000 -(Note: the following sections still need to be revised) +.. _virtualenv: http://docs.python-guide.org/en/latest/dev/virtualenvs/ +.. _`Create a virtualenv`: https://virtualenv.pypa.io/en/stable/userguide/ -Setting Up Env Vars for Production ------------------------------------ -`Cookiecutter Django` uses the excellent `django-environ`_ package, which includes a ``DATABASE_URL`` environment variable to simplify database configuration in your Django settings. +Setup Email Backend +------------------- -Rename env.example to .env to begin updating the file with your own environment variables. To add your database, define ``DATABASE_URL`` and add it to the .env file, as shown below: +MailHog +~~~~~~~ -.. parsed-literal:: +.. note:: In order for the project to support MailHog_ it must have been bootstrapped with ``use_mailhog`` set to ``y``. - DATABASE_URL="postgres://**:**\ @127.0.0.1:\ **/**" +MailHog is used to receive emails during development, it is written in Go and has no external dependencies. -.. _django-environ: http://django-environ.readthedocs.io +For instance, one of the packages we depend upon, ``django-allauth`` sends verification emails to new users signing up as well as to the existing ones who have not yet verified themselves. -Setup your email backend -------------------------- +#. `Download the latest MailHog release`_ for your OS. -django-allauth sends an email to verify users (and superusers) after signup and login (if they are still not verified). To send email you need to `configure your email backend`_ +#. Rename the build to ``MailHog``. -.. _configure your email backend: https://docs.djangoproject.com/en/dev/topics/email/#smtp-backend +#. Copy the file to the project root. -In development you can (optionally) use MailHog_ for email testing. MailHog is built with Go so there are no dependencies. To use MailHog: +#. Make it executable: :: -1. `Download the latest release`_ for your operating system -2. Rename the executable to ``mailhog`` and copy it to the root of your project directory -3. Make sure it is executable (e.g. ``chmod +x mailhog``) -4. Execute mailhog from the root of your project in a new terminal window (e.g. ``./mailhog``) -5. All emails generated from your django app can be seen on http://127.0.0.1:8025/ + $ chmod +x MailHog -.. _Mailhog: https://github.com/mailhog/MailHog/ -.. _Download the latest release: https://github.com/mailhog/MailHog/releases +#. Spin up another terminal window and start it there: :: -Alternatively simply output emails to the console via: ``EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'`` + ./MailHog -In production basic email configuration is setup to send emails with Mailgun_ +#. Check out ``_ to see how it goes. + +Now you have your own mail server running locally, ready to receive whatever you send it. + +.. _MailHog: https://github.com/mailhog/MailHog/ +.. _`properly configured`: https://docs.djangoproject.com/en/dev/topics/email/#smtp-backend + + +Console +~~~~~~~ + +.. note:: If you have generated your project with ``use_mailhog`` set to ``n`` this will be a default setup. + +Alternatively, deliver emails over console via ``EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'``. + +In production, we have Mailgun_ configured to have your back! .. _Mailgun: https://www.mailgun.com/ -**Live reloading and Sass CSS compilation** -If you’d like to take advantage of live reloading and Sass / Compass CSS compilation you can do so with a little bit of `prep work`_. +Sass Compilation & Live Reloading +--------------------------------- -.. _prep work: https://cookiecutter-django.readthedocs.io/en/latest/live-reloading-and-sass-compilation.html +If you’d like to take advantage of live reloading and Sass / Compass CSS compilation you can do so with a little bit of preparation_. + +.. _`Download the latest MailHog release`: https://github.com/mailhog/MailHog/releases +.. _preparation: https://cookiecutter-django.readthedocs.io/en/latest/live-reloading-and-sass-compilation.html + + +Summary +------- + +Congratulations, you have made it! Keep on reading to unleash full potential of Cookiecutter Django. diff --git a/docs/live-reloading-and-sass-compilation.rst b/docs/live-reloading-and-sass-compilation.rst index a456b81a..e2007cb0 100644 --- a/docs/live-reloading-and-sass-compilation.rst +++ b/docs/live-reloading-and-sass-compilation.rst @@ -1,5 +1,5 @@ -Live reloading and Sass CSS compilation -======================================= +Sass Compilation & Live Reloading +================================= If you'd like to take advantage of live reloading and Sass / Compass CSS compilation you can do so with a little bit of prep work. From 09af25547bd0e384b9edea89d5165f3e947009b3 Mon Sep 17 00:00:00 2001 From: "pyup.io bot" Date: Sun, 11 Mar 2018 09:33:10 +0100 Subject: [PATCH 099/166] Update django-extensions from 2.0.3 to 2.0.5 (#1568) --- {{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 a40da042..6b6323d4 100644 --- a/{{cookiecutter.project_slug}}/requirements/local.txt +++ b/{{cookiecutter.project_slug}}/requirements/local.txt @@ -20,6 +20,6 @@ factory-boy==2.10.0 # https://github.com/FactoryBoy/factory_boy django-test-plus==1.0.22 # https://github.com/revsys/django-test-plus django-debug-toolbar==1.9.1 # https://github.com/jazzband/django-debug-toolbar -django-extensions==2.0.3 # https://github.com/django-extensions/django-extensions +django-extensions==2.0.5 # https://github.com/django-extensions/django-extensions django-coverage-plugin==1.5.0 # https://github.com/nedbat/django_coverage_plugin pytest-django==3.1.2 # https://github.com/pytest-dev/pytest-django From edef0167fe3cbf0e402be9972ed4f3a04ecc6ec5 Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Sun, 11 Mar 2018 12:21:49 +0300 Subject: [PATCH 100/166] Gitignore MailHog in template --- {{cookiecutter.project_slug}}/.gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/{{cookiecutter.project_slug}}/.gitignore b/{{cookiecutter.project_slug}}/.gitignore index 207d2044..52e8c444 100644 --- a/{{cookiecutter.project_slug}}/.gitignore +++ b/{{cookiecutter.project_slug}}/.gitignore @@ -338,7 +338,7 @@ pip-selfcheck.json {% if cookiecutter.use_mailhog == 'y' and cookiecutter.use_docker == 'n' -%} -mailhog +MailHog {% endif %} {{ cookiecutter.project_slug }}/media/ From c06ce847b36e1762cdd6c1556798aa5e05652c50 Mon Sep 17 00:00:00 2001 From: Daniel Roy Greenfeld Date: Tue, 13 Mar 2018 22:13:36 -0500 Subject: [PATCH 101/166] Added DRF --- {{cookiecutter.project_slug}}/requirements/base.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/{{cookiecutter.project_slug}}/requirements/base.txt b/{{cookiecutter.project_slug}}/requirements/base.txt index 4b2ac77f..0df716ad 100644 --- a/{{cookiecutter.project_slug}}/requirements/base.txt +++ b/{{cookiecutter.project_slug}}/requirements/base.txt @@ -1,3 +1,4 @@ +djangorestframework==3.7.7 # https://github.com/encode/django-rest-framework pytz==2018.3 # https://github.com/stub42/pytz awesome-slugify==1.6.5 # https://github.com/dimka665/awesome-slugify Pillow==5.0.0 # https://github.com/python-pillow/Pillow From 19501ef26bc23ecb2a9502cf8bb4d89e81d1928d Mon Sep 17 00:00:00 2001 From: Daniel Roy Greenfeld Date: Tue, 13 Mar 2018 22:17:46 -0500 Subject: [PATCH 102/166] Adding DRF --- {{cookiecutter.project_slug}}/config/settings/base.py | 1 + 1 file changed, 1 insertion(+) diff --git a/{{cookiecutter.project_slug}}/config/settings/base.py b/{{cookiecutter.project_slug}}/config/settings/base.py index 3df64355..5b2cb7ba 100644 --- a/{{cookiecutter.project_slug}}/config/settings/base.py +++ b/{{cookiecutter.project_slug}}/config/settings/base.py @@ -73,6 +73,7 @@ THIRD_PARTY_APPS = [ 'allauth', 'allauth.account', 'allauth.socialaccount', + 'rest_framework', ] LOCAL_APPS = [ '{{ cookiecutter.project_slug }}.users.apps.UsersConfig', From b32fd78012f7f774a71c5ebe035540497f202f44 Mon Sep 17 00:00:00 2001 From: Daniel Roy Greenfeld Date: Tue, 13 Mar 2018 22:21:01 -0500 Subject: [PATCH 103/166] Update base.py --- {{cookiecutter.project_slug}}/config/settings/base.py | 1 - 1 file changed, 1 deletion(-) diff --git a/{{cookiecutter.project_slug}}/config/settings/base.py b/{{cookiecutter.project_slug}}/config/settings/base.py index 5b2cb7ba..7167d6f2 100644 --- a/{{cookiecutter.project_slug}}/config/settings/base.py +++ b/{{cookiecutter.project_slug}}/config/settings/base.py @@ -69,7 +69,6 @@ DJANGO_APPS = [ ] THIRD_PARTY_APPS = [ 'crispy_forms', - 'allauth', 'allauth.account', 'allauth.socialaccount', From bcd0a8c46eef3faa877d810e530e29f321f6b7bc Mon Sep 17 00:00:00 2001 From: Nikita Shupeyko Date: Wed, 14 Mar 2018 13:44:16 +0300 Subject: [PATCH 104/166] Fix & improve PostgreSQL backup/restore scripts (#1571) * Fix & imporve postgres backup/restore scripts * Update PostgreSQL backup/restore docs * Fix postgres Dockerfile regression * Extend error messages in PostgreSQL maintenance scipts --- docs/docker-postgres-backups.rst | 93 ++++++++++++++----- .../compose/production/postgres/Dockerfile | 12 +-- .../compose/production/postgres/backup.sh | 25 ----- .../production/postgres/list-backups.sh | 10 -- .../maintenance/_sourced/constants.sh | 5 + .../maintenance/_sourced/countdown.sh | 12 +++ .../postgres/maintenance/_sourced/messages.sh | 41 ++++++++ .../postgres/maintenance/_sourced/yes_no.sh | 16 ++++ .../production/postgres/maintenance/backup | 38 ++++++++ .../production/postgres/maintenance/backups | 22 +++++ .../production/postgres/maintenance/restore | 76 +++++++++++++++ .../compose/production/postgres/restore.sh | 58 ------------ 12 files changed, 286 insertions(+), 122 deletions(-) delete mode 100644 {{cookiecutter.project_slug}}/compose/production/postgres/backup.sh delete mode 100644 {{cookiecutter.project_slug}}/compose/production/postgres/list-backups.sh create mode 100644 {{cookiecutter.project_slug}}/compose/production/postgres/maintenance/_sourced/constants.sh create mode 100644 {{cookiecutter.project_slug}}/compose/production/postgres/maintenance/_sourced/countdown.sh create mode 100644 {{cookiecutter.project_slug}}/compose/production/postgres/maintenance/_sourced/messages.sh create mode 100644 {{cookiecutter.project_slug}}/compose/production/postgres/maintenance/_sourced/yes_no.sh create mode 100644 {{cookiecutter.project_slug}}/compose/production/postgres/maintenance/backup create mode 100644 {{cookiecutter.project_slug}}/compose/production/postgres/maintenance/backups create mode 100644 {{cookiecutter.project_slug}}/compose/production/postgres/maintenance/restore delete mode 100644 {{cookiecutter.project_slug}}/compose/production/postgres/restore.sh diff --git a/docs/docker-postgres-backups.rst b/docs/docker-postgres-backups.rst index d0ad1a52..112b612b 100644 --- a/docs/docker-postgres-backups.rst +++ b/docs/docker-postgres-backups.rst @@ -1,40 +1,91 @@ -============================ -Database Backups with Docker -============================ +PostgreSQL Backups with Docker +============================== -The database has to be running to create/restore a backup. These examples show local examples. If you want to use it on a remote server, use ``-f production.yml`` instead. +Prerequisites: -Running Backups -================ +#. the project was generated with ``use_docker`` set to ``y``. -Run the app with `docker-compose -f local.yml up`. +For brevity it is assumed that will be running the below commands against local environment, however, this is by no means mandatory so feel free switching to ``production.yml`` when needed. + +Note that the application stack should not necessarily be running when applying any of the instructions below, unless explicitly stated otherwise. For instance, suppose the stack has been down for quite some time or have never even been up yet -- rather than starting it beforehand use a single ``$ docker-compose -f local.yml run --rm `` with the desired command. By contrast, should you already have your application up and running do not bother waiting for ``run`` instruction to finish (they usually take a bit longer due to bootstrapping phase), just use ``$ docker-compose -f local.yml exec `` instead; note that any ``exec`` command fails unless all of the required containers are running. From now on, we will be using ``run``-style examples for general-case compatibility. + + +Creating a Backup +----------------- To create a backup, run:: - docker-compose -f local.yml run --rm postgres backup + $ docker-compose -f local.yml run --rm postgres backup + +Assuming your project's database is named ``my_project`` here is what you will see: :: + + Backing up the 'my_project' database... + SUCCESS: 'my_project' database backup 'backup_2018_03_13T09_05_07.sql.gz' has been created and placed in '/backups'. + +Keep in mind that ``/backups`` is the ``postgres`` container directory. -To list backups, run:: +Viewing the Existing Backups +---------------------------- - docker-compose -f local.yml run --rm postgres list-backups +To list existing backups, :: + + $ docker-compose -f local.yml run --rm postgres backups + +These are the sample contents of ``/backups``: :: + + These are the backups you have got: + total 24K + -rw-r--r-- 1 root root 5.2K Mar 13 09:05 backup_2018_03_13T09_05_07.sql.gz + -rw-r--r-- 1 root root 5.2K Mar 12 21:13 backup_2018_03_12T21_13_03.sql.gz + -rw-r--r-- 1 root root 5.2K Mar 12 21:12 backup_2018_03_12T21_12_58.sql.gz -To restore a backup, run:: +Copying Backups Locally +----------------------- - docker-compose -f local.yml run --rm postgres restore filename.sql +If you want to copy backups from your ``postgres`` container locally, ``docker cp`` command_ will help you on that. -Where is the ID of the Postgres container. To get it, run:: +For example, given ``9c5c3f055843`` is the container ID copying all the backups over to a local directory is as simple as :: - docker ps + $ docker cp 9c5c3f055843:/backups ./backups -To copy the files from the running Postgres container to the host system:: +With a single backup file copied to ``.`` that would be :: - docker cp :/backups /host/path/target + $ docker cp 9c5c3f055843:/backups/backup_2018_03_13T09_05_07.sql.gz . -Restoring From Backups -====================== +.. _`command`: https://docs.docker.com/engine/reference/commandline/cp/ -To restore the production database to a local PostgreSQL database:: - createdb NAME_OF_DATABASE - psql NAME_OF_DATABASE < NAME_OF_BACKUP_FILE +Restoring from the Existing Backup +---------------------------------- + +To restore from one of the backups you have already got (take the ``backup_2018_03_13T09_05_07.sql.gz`` for example), :: + + $ docker-compose -f local.yml run --rm postgres restore backup_2018_03_13T09_05_07.sql.gz + +You will see something like :: + + Restoring the 'my_project' database from the '/backups/backup_2018_03_13T09_05_07.sql.gz' backup... + INFO: Dropping all connections to the database... + pg_terminate_backend + ---------------------- + (0 rows) + + INFO: Dropping the database... + INFO: Creating a new database... + INFO: Applying the backup to the new database... + SET + SET + SET + SET + SET + set_config + ------------ + + (1 row) + + SET + # ... + ALTER TABLE + SUCCESS: The 'my_project' database has been restored from the '/backups/backup_2018_03_13T09_05_07.sql.gz' backup. diff --git a/{{cookiecutter.project_slug}}/compose/production/postgres/Dockerfile b/{{cookiecutter.project_slug}}/compose/production/postgres/Dockerfile index 84164d0b..eca29bad 100644 --- a/{{cookiecutter.project_slug}}/compose/production/postgres/Dockerfile +++ b/{{cookiecutter.project_slug}}/compose/production/postgres/Dockerfile @@ -1,10 +1,6 @@ FROM postgres:{{ cookiecutter.postgresql_version }} -COPY ./compose/production/postgres/backup.sh /usr/local/bin/backup -RUN chmod +x /usr/local/bin/backup - -COPY ./compose/production/postgres/restore.sh /usr/local/bin/restore -RUN chmod +x /usr/local/bin/restore - -COPY ./compose/production/postgres/list-backups.sh /usr/local/bin/list-backups -RUN chmod +x /usr/local/bin/list-backups +COPY ./compose/production/postgres/maintenance /usr/local/bin/maintenance +RUN chmod +x /usr/local/bin/maintenance/* +RUN mv /usr/local/bin/maintenance/* /usr/local/bin \ + && rmdir /usr/local/bin/maintenance diff --git a/{{cookiecutter.project_slug}}/compose/production/postgres/backup.sh b/{{cookiecutter.project_slug}}/compose/production/postgres/backup.sh deleted file mode 100644 index 46438011..00000000 --- a/{{cookiecutter.project_slug}}/compose/production/postgres/backup.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env bash - -set -o errexit -set -o pipefail -set -o nounset - - -# we might run into trouble when using the default `postgres` user, e.g. when dropping the postgres -# database in restore.sh. Check that something else is used here -if [ "$POSTGRES_USER" == "postgres" ] -then - echo "creating a backup as the postgres user is not supported, make sure to set the POSTGRES_USER environment variable" - exit 1 -fi - -# export the postgres password so that subsequent commands don't ask for it -export PGPASSWORD=$POSTGRES_PASSWORD - -echo "creating backup" -echo "---------------" - -FILENAME=backup_$(date +'%Y_%m_%dT%H_%M_%S').sql.gz -pg_dump -h postgres -U $POSTGRES_USER | gzip > /backups/$FILENAME - -echo "successfully created backup $FILENAME" diff --git a/{{cookiecutter.project_slug}}/compose/production/postgres/list-backups.sh b/{{cookiecutter.project_slug}}/compose/production/postgres/list-backups.sh deleted file mode 100644 index 2be3d1d6..00000000 --- a/{{cookiecutter.project_slug}}/compose/production/postgres/list-backups.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash - -set -o errexit -set -o pipefail -set -o nounset - - -echo "listing available backups" -echo "-------------------------" -ls /backups/ diff --git a/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/_sourced/constants.sh b/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/_sourced/constants.sh new file mode 100644 index 00000000..6ca4f0ca --- /dev/null +++ b/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/_sourced/constants.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + + +BACKUP_DIR_PATH='/backups' +BACKUP_FILE_PREFIX='backup' diff --git a/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/_sourced/countdown.sh b/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/_sourced/countdown.sh new file mode 100644 index 00000000..e6cbfb6f --- /dev/null +++ b/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/_sourced/countdown.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + + +countdown() { + declare desc="A simple countdown. Source: https://superuser.com/a/611582" + local seconds="${1}" + local d=$(($(date +%s) + "${seconds}")) + while [ "$d" -ge `date +%s` ]; do + echo -ne "$(date -u --date @$(($d - `date +%s`)) +%H:%M:%S)\r"; + sleep 0.1 + done +} diff --git a/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/_sourced/messages.sh b/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/_sourced/messages.sh new file mode 100644 index 00000000..f6be756e --- /dev/null +++ b/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/_sourced/messages.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash + + +message_newline() { + echo +} + +message_debug() +{ + echo -e "DEBUG: ${@}" +} + +message_welcome() +{ + echo -e "\e[1m${@}\e[0m" +} + +message_warning() +{ + echo -e "\e[33mWARNING\e[0m: ${@}" +} + +message_error() +{ + echo -e "\e[31mERROR\e[0m: ${@}" +} + +message_info() +{ + echo -e "\e[37mINFO\e[0m: ${@}" +} + +message_suggestion() +{ + echo -e "\e[33mSUGGESTION\e[0m: ${@}" +} + +message_success() +{ + echo -e "\e[32mSUCCESS\e[0m: ${@}" +} diff --git a/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/_sourced/yes_no.sh b/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/_sourced/yes_no.sh new file mode 100644 index 00000000..fd9cae16 --- /dev/null +++ b/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/_sourced/yes_no.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + + +yes_no() { + declare desc="Prompt for confirmation. \$\"\{1\}\": confirmation message." + local arg1="${1}" + + local response= + read -r -p "${arg1} (y/[n])? " response + if [[ "${response}" =~ ^[Yy]$ ]] + then + exit 0 + else + exit 1 + fi +} diff --git a/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/backup b/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/backup new file mode 100644 index 00000000..34516248 --- /dev/null +++ b/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/backup @@ -0,0 +1,38 @@ +#!/usr/bin/env bash + + +### Create a database backup. +### +### Usage: +### $ docker-compose -f .yml (exec |run --rm) postgres backup + + +set -o errexit +set -o pipefail +set -o nounset + + +working_dir="$(dirname ${0})" +source "${working_dir}/_sourced/constants.sh" +source "${working_dir}/_sourced/messages.sh" + + +message_welcome "Backing up the '${POSTGRES_DB}' database..." + + +if [[ "${POSTGRES_USER}" == "postgres" ]]; then + message_error "Backing up as 'postgres' user is not supported. Assign 'POSTGRES_USER' env with another one and try again." + exit 1 +fi + +export PGPASSWORD="${POSTGRES_PASSWORD}" + +backup_filename="${BACKUP_FILE_PREFIX}_$(date +'%Y_%m_%dT%H_%M_%S').sql.gz" +pg_dump \ + --host=postgres \ + --dbname="${POSTGRES_DB}" \ + --username="${POSTGRES_USER}" \ + | gzip > "${BACKUP_DIR_PATH}/${backup_filename}" + + +message_success "'${POSTGRES_DB}' database backup '${backup_filename}' has been created and placed in '${BACKUP_DIR_PATH}'." diff --git a/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/backups b/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/backups new file mode 100644 index 00000000..0484ccff --- /dev/null +++ b/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/backups @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + + +### View backups. +### +### Usage: +### $ docker-compose -f .yml (exec |run --rm) postgres backups + + +set -o errexit +set -o pipefail +set -o nounset + + +working_dir="$(dirname ${0})" +source "${working_dir}/_sourced/constants.sh" +source "${working_dir}/_sourced/messages.sh" + + +message_welcome "These are the backups you have got:" + +ls -lht "${BACKUP_DIR_PATH}" diff --git a/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/restore b/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/restore new file mode 100644 index 00000000..49814007 --- /dev/null +++ b/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/restore @@ -0,0 +1,76 @@ +#!/usr/bin/env bash + + +### Restore database from a backup. +### +### Parameters: +### <1> filename of an existing backup. +### +### Usage: +### $ docker-compose -f .yml (exec |run --rm) postgres restore <1> + + +set -o errexit +set -o pipefail +set -o nounset + + +working_dir="$(dirname ${0})" +source "${working_dir}/_sourced/constants.sh" +source "${working_dir}/_sourced/messages.sh" + + +if [[ -z ${1+x} ]]; then + message_error "Backup filename is not specified yet it is a required parameter. Make sure you provide one and try again." + exit 1 +fi +backup_filename="${BACKUP_DIR_PATH}/${1}" +if [[ ! -f "${backup_filename}" ]]; then + message_error "No backup with the specified filename found. Check out the 'backups' maintenance script output to see if there is one and try again." + exit 1 +fi + +message_welcome "Restoring the '${POSTGRES_DB}' database from the '${backup_filename}' backup..." + +if [[ "${POSTGRES_USER}" == "postgres" ]]; then + message_error "Restoring as 'postgres' user is not supported. Assign 'POSTGRES_USER' env with another one and try again." + exit 1 +fi + +export PGPASSWORD="${POSTGRES_PASSWORD}" + +message_info "Dropping all connections to the database..." +# Source: http://dba.stackexchange.com/a/11895 +drop_postgres_connections_sql='UPDATE pg_database' +drop_postgres_connections_sql+=" SET datallowconn = 'false'" +drop_postgres_connections_sql+=" WHERE datname = '${POSTGRES_DB}';" +drop_postgres_connections_sql+='SELECT pg_terminate_backend(pid)' +drop_postgres_connections_sql+=' FROM pg_stat_activity' +drop_postgres_connections_sql+=" WHERE datname = '${POSTGRES_DB}';" +psql \ + --host=localhost \ + --username=postgres \ + --dbname=postgres \ + --command="${drop_postgres_connections_sql}" + +message_info "Dropping the database..." +dropdb \ + --host=postgres \ + --username="${POSTGRES_USER}" \ + "${POSTGRES_DB}" + +message_info "Creating a new database..." +createdb \ + --host=postgres \ + --username="${POSTGRES_USER}" \ + --owner="${POSTGRES_USER}" \ + "${POSTGRES_DB}" + +message_info "Applying the backup to the new database..." +gunzip -c "${backup_filename}" \ + | psql \ + --host=postgres \ + --username="${POSTGRES_USER}" \ + "${POSTGRES_DB}" + +message_success "The '${POSTGRES_DB}' database has been restored from the '${backup_filename}' backup." diff --git a/{{cookiecutter.project_slug}}/compose/production/postgres/restore.sh b/{{cookiecutter.project_slug}}/compose/production/postgres/restore.sh deleted file mode 100644 index e7358949..00000000 --- a/{{cookiecutter.project_slug}}/compose/production/postgres/restore.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env bash - -set -o errexit -set -o pipefail -set -o nounset - - -# we might run into trouble when using the default `postgres` user, e.g. when dropping the postgres -# database in restore.sh. Check that something else is used here -if [ "$POSTGRES_USER" == "postgres" ] -then - echo "restoring as the postgres user is not supported, make sure to set the POSTGRES_USER environment variable" - exit 1 -fi - -# export the postgres password so that subsequent commands don't ask for it -export PGPASSWORD=$POSTGRES_PASSWORD - -# check that we have an argument for a filename candidate -if [[ $# -eq 0 ]] ; then - echo 'usage:' - echo ' docker-compose -f production.yml run postgres restore ' - echo '' - echo 'to get a list of available backups, run:' - echo ' docker-compose -f production.yml run postgres list-backups' - exit 1 -fi - -# set the backupfile variable -BACKUPFILE=/backups/$1 - -# check that the file exists -if ! [ -f $BACKUPFILE ]; then - echo "backup file not found" - echo 'to get a list of available backups, run:' - echo ' docker-compose -f production.yml run postgres list-backups' - exit 1 -fi - -echo "beginning restore from $1" -echo "-------------------------" - -# delete the db -# deleting the db can fail. Spit out a comment if this happens but continue since the db -# is created in the next step -echo "deleting old database $POSTGRES_USER" -if dropdb -h postgres -U $POSTGRES_USER $POSTGRES_USER -then echo "deleted $POSTGRES_USER database" -else echo "database $POSTGRES_USER does not exist, continue" -fi - -# create a new database -echo "creating new database $POSTGRES_USER" -createdb -h postgres -U $POSTGRES_USER $POSTGRES_USER -O $POSTGRES_USER - -# restore the database -echo "restoring database $POSTGRES_USER" -gunzip -c $BACKUPFILE | psql -h postgres -U $POSTGRES_USER From 4191e851075ab7aa531b9e22a8d32c62c71a66b4 Mon Sep 17 00:00:00 2001 From: Wan Liuyang Date: Thu, 15 Mar 2018 12:16:18 +0800 Subject: [PATCH 105/166] Add @sfdye to core team --- CONTRIBUTORS.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTORS.rst b/CONTRIBUTORS.rst index f0fcec39..8fbe4771 100644 --- a/CONTRIBUTORS.rst +++ b/CONTRIBUTORS.rst @@ -18,6 +18,7 @@ Jannis Gebauer `@jayfk`_ Burhan Khalid `@burhan`_ @burhan Nikita Shupeyko `@webyneter`_ @webyneter Bruno Alla               `@browniebroke`_ @_BrunoAlla +Wan Liuyang `@sfdye`_ @sfdye =========================== ================ =========== *Audrey is also the creator of Cookiecutter. Audrey and @@ -30,6 +31,7 @@ Daniel are on the Cookiecutter core team.* .. _@jayfk: https://github.com/jayfk .. _@webyneter: https://github.com/webyneter .. _@browniebroke: https://github.com/browniebroke +.. _@sfdye: https://github.com/sfdye Other Contributors ------------------ @@ -154,7 +156,6 @@ Listed in alphabetical order. Travis McNeill `@Travistock`_ @tavistock_esq Vitaly Babiy Vivian Guillen `@viviangb`_ - Wan Liuyang `@sfdye`_ @sfdye Will Farley `@goldhand`_ @g01dhand William Archinal `@archinal`_ Yaroslav Halchenko @@ -234,7 +235,6 @@ Listed in alphabetical order. .. _@romanosipenko: https://github.com/romanosipenko .. _@shireenrao: https://github.com/shireenrao .. _@show0k: https://github.com/show0k -.. _@sfdye: https://github.com/sfdye .. _@shultz: https://github.com/shultz .. _@siauPatrick: https://github.com/siauPatrick .. _@slafs: https://github.com/slafs From f3d0c6baf029471dc97203f96a99695cb58c9a92 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Thu, 15 Mar 2018 16:28:44 -0500 Subject: [PATCH 106/166] Update django-extensions from 2.0.5 to 2.0.6 --- {{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 6b6323d4..88946c12 100644 --- a/{{cookiecutter.project_slug}}/requirements/local.txt +++ b/{{cookiecutter.project_slug}}/requirements/local.txt @@ -20,6 +20,6 @@ factory-boy==2.10.0 # https://github.com/FactoryBoy/factory_boy django-test-plus==1.0.22 # https://github.com/revsys/django-test-plus django-debug-toolbar==1.9.1 # https://github.com/jazzband/django-debug-toolbar -django-extensions==2.0.5 # https://github.com/django-extensions/django-extensions +django-extensions==2.0.6 # https://github.com/django-extensions/django-extensions django-coverage-plugin==1.5.0 # https://github.com/nedbat/django_coverage_plugin pytest-django==3.1.2 # https://github.com/pytest-dev/pytest-django From 0601a1b858df002f0efa48df2eb5a49fb5618e0e Mon Sep 17 00:00:00 2001 From: jose Gabriel Guzman Lopez Date: Fri, 16 Mar 2018 11:35:39 -0500 Subject: [PATCH 107/166] Local add "127.0.0.1" --- {{cookiecutter.project_slug}}/config/settings/local.py | 1 + 1 file changed, 1 insertion(+) diff --git a/{{cookiecutter.project_slug}}/config/settings/local.py b/{{cookiecutter.project_slug}}/config/settings/local.py index 6dc27de4..62dff552 100644 --- a/{{cookiecutter.project_slug}}/config/settings/local.py +++ b/{{cookiecutter.project_slug}}/config/settings/local.py @@ -11,6 +11,7 @@ SECRET_KEY = env('DJANGO_SECRET_KEY', default='!!!SET DJANGO_SECRET_KEY!!!') ALLOWED_HOSTS = [ "localhost", "0.0.0.0", + "127.0.0.1", ] # CACHES From 80618f0acea7eb2a0d73ecb6053bdc722f06deb3 Mon Sep 17 00:00:00 2001 From: Bruno Alla Date: Fri, 16 Mar 2018 21:32:43 +0000 Subject: [PATCH 108/166] Install psycopg2-binary when not using docker locally (#1569) - The binary package should be installable on Windows locally - The binary package is not recommended for Production, compile from source --- {{cookiecutter.project_slug}}/requirements/base.txt | 5 ----- {{cookiecutter.project_slug}}/requirements/local.txt | 5 +++++ {{cookiecutter.project_slug}}/requirements/production.txt | 1 + 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/{{cookiecutter.project_slug}}/requirements/base.txt b/{{cookiecutter.project_slug}}/requirements/base.txt index 0df716ad..1e993936 100644 --- a/{{cookiecutter.project_slug}}/requirements/base.txt +++ b/{{cookiecutter.project_slug}}/requirements/base.txt @@ -9,11 +9,6 @@ argon2-cffi==18.1.0 # https://github.com/hynek/argon2_cffi {%- if cookiecutter.use_whitenoise == 'y' %} whitenoise==3.3.1 # https://github.com/evansd/whitenoise {%- endif %} -{%- if cookiecutter.windows == 'y' %} -# TODO: On Windows, install psycopg2 manually from http://www.lfd.uci.edu/~gohlke/pythonlibs/#psycopg -{%- else %} -psycopg2==2.7.4 --no-binary psycopg2 # https://github.com/psycopg/psycopg2 -{%- endif %} redis>=2.10.5 # https://github.com/antirez/redis {%- if cookiecutter.use_celery == "y" %} celery==3.1.25 # pyup: <4.0 # https://github.com/celery/celery diff --git a/{{cookiecutter.project_slug}}/requirements/local.txt b/{{cookiecutter.project_slug}}/requirements/local.txt index 88946c12..b867cf2e 100644 --- a/{{cookiecutter.project_slug}}/requirements/local.txt +++ b/{{cookiecutter.project_slug}}/requirements/local.txt @@ -3,6 +3,11 @@ Werkzeug==0.14.1 # https://github.com/pallets/werkzeug ipdb==0.11 # https://github.com/gotcha/ipdb Sphinx==1.7.1 # https://github.com/sphinx-doc/sphinx +{%- if cookiecutter.use_docker == 'y' %} +psycopg2==2.7.4 --no-binary psycopg2 # https://github.com/psycopg/psycopg2 +{%- else %} +psycopg2-binary==2.7.4 # https://github.com/psycopg/psycopg2 +{%- endif %} # Testing # ------------------------------------------------------------------------------ diff --git a/{{cookiecutter.project_slug}}/requirements/production.txt b/{{cookiecutter.project_slug}}/requirements/production.txt index e605e220..bec8ce3c 100644 --- a/{{cookiecutter.project_slug}}/requirements/production.txt +++ b/{{cookiecutter.project_slug}}/requirements/production.txt @@ -5,6 +5,7 @@ gevent==1.2.2 gunicorn==19.7.1 # https://github.com/benoitc/gunicorn boto3==1.6.2 # pyup: update minor # https://github.com/boto/boto3 +psycopg2==2.7.4 --no-binary psycopg2 # https://github.com/psycopg/psycopg2 {%- if cookiecutter.use_whitenoise == 'n' %} Collectfast==0.6.0 # https://github.com/antonagestam/collectfast {%- endif %} From d6e0b95d81c0ea98f54a7d0d1e8a0064ef762888 Mon Sep 17 00:00:00 2001 From: Daniel Roy Greenfeld Date: Sat, 17 Mar 2018 06:58:16 -0500 Subject: [PATCH 109/166] Adding coreapi and moving DRF to end of base.txt --- {{cookiecutter.project_slug}}/requirements/base.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/{{cookiecutter.project_slug}}/requirements/base.txt b/{{cookiecutter.project_slug}}/requirements/base.txt index 1e993936..e74c1e1c 100644 --- a/{{cookiecutter.project_slug}}/requirements/base.txt +++ b/{{cookiecutter.project_slug}}/requirements/base.txt @@ -1,4 +1,3 @@ -djangorestframework==3.7.7 # https://github.com/encode/django-rest-framework pytz==2018.3 # https://github.com/stub42/pytz awesome-slugify==1.6.5 # https://github.com/dimka665/awesome-slugify Pillow==5.0.0 # https://github.com/python-pillow/Pillow @@ -25,3 +24,7 @@ django-crispy-forms==1.7.2 # https://github.com/django-crispy-forms/django-cris django-compressor==2.2 # https://github.com/django-compressor/django-compressor {%- endif %} django-redis==4.9.0 # https://github.com/niwinz/django-redis + +# Django REST Framework +djangorestframework==3.7.7 # https://github.com/encode/django-rest-framework +coreapi==2.3.3 # https://github.com/core-api/python-client From f0175aa9bed6c3f71fc6c95a994d72be840dd0df Mon Sep 17 00:00:00 2001 From: "pyup.io bot" Date: Sat, 17 Mar 2018 15:29:44 +0100 Subject: [PATCH 110/166] Update collectfast to 0.6.2 (#1575) --- {{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 bec8ce3c..44c1597b 100644 --- a/{{cookiecutter.project_slug}}/requirements/production.txt +++ b/{{cookiecutter.project_slug}}/requirements/production.txt @@ -7,7 +7,7 @@ gunicorn==19.7.1 # https://github.com/benoitc/gunicorn boto3==1.6.2 # pyup: update minor # https://github.com/boto/boto3 psycopg2==2.7.4 --no-binary psycopg2 # https://github.com/psycopg/psycopg2 {%- if cookiecutter.use_whitenoise == 'n' %} -Collectfast==0.6.0 # https://github.com/antonagestam/collectfast +Collectfast==0.6.2 # https://github.com/antonagestam/collectfast {%- endif %} {%- if cookiecutter.use_sentry_for_error_reporting == "y" %} raven==6.6.0 # https://github.com/getsentry/raven-python From d1198f63b17d713042707d912b678aad10a6f918 Mon Sep 17 00:00:00 2001 From: Wan Liuyang Date: Wed, 21 Mar 2018 19:54:27 +0800 Subject: [PATCH 111/166] Drop Opbeat (#1578) --- README.rst | 3 --- cookiecutter.json | 1 - docs/project-generation-options.rst | 5 ---- docs/settings.rst | 3 --- .../.envs/.production/.django | 6 ----- .../config/settings/production.py | 15 ----------- .../requirements/production.txt | 3 --- .../taskapp/celery.py | 26 ------------------- 8 files changed, 62 deletions(-) diff --git a/README.rst b/README.rst index e2c24f5b..6cc1607e 100644 --- a/README.rst +++ b/README.rst @@ -68,7 +68,6 @@ Optional Integrations * Configuration for Celery_ * Integration with MailHog_ for local email testing * Integration with Sentry_ for error logging -* Integration with Opbeat_ for performance monitoring .. _Bootstrap: https://github.com/twbs/bootstrap .. _django-environ: https://github.com/joke2k/django-environ @@ -83,7 +82,6 @@ Optional Integrations .. _MailHog: https://github.com/mailhog/MailHog .. _Sentry: https://sentry.io/welcome/ .. _docker-compose: https://github.com/docker/compose -.. _Opbeat: https://opbeat.com/ .. _PythonAnywhere: https://www.pythonanywhere.com/ .. _Caddy: https://caddyserver.com/ .. _LetsEncrypt: https://letsencrypt.org/ @@ -164,7 +162,6 @@ Answer the prompts with your own desired options_. For example:: use_celery [n]: y use_mailhog [n]: n use_sentry_for_error_reporting [y]: y - use_opbeat [n]: y use_pycharm [n]: y windows [n]: n use_docker [y]: n diff --git a/cookiecutter.json b/cookiecutter.json index aa341801..d1ed0c26 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -36,7 +36,6 @@ "use_celery": "n", "use_mailhog": "n", "use_sentry_for_error_reporting": "y", - "use_opbeat": "n", "use_whitenoise": "y", "use_heroku": "n", "use_travisci": "n", diff --git a/docs/project-generation-options.rst b/docs/project-generation-options.rst index 2ca2872c..062cab3b 100644 --- a/docs/project-generation-options.rst +++ b/docs/project-generation-options.rst @@ -81,9 +81,6 @@ use_mailhog [n] 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_. @@ -123,8 +120,6 @@ keep_local_envs_in_vcs [y] .. _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 diff --git a/docs/settings.rst b/docs/settings.rst index 828b5de4..7962f715 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -51,9 +51,6 @@ MAILGUN_API_KEY MAILGUN_ACCESS_KEY n/a 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 -DJANGO_OPBEAT_SECRET_TOKEN OPBEAT['SECRET_TOKEN'] n/a raises error -DJANGO_OPBEAT_ORGANIZATION_ID OPBEAT['ORGANIZATION_ID'] n/a raises error ======================================= =========================== ============================================== ====================================================================== -------------------------- diff --git a/{{cookiecutter.project_slug}}/.envs/.production/.django b/{{cookiecutter.project_slug}}/.envs/.production/.django index 39bbaae4..3f5610d6 100644 --- a/{{cookiecutter.project_slug}}/.envs/.production/.django +++ b/{{cookiecutter.project_slug}}/.envs/.production/.django @@ -38,10 +38,4 @@ WEB_CONCURRENCY=4 # Sentry # ------------------------------------------------------------------------------ DJANGO_SENTRY_DSN= -{% endif %}{% if cookiecutter.use_opbeat == 'y' %} -# opbeat -# ------------------------------------------------------------------------------ -DJANGO_OPBEAT_ORGANIZATION_ID= -DJANGO_OPBEAT_APP_ID= -DJANGO_OPBEAT_SECRET_TOKEN= {% endif %} diff --git a/{{cookiecutter.project_slug}}/config/settings/production.py b/{{cookiecutter.project_slug}}/config/settings/production.py index b29a22b0..dca7cb38 100644 --- a/{{cookiecutter.project_slug}}/config/settings/production.py +++ b/{{cookiecutter.project_slug}}/config/settings/production.py @@ -289,21 +289,6 @@ LOGGING = { } } -{%- endif %} -{% if cookiecutter.use_opbeat == 'y' -%} -# opbeat -# ------------------------------------------------------------------------------ -# https://opbeat.com/docs/articles/get-started-with-django/#setup -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'), - '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}}/requirements/production.txt b/{{cookiecutter.project_slug}}/requirements/production.txt index 44c1597b..aa3cb727 100644 --- a/{{cookiecutter.project_slug}}/requirements/production.txt +++ b/{{cookiecutter.project_slug}}/requirements/production.txt @@ -12,9 +12,6 @@ Collectfast==0.6.2 # https://github.com/antonagestam/collectfast {%- if cookiecutter.use_sentry_for_error_reporting == "y" %} raven==6.6.0 # https://github.com/getsentry/raven-python {%- endif %} -{%- if cookiecutter.use_opbeat == "y" %} -opbeat==3.6.1 # https://github.com/opbeat/opbeat_python -{%- endif %} # Django # ------------------------------------------------------------------------------ diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/taskapp/celery.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/taskapp/celery.py index 9827fa02..dc676769 100644 --- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/taskapp/celery.py +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/taskapp/celery.py @@ -46,32 +46,6 @@ class CeleryConfig(AppConfig): raven_register_signal(raven_client) {%- endif %} - {% if cookiecutter.use_opbeat == 'y' -%} - if hasattr(settings, 'OPBEAT'): -{% if cookiecutter.use_pycharm == 'y' -%} - # Since opbeat is required in production only, - # imports might (most surely will) be wiped out - # during PyCharm code clean up started - # in other environments. - # @formatter:off -{%- endif %} - from opbeat.contrib.django.models import client as opbeat_client - from opbeat.contrib.django.models import logger as opbeat_logger - from opbeat.contrib.django.models import register_handlers as opbeat_register_handlers - from opbeat.contrib.celery import register_signal as opbeat_register_signal -{% if cookiecutter.use_pycharm == 'y' -%} - # @formatter:on -{%- endif %} - - try: - opbeat_register_signal(opbeat_client) - except Exception as e: - opbeat_logger.exception(f'Failed installing celery hook: {e}') - - if 'opbeat.contrib.django' in settings.INSTALLED_APPS: - opbeat_register_handlers() - {%- endif %} - @app.task(bind=True) def debug_task(self): From 3264e77696dd489c95c0067b3dd579149a83af6a Mon Sep 17 00:00:00 2001 From: "pyup.io bot" Date: Sun, 25 Mar 2018 14:30:58 +0200 Subject: [PATCH 112/166] Update pytest to 3.5.0 (#1580) * Update pytest from 3.4.2 to 3.5.0 * Update pytest from 3.4.2 to 3.5.0 --- requirements.txt | 2 +- {{cookiecutter.project_slug}}/requirements/local.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 7c4c5feb..4e0f8dc0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,5 +11,5 @@ pyflakes==1.6.0 # Testing # ------------------------------------------------------------------------------ tox==2.9.1 -pytest==3.4.2 +pytest==3.5.0 pytest-cookies==0.3.0 diff --git a/{{cookiecutter.project_slug}}/requirements/local.txt b/{{cookiecutter.project_slug}}/requirements/local.txt index b867cf2e..5750192b 100644 --- a/{{cookiecutter.project_slug}}/requirements/local.txt +++ b/{{cookiecutter.project_slug}}/requirements/local.txt @@ -11,7 +11,7 @@ psycopg2-binary==2.7.4 # https://github.com/psycopg/psycopg2 # Testing # ------------------------------------------------------------------------------ -pytest==3.4.2 # https://github.com/pytest-dev/pytest +pytest==3.5.0 # https://github.com/pytest-dev/pytest pytest-sugar==0.9.1 # https://github.com/Frozenball/pytest-sugar # Code quality From 60ebda8bf7b0cc0c752ff813a125316d3cb79ad3 Mon Sep 17 00:00:00 2001 From: "pyup.io bot" Date: Sun, 25 Mar 2018 14:45:00 +0200 Subject: [PATCH 113/166] Update sphinx from 1.7.1 to 1.7.2 (#1579) --- {{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 5750192b..a79698fd 100644 --- a/{{cookiecutter.project_slug}}/requirements/local.txt +++ b/{{cookiecutter.project_slug}}/requirements/local.txt @@ -2,7 +2,7 @@ Werkzeug==0.14.1 # https://github.com/pallets/werkzeug ipdb==0.11 # https://github.com/gotcha/ipdb -Sphinx==1.7.1 # https://github.com/sphinx-doc/sphinx +Sphinx==1.7.2 # https://github.com/sphinx-doc/sphinx {%- if cookiecutter.use_docker == 'y' %} psycopg2==2.7.4 --no-binary psycopg2 # https://github.com/psycopg/psycopg2 {%- else %} From 53623ae1fe117d619b03206ba5260aefe09acd26 Mon Sep 17 00:00:00 2001 From: Bruno Alla Date: Mon, 26 Mar 2018 23:31:10 +0100 Subject: [PATCH 114/166] Document server error when missing Mailgun config Fixes #789 --- docs/troubleshooting.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/troubleshooting.rst b/docs/troubleshooting.rst index 4a682ac2..0c827acf 100644 --- a/docs/troubleshooting.rst +++ b/docs/troubleshooting.rst @@ -5,6 +5,8 @@ This page contains some advice about errors and problems commonly encountered du #. ``project_slug`` must be a valid Python module name or you will have issues on imports. -#. ``jinja2.exceptions.TemplateSyntaxError: Encountered unknown tag 'now'.``: please upgrade your cookiecutter version to >= 1.4 (see # 528_) +#. ``jinja2.exceptions.TemplateSyntaxError: Encountered unknown tag 'now'.``: please upgrade your cookiecutter version to >= 1.4 (see `#528`_) -.. _528: https://github.com/pydanny/cookiecutter-django/issues/528#issuecomment-212650373 +#. Internal server error on user registration: make sure you have configured the mail backend (e.g. Mailgun) by adding the API key and sender domain + +.. _#528: https://github.com/pydanny/cookiecutter-django/issues/528#issuecomment-212650373 From 9c09675cb866d14adf8179bad35ce979bb879749 Mon Sep 17 00:00:00 2001 From: "pyup.io bot" Date: Tue, 27 Mar 2018 05:43:29 +0200 Subject: [PATCH 115/166] Update django-storages from 1.6.5 to 1.6.6 (#1585) --- {{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 aa3cb727..b60308c2 100644 --- a/{{cookiecutter.project_slug}}/requirements/production.txt +++ b/{{cookiecutter.project_slug}}/requirements/production.txt @@ -15,5 +15,5 @@ raven==6.6.0 # https://github.com/getsentry/raven-python # Django # ------------------------------------------------------------------------------ -django-storages==1.6.5 # https://github.com/jschneier/django-storages +django-storages==1.6.6 # https://github.com/jschneier/django-storages django-anymail==2.0 # https://github.com/anymail/django-anymail From 59cd5b4849a384f168740f0cd11072c99d4ea1cb Mon Sep 17 00:00:00 2001 From: Nikita Shupeyko Date: Tue, 27 Mar 2018 18:40:44 +0300 Subject: [PATCH 116/166] Celery code blocks are still generated even though Celery is not opted out for (#1587) * Celery jinja condition in .gitignore * Celery jinja conditions in Django Dockerfiles * Re-phrase Django Dockerfile requirements comments * Remove celery compose dirs through post_gen_project.py --- hooks/post_gen_project.py | 6 ++++++ {{cookiecutter.project_slug}}/.gitignore | 2 ++ .../compose/local/django/Dockerfile | 6 +++--- .../compose/production/django/Dockerfile | 6 +++--- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py index 4c987cd1..2ad936a9 100644 --- a/hooks/post_gen_project.py +++ b/hooks/post_gen_project.py @@ -254,6 +254,11 @@ def remove_celery_envs(): os.remove(os.path.join('.envs', '.production', '.celery')) +def remove_celery_compose_dirs(): + shutil.rmtree(os.path.join('compose', 'local', 'django', 'celery')) + shutil.rmtree(os.path.join('compose', 'production', 'django', 'celery')) + + def main(): postgres_user = generate_postgres_user() set_flags_in_envs(postgres_user) @@ -318,6 +323,7 @@ def main(): remove_celery_app() if '{{ cookiecutter.use_docker }}'.lower() == 'y': remove_celery_envs() + remove_celery_compose_dirs() if '{{ cookiecutter.use_travisci }}'.lower() == 'n': remove_dottravisyml_file() diff --git a/{{cookiecutter.project_slug}}/.gitignore b/{{cookiecutter.project_slug}}/.gitignore index 52e8c444..f3f92da2 100644 --- a/{{cookiecutter.project_slug}}/.gitignore +++ b/{{cookiecutter.project_slug}}/.gitignore @@ -62,8 +62,10 @@ target/ # pyenv .python-version +{% if cookiecutter.use_celery == 'y' -%} # celery beat schedule file celerybeat-schedule +{%- endif %} # Environments .venv diff --git a/{{cookiecutter.project_slug}}/compose/local/django/Dockerfile b/{{cookiecutter.project_slug}}/compose/local/django/Dockerfile index c4338109..90e3b693 100644 --- a/{{cookiecutter.project_slug}}/compose/local/django/Dockerfile +++ b/{{cookiecutter.project_slug}}/compose/local/django/Dockerfile @@ -15,7 +15,7 @@ RUN apk update \ # https://docs.djangoproject.com/en/2.0/ref/django-admin/#dbshell && apk add postgresql-client -# Requirements have to be pulled and installed here, otherwise caching won't work +# Requirements are installed here to ensure they will be cached. COPY ./requirements /requirements RUN pip install -r /requirements/local.txt @@ -26,7 +26,7 @@ RUN chmod +x /entrypoint.sh COPY ./compose/local/django/start.sh /start.sh RUN sed -i 's/\r//' /start.sh RUN chmod +x /start.sh - +{% if cookiecutter.use_celery == "y" %} COPY ./compose/local/django/celery/worker/start.sh /start-celeryworker.sh RUN sed -i 's/\r//' /start-celeryworker.sh RUN chmod +x /start-celeryworker.sh @@ -34,7 +34,7 @@ RUN chmod +x /start-celeryworker.sh COPY ./compose/local/django/celery/beat/start.sh /start-celerybeat.sh RUN sed -i 's/\r//' /start-celerybeat.sh RUN chmod +x /start-celerybeat.sh - +{% endif %} WORKDIR /app ENTRYPOINT ["/entrypoint.sh"] diff --git a/{{cookiecutter.project_slug}}/compose/production/django/Dockerfile b/{{cookiecutter.project_slug}}/compose/production/django/Dockerfile index 2ded8253..e8d2e0fc 100644 --- a/{{cookiecutter.project_slug}}/compose/production/django/Dockerfile +++ b/{{cookiecutter.project_slug}}/compose/production/django/Dockerfile @@ -14,7 +14,7 @@ RUN apk update \ RUN addgroup -S django \ && adduser -S -G django django -# Requirements have to be pulled and installed here, otherwise caching won't work +# Requirements are installed here to ensure they will be cached. COPY ./requirements /requirements RUN pip install --no-cache-dir -r /requirements/production.txt \ && rm -rf /requirements @@ -28,7 +28,7 @@ COPY ./compose/production/django/entrypoint.sh /entrypoint.sh RUN sed -i 's/\r//' /entrypoint.sh RUN chmod +x /entrypoint.sh RUN chown django /entrypoint.sh - +{% if cookiecutter.use_celery == "y" %} COPY ./compose/production/django/celery/worker/start.sh /start-celeryworker.sh RUN sed -i 's/\r//' /start-celeryworker.sh RUN chmod +x /start-celeryworker.sh @@ -36,7 +36,7 @@ RUN chmod +x /start-celeryworker.sh COPY ./compose/production/django/celery/beat/start.sh /start-celerybeat.sh RUN sed -i 's/\r//' /start-celerybeat.sh RUN chmod +x /start-celerybeat.sh - +{% endif %} COPY . /app RUN chown -R django /app From bf089fd2b6895ceef9389250b203d9706a717aa5 Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Wed, 28 Mar 2018 18:17:23 +0300 Subject: [PATCH 117/166] Fix celery services exit with status code 2 Fixes #1588. --- {{cookiecutter.project_slug}}/local.yml | 2 ++ {{cookiecutter.project_slug}}/production.yml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/{{cookiecutter.project_slug}}/local.yml b/{{cookiecutter.project_slug}}/local.yml index 8c0e2e89..3222ec12 100644 --- a/{{cookiecutter.project_slug}}/local.yml +++ b/{{cookiecutter.project_slug}}/local.yml @@ -58,6 +58,7 @@ services: {%- endif %} env_file: - ./.envs/.local/.celery + - ./.envs/.local/.postgres ports: [] command: /start-celeryworker.sh @@ -71,6 +72,7 @@ services: {%- endif %} env_file: - ./.envs/.local/.celery + - ./.envs/.local/.postgres ports: [] command: /start-celerybeat.sh diff --git a/{{cookiecutter.project_slug}}/production.yml b/{{cookiecutter.project_slug}}/production.yml index c2b6fccf..1581bea0 100644 --- a/{{cookiecutter.project_slug}}/production.yml +++ b/{{cookiecutter.project_slug}}/production.yml @@ -56,6 +56,7 @@ services: - redis env_file: - ./.envs/.production/.celery + - ./.envs/.production/.postgres command: /start-celeryworker.sh celerybeat: @@ -65,6 +66,7 @@ services: - redis env_file: - ./.envs/.production/.celery + - ./.envs/.production/.postgres command: /start-celerybeat.sh {%- endif %} From 3c3d5914d23ac9ccf83bb6509da3e26f4ad2fc4b Mon Sep 17 00:00:00 2001 From: "pyup.io bot" Date: Tue, 3 Apr 2018 03:50:34 +0200 Subject: [PATCH 118/166] Update pillow to 5.1.0 (#1592) --- {{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 e74c1e1c..976f5cb2 100644 --- a/{{cookiecutter.project_slug}}/requirements/base.txt +++ b/{{cookiecutter.project_slug}}/requirements/base.txt @@ -1,6 +1,6 @@ pytz==2018.3 # https://github.com/stub42/pytz awesome-slugify==1.6.5 # https://github.com/dimka665/awesome-slugify -Pillow==5.0.0 # https://github.com/python-pillow/Pillow +Pillow==5.1.0 # https://github.com/python-pillow/Pillow {%- if cookiecutter.use_compressor == "y" %} rcssmin==1.0.6{% if cookiecutter.windows == 'y' %} --install-option="--without-c-extensions"{% endif %} # https://github.com/ndparker/rcssmin {%- endif %} From 7465c3a8a889ca6f6369952b804a6d176b013b63 Mon Sep 17 00:00:00 2001 From: "pyup.io bot" Date: Tue, 3 Apr 2018 03:51:17 +0200 Subject: [PATCH 119/166] Update tox from 2.9.1 to 3.0.0 (#1591) --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 4e0f8dc0..78077b01 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,6 +10,6 @@ pyflakes==1.6.0 # Testing # ------------------------------------------------------------------------------ -tox==2.9.1 +tox==3.0.0 pytest==3.5.0 pytest-cookies==0.3.0 From 53186d26970ac8d292932972d36749b51183975f Mon Sep 17 00:00:00 2001 From: "pyup.io bot" Date: Tue, 3 Apr 2018 09:46:34 +0200 Subject: [PATCH 120/166] Update django from 2.0.3 to 2.0.4 (#1593) --- {{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 976f5cb2..b04dbfd1 100644 --- a/{{cookiecutter.project_slug}}/requirements/base.txt +++ b/{{cookiecutter.project_slug}}/requirements/base.txt @@ -15,7 +15,7 @@ celery==3.1.25 # pyup: <4.0 # https://github.com/celery/celery # Django # ------------------------------------------------------------------------------ -django==2.0.3 # pyup: < 2.1 # https://www.djangoproject.com/ +django==2.0.4 # pyup: < 2.1 # https://www.djangoproject.com/ django-environ==0.4.4 # https://github.com/joke2k/django-environ django-model-utils==3.1.1 # https://github.com/jazzband/django-model-utils django-allauth==0.35.0 # https://github.com/pennersr/django-allauth From 418b53bf77766afd5cfc668b1cc28c5212c095d8 Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Tue, 3 Apr 2018 12:12:26 +0300 Subject: [PATCH 121/166] Rename use_sentry_for_error_reporting to use_sentry Rationale: consistency --- README.rst | 2 +- cookiecutter.json | 2 +- docs/project-generation-options.rst | 2 +- {{cookiecutter.project_slug}}/.envs/.production/.django | 2 +- {{cookiecutter.project_slug}}/README.rst | 2 +- {{cookiecutter.project_slug}}/config/settings/production.py | 2 +- {{cookiecutter.project_slug}}/config/wsgi.py | 4 ++-- {{cookiecutter.project_slug}}/requirements/production.txt | 2 +- .../{{cookiecutter.project_slug}}/taskapp/celery.py | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README.rst b/README.rst index 6cc1607e..ceaec836 100644 --- a/README.rst +++ b/README.rst @@ -161,7 +161,7 @@ Answer the prompts with your own desired options_. For example:: use_whitenoise [y]: n use_celery [n]: y use_mailhog [n]: n - use_sentry_for_error_reporting [y]: y + use_sentry [y]: y use_pycharm [n]: y windows [n]: n use_docker [y]: n diff --git a/cookiecutter.json b/cookiecutter.json index d1ed0c26..1ba322c1 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -35,7 +35,7 @@ "use_compressor": "n", "use_celery": "n", "use_mailhog": "n", - "use_sentry_for_error_reporting": "y", + "use_sentry": "y", "use_whitenoise": "y", "use_heroku": "n", "use_travisci": "n", diff --git a/docs/project-generation-options.rst b/docs/project-generation-options.rst index 062cab3b..3a1201f0 100644 --- a/docs/project-generation-options.rst +++ b/docs/project-generation-options.rst @@ -78,7 +78,7 @@ use_celery [n] use_mailhog [n] Indicates whether the project should be configured to use MailHog_. -use_sentry_for_error_reporting [n] +use_sentry [n] Indicates whether the project should be configured to use Sentry_. use_whitenoise [y] diff --git a/{{cookiecutter.project_slug}}/.envs/.production/.django b/{{cookiecutter.project_slug}}/.envs/.production/.django index 3f5610d6..284a3488 100644 --- a/{{cookiecutter.project_slug}}/.envs/.production/.django +++ b/{{cookiecutter.project_slug}}/.envs/.production/.django @@ -34,7 +34,7 @@ COMPRESS_ENABLED= # Gunicorn # ------------------------------------------------------------------------------ WEB_CONCURRENCY=4 -{% if cookiecutter.use_sentry_for_error_reporting == 'y' %} +{% if cookiecutter.use_sentry == 'y' %} # Sentry # ------------------------------------------------------------------------------ DJANGO_SENTRY_DSN= diff --git a/{{cookiecutter.project_slug}}/README.rst b/{{cookiecutter.project_slug}}/README.rst index dc3495d5..3386d985 100644 --- a/{{cookiecutter.project_slug}}/README.rst +++ b/{{cookiecutter.project_slug}}/README.rst @@ -99,7 +99,7 @@ The email server will exit when you exit the Grunt task on the CLI with Ctrl+C. {% endif %} .. _mailhog: https://github.com/mailhog/MailHog {% endif %} -{% if cookiecutter.use_sentry_for_error_reporting == "y" %} +{% if cookiecutter.use_sentry == "y" %} Sentry ^^^^^^ diff --git a/{{cookiecutter.project_slug}}/config/settings/production.py b/{{cookiecutter.project_slug}}/config/settings/production.py index dca7cb38..121cdcd9 100644 --- a/{{cookiecutter.project_slug}}/config/settings/production.py +++ b/{{cookiecutter.project_slug}}/config/settings/production.py @@ -176,7 +176,7 @@ INSTALLED_APPS = ['collectfast'] + INSTALLED_APPS # noqa F405 AWS_PRELOAD_METADATA = True {%- endif %} -{% if cookiecutter.use_sentry_for_error_reporting == 'y' -%} +{% if cookiecutter.use_sentry == 'y' -%} # raven # ------------------------------------------------------------------------------ # https://docs.sentry.io/clients/python/integrations/django/ diff --git a/{{cookiecutter.project_slug}}/config/wsgi.py b/{{cookiecutter.project_slug}}/config/wsgi.py index 5f49644c..7d180b1b 100644 --- a/{{cookiecutter.project_slug}}/config/wsgi.py +++ b/{{cookiecutter.project_slug}}/config/wsgi.py @@ -24,7 +24,7 @@ app_path = os.path.abspath(os.path.join( os.path.dirname(os.path.abspath(__file__)), os.pardir)) sys.path.append(os.path.join(app_path, '{{ cookiecutter.project_slug }}')) -{% if cookiecutter.use_sentry_for_error_reporting == 'y' -%} +{% if cookiecutter.use_sentry == 'y' -%} if os.environ.get('DJANGO_SETTINGS_MODULE') == 'config.settings.production': from raven.contrib.django.raven_compat.middleware.wsgi import Sentry {%- endif %} @@ -39,7 +39,7 @@ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.production") # file. This includes Django's development server, if the WSGI_APPLICATION # setting points here. application = get_wsgi_application() -{% if cookiecutter.use_sentry_for_error_reporting == 'y' -%} +{% if cookiecutter.use_sentry == 'y' -%} if os.environ.get('DJANGO_SETTINGS_MODULE') == 'config.settings.production': application = Sentry(application) {%- endif %} diff --git a/{{cookiecutter.project_slug}}/requirements/production.txt b/{{cookiecutter.project_slug}}/requirements/production.txt index b60308c2..1d2e3fad 100644 --- a/{{cookiecutter.project_slug}}/requirements/production.txt +++ b/{{cookiecutter.project_slug}}/requirements/production.txt @@ -9,7 +9,7 @@ psycopg2==2.7.4 --no-binary psycopg2 # https://github.com/psycopg/psycopg2 {%- if cookiecutter.use_whitenoise == 'n' %} Collectfast==0.6.2 # https://github.com/antonagestam/collectfast {%- endif %} -{%- if cookiecutter.use_sentry_for_error_reporting == "y" %} +{%- if cookiecutter.use_sentry == "y" %} raven==6.6.0 # https://github.com/getsentry/raven-python {%- endif %} diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/taskapp/celery.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/taskapp/celery.py index dc676769..c568ca88 100644 --- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/taskapp/celery.py +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/taskapp/celery.py @@ -24,7 +24,7 @@ class CeleryConfig(AppConfig): installed_apps = [app_config.name for app_config in apps.get_app_configs()] app.autodiscover_tasks(lambda: installed_apps, force=True) - {% if cookiecutter.use_sentry_for_error_reporting == 'y' -%} + {% if cookiecutter.use_sentry == 'y' -%} if hasattr(settings, 'RAVEN_CONFIG'): # Celery signal registration {% if cookiecutter.use_pycharm == 'y' -%} From 34673ff686e346bd4bf63c7fff7007ffb634d06c Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Wed, 4 Apr 2018 10:52:16 +0300 Subject: [PATCH 122/166] Merge .celery envs file with .django Rationale: workflow simplification. --- hooks/post_gen_project.py | 6 ------ {{cookiecutter.project_slug}}/.envs/.local/.celery | 3 --- {{cookiecutter.project_slug}}/.envs/.local/.django | 5 +++++ {{cookiecutter.project_slug}}/.envs/.production/.celery | 3 --- {{cookiecutter.project_slug}}/.envs/.production/.django | 6 +++++- {{cookiecutter.project_slug}}/local.yml | 7 ++----- .../merge_production_dotenvs_in_dotenv.py | 3 --- {{cookiecutter.project_slug}}/production.yml | 7 ++----- 8 files changed, 14 insertions(+), 26 deletions(-) delete mode 100644 {{cookiecutter.project_slug}}/.envs/.local/.celery delete mode 100644 {{cookiecutter.project_slug}}/.envs/.production/.celery diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py index 2ad936a9..050a0ca4 100644 --- a/hooks/post_gen_project.py +++ b/hooks/post_gen_project.py @@ -249,11 +249,6 @@ def remove_envs_and_associated_files(): os.remove('merge_production_dotenvs_in_dotenv.py') -def remove_celery_envs(): - os.remove(os.path.join('.envs', '.local', '.celery')) - os.remove(os.path.join('.envs', '.production', '.celery')) - - def remove_celery_compose_dirs(): shutil.rmtree(os.path.join('compose', 'local', 'django', 'celery')) shutil.rmtree(os.path.join('compose', 'production', 'django', 'celery')) @@ -322,7 +317,6 @@ def main(): if '{{ cookiecutter.use_celery }}'.lower() == 'n': remove_celery_app() if '{{ cookiecutter.use_docker }}'.lower() == 'y': - remove_celery_envs() remove_celery_compose_dirs() if '{{ cookiecutter.use_travisci }}'.lower() == 'n': diff --git a/{{cookiecutter.project_slug}}/.envs/.local/.celery b/{{cookiecutter.project_slug}}/.envs/.local/.celery deleted file mode 100644 index f779a430..00000000 --- a/{{cookiecutter.project_slug}}/.envs/.local/.celery +++ /dev/null @@ -1,3 +0,0 @@ -# Celery -# ------------------------------------------------------------------------------ -CELERY_BROKER_URL=redis://redis:6379/0 diff --git a/{{cookiecutter.project_slug}}/.envs/.local/.django b/{{cookiecutter.project_slug}}/.envs/.local/.django index 630aa890..e0d21567 100644 --- a/{{cookiecutter.project_slug}}/.envs/.local/.django +++ b/{{cookiecutter.project_slug}}/.envs/.local/.django @@ -1,3 +1,8 @@ # General # ------------------------------------------------------------------------------ USE_DOCKER=yes +{% if cookiecutter.use_celery == "y" %} +# Celery +# ------------------------------------------------------------------------------ +CELERY_BROKER_URL=redis://redis:6379/0 +{% endif %} diff --git a/{{cookiecutter.project_slug}}/.envs/.production/.celery b/{{cookiecutter.project_slug}}/.envs/.production/.celery deleted file mode 100644 index f779a430..00000000 --- a/{{cookiecutter.project_slug}}/.envs/.production/.celery +++ /dev/null @@ -1,3 +0,0 @@ -# Celery -# ------------------------------------------------------------------------------ -CELERY_BROKER_URL=redis://redis:6379/0 diff --git a/{{cookiecutter.project_slug}}/.envs/.production/.django b/{{cookiecutter.project_slug}}/.envs/.production/.django index 284a3488..934d03db 100644 --- a/{{cookiecutter.project_slug}}/.envs/.production/.django +++ b/{{cookiecutter.project_slug}}/.envs/.production/.django @@ -16,7 +16,11 @@ DJANGO_SECURE_SSL_REDIRECT=False MAILGUN_API_KEY= DJANGO_SERVER_EMAIL= MAILGUN_DOMAIN= - +{% if cookiecutter.use_celery == "y" %} +# Celery +# ------------------------------------------------------------------------------ +CELERY_BROKER_URL=redis://redis:6379/0 +{% endif %} # AWS # ------------------------------------------------------------------------------ DJANGO_AWS_ACCESS_KEY_ID= diff --git a/{{cookiecutter.project_slug}}/local.yml b/{{cookiecutter.project_slug}}/local.yml index 3222ec12..09e065dd 100644 --- a/{{cookiecutter.project_slug}}/local.yml +++ b/{{cookiecutter.project_slug}}/local.yml @@ -19,9 +19,6 @@ services: env_file: - ./.envs/.local/.django - ./.envs/.local/.postgres - {%- if cookiecutter.use_celery == 'y' %} - - ./.envs/.local/.celery - {%- endif %} ports: - "8000:8000" command: /start.sh @@ -57,7 +54,7 @@ services: - mailhog {%- endif %} env_file: - - ./.envs/.local/.celery + - ./.envs/.local/.django - ./.envs/.local/.postgres ports: [] command: /start-celeryworker.sh @@ -71,7 +68,7 @@ services: - mailhog {%- endif %} env_file: - - ./.envs/.local/.celery + - ./.envs/.local/.django - ./.envs/.local/.postgres ports: [] command: /start-celerybeat.sh diff --git a/{{cookiecutter.project_slug}}/merge_production_dotenvs_in_dotenv.py b/{{cookiecutter.project_slug}}/merge_production_dotenvs_in_dotenv.py index fe4560ad..c1bfe30a 100644 --- a/{{cookiecutter.project_slug}}/merge_production_dotenvs_in_dotenv.py +++ b/{{cookiecutter.project_slug}}/merge_production_dotenvs_in_dotenv.py @@ -8,9 +8,6 @@ PRODUCTION_DOTENVS_DIR_PATH = os.path.join(ROOT_DIR_PATH, '.envs', '.production' PRODUCTION_DOTENV_FILE_PATHS = [ os.path.join(PRODUCTION_DOTENVS_DIR_PATH, '.django'), os.path.join(PRODUCTION_DOTENVS_DIR_PATH, '.postgres'), - {%- if cookiecutter.use_celery == 'y' %} - os.path.join(PRODUCTION_DOTENVS_DIR_PATH, '.celery'), - {%- endif %} os.path.join(PRODUCTION_DOTENVS_DIR_PATH, '.caddy'), ] DOTENV_FILE_PATH = os.path.join(ROOT_DIR_PATH, '.env') diff --git a/{{cookiecutter.project_slug}}/production.yml b/{{cookiecutter.project_slug}}/production.yml index 1581bea0..b36c5e1f 100644 --- a/{{cookiecutter.project_slug}}/production.yml +++ b/{{cookiecutter.project_slug}}/production.yml @@ -16,9 +16,6 @@ services: env_file: - ./.envs/.production/.django - ./.envs/.production/.postgres - {%- if cookiecutter.use_celery == 'y' %} - - ./.envs/.production/.celery - {%- endif %} command: /gunicorn.sh postgres: @@ -55,7 +52,7 @@ services: - postgres - redis env_file: - - ./.envs/.production/.celery + - ./.envs/.production/.django - ./.envs/.production/.postgres command: /start-celeryworker.sh @@ -65,7 +62,7 @@ services: - postgres - redis env_file: - - ./.envs/.production/.celery + - ./.envs/.production/.django - ./.envs/.production/.postgres command: /start-celerybeat.sh From 897d54b6906a6972b138c0e8e8bf875d71c9943d Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Wed, 4 Apr 2018 11:16:11 +0300 Subject: [PATCH 123/166] Alter Dockerfile comment url to point at dev Django --- {{cookiecutter.project_slug}}/compose/local/django/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/{{cookiecutter.project_slug}}/compose/local/django/Dockerfile b/{{cookiecutter.project_slug}}/compose/local/django/Dockerfile index 90e3b693..3e3691d0 100644 --- a/{{cookiecutter.project_slug}}/compose/local/django/Dockerfile +++ b/{{cookiecutter.project_slug}}/compose/local/django/Dockerfile @@ -12,7 +12,7 @@ RUN apk update \ && apk add libffi-dev openssl-dev py-cffi \ # Translations dependencies && apk add gettext \ - # https://docs.djangoproject.com/en/2.0/ref/django-admin/#dbshell + # https://docs.djangoproject.com/en/dev/ref/django-admin/#dbshell && apk add postgresql-client # Requirements are installed here to ensure they will be cached. From 2fa5adc2b0b42f2e2d2d95c83254f33614d245a0 Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Wed, 4 Apr 2018 11:43:39 +0300 Subject: [PATCH 124/166] Designate 'postgres' as a variable in entrypoint.sh Rationale: clarity. --- .../compose/production/django/entrypoint.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/{{cookiecutter.project_slug}}/compose/production/django/entrypoint.sh b/{{cookiecutter.project_slug}}/compose/production/django/entrypoint.sh index 19d2ad7b..67302e2b 100644 --- a/{{cookiecutter.project_slug}}/compose/production/django/entrypoint.sh +++ b/{{cookiecutter.project_slug}}/compose/production/django/entrypoint.sh @@ -8,8 +8,8 @@ set -o nounset cmd="$@" if [ -z "${POSTGRES_USER}" ]; then - # the official postgres image uses 'postgres' as default user if not set explictly. - export POSTGRES_USER=postgres + base_postgres_image_default_user='postgres' + export POSTGRES_USER="${base_postgres_image_default_user}" fi export DATABASE_URL="postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}" From ae9dc2e782ccd734ef0dbe136960b09a8da1a760 Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Wed, 4 Apr 2018 13:38:57 +0300 Subject: [PATCH 125/166] Distinguish between local and production compose services Rationale: 1. building production stack on the same machine with local doesn't lead to conflicts anymore; 2. production and local service images are now clearly distinguished by name. --- {{cookiecutter.project_slug}}/local.yml | 4 ++++ {{cookiecutter.project_slug}}/production.yml | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/{{cookiecutter.project_slug}}/local.yml b/{{cookiecutter.project_slug}}/local.yml index 09e065dd..ed8dec0b 100644 --- a/{{cookiecutter.project_slug}}/local.yml +++ b/{{cookiecutter.project_slug}}/local.yml @@ -9,6 +9,7 @@ services: build: context: . dockerfile: ./compose/local/django/Dockerfile + image: {{ cookiecutter.project_slug }}_local_django depends_on: - postgres {%- if cookiecutter.use_mailhog == 'y' %} @@ -27,6 +28,7 @@ services: build: context: . dockerfile: ./compose/production/postgres/Dockerfile + image: {{ cookiecutter.project_slug }}_production_postgres volumes: - postgres_data_local:/var/lib/postgresql/data - postgres_backup_local:/backups @@ -47,6 +49,7 @@ services: celeryworker: <<: *django + image: {{ cookiecutter.project_slug }}_local_celeryworker depends_on: - redis - postgres @@ -61,6 +64,7 @@ services: celerybeat: <<: *django + image: {{ cookiecutter.project_slug }}_local_celerybeat depends_on: - redis - postgres diff --git a/{{cookiecutter.project_slug}}/production.yml b/{{cookiecutter.project_slug}}/production.yml index b36c5e1f..f57c9810 100644 --- a/{{cookiecutter.project_slug}}/production.yml +++ b/{{cookiecutter.project_slug}}/production.yml @@ -10,6 +10,7 @@ services: build: context: . dockerfile: ./compose/production/django/Dockerfile + image: {{ cookiecutter.project_slug }}_production_django depends_on: - postgres - redis @@ -22,6 +23,7 @@ services: build: context: . dockerfile: ./compose/production/postgres/Dockerfile + image: {{ cookiecutter.project_slug }}_production_postgres volumes: - postgres_data:/var/lib/postgresql/data - postgres_backup:/backups @@ -32,6 +34,7 @@ services: build: context: . dockerfile: ./compose/production/caddy/Dockerfile + image: {{ cookiecutter.project_slug }}_production_caddy depends_on: - django volumes: @@ -48,6 +51,7 @@ services: celeryworker: <<: *django + image: {{ cookiecutter.project_slug }}_production_celeryworker depends_on: - postgres - redis @@ -58,6 +62,7 @@ services: celerybeat: <<: *django + image: {{ cookiecutter.project_slug }}_production_celerybeat depends_on: - postgres - redis From 26ccf9307fb642b5a7afbb9b364dcced619218c2 Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Wed, 4 Apr 2018 13:42:01 +0300 Subject: [PATCH 126/166] Fix REDIS_URL missing Fixes #1570. --- {{cookiecutter.project_slug}}/.envs/.local/.django | 7 +++---- .../.envs/.production/.django | 10 +++++----- .../compose/production/django/entrypoint.sh | 3 +++ .../config/settings/production.py | 2 +- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/{{cookiecutter.project_slug}}/.envs/.local/.django b/{{cookiecutter.project_slug}}/.envs/.local/.django index e0d21567..8aa9a994 100644 --- a/{{cookiecutter.project_slug}}/.envs/.local/.django +++ b/{{cookiecutter.project_slug}}/.envs/.local/.django @@ -1,8 +1,7 @@ # General # ------------------------------------------------------------------------------ USE_DOCKER=yes -{% if cookiecutter.use_celery == "y" %} -# Celery + +# Redis # ------------------------------------------------------------------------------ -CELERY_BROKER_URL=redis://redis:6379/0 -{% endif %} +REDIS_URL=redis://redis:6379/0 diff --git a/{{cookiecutter.project_slug}}/.envs/.production/.django b/{{cookiecutter.project_slug}}/.envs/.production/.django index 934d03db..2e9eefea 100644 --- a/{{cookiecutter.project_slug}}/.envs/.production/.django +++ b/{{cookiecutter.project_slug}}/.envs/.production/.django @@ -16,11 +16,7 @@ DJANGO_SECURE_SSL_REDIRECT=False MAILGUN_API_KEY= DJANGO_SERVER_EMAIL= MAILGUN_DOMAIN= -{% if cookiecutter.use_celery == "y" %} -# Celery -# ------------------------------------------------------------------------------ -CELERY_BROKER_URL=redis://redis:6379/0 -{% endif %} + # AWS # ------------------------------------------------------------------------------ DJANGO_AWS_ACCESS_KEY_ID= @@ -43,3 +39,7 @@ WEB_CONCURRENCY=4 # ------------------------------------------------------------------------------ DJANGO_SENTRY_DSN= {% endif %} + +# Redis +# ------------------------------------------------------------------------------ +REDIS_URL=redis://redis:6379/0 diff --git a/{{cookiecutter.project_slug}}/compose/production/django/entrypoint.sh b/{{cookiecutter.project_slug}}/compose/production/django/entrypoint.sh index 67302e2b..0e0121c2 100644 --- a/{{cookiecutter.project_slug}}/compose/production/django/entrypoint.sh +++ b/{{cookiecutter.project_slug}}/compose/production/django/entrypoint.sh @@ -7,6 +7,9 @@ set -o nounset cmd="$@" +# N.B. If only .env files supported variable expansion... +export CELERY_BROKER_URL="${REDIS_URL}" + if [ -z "${POSTGRES_USER}" ]; then base_postgres_image_default_user='postgres' export POSTGRES_USER="${base_postgres_image_default_user}" diff --git a/{{cookiecutter.project_slug}}/config/settings/production.py b/{{cookiecutter.project_slug}}/config/settings/production.py index 121cdcd9..236cecbf 100644 --- a/{{cookiecutter.project_slug}}/config/settings/production.py +++ b/{{cookiecutter.project_slug}}/config/settings/production.py @@ -21,7 +21,7 @@ DATABASES['default']['CONN_MAX_AGE'] = env.int('CONN_MAX_AGE', default=60) # no CACHES = { 'default': { 'BACKEND': 'django_redis.cache.RedisCache', - 'LOCATION': f'{env("REDIS_URL", default="redis://127.0.0.1:6379")}/{0}', + 'LOCATION': env('REDIS_URL'), 'OPTIONS': { 'CLIENT_CLASS': 'django_redis.client.DefaultClient', # Mimicing memcache behavior. From dffacdc2ed3059a1c62db38694fe9f1e2b2a2690 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Fri, 6 Apr 2018 11:40:11 -0500 Subject: [PATCH 127/166] Update djangorestframework from 3.7.7 to 3.8.2 --- {{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 b04dbfd1..e628da49 100644 --- a/{{cookiecutter.project_slug}}/requirements/base.txt +++ b/{{cookiecutter.project_slug}}/requirements/base.txt @@ -26,5 +26,5 @@ django-compressor==2.2 # https://github.com/django-compressor/django-compressor django-redis==4.9.0 # https://github.com/niwinz/django-redis # Django REST Framework -djangorestframework==3.7.7 # https://github.com/encode/django-rest-framework +djangorestframework==3.8.2 # https://github.com/encode/django-rest-framework coreapi==2.3.3 # https://github.com/core-api/python-client From 0e7005d3d18100c4dec0d440467a7ea310dc0e2c Mon Sep 17 00:00:00 2001 From: MaziyarMK Date: Sun, 8 Apr 2018 10:04:31 +0400 Subject: [PATCH 128/166] Fixes heroku deployment error Specifically fixes this confusing error: ModuleNotFoundError: No module named "'config" The single quotes are not required in the heroku config vars. --- docs/deployment-on-heroku.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/deployment-on-heroku.rst b/docs/deployment-on-heroku.rst index e770219b..7ce94d05 100644 --- a/docs/deployment-on-heroku.rst +++ b/docs/deployment-on-heroku.rst @@ -20,7 +20,7 @@ Run these commands to deploy the project to Heroku: # 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_SETTINGS_MODULE=config.settings.production heroku config:set DJANGO_ALLOWED_HOSTS='.herokuapp.com' heroku config:set DJANGO_AWS_ACCESS_KEY_ID=YOUR_AWS_ID_HERE From 3f753e04114471a87a9b85e6078692c91b4bf164 Mon Sep 17 00:00:00 2001 From: Daniel Roy Greenfeld Date: Sun, 8 Apr 2018 17:03:29 -0500 Subject: [PATCH 129/166] First pass at running black across the project (#1602) --- docs/conf.py | 56 +++--- hooks/post_gen_project.py | 183 +++++++----------- hooks/pre_gen_project.py | 41 ++-- setup.py | 46 ++--- tests/test_cookiecutter_generation.py | 31 +-- .../config/settings/test.py | 29 ++- {{cookiecutter.project_slug}}/config/urls.py | 51 +++-- {{cookiecutter.project_slug}}/docs/conf.py | 56 +++--- {{cookiecutter.project_slug}}/manage.py | 7 +- .../merge_production_dotenvs_in_dotenv.py | 40 ++-- .../{{cookiecutter.project_slug}}/__init__.py | 9 +- .../contrib/sites/migrations/0001_initial.py | 39 ++-- .../migrations/0002_alter_domain_unique.py | 16 +- .../0003_set_site_domain_and_name.py | 24 +-- .../users/adapters.py | 6 +- .../users/admin.py | 18 +- .../users/apps.py | 2 +- .../users/migrations/0001_initial.py | 139 ++++++++++--- .../users/models.py | 4 +- .../users/tests/factories.py | 10 +- .../users/tests/test_admin.py | 30 +-- .../users/tests/test_models.py | 7 +- .../users/tests/test_urls.py | 23 +-- .../users/tests/test_views.py | 24 +-- .../users/urls.py | 24 +-- .../users/views.py | 17 +- 26 files changed, 499 insertions(+), 433 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index aa023b74..e3ddae9a 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -29,19 +29,19 @@ now = datetime.now() extensions = [] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # The suffix of source filenames. -source_suffix = '.rst' +source_suffix = ".rst" # The encoding of source files. # source_encoding = 'utf-8-sig' # The master toctree document. -master_doc = 'index' +master_doc = "index" # General information about the project. -project = 'Cookiecutter Django' +project = "Cookiecutter Django" copyright = "2013-2018, Daniel Roy Greenfeld".format(now.year) # The version info for the project you're documenting, acts as replacement for @@ -49,9 +49,9 @@ copyright = "2013-2018, Daniel Roy Greenfeld".format(now.year) # built documents. # # The short X.Y version. -version = '{}.{}.{}'.format(*now.isocalendar()) +version = "{}.{}.{}".format(*now.isocalendar()) # The full version, including alpha/beta/rc tags. -release = '{}.{}.{}'.format(*now.isocalendar()) +release = "{}.{}.{}".format(*now.isocalendar()) # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -65,7 +65,7 @@ release = '{}.{}.{}'.format(*now.isocalendar()) # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. -exclude_patterns = ['_build'] +exclude_patterns = ["_build"] # The reST default role (used for this markup: `text`) to use for all documents. # default_role = None @@ -82,7 +82,7 @@ exclude_patterns = ['_build'] # show_authors = False # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # A list of ignored prefixes for module index sorting. # modindex_common_prefix = [] @@ -92,7 +92,7 @@ pygments_style = 'sphinx' # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'default' +html_theme = "default" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the @@ -121,7 +121,7 @@ html_theme = 'default' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ["_static"] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. @@ -165,7 +165,7 @@ html_static_path = ['_static'] # html_file_suffix = None # Output file base name for HTML help builder. -htmlhelp_basename = 'cookiecutter-djangodoc' +htmlhelp_basename = "cookiecutter-djangodoc" # -- Options for LaTeX output -------------------------------------------------- @@ -173,10 +173,8 @@ htmlhelp_basename = 'cookiecutter-djangodoc' latex_elements = { # The paper size ('letterpaper' or 'a4paper'). # 'papersize': 'letterpaper', - # The font size ('10pt', '11pt' or '12pt'). # 'pointsize': '10pt', - # Additional stuff for the LaTeX preamble. # 'preamble': '', } @@ -184,10 +182,13 @@ latex_elements = { # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ - ('index', - 'cookiecutter-django.tex', - 'cookiecutter-django Documentation', - 'cookiecutter-django', 'manual'), + ( + "index", + "cookiecutter-django.tex", + "cookiecutter-django Documentation", + "cookiecutter-django", + "manual", + ) ] # The name of an image file (relative to this directory) to place at the top of @@ -216,8 +217,13 @@ latex_documents = [ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - ('index', 'Cookiecutter Django', 'Cookiecutter Django documentation', - ['Daniel Roy Greenfeld'], 1) + ( + "index", + "Cookiecutter Django", + "Cookiecutter Django documentation", + ["Daniel Roy Greenfeld"], + 1, + ) ] # If true, show URL addresses after external links. @@ -230,9 +236,15 @@ man_pages = [ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - ('index', 'Cookiecutter Django', 'Cookiecutter Django documentation', - 'Daniel Roy Greenfeld', 'Cookiecutter Django', - 'A Cookiecutter template for creating production-ready Django projects quickly.', 'Miscellaneous'), + ( + "index", + "Cookiecutter Django", + "Cookiecutter Django documentation", + "Daniel Roy Greenfeld", + "Cookiecutter Django", + "A Cookiecutter template for creating production-ready Django projects quickly.", + "Miscellaneous", + ) ] # Documents to append as an appendix to all manuals. diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py index 050a0ca4..e353c77f 100644 --- a/hooks/post_gen_project.py +++ b/hooks/post_gen_project.py @@ -30,96 +30,77 @@ SUCCESS = "\x1b[1;32m [SUCCESS]: " def remove_open_source_files(): - file_names = [ - 'CONTRIBUTORS.txt', - ] + file_names = ["CONTRIBUTORS.txt"] for file_name in file_names: os.remove(file_name) def remove_gplv3_files(): - file_names = [ - 'COPYING', - ] + file_names = ["COPYING"] for file_name in file_names: os.remove(file_name) def remove_pycharm_files(): - idea_dir_path = '.idea' + idea_dir_path = ".idea" if os.path.exists(idea_dir_path): shutil.rmtree(idea_dir_path) - docs_dir_path = os.path.join('docs', 'pycharm') + docs_dir_path = os.path.join("docs", "pycharm") if os.path.exists(docs_dir_path): shutil.rmtree(docs_dir_path) def remove_docker_files(): - shutil.rmtree('compose') + shutil.rmtree("compose") - file_names = [ - 'local.yml', - 'production.yml', - '.dockerignore', - ] + file_names = ["local.yml", "production.yml", ".dockerignore"] for file_name in file_names: os.remove(file_name) def remove_heroku_files(): - file_names = [ - 'Procfile', - 'runtime.txt', - 'requirements.txt', - ] + file_names = ["Procfile", "runtime.txt", "requirements.txt"] for file_name in file_names: os.remove(file_name) def remove_grunt_files(): - file_names = [ - 'Gruntfile.js', - ] + file_names = ["Gruntfile.js"] for file_name in file_names: os.remove(file_name) def remove_gulp_files(): - file_names = [ - 'gulpfile.js', - ] + file_names = ["gulpfile.js"] for file_name in file_names: os.remove(file_name) def remove_packagejson_file(): - file_names = [ - 'package.json', - ] + file_names = ["package.json"] for file_name in file_names: os.remove(file_name) def remove_celery_app(): - shutil.rmtree(os.path.join('{{ cookiecutter.project_slug }}', 'taskapp')) + shutil.rmtree(os.path.join("{{ cookiecutter.project_slug }}", "taskapp")) def remove_dottravisyml_file(): - os.remove('.travis.yml') + os.remove(".travis.yml") def append_to_project_gitignore(path): - gitignore_file_path = '.gitignore' - with open(gitignore_file_path, 'a') as gitignore_file: + gitignore_file_path = ".gitignore" + with open(gitignore_file_path, "a") as gitignore_file: gitignore_file.write(path) gitignore_file.write(os.linesep) -def generate_random_string(length, - using_digits=False, - using_ascii_letters=False, - using_punctuation=False): +def generate_random_string( + length, using_digits=False, using_ascii_letters=False, using_punctuation=False +): """ Example: opting out for 50 symbol-long, [a-z][A-Z][0-9] string @@ -134,19 +115,13 @@ def generate_random_string(length, if using_ascii_letters: symbols += string.ascii_letters if using_punctuation: - symbols += string.punctuation \ - .replace('"', '') \ - .replace("'", '') \ - .replace('\\', '') - return ''.join([random.choice(symbols) for _ in range(length)]) + symbols += string.punctuation.replace('"', "").replace("'", "").replace( + "\\", "" + ) + return "".join([random.choice(symbols) for _ in range(length)]) -def set_flag(file_path, - flag, - value=None, - formatted=None, - *args, - **kwargs): +def set_flag(file_path, flag, value=None, formatted=None, *args, **kwargs): if value is None: random_string = generate_random_string(*args, **kwargs) if random_string is None: @@ -159,7 +134,7 @@ def set_flag(file_path, random_string = formatted.format(random_string) value = random_string - with open(file_path, 'r+') as f: + with open(file_path, "r+") as f: file_contents = f.read().replace(flag, value) f.seek(0) f.write(file_contents) @@ -171,10 +146,10 @@ def set_flag(file_path, def set_django_secret_key(file_path): django_secret_key = set_flag( file_path, - '!!!SET DJANGO_SECRET_KEY!!!', + "!!!SET DJANGO_SECRET_KEY!!!", length=64, using_digits=True, - using_ascii_letters=True + using_ascii_letters=True, ) return django_secret_key @@ -182,28 +157,22 @@ def set_django_secret_key(file_path): def set_django_admin_url(file_path): django_admin_url = set_flag( file_path, - '!!!SET DJANGO_ADMIN_URL!!!', - formatted='^{}/', + "!!!SET DJANGO_ADMIN_URL!!!", + formatted="^{}/", length=32, using_digits=True, - using_ascii_letters=True + using_ascii_letters=True, ) return django_admin_url def generate_postgres_user(): - return generate_random_string( - length=32, - using_ascii_letters=True - ) + return generate_random_string(length=32, using_ascii_letters=True) -def set_postgres_user(file_path, - value=None): +def set_postgres_user(file_path, value=None): postgres_user = set_flag( - file_path, - '!!!SET POSTGRES_USER!!!', - value=value or generate_postgres_user() + file_path, "!!!SET POSTGRES_USER!!!", value=value or generate_postgres_user() ) return postgres_user @@ -211,47 +180,47 @@ def set_postgres_user(file_path, def set_postgres_password(file_path): postgres_password = set_flag( file_path, - '!!!SET POSTGRES_PASSWORD!!!', + "!!!SET POSTGRES_PASSWORD!!!", length=64, using_digits=True, - using_ascii_letters=True + using_ascii_letters=True, ) return postgres_password def append_to_gitignore_file(s): - with open('.gitignore', 'a') as gitignore_file: + with open(".gitignore", "a") as gitignore_file: gitignore_file.write(s) gitignore_file.write(os.linesep) def set_flags_in_envs(postgres_user): - local_postgres_envs_path = os.path.join('.envs', '.local', '.postgres') + local_postgres_envs_path = os.path.join(".envs", ".local", ".postgres") set_postgres_user(local_postgres_envs_path, value=postgres_user) set_postgres_password(local_postgres_envs_path) - production_django_envs_path = os.path.join('.envs', '.production', '.django') + production_django_envs_path = os.path.join(".envs", ".production", ".django") set_django_secret_key(production_django_envs_path) set_django_admin_url(production_django_envs_path) - production_postgres_envs_path = os.path.join('.envs', '.production', '.postgres') + production_postgres_envs_path = os.path.join(".envs", ".production", ".postgres") set_postgres_user(production_postgres_envs_path, value=postgres_user) set_postgres_password(production_postgres_envs_path) def set_flags_in_settings_files(): - set_django_secret_key(os.path.join('config', 'settings', 'local.py')) - set_django_secret_key(os.path.join('config', 'settings', 'test.py')) + set_django_secret_key(os.path.join("config", "settings", "local.py")) + set_django_secret_key(os.path.join("config", "settings", "test.py")) def remove_envs_and_associated_files(): - shutil.rmtree('.envs') - os.remove('merge_production_dotenvs_in_dotenv.py') + shutil.rmtree(".envs") + os.remove("merge_production_dotenvs_in_dotenv.py") def remove_celery_compose_dirs(): - shutil.rmtree(os.path.join('compose', 'local', 'django', 'celery')) - shutil.rmtree(os.path.join('compose', 'production', 'django', 'celery')) + shutil.rmtree(os.path.join("compose", "local", "django", "celery")) + shutil.rmtree(os.path.join("compose", "production", "django", "celery")) def main(): @@ -259,75 +228,67 @@ def main(): set_flags_in_envs(postgres_user) set_flags_in_settings_files() - if '{{ cookiecutter.open_source_license }}' == 'Not open source': + if "{{ cookiecutter.open_source_license }}" == "Not open source": remove_open_source_files() - if '{{ cookiecutter.open_source_license}}' != 'GPLv3': + if "{{ cookiecutter.open_source_license}}" != "GPLv3": remove_gplv3_files() - if '{{ cookiecutter.use_pycharm }}'.lower() == 'n': + if "{{ cookiecutter.use_pycharm }}".lower() == "n": remove_pycharm_files() - if '{{ cookiecutter.use_docker }}'.lower() == 'n': + if "{{ cookiecutter.use_docker }}".lower() == "n": remove_docker_files() - if '{{ cookiecutter.use_heroku }}'.lower() == 'n': + if "{{ cookiecutter.use_heroku }}".lower() == "n": remove_heroku_files() - if '{{ cookiecutter.use_docker }}'.lower() == 'n' and '{{ cookiecutter.use_heroku }}'.lower() == 'n': - if '{{ cookiecutter.keep_local_envs_in_vcs }}'.lower() == 'y': + if "{{ cookiecutter.use_docker }}".lower() == "n" and "{{ cookiecutter.use_heroku }}".lower() == "n": + if "{{ cookiecutter.keep_local_envs_in_vcs }}".lower() == "y": print( - INFO + - ".env(s) are only utilized when Docker Compose and/or " + INFO + ".env(s) are only utilized when Docker Compose and/or " "Heroku support is enabled so keeping them does not " - "make sense given your current setup." + - TERMINATOR + "make sense given your current setup." + TERMINATOR ) remove_envs_and_associated_files() else: - append_to_gitignore_file('.env') - append_to_gitignore_file('.envs/*') - if '{{ cookiecutter.keep_local_envs_in_vcs }}'.lower() == 'y': - append_to_gitignore_file('!.envs/.local/') + append_to_gitignore_file(".env") + append_to_gitignore_file(".envs/*") + if "{{ cookiecutter.keep_local_envs_in_vcs }}".lower() == "y": + append_to_gitignore_file("!.envs/.local/") - if '{{ cookiecutter.js_task_runner}}'.lower() == 'gulp': + if "{{ cookiecutter.js_task_runner}}".lower() == "gulp": remove_grunt_files() - elif '{{ cookiecutter.js_task_runner}}'.lower() == 'grunt': + elif "{{ cookiecutter.js_task_runner}}".lower() == "grunt": remove_gulp_files() else: remove_gulp_files() remove_grunt_files() remove_packagejson_file() - if '{{ cookiecutter.js_task_runner }}'.lower() in ['grunt', 'gulp'] \ - and '{{ cookiecutter.use_docker }}'.lower() == 'y': + if "{{ cookiecutter.js_task_runner }}".lower() in [ + "grunt", "gulp" + ] and "{{ cookiecutter.use_docker }}".lower() == "y": print( - WARNING + - "Docker and {} JS task runner ".format( - '{{ cookiecutter.js_task_runner }}' - .lower() - .capitalize() - ) + - "working together not supported yet. " + WARNING + + "Docker and {} JS task runner ".format( + "{{ cookiecutter.js_task_runner }}".lower().capitalize() + ) + + "working together not supported yet. " "You can continue using the generated project like you " "normally would, however you would need to add a JS " "task runner service to your Docker Compose configuration " - "manually." + - TERMINATOR + "manually." + TERMINATOR ) - if '{{ cookiecutter.use_celery }}'.lower() == 'n': + if "{{ cookiecutter.use_celery }}".lower() == "n": remove_celery_app() - if '{{ cookiecutter.use_docker }}'.lower() == 'y': + if "{{ cookiecutter.use_docker }}".lower() == "y": remove_celery_compose_dirs() - if '{{ cookiecutter.use_travisci }}'.lower() == 'n': + if "{{ cookiecutter.use_travisci }}".lower() == "n": remove_dottravisyml_file() - print( - SUCCESS + - "Project initialized, keep up the good work!" + - TERMINATOR - ) + print(SUCCESS + "Project initialized, keep up the good work!" + TERMINATOR) -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/hooks/pre_gen_project.py b/hooks/pre_gen_project.py index ed2bef18..b7f4dfbb 100644 --- a/hooks/pre_gen_project.py +++ b/hooks/pre_gen_project.py @@ -16,40 +16,41 @@ INFO = "\x1b[1;33m [INFO]: " HINT = "\x1b[3;33m" SUCCESS = "\x1b[1;32m [SUCCESS]: " -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) +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." -if '{{ cookiecutter.use_docker }}'.lower() == 'n': +if "{{ cookiecutter.use_docker }}".lower() == "n": python_major_version = sys.version_info[0] if python_major_version == 2: print( - WARNING + - "Cookiecutter Django does not support Python 2. " + WARNING + "Cookiecutter Django does not support Python 2. " "Stability is guaranteed with Python 3.6+ only, " - "are you sure you want to proceed (y/n)? " + - TERMINATOR + "are you sure you want to proceed (y/n)? " + TERMINATOR ) - yes_options, no_options = frozenset(['y']), frozenset(['n']) + yes_options, no_options = frozenset(["y"]), frozenset(["n"]) while True: choice = raw_input().lower() if choice in yes_options: break + elif choice in no_options: - print( - INFO + - "Generation process stopped as requested." + - TERMINATOR - ) + print(INFO + "Generation process stopped as requested." + TERMINATOR) sys.exit(1) else: print( - HINT + - "Please respond with {} or {}: ".format( - ', '.join(["'{}'".format(o) for o in yes_options if not o == '']), - ', '.join(["'{}'".format(o) for o in no_options if not o == '']) - ) + - TERMINATOR + HINT + + "Please respond with {} or {}: ".format( + ", ".join( + ["'{}'".format(o) for o in yes_options if not o == ""] + ), + ", ".join( + ["'{}'".format(o) for o in no_options if not o == ""] + ), + ) + + TERMINATOR ) diff --git a/setup.py b/setup.py index a7efb0a6..65bcd8fc 100644 --- a/setup.py +++ b/setup.py @@ -10,42 +10,42 @@ 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 = '2.0.2' +version = "2.0.2" -if sys.argv[-1] == 'tag': +if sys.argv[-1] == "tag": os.system('git tag -a %s -m "version %s"' % (version, version)) - os.system('git push --tags') + os.system("git push --tags") sys.exit() -with open('README.rst') as readme_file: +with open("README.rst") as readme_file: long_description = readme_file.read() setup( - name='cookiecutter-django', + name="cookiecutter-django", version=version, - description='A Cookiecutter template for creating production-ready Django projects quickly.', + description="A Cookiecutter template for creating production-ready Django projects quickly.", long_description=long_description, - author='Daniel Roy Greenfeld', - author_email='pydanny@gmail.com', - url='https://github.com/pydanny/cookiecutter-django', + author="Daniel Roy Greenfeld", + author_email="pydanny@gmail.com", + url="https://github.com/pydanny/cookiecutter-django", packages=[], - license='BSD', + license="BSD", zip_safe=False, classifiers=[ - 'Development Status :: 4 - Beta', - 'Environment :: Console', - 'Framework :: Django :: 2.0', - 'Intended Audience :: Developers', - 'Natural Language :: English', - 'License :: OSI Approved :: BSD License', - 'Programming Language :: Python', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: Implementation :: CPython', - 'Topic :: Software Development', + "Development Status :: 4 - Beta", + "Environment :: Console", + "Framework :: Django :: 2.0", + "Intended Audience :: Developers", + "Natural Language :: English", + "License :: OSI Approved :: BSD License", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: Implementation :: CPython", + "Topic :: Software Development", ], keywords=( - 'cookiecutter, Python, projects, project templates, django, ' - 'skeleton, scaffolding, project directory, setup.py' + "cookiecutter, Python, projects, project templates, django, " + "skeleton, scaffolding, project directory, setup.py" ), ) diff --git a/tests/test_cookiecutter_generation.py b/tests/test_cookiecutter_generation.py index acbc2c09..cf173576 100755 --- a/tests/test_cookiecutter_generation.py +++ b/tests/test_cookiecutter_generation.py @@ -5,21 +5,21 @@ import sh import pytest from binaryornot.check import is_binary -PATTERN = '{{(\s?cookiecutter)[.](.*?)}}' +PATTERN = "{{(\s?cookiecutter)[.](.*?)}}" RE_OBJ = re.compile(PATTERN) @pytest.fixture def context(): return { - 'project_name': 'My Test Project', - 'project_slug': 'my_test_project', - 'author_name': 'Test Author', - 'email': 'test@example.com', - 'description': 'A short description of the project.', - 'domain_name': 'example.com', - 'version': '0.1.0', - 'timezone': 'UTC', + "project_name": "My Test Project", + "project_slug": "my_test_project", + "author_name": "Test Author", + "email": "test@example.com", + "description": "A short description of the project.", + "domain_name": "example.com", + "version": "0.1.0", + "timezone": "UTC", } @@ -40,9 +40,10 @@ def check_paths(paths): for path in paths: if is_binary(path): continue - for line in open(path, 'r'): + + for line in open(path, "r"): match = RE_OBJ.search(line) - msg = 'cookiecutter variable not replaced in {}' + msg = "cookiecutter variable not replaced in {}" assert match is None, msg.format(path) @@ -50,7 +51,7 @@ def test_default_configuration(cookies, context): result = cookies.bake(extra_context=context) assert result.exit_code == 0 assert result.exception is None - assert result.project.basename == context['project_slug'] + assert result.project.basename == context["project_slug"] assert result.project.isdir() paths = build_files_list(str(result.project)) @@ -58,9 +59,9 @@ def test_default_configuration(cookies, context): check_paths(paths) -@pytest.fixture(params=['use_mailhog', 'use_celery', 'windows']) +@pytest.fixture(params=["use_mailhog", "use_celery", "windows"]) def feature_context(request, context): - context.update({request.param: 'y'}) + context.update({request.param: "y"}) return context @@ -68,7 +69,7 @@ def test_enabled_features(cookies, feature_context): result = cookies.bake(extra_context=feature_context) assert result.exit_code == 0 assert result.exception is None - assert result.project.basename == feature_context['project_slug'] + assert result.project.basename == feature_context["project_slug"] assert result.project.isdir() paths = build_files_list(str(result.project)) diff --git a/{{cookiecutter.project_slug}}/config/settings/test.py b/{{cookiecutter.project_slug}}/config/settings/test.py index e206c2f5..e947d410 100644 --- a/{{cookiecutter.project_slug}}/config/settings/test.py +++ b/{{cookiecutter.project_slug}}/config/settings/test.py @@ -10,47 +10,44 @@ from .base import env # https://docs.djangoproject.com/en/dev/ref/settings/#debug DEBUG = False # https://docs.djangoproject.com/en/dev/ref/settings/#secret-key -SECRET_KEY = env('DJANGO_SECRET_KEY', default='!!!SET DJANGO_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' +TEST_RUNNER = "django.test.runner.DiscoverRunner" # CACHES # ------------------------------------------------------------------------------ # https://docs.djangoproject.com/en/dev/ref/settings/#caches CACHES = { - 'default': { - 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', - 'LOCATION': '' + "default": { + "BACKEND": "django.core.cache.backends.locmem.LocMemCache", "LOCATION": "" } } # PASSWORDS # ------------------------------------------------------------------------------ # https://docs.djangoproject.com/en/dev/ref/settings/#password-hashers -PASSWORD_HASHERS = [ - 'django.contrib.auth.hashers.MD5PasswordHasher', -] +PASSWORD_HASHERS = ["django.contrib.auth.hashers.MD5PasswordHasher"] # TEMPLATES # ------------------------------------------------------------------------------ # https://docs.djangoproject.com/en/dev/ref/settings/#templates -TEMPLATES[0]['OPTIONS']['debug'] = DEBUG # noqa F405 -TEMPLATES[0]['OPTIONS']['loaders'] = [ # noqa F405 +TEMPLATES[0]["OPTIONS"]["debug"] = DEBUG # noqa F405 +TEMPLATES[0]["OPTIONS"]["loaders"] = [ # noqa F405 ( - 'django.template.loaders.cached.Loader', + "django.template.loaders.cached.Loader", [ - 'django.template.loaders.filesystem.Loader', - 'django.template.loaders.app_directories.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' +EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend" # https://docs.djangoproject.com/en/dev/ref/settings/#email-host -EMAIL_HOST = 'localhost' +EMAIL_HOST = "localhost" # https://docs.djangoproject.com/en/dev/ref/settings/#email-port EMAIL_PORT = 1025 diff --git a/{{cookiecutter.project_slug}}/config/urls.py b/{{cookiecutter.project_slug}}/config/urls.py index 930d210e..2a126f6e 100644 --- a/{{cookiecutter.project_slug}}/config/urls.py +++ b/{{cookiecutter.project_slug}}/config/urls.py @@ -6,32 +6,47 @@ from django.views.generic import TemplateView from django.views import defaults as default_views urlpatterns = [ - url(r'^$', TemplateView.as_view(template_name='pages/home.html'), name='home'), - url(r'^about/$', TemplateView.as_view(template_name='pages/about.html'), name='about'), - + url(r"^$", TemplateView.as_view(template_name="pages/home.html"), name="home"), + url( + r"^about/$", + TemplateView.as_view(template_name="pages/about.html"), + name="about", + ), # Django Admin, use {% raw %}{% url 'admin:index' %}{% endraw %} url(settings.ADMIN_URL, admin.site.urls), - # User management - url(r'^users/', include('{{ cookiecutter.project_slug }}.users.urls', namespace='users')), - url(r'^accounts/', include('allauth.urls')), - + url( + r"^users/", + include("{{ cookiecutter.project_slug }}.users.urls", namespace="users"), + ), + url(r"^accounts/", include("allauth.urls")), # Your stuff: custom urls includes go here - - -] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) +] + static( + settings.MEDIA_URL, document_root=settings.MEDIA_ROOT +) if settings.DEBUG: # This allows the error pages to be debugged during development, just visit # these url in browser to see how these error pages look like. urlpatterns += [ - url(r'^400/$', default_views.bad_request, kwargs={'exception': Exception('Bad Request!')}), - url(r'^403/$', default_views.permission_denied, kwargs={'exception': Exception('Permission Denied')}), - url(r'^404/$', default_views.page_not_found, kwargs={'exception': Exception('Page not Found')}), - url(r'^500/$', default_views.server_error), + url( + r"^400/$", + default_views.bad_request, + kwargs={"exception": Exception("Bad Request!")}, + ), + url( + r"^403/$", + default_views.permission_denied, + kwargs={"exception": Exception("Permission Denied")}, + ), + url( + r"^404/$", + default_views.page_not_found, + kwargs={"exception": Exception("Page not Found")}, + ), + url(r"^500/$", default_views.server_error), ] - if 'debug_toolbar' in settings.INSTALLED_APPS: + if "debug_toolbar" in settings.INSTALLED_APPS: import debug_toolbar - urlpatterns = [ - url(r'^__debug__/', include(debug_toolbar.urls)), - ] + urlpatterns + + urlpatterns = [url(r"^__debug__/", include(debug_toolbar.urls))] + urlpatterns diff --git a/{{cookiecutter.project_slug}}/docs/conf.py b/{{cookiecutter.project_slug}}/docs/conf.py index 80c45032..154c3a7a 100644 --- a/{{cookiecutter.project_slug}}/docs/conf.py +++ b/{{cookiecutter.project_slug}}/docs/conf.py @@ -27,19 +27,19 @@ import sys extensions = [] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # The suffix of source filenames. -source_suffix = '.rst' +source_suffix = ".rst" # The encoding of source files. # source_encoding = 'utf-8-sig' # The master toctree document. -master_doc = 'index' +master_doc = "index" # General information about the project. -project = '{{ cookiecutter.project_name }}' +project = "{{ cookiecutter.project_name }}" copyright = """{% now 'utc', '%Y' %}, {{ cookiecutter.author_name }}""" # The version info for the project you're documenting, acts as replacement for @@ -47,9 +47,9 @@ copyright = """{% now 'utc', '%Y' %}, {{ cookiecutter.author_name }}""" # built documents. # # The short X.Y version. -version = '0.1' +version = "0.1" # The full version, including alpha/beta/rc tags. -release = '0.1' +release = "0.1" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -63,7 +63,7 @@ release = '0.1' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. -exclude_patterns = ['_build'] +exclude_patterns = ["_build"] # The reST default role (used for this markup: `text`) to use for all documents. # default_role = None @@ -80,7 +80,7 @@ exclude_patterns = ['_build'] # show_authors = False # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # A list of ignored prefixes for module index sorting. # modindex_common_prefix = [] @@ -90,7 +90,7 @@ pygments_style = 'sphinx' # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'default' +html_theme = "default" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the @@ -119,7 +119,7 @@ html_theme = 'default' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ["_static"] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. @@ -163,7 +163,7 @@ html_static_path = ['_static'] # html_file_suffix = None # Output file base name for HTML help builder. -htmlhelp_basename = '{{ cookiecutter.project_slug }}doc' +htmlhelp_basename = "{{ cookiecutter.project_slug }}doc" # -- Options for LaTeX output -------------------------------------------------- @@ -171,10 +171,8 @@ htmlhelp_basename = '{{ cookiecutter.project_slug }}doc' latex_elements = { # The paper size ('letterpaper' or 'a4paper'). # 'papersize': 'letterpaper', - # The font size ('10pt', '11pt' or '12pt'). # 'pointsize': '10pt', - # Additional stuff for the LaTeX preamble. # 'preamble': '', } @@ -182,10 +180,13 @@ latex_elements = { # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ - ('index', - '{{ cookiecutter.project_slug }}.tex', - '{{ cookiecutter.project_name }} Documentation', - """{{ cookiecutter.author_name }}""", 'manual'), + ( + "index", + "{{ cookiecutter.project_slug }}.tex", + "{{ cookiecutter.project_name }} Documentation", + """{{ cookiecutter.author_name }}""", + "manual", + ) ] # The name of an image file (relative to this directory) to place at the top of @@ -214,8 +215,13 @@ latex_documents = [ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - ('index', '{{ cookiecutter.project_slug }}', '{{ cookiecutter.project_name }} Documentation', - ["""{{ cookiecutter.author_name }}"""], 1) + ( + "index", + "{{ cookiecutter.project_slug }}", + "{{ cookiecutter.project_name }} Documentation", + ["""{{ cookiecutter.author_name }}"""], + 1, + ) ] # If true, show URL addresses after external links. @@ -228,9 +234,15 @@ man_pages = [ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - ('index', '{{ cookiecutter.project_slug }}', '{{ cookiecutter.project_name }} Documentation', - """{{ cookiecutter.author_name }}""", '{{ cookiecutter.project_name }}', - """{{ cookiecutter.description }}""", 'Miscellaneous'), + ( + "index", + "{{ cookiecutter.project_slug }}", + "{{ cookiecutter.project_name }} Documentation", + """{{ cookiecutter.author_name }}""", + "{{ cookiecutter.project_name }}", + """{{ cookiecutter.description }}""", + "Miscellaneous", + ) ] # Documents to append as an appendix to all manuals. diff --git a/{{cookiecutter.project_slug}}/manage.py b/{{cookiecutter.project_slug}}/manage.py index 9694c5f8..7e9c99e0 100755 --- a/{{cookiecutter.project_slug}}/manage.py +++ b/{{cookiecutter.project_slug}}/manage.py @@ -2,8 +2,8 @@ import os import sys -if __name__ == '__main__': - os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings.local') +if __name__ == "__main__": + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.local") try: from django.core.management import execute_from_command_line @@ -19,11 +19,12 @@ if __name__ == '__main__': "available on your PYTHONPATH environment variable? Did you " "forget to activate a virtual environment?" ) + raise # This allows easy placement of apps within the interior # {{ cookiecutter.project_slug }} directory. current_path = os.path.dirname(os.path.abspath(__file__)) - sys.path.append(os.path.join(current_path, '{{ cookiecutter.project_slug }}')) + sys.path.append(os.path.join(current_path, "{{ cookiecutter.project_slug }}")) execute_from_command_line(sys.argv) diff --git a/{{cookiecutter.project_slug}}/merge_production_dotenvs_in_dotenv.py b/{{cookiecutter.project_slug}}/merge_production_dotenvs_in_dotenv.py index c1bfe30a..5c3027a4 100644 --- a/{{cookiecutter.project_slug}}/merge_production_dotenvs_in_dotenv.py +++ b/{{cookiecutter.project_slug}}/merge_production_dotenvs_in_dotenv.py @@ -4,21 +4,21 @@ from typing import Sequence import pytest ROOT_DIR_PATH = os.path.dirname(os.path.realpath(__file__)) -PRODUCTION_DOTENVS_DIR_PATH = os.path.join(ROOT_DIR_PATH, '.envs', '.production') +PRODUCTION_DOTENVS_DIR_PATH = os.path.join(ROOT_DIR_PATH, ".envs", ".production") PRODUCTION_DOTENV_FILE_PATHS = [ - os.path.join(PRODUCTION_DOTENVS_DIR_PATH, '.django'), - os.path.join(PRODUCTION_DOTENVS_DIR_PATH, '.postgres'), - os.path.join(PRODUCTION_DOTENVS_DIR_PATH, '.caddy'), + os.path.join(PRODUCTION_DOTENVS_DIR_PATH, ".django"), + os.path.join(PRODUCTION_DOTENVS_DIR_PATH, ".postgres"), + os.path.join(PRODUCTION_DOTENVS_DIR_PATH, ".caddy"), ] -DOTENV_FILE_PATH = os.path.join(ROOT_DIR_PATH, '.env') +DOTENV_FILE_PATH = os.path.join(ROOT_DIR_PATH, ".env") -def merge(output_file_path: str, - merged_file_paths: Sequence[str], - append_linesep: bool = True) -> None: - with open(output_file_path, 'w') as output_file: +def merge( + output_file_path: str, merged_file_paths: Sequence[str], append_linesep: bool = True +) -> None: + with open(output_file_path, "w") as output_file: for merged_file_path in merged_file_paths: - with open(merged_file_path, 'r') as merged_file: + with open(merged_file_path, "r") as merged_file: merged_file_content = merged_file.read() output_file.write(merged_file_content) if append_linesep: @@ -29,26 +29,24 @@ def main(): merge(DOTENV_FILE_PATH, PRODUCTION_DOTENV_FILE_PATHS) -@pytest.mark.parametrize('merged_file_count', range(3)) -@pytest.mark.parametrize('append_linesep', [True, False]) -def test_merge(tmpdir_factory, - merged_file_count: int, - append_linesep: bool): +@pytest.mark.parametrize("merged_file_count", range(3)) +@pytest.mark.parametrize("append_linesep", [True, False]) +def test_merge(tmpdir_factory, merged_file_count: int, append_linesep: bool): tmp_dir_path = str(tmpdir_factory.getbasetemp()) - output_file_path = os.path.join(tmp_dir_path, '.env') + output_file_path = os.path.join(tmp_dir_path, ".env") - expected_output_file_content = '' + expected_output_file_content = "" merged_file_paths = [] for i in range(merged_file_count): merged_file_ord = i + 1 - merged_filename = '.service{}'.format(merged_file_ord) + merged_filename = ".service{}".format(merged_file_ord) merged_file_path = os.path.join(tmp_dir_path, merged_filename) merged_file_content = merged_filename * merged_file_ord - with open(merged_file_path, 'w+') as file: + with open(merged_file_path, "w+") as file: file.write(merged_file_content) expected_output_file_content += merged_file_content @@ -59,11 +57,11 @@ def test_merge(tmpdir_factory, merge(output_file_path, merged_file_paths, append_linesep) - with open(output_file_path, 'r') as output_file: + with open(output_file_path, "r") as output_file: actual_output_file_content = output_file.read() assert actual_output_file_content == expected_output_file_content -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/__init__.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/__init__.py index 14a422a2..b4056707 100644 --- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/__init__.py +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/__init__.py @@ -1,2 +1,7 @@ -__version__ = '{{ cookiecutter.version }}' -__version_info__ = tuple([int(num) if num.isdigit() else num for num in __version__.replace('-', '.', 1).split('.')]) +__version__ = "{{ cookiecutter.version }}" +__version_info__ = tuple( + [ + int(num) if num.isdigit() else num + for num in __version__.replace("-", ".", 1).split(".") + ] +) diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/contrib/sites/migrations/0001_initial.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/contrib/sites/migrations/0001_initial.py index a7639869..304cd6d7 100644 --- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/contrib/sites/migrations/0001_initial.py +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/contrib/sites/migrations/0001_initial.py @@ -9,23 +9,34 @@ class Migration(migrations.Migration): operations = [ migrations.CreateModel( - name='Site', + name="Site", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('domain', models.CharField( - max_length=100, verbose_name='domain name', validators=[_simple_domain_name_validator] - )), - ('name', models.CharField(max_length=50, verbose_name='display name')), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "domain", + models.CharField( + max_length=100, + verbose_name="domain name", + validators=[_simple_domain_name_validator], + ), + ), + ("name", models.CharField(max_length=50, verbose_name="display name")), ], options={ - 'ordering': ('domain',), - 'db_table': 'django_site', - 'verbose_name': 'site', - 'verbose_name_plural': 'sites', + "ordering": ("domain",), + "db_table": "django_site", + "verbose_name": "site", + "verbose_name_plural": "sites", }, bases=(models.Model,), - managers=[ - ('objects', django.contrib.sites.models.SiteManager()), - ], - ), + managers=[("objects", django.contrib.sites.models.SiteManager())], + ) ] diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/contrib/sites/migrations/0002_alter_domain_unique.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/contrib/sites/migrations/0002_alter_domain_unique.py index 6a26ebcd..2c8d6dac 100644 --- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/contrib/sites/migrations/0002_alter_domain_unique.py +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/contrib/sites/migrations/0002_alter_domain_unique.py @@ -4,17 +4,17 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('sites', '0001_initial'), - ] + dependencies = [("sites", "0001_initial")] operations = [ migrations.AlterField( - model_name='site', - name='domain', + model_name="site", + name="domain", field=models.CharField( - max_length=100, unique=True, validators=[django.contrib.sites.models._simple_domain_name_validator], - verbose_name='domain name' + max_length=100, + unique=True, + validators=[django.contrib.sites.models._simple_domain_name_validator], + verbose_name="domain name", ), - ), + ) ] diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/contrib/sites/migrations/0003_set_site_domain_and_name.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/contrib/sites/migrations/0003_set_site_domain_and_name.py index 05a47ba4..8f4a8f99 100644 --- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/contrib/sites/migrations/0003_set_site_domain_and_name.py +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/contrib/sites/migrations/0003_set_site_domain_and_name.py @@ -9,34 +9,26 @@ from django.db import migrations def update_site_forward(apps, schema_editor): """Set site domain and name.""" - Site = apps.get_model('sites', 'Site') + Site = apps.get_model("sites", "Site") Site.objects.update_or_create( id=settings.SITE_ID, defaults={ - 'domain': '{{cookiecutter.domain_name}}', - 'name': '{{cookiecutter.project_name}}' - } + "domain": "{{cookiecutter.domain_name}}", + "name": "{{cookiecutter.project_name}}", + }, ) def update_site_backward(apps, schema_editor): """Revert site domain and name to default.""" - Site = apps.get_model('sites', 'Site') + Site = apps.get_model("sites", "Site") Site.objects.update_or_create( - id=settings.SITE_ID, - defaults={ - 'domain': 'example.com', - 'name': 'example.com' - } + id=settings.SITE_ID, defaults={"domain": "example.com", "name": "example.com"} ) class Migration(migrations.Migration): - dependencies = [ - ('sites', '0002_alter_domain_unique'), - ] + dependencies = [("sites", "0002_alter_domain_unique")] - operations = [ - migrations.RunPython(update_site_forward, update_site_backward), - ] + operations = [migrations.RunPython(update_site_forward, update_site_backward)] diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/adapters.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/adapters.py index b31450ae..5b63593b 100644 --- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/adapters.py +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/adapters.py @@ -4,10 +4,12 @@ from allauth.socialaccount.adapter import DefaultSocialAccountAdapter class AccountAdapter(DefaultAccountAdapter): + def is_open_for_signup(self, request): - return getattr(settings, 'ACCOUNT_ALLOW_REGISTRATION', True) + return getattr(settings, "ACCOUNT_ALLOW_REGISTRATION", True) class SocialAccountAdapter(DefaultSocialAccountAdapter): + def is_open_for_signup(self, request, sociallogin): - return getattr(settings, 'ACCOUNT_ALLOW_REGISTRATION', True) + return getattr(settings, "ACCOUNT_ALLOW_REGISTRATION", True) diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/admin.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/admin.py index 9b615121..8da8f86a 100644 --- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/admin.py +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/admin.py @@ -6,15 +6,16 @@ from .models import User class MyUserChangeForm(UserChangeForm): + class Meta(UserChangeForm.Meta): model = User class MyUserCreationForm(UserCreationForm): - error_message = UserCreationForm.error_messages.update({ - 'duplicate_username': 'This username has already been taken.' - }) + error_message = UserCreationForm.error_messages.update( + {"duplicate_username": "This username has already been taken."} + ) class Meta(UserCreationForm.Meta): model = User @@ -25,15 +26,14 @@ class MyUserCreationForm(UserCreationForm): User.objects.get(username=username) except User.DoesNotExist: return username - raise forms.ValidationError(self.error_messages['duplicate_username']) + + raise forms.ValidationError(self.error_messages["duplicate_username"]) @admin.register(User) class MyUserAdmin(AuthUserAdmin): form = MyUserChangeForm add_form = MyUserCreationForm - fieldsets = ( - ('User Profile', {'fields': ('name',)}), - ) + AuthUserAdmin.fieldsets - list_display = ('username', 'name', 'is_superuser') - search_fields = ['name'] + fieldsets = (("User Profile", {"fields": ("name",)}),) + AuthUserAdmin.fieldsets + list_display = ("username", "name", "is_superuser") + search_fields = ["name"] diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/apps.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/apps.py index 24c319df..118bfda9 100644 --- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/apps.py +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/apps.py @@ -2,7 +2,7 @@ from django.apps import AppConfig class UsersConfig(AppConfig): - name = '{{cookiecutter.project_slug}}.users' + name = "{{cookiecutter.project_slug}}.users" verbose_name = "Users" def ready(self): diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/migrations/0001_initial.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/migrations/0001_initial.py index 7cc96f62..c9d89056 100644 --- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/migrations/0001_initial.py +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/migrations/0001_initial.py @@ -8,36 +8,125 @@ class Migration(migrations.Migration): initial = True - dependencies = [ - ('auth', '0008_alter_user_username_max_length'), - ] + dependencies = [("auth", "0008_alter_user_username_max_length")] operations = [ migrations.CreateModel( - name='User', + name="User", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('password', models.CharField(max_length=128, verbose_name='password')), - ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), - ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), - ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')), - ('first_name', models.CharField(blank=True, max_length=30, verbose_name='first name')), - ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')), - ('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')), - ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), - ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')), - ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), - ('name', models.CharField(blank=True, max_length=255, verbose_name='Name of User')), - ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')), - ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("password", models.CharField(max_length=128, verbose_name="password")), + ( + "last_login", + models.DateTimeField( + blank=True, null=True, verbose_name="last login" + ), + ), + ( + "is_superuser", + models.BooleanField( + default=False, + help_text="Designates that this user has all permissions without explicitly assigning them.", + verbose_name="superuser status", + ), + ), + ( + "username", + models.CharField( + error_messages={ + "unique": "A user with that username already exists." + }, + help_text="Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.", + max_length=150, + unique=True, + validators=[ + django.contrib.auth.validators.UnicodeUsernameValidator() + ], + verbose_name="username", + ), + ), + ( + "first_name", + models.CharField( + blank=True, max_length=30, verbose_name="first name" + ), + ), + ( + "last_name", + models.CharField( + blank=True, max_length=150, verbose_name="last name" + ), + ), + ( + "email", + models.EmailField( + blank=True, max_length=254, verbose_name="email address" + ), + ), + ( + "is_staff", + models.BooleanField( + default=False, + help_text="Designates whether the user can log into this admin site.", + verbose_name="staff status", + ), + ), + ( + "is_active", + models.BooleanField( + default=True, + help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.", + verbose_name="active", + ), + ), + ( + "date_joined", + models.DateTimeField( + default=django.utils.timezone.now, verbose_name="date joined" + ), + ), + ( + "name", + models.CharField( + blank=True, max_length=255, verbose_name="Name of User" + ), + ), + ( + "groups", + models.ManyToManyField( + blank=True, + help_text="The groups this user belongs to. A user will get all permissions granted to each of their groups.", + related_name="user_set", + related_query_name="user", + to="auth.Group", + verbose_name="groups", + ), + ), + ( + "user_permissions", + models.ManyToManyField( + blank=True, + help_text="Specific permissions for this user.", + related_name="user_set", + related_query_name="user", + to="auth.Permission", + verbose_name="user permissions", + ), + ), ], options={ - 'verbose_name_plural': 'users', - 'verbose_name': 'user', - 'abstract': False, + "verbose_name_plural": "users", + "verbose_name": "user", + "abstract": False, }, - managers=[ - ('objects', django.contrib.auth.models.UserManager()), - ], - ), + managers=[("objects", django.contrib.auth.models.UserManager())], + ) ] diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/models.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/models.py index 4b1a10d1..30475871 100644 --- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/models.py +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/models.py @@ -8,10 +8,10 @@ class User(AbstractUser): # First Name and Last Name do not cover name patterns # around the globe. - name = models.CharField(_('Name of User'), blank=True, max_length=255) + name = models.CharField(_("Name of User"), blank=True, max_length=255) def __str__(self): return self.username def get_absolute_url(self): - return reverse('users:detail', kwargs={'username': self.username}) + return reverse("users:detail", kwargs={"username": self.username}) 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 a777ae9e..8a871b64 100644 --- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/factories.py +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/factories.py @@ -2,10 +2,10 @@ import factory class UserFactory(factory.django.DjangoModelFactory): - username = factory.Sequence(lambda n: f'user-{n}') - email = factory.Sequence(lambda n: f'user-{n}@example.com') - password = factory.PostGenerationMethodCall('set_password', 'password') + 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: - model = 'users.User' - django_get_or_create = ('username', ) + model = "users.User" + django_get_or_create = ("username",) diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_admin.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_admin.py index a1ff0b84..a3307103 100644 --- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_admin.py +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_admin.py @@ -6,30 +6,34 @@ from ..admin import MyUserCreationForm class TestMyUserCreationForm(TestCase): def setUp(self): - self.user = self.make_user('notalamode', 'notalamodespassword') + self.user = self.make_user("notalamode", "notalamodespassword") def test_clean_username_success(self): # Instantiate the form with a new username - form = MyUserCreationForm({ - 'username': 'alamode', - 'password1': '7jefB#f@Cc7YJB]2v', - 'password2': '7jefB#f@Cc7YJB]2v', - }) + form = MyUserCreationForm( + { + "username": "alamode", + "password1": "7jefB#f@Cc7YJB]2v", + "password2": "7jefB#f@Cc7YJB]2v", + } + ) # Run is_valid() to trigger the validation valid = form.is_valid() self.assertTrue(valid) # Run the actual clean_username method username = form.clean_username() - self.assertEqual('alamode', username) + self.assertEqual("alamode", username) def test_clean_username_false(self): # Instantiate the form with the same username as self.user - form = MyUserCreationForm({ - 'username': self.user.username, - 'password1': 'notalamodespassword', - 'password2': 'notalamodespassword', - }) + form = MyUserCreationForm( + { + "username": self.user.username, + "password1": "notalamodespassword", + "password2": "notalamodespassword", + } + ) # Run is_valid() to trigger the validation, which is going to fail # because the username is already taken valid = form.is_valid() @@ -37,4 +41,4 @@ class TestMyUserCreationForm(TestCase): # The form.errors dict should contain a single error called 'username' self.assertTrue(len(form.errors) == 1) - self.assertTrue('username' in form.errors) + self.assertTrue("username" in form.errors) diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_models.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_models.py index 894ed183..13121a01 100644 --- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_models.py +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_models.py @@ -9,11 +9,8 @@ class TestUser(TestCase): def test__str__(self): self.assertEqual( self.user.__str__(), - 'testuser' # This is the default username for self.make_user() + "testuser", # This is the default username for self.make_user() ) def test_get_absolute_url(self): - self.assertEqual( - self.user.get_absolute_url(), - '/users/testuser/' - ) + self.assertEqual(self.user.get_absolute_url(), "/users/testuser/") diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_urls.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_urls.py index 4935b0f3..6b072436 100644 --- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_urls.py +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_urls.py @@ -11,41 +11,34 @@ class TestUserURLs(TestCase): def test_list_reverse(self): """users:list should reverse to /users/.""" - self.assertEqual(reverse('users:list'), '/users/') + self.assertEqual(reverse("users:list"), "/users/") def test_list_resolve(self): """/users/ should resolve to users:list.""" - self.assertEqual(resolve('/users/').view_name, 'users:list') + self.assertEqual(resolve("/users/").view_name, "users:list") def test_redirect_reverse(self): """users:redirect should reverse to /users/~redirect/.""" - self.assertEqual(reverse('users:redirect'), '/users/~redirect/') + self.assertEqual(reverse("users:redirect"), "/users/~redirect/") def test_redirect_resolve(self): """/users/~redirect/ should resolve to users:redirect.""" - self.assertEqual( - resolve('/users/~redirect/').view_name, - 'users:redirect' - ) + self.assertEqual(resolve("/users/~redirect/").view_name, "users:redirect") def test_detail_reverse(self): """users:detail should reverse to /users/testuser/.""" self.assertEqual( - reverse('users:detail', kwargs={'username': 'testuser'}), - '/users/testuser/' + reverse("users:detail", kwargs={"username": "testuser"}), "/users/testuser/" ) def test_detail_resolve(self): """/users/testuser/ should resolve to users:detail.""" - self.assertEqual(resolve('/users/testuser/').view_name, 'users:detail') + self.assertEqual(resolve("/users/testuser/").view_name, "users:detail") def test_update_reverse(self): """users:update should reverse to /users/~update/.""" - self.assertEqual(reverse('users:update'), '/users/~update/') + self.assertEqual(reverse("users:update"), "/users/~update/") def test_update_resolve(self): """/users/~update/ should resolve to users:update.""" - self.assertEqual( - resolve('/users/~update/').view_name, - 'users:update' - ) + self.assertEqual(resolve("/users/~update/").view_name, "users:update") diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_views.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_views.py index 23f30f03..1fa45697 100644 --- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_views.py +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_views.py @@ -2,10 +2,7 @@ from django.test import RequestFactory from test_plus.test import TestCase -from ..views import ( - UserRedirectView, - UserUpdateView -) +from ..views import (UserRedirectView, UserUpdateView) class BaseUserTestCase(TestCase): @@ -21,17 +18,14 @@ class TestUserRedirectView(BaseUserTestCase): # Instantiate the view directly. Never do this outside a test! view = UserRedirectView() # Generate a fake request - request = self.factory.get('/fake-url') + request = self.factory.get("/fake-url") # Attach the user to the request request.user = self.user # Attach the request to the view view.request = request # Expect: '/users/testuser/', as that is the default username for # self.make_user() - self.assertEqual( - view.get_redirect_url(), - '/users/testuser/' - ) + self.assertEqual(view.get_redirect_url(), "/users/testuser/") class TestUserUpdateView(BaseUserTestCase): @@ -42,7 +36,7 @@ class TestUserUpdateView(BaseUserTestCase): # Instantiate the view directly. Never do this outside a test! self.view = UserUpdateView() # Generate a fake request - request = self.factory.get('/fake-url') + request = self.factory.get("/fake-url") # Attach the user to the request request.user = self.user # Attach the request to the view @@ -51,14 +45,8 @@ class TestUserUpdateView(BaseUserTestCase): def test_get_success_url(self): # Expect: '/users/testuser/', as that is the default username for # self.make_user() - self.assertEqual( - self.view.get_success_url(), - '/users/testuser/' - ) + self.assertEqual(self.view.get_success_url(), "/users/testuser/") def test_get_object(self): # Expect: self.user, as that is the request's user object - self.assertEqual( - self.view.get_object(), - self.user - ) + self.assertEqual(self.view.get_object(), self.user) diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/urls.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/urls.py index 1e161836..69414f47 100644 --- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/urls.py +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/urls.py @@ -2,26 +2,14 @@ from django.conf.urls import url from . import views -app_name = 'users' +app_name = "users" urlpatterns = [ + url(regex=r"^$", view=views.UserListView.as_view(), name="list"), + url(regex=r"^~redirect/$", view=views.UserRedirectView.as_view(), name="redirect"), + url(regex=r"^~update/$", view=views.UserUpdateView.as_view(), name="update"), url( - regex=r'^$', - view=views.UserListView.as_view(), - name='list' - ), - url( - regex=r'^~redirect/$', - view=views.UserRedirectView.as_view(), - name='redirect' - ), - url( - regex=r'^~update/$', - view=views.UserUpdateView.as_view(), - name='update' - ), - url( - regex=r'^(?P[\w.@+-]+)/$', + regex=r"^(?P[\w.@+-]+)/$", view=views.UserDetailView.as_view(), - name='detail' + name="detail", ), ] diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/views.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/views.py index acde4a8f..a9038b71 100644 --- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/views.py +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/views.py @@ -8,29 +8,28 @@ from .models import User class UserDetailView(LoginRequiredMixin, DetailView): model = User # These next two lines tell the view to index lookups by username - slug_field = 'username' - slug_url_kwarg = 'username' + slug_field = "username" + slug_url_kwarg = "username" class UserRedirectView(LoginRequiredMixin, RedirectView): permanent = False def get_redirect_url(self): - return reverse('users:detail', - kwargs={'username': self.request.user.username}) + return reverse("users:detail", kwargs={"username": self.request.user.username}) class UserUpdateView(LoginRequiredMixin, UpdateView): - fields = ['name', ] + fields = ["name"] # we already imported User in the view code above, remember? model = User # send the user back to their own page after a successful update + def get_success_url(self): - return reverse('users:detail', - kwargs={'username': self.request.user.username}) + return reverse("users:detail", kwargs={"username": self.request.user.username}) def get_object(self): # Only get the User record for the user making the request @@ -40,5 +39,5 @@ class UserUpdateView(LoginRequiredMixin, UpdateView): class UserListView(LoginRequiredMixin, ListView): model = User # These next two lines tell the view to index lookups by username - slug_field = 'username' - slug_url_kwarg = 'username' + slug_field = "username" + slug_url_kwarg = "username" From e8c91c1fa76921c0c7df7109d6ed7af9489a7093 Mon Sep 17 00:00:00 2001 From: Daniel Roy Greenfeld Date: Sun, 8 Apr 2018 17:04:02 -0500 Subject: [PATCH 130/166] Update README.rst --- README.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.rst b/README.rst index ceaec836..d7eec9b5 100644 --- a/README.rst +++ b/README.rst @@ -15,6 +15,10 @@ Cookiecutter Django .. image:: https://www.codetriage.com/pydanny/cookiecutter-django/badges/users.svg :target: https://www.codetriage.com/pydanny/cookiecutter-django :alt: Code Helpers Badge + +.. image:: https://www.codetriage.com/pydanny/cookiecutter-django/badges/users.svg + :target: https://www.codetriage.com/pydanny/cookiecutter-django + :alt: Code Helpers Badge Powered by Cookiecutter_, Cookiecutter Django is a framework for jumpstarting production-ready Django projects quickly. From 1355222385fbabbe68fe9a89db66ef3cfdb23d9e Mon Sep 17 00:00:00 2001 From: Daniel Roy Greenfeld Date: Sun, 8 Apr 2018 17:05:08 -0500 Subject: [PATCH 131/166] Add black badge --- README.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index d7eec9b5..21e723bc 100644 --- a/README.rst +++ b/README.rst @@ -16,9 +16,9 @@ Cookiecutter Django :target: https://www.codetriage.com/pydanny/cookiecutter-django :alt: Code Helpers Badge -.. image:: https://www.codetriage.com/pydanny/cookiecutter-django/badges/users.svg - :target: https://www.codetriage.com/pydanny/cookiecutter-django - :alt: Code Helpers Badge +.. image:: https://img.shields.io/badge/code%20style-black-000000.svg + :target: https://github.com/ambv/black + :alt: Code style: black Powered by Cookiecutter_, Cookiecutter Django is a framework for jumpstarting production-ready Django projects quickly. From a4f059196e640ac9b3876d6b6ab0340afba6a86e Mon Sep 17 00:00:00 2001 From: Osaetin Daniel Date: Tue, 10 Apr 2018 03:39:44 +0100 Subject: [PATCH 132/166] Removed unnecessary sentry configuration (#1598) --- {{cookiecutter.project_slug}}/config/settings/production.py | 3 +-- .../{{cookiecutter.project_slug}}/taskapp/celery.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/{{cookiecutter.project_slug}}/config/settings/production.py b/{{cookiecutter.project_slug}}/config/settings/production.py index 236cecbf..e1c6de89 100644 --- a/{{cookiecutter.project_slug}}/config/settings/production.py +++ b/{{cookiecutter.project_slug}}/config/settings/production.py @@ -237,8 +237,7 @@ LOGGING = { 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 + 'dsn': SENTRY_DSN } {%- else %} # LOGGING diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/taskapp/celery.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/taskapp/celery.py index c568ca88..3c5d0e9c 100644 --- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/taskapp/celery.py +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/taskapp/celery.py @@ -41,7 +41,7 @@ class CeleryConfig(AppConfig): # @formatter:on {%- endif %} - raven_client = RavenClient(dsn=settings.RAVEN_CONFIG['DSN']) + raven_client = RavenClient(dsn=settings.RAVEN_CONFIG['dsn']) raven_register_logger_signal(raven_client) raven_register_signal(raven_client) {%- endif %} From b6c80ab3338cde9f3c69bf1b9e16402e094ac84b Mon Sep 17 00:00:00 2001 From: "pyup.io bot" Date: Tue, 10 Apr 2018 22:34:01 +0200 Subject: [PATCH 133/166] Update pytz from 2018.3 to 2018.4 (#1605) --- {{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 e628da49..bd024298 100644 --- a/{{cookiecutter.project_slug}}/requirements/base.txt +++ b/{{cookiecutter.project_slug}}/requirements/base.txt @@ -1,4 +1,4 @@ -pytz==2018.3 # https://github.com/stub42/pytz +pytz==2018.4 # https://github.com/stub42/pytz awesome-slugify==1.6.5 # https://github.com/dimka665/awesome-slugify Pillow==5.1.0 # https://github.com/python-pillow/Pillow {%- if cookiecutter.use_compressor == "y" %} From 1c5f1bb62b546d44189aded310eee381b1e0ab27 Mon Sep 17 00:00:00 2001 From: "pyup.io bot" Date: Thu, 12 Apr 2018 02:32:02 +0200 Subject: [PATCH 134/166] Update django-anymail from 2.0 to 2.1 (#1607) --- {{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 1d2e3fad..60fa3451 100644 --- a/{{cookiecutter.project_slug}}/requirements/production.txt +++ b/{{cookiecutter.project_slug}}/requirements/production.txt @@ -16,4 +16,4 @@ raven==6.6.0 # https://github.com/getsentry/raven-python # Django # ------------------------------------------------------------------------------ django-storages==1.6.6 # https://github.com/jschneier/django-storages -django-anymail==2.0 # https://github.com/anymail/django-anymail +django-anymail==2.1 # https://github.com/anymail/django-anymail From 56b3ac7311a3e48375e9a13987fbc04638019850 Mon Sep 17 00:00:00 2001 From: "pyup.io bot" Date: Sat, 14 Apr 2018 17:27:58 +0200 Subject: [PATCH 135/166] Update pytest-django from 3.1.2 to 3.2.1 (#1608) --- {{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 a79698fd..2378c76f 100644 --- a/{{cookiecutter.project_slug}}/requirements/local.txt +++ b/{{cookiecutter.project_slug}}/requirements/local.txt @@ -27,4 +27,4 @@ django-test-plus==1.0.22 # https://github.com/revsys/django-test-plus django-debug-toolbar==1.9.1 # https://github.com/jazzband/django-debug-toolbar django-extensions==2.0.6 # https://github.com/django-extensions/django-extensions django-coverage-plugin==1.5.0 # https://github.com/nedbat/django_coverage_plugin -pytest-django==3.1.2 # https://github.com/pytest-dev/pytest-django +pytest-django==3.2.1 # https://github.com/pytest-dev/pytest-django From 6a0a2e5637fb72f3c55e25d0e59811416f8525b6 Mon Sep 17 00:00:00 2001 From: Aleksei Kuznetcov Date: Sun, 15 Apr 2018 17:14:11 -0400 Subject: [PATCH 136/166] Update runtime python version from 3.6.4 to 3.6.5 --- {{cookiecutter.project_slug}}/runtime.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/{{cookiecutter.project_slug}}/runtime.txt b/{{cookiecutter.project_slug}}/runtime.txt index 5c453803..486fcce1 100644 --- a/{{cookiecutter.project_slug}}/runtime.txt +++ b/{{cookiecutter.project_slug}}/runtime.txt @@ -1 +1 @@ -python-3.6.4 +python-3.6.5 From cbc51bfc5f0cbe419f58eca2403ee07465319ef3 Mon Sep 17 00:00:00 2001 From: "pyup.io bot" Date: Tue, 17 Apr 2018 04:02:06 +0200 Subject: [PATCH 137/166] Update django-anymail to 2.2 (#1612) --- {{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 60fa3451..9510666a 100644 --- a/{{cookiecutter.project_slug}}/requirements/production.txt +++ b/{{cookiecutter.project_slug}}/requirements/production.txt @@ -16,4 +16,4 @@ raven==6.6.0 # https://github.com/getsentry/raven-python # Django # ------------------------------------------------------------------------------ django-storages==1.6.6 # https://github.com/jschneier/django-storages -django-anymail==2.1 # https://github.com/anymail/django-anymail +django-anymail==2.2 # https://github.com/anymail/django-anymail From bbc69b3bf1a654b05b4db2ad1a69810d2976a90e Mon Sep 17 00:00:00 2001 From: "pyup.io bot" Date: Wed, 18 Apr 2018 10:30:35 +0200 Subject: [PATCH 138/166] Update django-extensions to 2.0.7 (#1613) --- {{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 2378c76f..38e773c6 100644 --- a/{{cookiecutter.project_slug}}/requirements/local.txt +++ b/{{cookiecutter.project_slug}}/requirements/local.txt @@ -25,6 +25,6 @@ factory-boy==2.10.0 # https://github.com/FactoryBoy/factory_boy django-test-plus==1.0.22 # https://github.com/revsys/django-test-plus django-debug-toolbar==1.9.1 # https://github.com/jazzband/django-debug-toolbar -django-extensions==2.0.6 # https://github.com/django-extensions/django-extensions +django-extensions==2.0.7 # https://github.com/django-extensions/django-extensions django-coverage-plugin==1.5.0 # https://github.com/nedbat/django_coverage_plugin pytest-django==3.2.1 # https://github.com/pytest-dev/pytest-django From edae0854bf899238e37d088bfc671e73ababbd89 Mon Sep 17 00:00:00 2001 From: "pyup.io bot" Date: Wed, 18 Apr 2018 16:56:29 +0200 Subject: [PATCH 139/166] Update raven from 6.6.0 to 6.7.0 (#1614) --- {{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 9510666a..3dcb5662 100644 --- a/{{cookiecutter.project_slug}}/requirements/production.txt +++ b/{{cookiecutter.project_slug}}/requirements/production.txt @@ -10,7 +10,7 @@ psycopg2==2.7.4 --no-binary psycopg2 # https://github.com/psycopg/psycopg2 Collectfast==0.6.2 # https://github.com/antonagestam/collectfast {%- endif %} {%- if cookiecutter.use_sentry == "y" %} -raven==6.6.0 # https://github.com/getsentry/raven-python +raven==6.7.0 # https://github.com/getsentry/raven-python {%- endif %} # Django From 47cc9f03fed96332da08a5b6c43ad7238ced899e Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Sun, 22 Apr 2018 21:36:42 -0500 Subject: [PATCH 140/166] Update sphinx from 1.7.2 to 1.7.3 --- {{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 38e773c6..c15bbf90 100644 --- a/{{cookiecutter.project_slug}}/requirements/local.txt +++ b/{{cookiecutter.project_slug}}/requirements/local.txt @@ -2,7 +2,7 @@ Werkzeug==0.14.1 # https://github.com/pallets/werkzeug ipdb==0.11 # https://github.com/gotcha/ipdb -Sphinx==1.7.2 # https://github.com/sphinx-doc/sphinx +Sphinx==1.7.3 # https://github.com/sphinx-doc/sphinx {%- if cookiecutter.use_docker == 'y' %} psycopg2==2.7.4 --no-binary psycopg2 # https://github.com/psycopg/psycopg2 {%- else %} From 1ed61dafc211e3e3cdc3daae53182f1704581cbf Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Wed, 25 Apr 2018 03:24:50 -0700 Subject: [PATCH 141/166] Update pytest from 3.5.0 to 3.5.1 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 78077b01..4f981d0e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,5 +11,5 @@ pyflakes==1.6.0 # Testing # ------------------------------------------------------------------------------ tox==3.0.0 -pytest==3.5.0 +pytest==3.5.1 pytest-cookies==0.3.0 From f8e322162239e2cb7f7bdc8d77c83249f0896976 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Wed, 25 Apr 2018 03:24:51 -0700 Subject: [PATCH 142/166] Update pytest from 3.5.0 to 3.5.1 --- {{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 c15bbf90..04bbae30 100644 --- a/{{cookiecutter.project_slug}}/requirements/local.txt +++ b/{{cookiecutter.project_slug}}/requirements/local.txt @@ -11,7 +11,7 @@ psycopg2-binary==2.7.4 # https://github.com/psycopg/psycopg2 # Testing # ------------------------------------------------------------------------------ -pytest==3.5.0 # https://github.com/pytest-dev/pytest +pytest==3.5.1 # https://github.com/pytest-dev/pytest pytest-sugar==0.9.1 # https://github.com/Frozenball/pytest-sugar # Code quality From 34d9bd5d800c23d0b62750a510f9cbe8e97a8ddb Mon Sep 17 00:00:00 2001 From: "pyup.io bot" Date: Thu, 26 Apr 2018 03:06:35 +0200 Subject: [PATCH 143/166] Update sphinx to 1.7.4 (#1620) --- {{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 04bbae30..e9f057b4 100644 --- a/{{cookiecutter.project_slug}}/requirements/local.txt +++ b/{{cookiecutter.project_slug}}/requirements/local.txt @@ -2,7 +2,7 @@ Werkzeug==0.14.1 # https://github.com/pallets/werkzeug ipdb==0.11 # https://github.com/gotcha/ipdb -Sphinx==1.7.3 # https://github.com/sphinx-doc/sphinx +Sphinx==1.7.4 # https://github.com/sphinx-doc/sphinx {%- if cookiecutter.use_docker == 'y' %} psycopg2==2.7.4 --no-binary psycopg2 # https://github.com/psycopg/psycopg2 {%- else %} From 3e6caf66927ee10c7f19aada6eb5c43c50ae5dbb Mon Sep 17 00:00:00 2001 From: "pyup.io bot" Date: Sun, 29 Apr 2018 20:48:53 +0200 Subject: [PATCH 144/166] Update gunicorn from 19.7.1 to 19.8.0 (#1624) --- {{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 3dcb5662..fa27b664 100644 --- a/{{cookiecutter.project_slug}}/requirements/production.txt +++ b/{{cookiecutter.project_slug}}/requirements/production.txt @@ -3,7 +3,7 @@ -r base.txt gevent==1.2.2 -gunicorn==19.7.1 # https://github.com/benoitc/gunicorn +gunicorn==19.8.0 # https://github.com/benoitc/gunicorn boto3==1.6.2 # pyup: update minor # https://github.com/boto/boto3 psycopg2==2.7.4 --no-binary psycopg2 # https://github.com/psycopg/psycopg2 {%- if cookiecutter.use_whitenoise == 'n' %} From cf03bf74e7698564921698132b1d060ab0283afa Mon Sep 17 00:00:00 2001 From: "pyup.io bot" Date: Mon, 30 Apr 2018 21:16:09 +0200 Subject: [PATCH 145/166] Update gunicorn from 19.8.0 to 19.8.1 (#1627) --- {{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 fa27b664..9f997c2d 100644 --- a/{{cookiecutter.project_slug}}/requirements/production.txt +++ b/{{cookiecutter.project_slug}}/requirements/production.txt @@ -3,7 +3,7 @@ -r base.txt gevent==1.2.2 -gunicorn==19.8.0 # https://github.com/benoitc/gunicorn +gunicorn==19.8.1 # https://github.com/benoitc/gunicorn boto3==1.6.2 # pyup: update minor # https://github.com/boto/boto3 psycopg2==2.7.4 --no-binary psycopg2 # https://github.com/psycopg/psycopg2 {%- if cookiecutter.use_whitenoise == 'n' %} From b8a709b191bb7ba77a91470c3601f2b8ae19f2b3 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Wed, 2 May 2018 01:08:03 -0700 Subject: [PATCH 146/166] Update django from 2.0.4 to 2.0.5 --- {{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 bd024298..236f483c 100644 --- a/{{cookiecutter.project_slug}}/requirements/base.txt +++ b/{{cookiecutter.project_slug}}/requirements/base.txt @@ -15,7 +15,7 @@ celery==3.1.25 # pyup: <4.0 # https://github.com/celery/celery # Django # ------------------------------------------------------------------------------ -django==2.0.4 # pyup: < 2.1 # https://www.djangoproject.com/ +django==2.0.5 # pyup: < 2.1 # https://www.djangoproject.com/ django-environ==0.4.4 # https://github.com/joke2k/django-environ django-model-utils==3.1.1 # https://github.com/jazzband/django-model-utils django-allauth==0.35.0 # https://github.com/pennersr/django-allauth From b7172cfebaa0dd8860e1173f4a97b1e6fdfdd8b7 Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Sat, 5 May 2018 01:29:47 +0300 Subject: [PATCH 147/166] Conditionally gitignore virtualenv files Fixes #1321 the right way. --- {{cookiecutter.project_slug}}/.gitignore | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/{{cookiecutter.project_slug}}/.gitignore b/{{cookiecutter.project_slug}}/.gitignore index f3f92da2..84b7e6d6 100644 --- a/{{cookiecutter.project_slug}}/.gitignore +++ b/{{cookiecutter.project_slug}}/.gitignore @@ -324,7 +324,7 @@ Session.vim # Auto-generated tag files tags - +{% if cookiecutter.use_docker == 'n' %} ### VirtualEnv template # Virtualenv @@ -337,16 +337,10 @@ tags [Ss]cripts pyvenv.cfg pip-selfcheck.json +{% endif %} - -{% if cookiecutter.use_mailhog == 'y' and cookiecutter.use_docker == 'n' -%} +### Project template +{% if cookiecutter.use_mailhog == 'y' and cookiecutter.use_docker == 'n' %} MailHog -{% endif %} - +{%- endif %} {{ cookiecutter.project_slug }}/media/ - -{% if cookiecutter.use_docker == 'y' -%} -# Added to maintain local compose files which are ignored by something above. -# See issue https://github.com/pydanny/cookiecutter-django/issues/1321 -!/compose/local/ -{% endif %} From 4944907fb578181e103ea96bed409d85bf1d21b3 Mon Sep 17 00:00:00 2001 From: Nikita Shupeyko Date: Sat, 5 May 2018 01:30:57 +0300 Subject: [PATCH 148/166] Upgrade redis service to 3.2 (#1631) --- {{cookiecutter.project_slug}}/local.yml | 2 +- {{cookiecutter.project_slug}}/production.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/{{cookiecutter.project_slug}}/local.yml b/{{cookiecutter.project_slug}}/local.yml index ed8dec0b..d22a9d08 100644 --- a/{{cookiecutter.project_slug}}/local.yml +++ b/{{cookiecutter.project_slug}}/local.yml @@ -45,7 +45,7 @@ services: {%- if cookiecutter.use_celery == 'y' %} redis: - image: redis:3.0 + image: redis:3.2 celeryworker: <<: *django diff --git a/{{cookiecutter.project_slug}}/production.yml b/{{cookiecutter.project_slug}}/production.yml index f57c9810..f8f8ca22 100644 --- a/{{cookiecutter.project_slug}}/production.yml +++ b/{{cookiecutter.project_slug}}/production.yml @@ -46,7 +46,7 @@ services: - "0.0.0.0:443:443" redis: - image: redis:3.0 + image: redis:3.2 {%- if cookiecutter.use_celery == 'y' %} celeryworker: From 8203cfe4fc1650d2abe8d600aba7ca87d2c6d160 Mon Sep 17 00:00:00 2001 From: "pyup.io bot" Date: Sat, 5 May 2018 03:06:41 +0200 Subject: [PATCH 149/166] Update factory-boy to 2.11.0 (#1632) --- {{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 e9f057b4..7bdc013a 100644 --- a/{{cookiecutter.project_slug}}/requirements/local.txt +++ b/{{cookiecutter.project_slug}}/requirements/local.txt @@ -21,7 +21,7 @@ coverage==4.5.1 # https://github.com/nedbat/coveragepy # Django # ------------------------------------------------------------------------------ -factory-boy==2.10.0 # https://github.com/FactoryBoy/factory_boy +factory-boy==2.11.0 # https://github.com/FactoryBoy/factory_boy django-test-plus==1.0.22 # https://github.com/revsys/django-test-plus django-debug-toolbar==1.9.1 # https://github.com/jazzband/django-debug-toolbar From b4d0416530ba9bc75f0c62cf078017eaff3f64cb Mon Sep 17 00:00:00 2001 From: Nikita Shupeyko Date: Sat, 5 May 2018 12:27:27 +0300 Subject: [PATCH 150/166] Fix PostgreSQL backup restore (#1628) * Export PG* envs when backing up postgres * Export PG* envs when restoring postgres from backup * Prevent postgres connection from dropping all at ones * Alter postgres backups docs Include another crucial prerequisite. * "feel free switching" -> "feel free to switch" * Address the feedback --- docs/docker-postgres-backups.rst | 20 +++++------ .../production/postgres/maintenance/backup | 9 +++-- .../production/postgres/maintenance/restore | 34 ++++--------------- 3 files changed, 18 insertions(+), 45 deletions(-) diff --git a/docs/docker-postgres-backups.rst b/docs/docker-postgres-backups.rst index 112b612b..c1a8a5e0 100644 --- a/docs/docker-postgres-backups.rst +++ b/docs/docker-postgres-backups.rst @@ -1,13 +1,14 @@ PostgreSQL Backups with Docker ============================== -Prerequisites: +.. note:: For brevity it is assumed that you will be running the below commands against local environment, however, this is by no means mandatory so feel free to switch to ``production.yml`` when needed. -#. the project was generated with ``use_docker`` set to ``y``. -For brevity it is assumed that will be running the below commands against local environment, however, this is by no means mandatory so feel free switching to ``production.yml`` when needed. +Prerequisites +------------- -Note that the application stack should not necessarily be running when applying any of the instructions below, unless explicitly stated otherwise. For instance, suppose the stack has been down for quite some time or have never even been up yet -- rather than starting it beforehand use a single ``$ docker-compose -f local.yml run --rm `` with the desired command. By contrast, should you already have your application up and running do not bother waiting for ``run`` instruction to finish (they usually take a bit longer due to bootstrapping phase), just use ``$ docker-compose -f local.yml exec `` instead; note that any ``exec`` command fails unless all of the required containers are running. From now on, we will be using ``run``-style examples for general-case compatibility. +#. the project was generated with ``use_docker`` set to ``y``; +#. the stack is up and running: ``docker-compose -f local.yml up -d postgres``. Creating a Backup @@ -15,7 +16,7 @@ Creating a Backup To create a backup, run:: - $ docker-compose -f local.yml run --rm postgres backup + $ docker-compose -f local.yml exec postgres backup Assuming your project's database is named ``my_project`` here is what you will see: :: @@ -30,7 +31,7 @@ Viewing the Existing Backups To list existing backups, :: - $ docker-compose -f local.yml run --rm postgres backups + $ docker-compose -f local.yml exec postgres backups These are the sample contents of ``/backups``: :: @@ -62,16 +63,11 @@ Restoring from the Existing Backup To restore from one of the backups you have already got (take the ``backup_2018_03_13T09_05_07.sql.gz`` for example), :: - $ docker-compose -f local.yml run --rm postgres restore backup_2018_03_13T09_05_07.sql.gz + $ docker-compose -f local.yml exec postgres restore backup_2018_03_13T09_05_07.sql.gz You will see something like :: Restoring the 'my_project' database from the '/backups/backup_2018_03_13T09_05_07.sql.gz' backup... - INFO: Dropping all connections to the database... - pg_terminate_backend - ---------------------- - (0 rows) - INFO: Dropping the database... INFO: Creating a new database... INFO: Applying the backup to the new database... diff --git a/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/backup b/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/backup index 34516248..10674f9f 100644 --- a/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/backup +++ b/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/backup @@ -25,14 +25,13 @@ if [[ "${POSTGRES_USER}" == "postgres" ]]; then exit 1 fi +export PGHOST="postgres" +export PGUSER="${POSTGRES_USER}" export PGPASSWORD="${POSTGRES_PASSWORD}" +export PGDATABASE="${POSTGRES_DB}" backup_filename="${BACKUP_FILE_PREFIX}_$(date +'%Y_%m_%dT%H_%M_%S').sql.gz" -pg_dump \ - --host=postgres \ - --dbname="${POSTGRES_DB}" \ - --username="${POSTGRES_USER}" \ - | gzip > "${BACKUP_DIR_PATH}/${backup_filename}" +pg_dump | gzip > "${BACKUP_DIR_PATH}/${backup_filename}" message_success "'${POSTGRES_DB}' database backup '${backup_filename}' has been created and placed in '${BACKUP_DIR_PATH}'." diff --git a/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/restore b/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/restore index 49814007..b2e0a18d 100644 --- a/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/restore +++ b/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/restore @@ -37,40 +37,18 @@ if [[ "${POSTGRES_USER}" == "postgres" ]]; then exit 1 fi +export PGHOST="postgres" +export PGUSER="${POSTGRES_USER}" export PGPASSWORD="${POSTGRES_PASSWORD}" - -message_info "Dropping all connections to the database..." -# Source: http://dba.stackexchange.com/a/11895 -drop_postgres_connections_sql='UPDATE pg_database' -drop_postgres_connections_sql+=" SET datallowconn = 'false'" -drop_postgres_connections_sql+=" WHERE datname = '${POSTGRES_DB}';" -drop_postgres_connections_sql+='SELECT pg_terminate_backend(pid)' -drop_postgres_connections_sql+=' FROM pg_stat_activity' -drop_postgres_connections_sql+=" WHERE datname = '${POSTGRES_DB}';" -psql \ - --host=localhost \ - --username=postgres \ - --dbname=postgres \ - --command="${drop_postgres_connections_sql}" +export PGDATABASE="${POSTGRES_DB}" message_info "Dropping the database..." -dropdb \ - --host=postgres \ - --username="${POSTGRES_USER}" \ - "${POSTGRES_DB}" +dropdb "${PGDATABASE}" message_info "Creating a new database..." -createdb \ - --host=postgres \ - --username="${POSTGRES_USER}" \ - --owner="${POSTGRES_USER}" \ - "${POSTGRES_DB}" +createdb --owner="${POSTGRES_USER}" message_info "Applying the backup to the new database..." -gunzip -c "${backup_filename}" \ - | psql \ - --host=postgres \ - --username="${POSTGRES_USER}" \ - "${POSTGRES_DB}" +gunzip -c "${backup_filename}" | psql "${POSTGRES_DB}" message_success "The '${POSTGRES_DB}' database has been restored from the '${backup_filename}' backup." From ec78d9ce97d44a088803a8ba96a73803365746b4 Mon Sep 17 00:00:00 2001 From: Marlon Date: Sat, 5 May 2018 09:28:30 +0000 Subject: [PATCH 151/166] Use Heroku's Release Phase for Migrations (#1615) Automatically run migrations on deployments to Heroku. Advantages include deployments are rolled-back if a migration fails, preventing broken applications due to failed migrations, no time between when application is released and database is migrated, and removes risk of forgetting to manually run migrations. --- {{cookiecutter.project_slug}}/Procfile | 1 + 1 file changed, 1 insertion(+) diff --git a/{{cookiecutter.project_slug}}/Procfile b/{{cookiecutter.project_slug}}/Procfile index c77d76d9..9441ca23 100644 --- a/{{cookiecutter.project_slug}}/Procfile +++ b/{{cookiecutter.project_slug}}/Procfile @@ -1,3 +1,4 @@ +release: ./manage.py migrate web: gunicorn config.wsgi:application {% if cookiecutter.use_celery == "y" -%} worker: celery worker --app={{cookiecutter.project_slug}}.taskapp --loglevel=info From 21dd1987615d5df09658c60131232e539def71e3 Mon Sep 17 00:00:00 2001 From: Marlon Date: Sat, 5 May 2018 09:28:46 +0000 Subject: [PATCH 152/166] Update deployment-on-heroku.rst (#1630) `heroku python manage.py migrate` no longer necessary, since it's now run by the release process in the Procfile. Related to https://github.com/pydanny/cookiecutter-django/pull/1615 --- docs/deployment-on-heroku.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/deployment-on-heroku.rst b/docs/deployment-on-heroku.rst index 7ce94d05..1f249c44 100644 --- a/docs/deployment-on-heroku.rst +++ b/docs/deployment-on-heroku.rst @@ -33,7 +33,6 @@ Run these commands to deploy the project to Heroku: heroku config:set PYTHONHASHSEED=random git push heroku master - heroku run python manage.py migrate heroku run python manage.py check --deploy heroku run python manage.py createsuperuser heroku open From 8ef1019e01f653fba87a3b264b3b510b23a30c7f Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Sat, 5 May 2018 12:30:20 +0300 Subject: [PATCH 153/166] Use implicit path to manage.py in Procfile --- {{cookiecutter.project_slug}}/Procfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/{{cookiecutter.project_slug}}/Procfile b/{{cookiecutter.project_slug}}/Procfile index 9441ca23..669607fc 100644 --- a/{{cookiecutter.project_slug}}/Procfile +++ b/{{cookiecutter.project_slug}}/Procfile @@ -1,4 +1,4 @@ -release: ./manage.py migrate +release: manage.py migrate web: gunicorn config.wsgi:application {% if cookiecutter.use_celery == "y" -%} worker: celery worker --app={{cookiecutter.project_slug}}.taskapp --loglevel=info From d8267edd0995a49e1c96cd31497bc59549a09f2b Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Sat, 5 May 2018 12:37:10 +0300 Subject: [PATCH 154/166] Run black reformatting https://github.com/ambv/black --- hooks/post_gen_project.py | 12 ++++++++---- .../users/tests/test_views.py | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py index e353c77f..eba26bac 100644 --- a/hooks/post_gen_project.py +++ b/hooks/post_gen_project.py @@ -242,7 +242,10 @@ def main(): if "{{ cookiecutter.use_heroku }}".lower() == "n": remove_heroku_files() - if "{{ cookiecutter.use_docker }}".lower() == "n" and "{{ cookiecutter.use_heroku }}".lower() == "n": + if ( + "{{ cookiecutter.use_docker }}".lower() == "n" + and "{{ cookiecutter.use_heroku }}".lower() == "n" + ): if "{{ cookiecutter.keep_local_envs_in_vcs }}".lower() == "y": print( INFO + ".env(s) are only utilized when Docker Compose and/or " @@ -264,9 +267,10 @@ def main(): remove_gulp_files() remove_grunt_files() remove_packagejson_file() - if "{{ cookiecutter.js_task_runner }}".lower() in [ - "grunt", "gulp" - ] and "{{ cookiecutter.use_docker }}".lower() == "y": + if ( + "{{ cookiecutter.js_task_runner }}".lower() in ["grunt", "gulp"] + and "{{ cookiecutter.use_docker }}".lower() == "y" + ): print( WARNING + "Docker and {} JS task runner ".format( diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_views.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_views.py index 1fa45697..07cbda66 100644 --- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_views.py +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_views.py @@ -2,7 +2,7 @@ from django.test import RequestFactory from test_plus.test import TestCase -from ..views import (UserRedirectView, UserUpdateView) +from ..views import UserRedirectView, UserUpdateView class BaseUserTestCase(TestCase): From 5e2a907c35bd82756e7cea977e320d4a4c6c6635 Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Sat, 5 May 2018 12:42:10 +0300 Subject: [PATCH 155/166] Remove pycodestyle and pyflakes as implicit dependencies from flakes8 Closes #1606. --- requirements.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 4f981d0e..eedbfad0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,8 +5,6 @@ binaryornot==0.4.4 # Code quality # ------------------------------------------------------------------------------ flake8==3.5.0 -pycodestyle==2.3.1 -pyflakes==1.6.0 # Testing # ------------------------------------------------------------------------------ From 9f14254e8e6c1f337a4a0244a9236da6c4607f9b Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Sat, 5 May 2018 12:45:49 +0300 Subject: [PATCH 156/166] Move pytest settings from setup.cfg to pytest.ini --- setup.cfg => pytest.ini | 2 +- {{cookiecutter.project_slug}}/setup.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename setup.cfg => pytest.ini (88%) diff --git a/setup.cfg b/pytest.ini similarity index 88% rename from setup.cfg rename to pytest.ini index 140796cf..c5b30199 100644 --- a/setup.cfg +++ b/pytest.ini @@ -1,3 +1,3 @@ -[tool:pytest] +[pytest] python_paths = . norecursedirs = .tox .git */migrations/* */static/* docs venv */{{cookiecutter.project_slug}}/* diff --git a/{{cookiecutter.project_slug}}/setup.cfg b/{{cookiecutter.project_slug}}/setup.cfg index 2b26ba61..1ec89c78 100644 --- a/{{cookiecutter.project_slug}}/setup.cfg +++ b/{{cookiecutter.project_slug}}/setup.cfg @@ -4,4 +4,4 @@ exclude = .tox,.git,*/migrations/*,*/static/CACHE/*,docs,node_modules [pycodestyle] max-line-length = 120 -exclude=.tox,.git,*/migrations/*,*/static/CACHE/*,docs,node_modules +exclude = .tox,.git,*/migrations/*,*/static/CACHE/*,docs,node_modules From a22390ad4f1b49db21b55a7e22a93d66f3930c9c Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Sat, 5 May 2018 13:47:25 +0300 Subject: [PATCH 157/166] Introduce debug cookiecutter option --- README.rst | 3 ++- cookiecutter.json | 4 +++- docs/project-generation-options.rst | 4 ++++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 21e723bc..acb5d6a1 100644 --- a/README.rst +++ b/README.rst @@ -15,7 +15,7 @@ Cookiecutter Django .. image:: https://www.codetriage.com/pydanny/cookiecutter-django/badges/users.svg :target: https://www.codetriage.com/pydanny/cookiecutter-django :alt: Code Helpers Badge - + .. image:: https://img.shields.io/badge/code%20style-black-000000.svg :target: https://github.com/ambv/black :alt: Code style: black @@ -194,6 +194,7 @@ Answer the prompts with your own desired options_. For example:: 5 - Not open source Choose from 1, 2, 3, 4, 5 [1]: 1 keep_local_envs_in_vcs [y]: y + debug[n]: n Enter the project and take a look around:: diff --git a/cookiecutter.json b/cookiecutter.json index 1ba322c1..e6687822 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -39,5 +39,7 @@ "use_whitenoise": "y", "use_heroku": "n", "use_travisci": "n", - "keep_local_envs_in_vcs": "y" + "keep_local_envs_in_vcs": "y", + + "debug": "n" } diff --git a/docs/project-generation-options.rst b/docs/project-generation-options.rst index 3a1201f0..4c46cbdc 100644 --- a/docs/project-generation-options.rst +++ b/docs/project-generation-options.rst @@ -96,6 +96,10 @@ keep_local_envs_in_vcs [y] (comes in handy when working in teams where local environment reproducibility is strongly encouraged). +debug [n] + Indicates whether the project should be configured for debugging. + This option is relevant for Cookiecutter Django developers only. + .. _MIT: https://opensource.org/licenses/MIT .. _BSD: https://opensource.org/licenses/BSD-3-Clause From 17326596784b05c29e26e62b6432fc2fd93b1351 Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Sat, 5 May 2018 13:47:58 +0300 Subject: [PATCH 158/166] Set POSTGRES_USER and POSTGRES_PASSWORD to the debug value when opting for debug --- hooks/post_gen_project.py | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py index eba26bac..5e60b23a 100644 --- a/hooks/post_gen_project.py +++ b/hooks/post_gen_project.py @@ -28,6 +28,8 @@ INFO = "\x1b[1;33m [INFO]: " HINT = "\x1b[3;33m" SUCCESS = "\x1b[1;32m [SUCCESS]: " +DEBUG_VALUE = "debug" + def remove_open_source_files(): file_names = ["CONTRIBUTORS.txt"] @@ -166,21 +168,24 @@ def set_django_admin_url(file_path): return django_admin_url -def generate_postgres_user(): - return generate_random_string(length=32, using_ascii_letters=True) +def generate_postgres_user(debug=False): + return DEBUG_VALUE if debug else generate_random_string(length=32, using_ascii_letters=True) -def set_postgres_user(file_path, value=None): +def set_postgres_user(file_path, value): postgres_user = set_flag( - file_path, "!!!SET POSTGRES_USER!!!", value=value or generate_postgres_user() + file_path, + "!!!SET POSTGRES_USER!!!", + value=value, ) return postgres_user -def set_postgres_password(file_path): +def set_postgres_password(file_path, value=None): postgres_password = set_flag( file_path, "!!!SET POSTGRES_PASSWORD!!!", + value=value, length=64, using_digits=True, using_ascii_letters=True, @@ -194,10 +199,10 @@ def append_to_gitignore_file(s): gitignore_file.write(os.linesep) -def set_flags_in_envs(postgres_user): +def set_flags_in_envs(postgres_user, debug=False): local_postgres_envs_path = os.path.join(".envs", ".local", ".postgres") set_postgres_user(local_postgres_envs_path, value=postgres_user) - set_postgres_password(local_postgres_envs_path) + set_postgres_password(local_postgres_envs_path, value=DEBUG_VALUE if debug else None) production_django_envs_path = os.path.join(".envs", ".production", ".django") set_django_secret_key(production_django_envs_path) @@ -205,7 +210,7 @@ def set_flags_in_envs(postgres_user): production_postgres_envs_path = os.path.join(".envs", ".production", ".postgres") set_postgres_user(production_postgres_envs_path, value=postgres_user) - set_postgres_password(production_postgres_envs_path) + set_postgres_password(production_postgres_envs_path, value=DEBUG_VALUE if debug else None) def set_flags_in_settings_files(): @@ -224,8 +229,8 @@ def remove_celery_compose_dirs(): def main(): - postgres_user = generate_postgres_user() - set_flags_in_envs(postgres_user) + postgres_user = generate_postgres_user(debug="{{ cookiecutter.debug }}".lower() == "y") + set_flags_in_envs(postgres_user, debug="{{ cookiecutter.debug }}".lower() == "y") set_flags_in_settings_files() if "{{ cookiecutter.open_source_license }}" == "Not open source": @@ -249,8 +254,8 @@ def main(): if "{{ cookiecutter.keep_local_envs_in_vcs }}".lower() == "y": print( INFO + ".env(s) are only utilized when Docker Compose and/or " - "Heroku support is enabled so keeping them does not " - "make sense given your current setup." + TERMINATOR + "Heroku support is enabled so keeping them does not " + "make sense given your current setup." + TERMINATOR ) remove_envs_and_associated_files() else: @@ -277,10 +282,10 @@ def main(): "{{ cookiecutter.js_task_runner }}".lower().capitalize() ) + "working together not supported yet. " - "You can continue using the generated project like you " - "normally would, however you would need to add a JS " - "task runner service to your Docker Compose configuration " - "manually." + TERMINATOR + "You can continue using the generated project like you " + "normally would, however you would need to add a JS " + "task runner service to your Docker Compose configuration " + "manually." + TERMINATOR ) if "{{ cookiecutter.use_celery }}".lower() == "n": From 2eac9648a144a6f30417f3bb039a5c2cda53b02f Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Sat, 5 May 2018 15:01:03 +0300 Subject: [PATCH 159/166] Install boto3 as extra of django-storages Closes #1586. --- {{cookiecutter.project_slug}}/requirements/production.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/{{cookiecutter.project_slug}}/requirements/production.txt b/{{cookiecutter.project_slug}}/requirements/production.txt index 9f997c2d..0d9af985 100644 --- a/{{cookiecutter.project_slug}}/requirements/production.txt +++ b/{{cookiecutter.project_slug}}/requirements/production.txt @@ -4,7 +4,6 @@ gevent==1.2.2 gunicorn==19.8.1 # https://github.com/benoitc/gunicorn -boto3==1.6.2 # pyup: update minor # https://github.com/boto/boto3 psycopg2==2.7.4 --no-binary psycopg2 # https://github.com/psycopg/psycopg2 {%- if cookiecutter.use_whitenoise == 'n' %} Collectfast==0.6.2 # https://github.com/antonagestam/collectfast @@ -15,5 +14,5 @@ raven==6.7.0 # https://github.com/getsentry/raven-python # Django # ------------------------------------------------------------------------------ -django-storages==1.6.6 # https://github.com/jschneier/django-storages +django-storages[boto3]==1.6.6 # https://github.com/jschneier/django-storages django-anymail==2.2 # https://github.com/anymail/django-anymail From 5a3dd8f0c6cfbc245e48358b10ef964c48451711 Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Sat, 5 May 2018 15:03:01 +0300 Subject: [PATCH 160/166] Uninstall gevent Closes #1555. --- {{cookiecutter.project_slug}}/requirements/production.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/{{cookiecutter.project_slug}}/requirements/production.txt b/{{cookiecutter.project_slug}}/requirements/production.txt index 0d9af985..507644ce 100644 --- a/{{cookiecutter.project_slug}}/requirements/production.txt +++ b/{{cookiecutter.project_slug}}/requirements/production.txt @@ -2,7 +2,6 @@ -r base.txt -gevent==1.2.2 gunicorn==19.8.1 # https://github.com/benoitc/gunicorn psycopg2==2.7.4 --no-binary psycopg2 # https://github.com/psycopg/psycopg2 {%- if cookiecutter.use_whitenoise == 'n' %} From 0d2f8fcfd9ce7e861cdf45e16c0f2fcee0de2cd8 Mon Sep 17 00:00:00 2001 From: "pyup.io bot" Date: Sat, 5 May 2018 21:18:56 +0200 Subject: [PATCH 161/166] Update factory-boy from 2.11.0 to 2.11.1 (#1635) --- {{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 7bdc013a..958dba1b 100644 --- a/{{cookiecutter.project_slug}}/requirements/local.txt +++ b/{{cookiecutter.project_slug}}/requirements/local.txt @@ -21,7 +21,7 @@ coverage==4.5.1 # https://github.com/nedbat/coveragepy # Django # ------------------------------------------------------------------------------ -factory-boy==2.11.0 # https://github.com/FactoryBoy/factory_boy +factory-boy==2.11.1 # https://github.com/FactoryBoy/factory_boy django-test-plus==1.0.22 # https://github.com/revsys/django-test-plus django-debug-toolbar==1.9.1 # https://github.com/jazzband/django-debug-toolbar From 74c838dc0c910e7ef53b38e03981cd16694fce99 Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Sat, 5 May 2018 22:25:07 +0300 Subject: [PATCH 162/166] Link favicon from base.html --- .../static/images/{ => favicons}/favicon.ico | Bin .../templates/base.html | 2 ++ 2 files changed, 2 insertions(+) rename {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/static/images/{ => favicons}/favicon.ico (100%) diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/static/images/favicon.ico b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/static/images/favicons/favicon.ico similarity index 100% rename from {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/static/images/favicon.ico rename to {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/static/images/favicons/favicon.ico diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/base.html b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/base.html index c767cb3b..2cb70566 100644 --- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/base.html +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/base.html @@ -13,6 +13,8 @@ + + {% block css %} {% endraw %}{% if cookiecutter.custom_bootstrap_compilation == "n" %}{% raw %} From 5c166b28a9fe3db23197d261d916cd3ab7a87c32 Mon Sep 17 00:00:00 2001 From: Nikita Shupeyko Date: Sun, 6 May 2018 19:37:57 +0300 Subject: [PATCH 163/166] Remove "My Favorite Cookie" tutorial (#1633) Closes #1611. --- docs/index.rst | 1 - docs/my-favorite-cookie.rst | 100 ------------------------------------ 2 files changed, 101 deletions(-) delete mode 100644 docs/my-favorite-cookie.rst diff --git a/docs/index.rst b/docs/index.rst index 41a1138f..c9f70ab1 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -24,7 +24,6 @@ Contents: docker-postgres-backups faq troubleshooting - my-favorite-cookie Indices and tables ================== diff --git a/docs/my-favorite-cookie.rst b/docs/my-favorite-cookie.rst deleted file mode 100644 index a6583352..00000000 --- a/docs/my-favorite-cookie.rst +++ /dev/null @@ -1,100 +0,0 @@ -************************************************ -Creating your first app with Cookiecutter-Django -************************************************ - -This tutorial will show you how to build a simple app using the `Cookiecutter Django `_ templating system. We'll be building a cookie polling app to determine the most popular flavor of cookie. - -Developers who have never used Django will learn the basics of creating a Django app; developers who are experienced with Django will learn how to set up a project within the Cookiecutter system. While many Django tutorials use the default SQLite database, Cookiecutter Django uses PostGres only, so we'll have you install and use that. - - -Dependencies -============ -This tutorial was written on Windows 10 using `git bash `_; alternate instructions for Mac OS and Linux will be provided when needed. Any Linux-style shell should work for the following commands. - -You should have your preferred versions of `Python `_ -and `Django `_ installed. Use the latest stable versions if you have no preference. - -You should have `Virtualenv `_ and `Cookiecutter `_ installed: - -.. code-block:: python - - $ pip install virtualenv - $ pip install cookiecutter - -You should also have `PostgreSQL `_ installed on your machine--just download and run the installer for your OS. The install menu will prompt you for a password, which you'll use when creating the project's database. - - -Instructions -============ - -1. **Setup** -- how to set up a virtual environment -2. **Cookiecutter** -- use Cookiecutter to initialize a project with your own customized information. -3. **Building the App** -- creating the My Favorite Cookie application. - -============ -1. Setup -============ - -Virtual Environment -""""""""""""""""""" - -Create a virtual environment for your project. Cookiecutter will install a bunch of dependencies for you automatically; using a virtualenv will prevent this from interfering with your other work. - -.. code-block:: python - - $ virtualenv c:/.virtualenvs/cookie_polls - -Replace ``c:/.virtualenvs`` with the path to your own ``.virtualenvs`` folder. - -Activate the virtual environment by calling ``source`` on the ``activate`` shell script . On Windows you'll call this from the virtualenv's ``scripts`` folder: - -.. code-block:: python - - $ source /path/to/.virtualenvs/cookie_polls/scripts/activate - -On other operating systems, it'll be found in the ``bin`` folder. - -.. code-block:: python - - $ source /path/to/.virtualenvs/cookie_polls/bin/activate - -You'll know the virtual environment is active because its name will appear in parentheses before the command prompt. When you're done with this project, you can leave the virtual environment with the ``deactivate`` command. - -.. code-block:: python - - (cookie_polls) - $ deactivate - - -Now you're ready to create your project using Cookiecutter. - - -=============== -2. Cookiecutter -=============== - -Django developers may be familiar with the ``startproject`` command, which initializes the directory structure and required files for a bare-bones Django project. While this is fine when you're just learning Django for the first time, it's not great for a real production app. Cookiecutter takes care of a lot of standard tasks for you, including installing software dependencies, setting up testing files, and including and organizing common libraries like Bootstrap and AngularJS. It also generates a software license and a README. - -Change directories into the folder where you want your project to live, and run ``cookiecutter`` followed by the URL of Cookiecutter's Github repo. - -.. code-block:: python - - $ cd /my/project/folder - (cookie_polls) - my/project/folder - $ cookiecutter https://github.com/pydanny/cookiecutter-django - -This will prompt you for a bunch of values specific to your project. Press "enter" without typing anything to use the default values, which are shown in [brackets] after the question. You can learn about all the different options `here, `_ but for now we'll use the defaults for everything but your name, your email, the project's name, and the project's description. - -.. code-block:: python - - project_name [project_name]: My Favorite Cookie - project_slug [My_Favorite_Cookie]: - author_name [Your Name]: Emily Cain - email [Your email]: contact@emcain.net - description [A short description of the project.]: Poll your friends to determine the most popular cookie. - -Then hit "enter" to use the default values for everything else. - - - From 35b2aac87aa6d7bddb0bd9bed2d59e3d10283adb Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Mon, 7 May 2018 20:30:14 +0300 Subject: [PATCH 164/166] Use relative -r path in 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 507644ce..95338849 100644 --- a/{{cookiecutter.project_slug}}/requirements/production.txt +++ b/{{cookiecutter.project_slug}}/requirements/production.txt @@ -1,6 +1,6 @@ # PRECAUTION: avoid production dependencies that aren't in development --r base.txt +-r ./base.txt gunicorn==19.8.1 # https://github.com/benoitc/gunicorn psycopg2==2.7.4 --no-binary psycopg2 # https://github.com/psycopg/psycopg2 From 00ff5c8506f3a100addd84eb25bf340c8a01ea18 Mon Sep 17 00:00:00 2001 From: "Nikita P. Shupeyko" Date: Mon, 7 May 2018 20:33:34 +0300 Subject: [PATCH 165/166] Fix a typo in production.py --- {{cookiecutter.project_slug}}/config/settings/production.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/{{cookiecutter.project_slug}}/config/settings/production.py b/{{cookiecutter.project_slug}}/config/settings/production.py index e1c6de89..24df1886 100644 --- a/{{cookiecutter.project_slug}}/config/settings/production.py +++ b/{{cookiecutter.project_slug}}/config/settings/production.py @@ -245,7 +245,7 @@ RAVEN_CONFIG = { # 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 bon every HTTP 500 error when DEBUG=False. +# the site admins on 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 = { From b4b3c0425359225c8eccf15b687cde156631d3ad Mon Sep 17 00:00:00 2001 From: "pyup.io bot" Date: Tue, 8 May 2018 09:28:52 +0200 Subject: [PATCH 166/166] Update django-allauth from 0.35.0 to 0.36.0 (#1638) --- {{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 236f483c..92d31f46 100644 --- a/{{cookiecutter.project_slug}}/requirements/base.txt +++ b/{{cookiecutter.project_slug}}/requirements/base.txt @@ -18,7 +18,7 @@ celery==3.1.25 # pyup: <4.0 # https://github.com/celery/celery django==2.0.5 # pyup: < 2.1 # https://www.djangoproject.com/ django-environ==0.4.4 # https://github.com/joke2k/django-environ django-model-utils==3.1.1 # https://github.com/jazzband/django-model-utils -django-allauth==0.35.0 # https://github.com/pennersr/django-allauth +django-allauth==0.36.0 # https://github.com/pennersr/django-allauth django-crispy-forms==1.7.2 # https://github.com/django-crispy-forms/django-crispy-forms {%- if cookiecutter.use_compressor == "y" %} django-compressor==2.2 # https://github.com/django-compressor/django-compressor