Merge branch 'master' into master

This commit is contained in:
Nikita Shupeyko 2018-03-06 19:58:28 +03:00 committed by GitHub
commit 3e0bc83bfe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
46 changed files with 771 additions and 721 deletions

2
.gitignore vendored
View File

@ -226,3 +226,5 @@ pip-selfcheck.json
# to 'run' anything within it since any particular cookiecutter # to 'run' anything within it since any particular cookiecutter
# is declarative by nature. # is declarative by nature.
.idea/ .idea/
.pytest_cache/

View File

@ -13,15 +13,6 @@ env:
- TOX_ENV=py36 - TOX_ENV=py36
before_install: 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-compose -v
- docker -v - docker -v

View File

@ -2,6 +2,10 @@
All enhancements and patches to Cookiecutter Django will be documented in this file. All enhancements and patches to Cookiecutter Django will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/). This project adheres to [Semantic Versioning](http://semver.org/).
## [2018-02-16]
### Changed
- Upgraded to Django 2.0 (@epicwhale)
## [2018-01-15] ## [2018-01-15]
### Changed ### Changed
- Removed Elastic Beanstalk support (@pydanny) - Removed Elastic Beanstalk support (@pydanny)

View File

@ -44,6 +44,7 @@ Listed in alphabetical order.
Aaron Eikenberry `@aeikenberry`_ Aaron Eikenberry `@aeikenberry`_
Adam Bogdał `@bogdal`_ Adam Bogdał `@bogdal`_
Adam Dobrawy `@ad-m`_ Adam Dobrawy `@ad-m`_
Adam Steele `@adammsteele`
Agam Dua Agam Dua
Alberto Sanchez `@alb3rto`_ Alberto Sanchez `@alb3rto`_
Alex Tsai `@caffodian`_ Alex Tsai `@caffodian`_
@ -88,6 +89,7 @@ Listed in alphabetical order.
Dong Huynh `@trungdong`_ Dong Huynh `@trungdong`_
Emanuel Calso `@bloodpet`_ @bloodpet Emanuel Calso `@bloodpet`_ @bloodpet
Eraldo Energy `@eraldo`_ Eraldo Energy `@eraldo`_
Eric Groom `@ericgroom`_
Eyad Al Sibai `@eyadsibai`_ Eyad Al Sibai `@eyadsibai`_
Felipe Arruda `@arruda`_ Felipe Arruda `@arruda`_
Garry Cairns `@garry-cairns`_ Garry Cairns `@garry-cairns`_
@ -159,6 +161,7 @@ Listed in alphabetical order.
.. _@a7p: https://github.com/a7p .. _@a7p: https://github.com/a7p
.. _@ad-m: https://github.com/ad-m .. _@ad-m: https://github.com/ad-m
.. _@adammsteele: https://github.com/adammsteele
.. _@aeikenberry: https://github.com/aeikenberry .. _@aeikenberry: https://github.com/aeikenberry
.. _@alb3rto: https://github.com/alb3rto .. _@alb3rto: https://github.com/alb3rto
.. _@ameistad: https://github.com/ameistad .. _@ameistad: https://github.com/ameistad

View File

@ -41,7 +41,7 @@ Features
* For Django 2.0 * For Django 2.0
* Works with Python 3.6 * Works with Python 3.6
* Renders Django projects with 100% starting test coverage * 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_ * 12-Factor_ based settings via django-environ_
* Secure by default. We believe in SSL. * Secure by default. We believe in SSL.
* Optimized development and production settings * Optimized development and production settings
@ -111,7 +111,7 @@ Two Scoops of Django 1.11
:name: Two Scoops of Django 1.11 Cover :name: Two Scoops of Django 1.11 Cover
:align: center :align: center
:alt: Two Scoops of Django :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 Two Scoops of Django is the best dessert-themed Django reference in the universe
@ -171,12 +171,13 @@ Answer the prompts with your own desired options_. For example::
use_heroku [n]: y use_heroku [n]: y
use_compressor [n]: y use_compressor [n]: y
Select postgresql_version: Select postgresql_version:
1 - 10 1 - 10.3
2 - 9.6 2 - 10.2
3 - 9.5 3 - 10.1
4 - 9.4 4 - 9.6
5 - 9.3 5 - 9.5
6 - 9.2 6 - 9.4
7 - 9.3
Choose from 1, 2, 3, 4 [1]: 1 Choose from 1, 2, 3, 4 [1]: 1
Select js_task_runner: Select js_task_runner:
1 - Gulp 1 - Gulp

View File

@ -1,24 +1,43 @@
{ {
"project_name": "Project Name", "project_name": "My Awesome Project",
"project_slug": "{{ cookiecutter.project_name.lower()|replace(' ', '_')|replace('-', '_') }}", "project_slug": "{{ cookiecutter.project_name.lower()|replace(' ', '_')|replace('-', '_') }}",
"author_name": "Daniel Roy Greenfeld", "description": "Behold My Awesome Project!",
"email": "you@example.com", "author_name": "Daniel Roy Greenfeld",
"description": "A short description of the project.", "email": "{{ cookiecutter.author_name.lower()|replace(' ', '-') }}@example.com",
"domain_name": "example.com", "domain_name": "example.com",
"version": "0.1.0", "version": "0.1.0",
"timezone": "UTC", "open_source_license": [
"use_whitenoise": "y", "MIT",
"use_celery": "n", "BSD",
"use_mailhog": "n", "GPLv3",
"use_sentry_for_error_reporting": "y", "Apache Software License 2.0",
"use_opbeat": "n", "Not open source"
"use_pycharm": "n", ],
"windows": "n", "timezone": "UTC",
"use_docker": "n", "windows": "n",
"use_heroku": "n", "use_pycharm": "n",
"use_compressor": "n", "use_docker": "n",
"postgresql_version": ["10", "9.6", "9.5", "9.4", "9.3", "9.2"], "postgresql_version": [
"js_task_runner": ["Gulp", "Grunt", "None"], "10.3",
"custom_bootstrap_compilation": "n", "10.2",
"open_source_license": ["MIT", "BSD", "GPLv3", "Apache Software License 2.0", "Not open source"] "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"
} }

View File

@ -16,7 +16,9 @@ Run these commands to deploy the project to Heroku:
heroku addons:create heroku-redis:hobby-dev heroku addons:create heroku-redis:hobby-dev
heroku addons:create mailgun heroku addons:create mailgun
heroku config:set DJANGO_ADMIN_URL="$(openssl rand -base64 32)" heroku config:set WEB_CONCURRENCY=4
# 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_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_ALLOWED_HOSTS='.herokuapp.com'
@ -25,12 +27,10 @@ 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_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_AWS_STORAGE_BUCKET_NAME=YOUR_AWS_S3_BUCKET_NAME_HERE
heroku config:set DJANGO_MAILGUN_SERVER_NAME=YOUR_MALGUN_SERVER # This is to be set only if you're using Sentry:
heroku config:set DJANGO_MAILGUN_API_KEY=YOUR_MAILGUN_API_KEY heroku config:set DJANGO_SENTRY_DSN=YOUR_SENTRY_DSN
heroku config:set MAILGUN_SENDER_DOMAIN=YOUR_MAILGUN_SENDER_DOMAIN
heroku config:set PYTHONHASHSEED=random heroku config:set PYTHONHASHSEED=random
heroku config:set DJANGO_ADMIN_URL=\^somelocation/
git push heroku master git push heroku master
heroku run python manage.py migrate heroku run python manage.py migrate

View File

@ -63,13 +63,13 @@ Add these exports
.. code-block:: bash .. code-block:: bash
export WEB_CONCURRENCY=4
export DJANGO_SETTINGS_MODULE='config.settings.production' export DJANGO_SETTINGS_MODULE='config.settings.production'
export DJANGO_SECRET_KEY='<secret key goes here>' export DJANGO_SECRET_KEY='<secret key goes here>'
export DJANGO_ALLOWED_HOSTS='<www.your-domain.com>' export DJANGO_ALLOWED_HOSTS='<www.your-domain.com>'
export DJANGO_ADMIN_URL='<not admin/>' export DJANGO_ADMIN_URL='<not admin/>'
export DJANGO_MAILGUN_API_KEY='<mailgun key>' export MAILGUN_API_KEY='<mailgun key>'
export DJANGO_MAILGUN_SERVER_NAME='<mailgun server name>' export MAILGUN_DOMAIN='<mailgun sender domain (e.g. mg.yourdomain.com)>'
export MAILGUN_SENDER_DOMAIN='<mailgun sender domain (e.g. mg.yourdomain.com)>'
export DJANGO_AWS_ACCESS_KEY_ID= export DJANGO_AWS_ACCESS_KEY_ID=
export DJANGO_AWS_SECRET_ACCESS_KEY= export DJANGO_AWS_SECRET_ACCESS_KEY=
export DJANGO_AWS_STORAGE_BUCKET_NAME= export DJANGO_AWS_STORAGE_BUCKET_NAME=
@ -138,9 +138,8 @@ Click through to the **WSGI configuration file** link (near the top) and edit th
os.environ['DJANGO_SECRET_KEY'] = '<as above>' os.environ['DJANGO_SECRET_KEY'] = '<as above>'
os.environ['DJANGO_ALLOWED_HOSTS'] = '<as above>' os.environ['DJANGO_ALLOWED_HOSTS'] = '<as above>'
os.environ['DJANGO_ADMIN_URL'] = '<as above>' os.environ['DJANGO_ADMIN_URL'] = '<as above>'
os.environ['DJANGO_MAILGUN_API_KEY'] = '<as above>' os.environ['MAILGUN_API_KEY'] = '<as above>'
os.environ['DJANGO_MAILGUN_SERVER_NAME'] = '<as above>' os.environ['MAILGUN_DOMAIN'] = '<as above>'
os.environ['MAILGUN_SENDER_DOMAIN'] = '<as above>'
os.environ['DJANGO_AWS_ACCESS_KEY_ID'] = '' os.environ['DJANGO_AWS_ACCESS_KEY_ID'] = ''
os.environ['DJANGO_AWS_SECRET_ACCESS_KEY'] = '' os.environ['DJANGO_AWS_SECRET_ACCESS_KEY'] = ''
os.environ['DJANGO_AWS_STORAGE_BUCKET_NAME'] = '' os.environ['DJANGO_AWS_STORAGE_BUCKET_NAME'] = ''

View File

@ -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 .. _sentry.io: https://sentry.io/welcome
.. _Mailgun: https://mailgun.com .. _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`.
.. _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
---------------------- ----------------------

View File

@ -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:: 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. The base app will now run as it would with the usual ``manage.py runserver`` but with live reloading and Sass compilation enabled.

View File

@ -1,69 +1,61 @@
Project Generation Options Project Generation Options
========================== ==========================
project_name [project_name]: project_name [My Awesome Project]:
Your human-readable project name, including any capitalization or spaces. Your project's human-readable name, capitals and spaces allowed.
project_slug [project_name]: project_slug [my_awesome_project]:
The slug of your project, without dashes or spaces. Used to name your repo 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 and in other places where a Python-importable version of your project name
is needed. is needed.
author_name [Your Name]: description [Behold My Awesome Project!]
You! This goes into places like the LICENSE file. Describes your project and gets used in places like `README.rst` and such.
email [Your email]: author_name [Daniel Roy Greenfeld]:
Your email address. This is you! The value goes into places like `LICENSE` and such.
description [A short description of the project.] email [daniel-roy-greenfeld@example.com]:
Used in the generated README.rst and other places. The email address you want to identify yourself in the project.
domain_name [example.com] 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 once it goes live.
Note that it can be safely changed later on whenever you need to.
version [0.1.0] 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] timezone [UTC]
Used in the base settings file for the `TIME_ZONE` value. The value to be used for the `TIME_ZONE` setting of the project.
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.
windows [n] 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] use_docker [y]
Whether to use Docker_, separating the app and database into separate Indicates whether the project should be configured to use Docker_ and `Docker Compose`_.
containers.
use_heroku [n] postgresql_version [1]
Add configuration to deploy the application to a Heroku_ instance. Select a PostgreSQL_ version to use. The choices are:
use_compressor [n] 1. 10.3
Use `Django Compressor`_ to minify and combine rendered JavaScript and CSS 2. 10.2
into cachable static resources. 3. 10.1
4. 9.6
5. 9.5
6. 9.4
7. 9.3
js_task_runner [1] js_task_runner [1]
Select a JavaScript task runner. The choices are: Select a JavaScript task runner. The choices are:
@ -73,36 +65,63 @@ js_task_runner [1]
3. None 3. None
custom_bootstrap_compilation [n] custom_bootstrap_compilation [n]
Scaffold out recompiling Bootstrap as as task, with Gulp_ or Grunt_. Indicates whether the project should support Bootstrap recompilation
Useful for letting you change Bootstrap variables in real time. via the selected JavaScript task runner's task. This can be useful
Consult project README for more details. for real-time Bootstrap variable alteration.
open_source_license [1] use_compressor [n]
Select a software license for the project. The choices are: Indicates whether the project should be configured to use `Django Compressor`_.
1. MIT_ use_celery [n]
2. BSD_ Indicates whether the project should be configured to use Celery_.
3. GPLv3_
4. `Apache Software License 2.0`_ use_mailhog [n]
5. Not open source 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]
Indicates whether the project should be configured to use `Travis CI`_.
**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
.. _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 .. _MIT: https://opensource.org/licenses/MIT
.. _BSD: https://opensource.org/licenses/BSD-3-Clause .. _BSD: https://opensource.org/licenses/BSD-3-Clause
.. _GPLv3: https://www.gnu.org/licenses/gpl.html .. _GPLv3: https://www.gnu.org/licenses/gpl.html
.. _Apache Software License 2.0: http://www.apache.org/licenses/LICENSE-2.0 .. _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/

View File

@ -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_DSN SENTRY_DSN n/a raises error
DJANGO_SENTRY_CLIENT SENTRY_CLIENT n/a raven.contrib.django.raven_compat.DjangoClient 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_SENTRY_LOG_LEVEL SENTRY_LOG_LEVEL n/a logging.INFO
DJANGO_MAILGUN_API_KEY MAILGUN_ACCESS_KEY n/a raises error MAILGUN_API_KEY MAILGUN_ACCESS_KEY n/a raises error
DJANGO_MAILGUN_SERVER_NAME MAILGUN_SERVER_NAME n/a raises error MAILGUN_DOMAIN MAILGUN_SENDER_DOMAIN n/a raises error
MAILGUN_SENDER_DOMAIN MAILGUN_SENDER_DOMAIN n/a raises error
NEW_RELIC_APP_NAME NEW_RELIC_APP_NAME 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 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_APP_ID OPBEAT['APP_ID'] n/a raises error

View File

@ -25,11 +25,6 @@ except NotImplementedError:
PROJECT_DIR_PATH = os.path.realpath(os.path.curdir) 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(): def remove_open_source_project_only_files():
file_names = [ file_names = [
'CONTRIBUTORS.txt', 'CONTRIBUTORS.txt',
@ -72,22 +67,14 @@ def remove_heroku_files():
file_names = [ file_names = [
'Procfile', 'Procfile',
'runtime.txt', 'runtime.txt',
'requirements.txt',
] ]
for file_name in file_names: 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_paas_files(): def remove_dotenv_file():
none_paas_files_left = True os.remove(os.path.join(PROJECT_DIR_PATH, '.env'))
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(): def remove_grunt_files():
@ -118,6 +105,10 @@ def remove_celery_app():
shutil.rmtree(os.path.join(PROJECT_DIR_PATH, '{{ cookiecutter.project_slug }}', 'taskapp')) 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): def append_to_project_gitignore(path):
gitignore_file_path = os.path.join(PROJECT_DIR_PATH, '.gitignore') gitignore_file_path = os.path.join(PROJECT_DIR_PATH, '.gitignore')
with open(gitignore_file_path, 'a') as gitignore_file: with open(gitignore_file_path, 'a') as gitignore_file:
@ -241,7 +232,7 @@ def main():
if '{{ cookiecutter.open_source_license }}' == 'Not open source': if '{{ cookiecutter.open_source_license }}' == 'Not open source':
remove_open_source_project_only_files() remove_open_source_project_only_files()
elif '{{ cookiecutter.open_source_license}}' != 'GPLv3': if '{{ cookiecutter.open_source_license}}' != 'GPLv3':
remove_gplv3_files() remove_gplv3_files()
if '{{ cookiecutter.use_pycharm }}'.lower() == 'n': if '{{ cookiecutter.use_pycharm }}'.lower() == 'n':
@ -250,7 +241,11 @@ def main():
if '{{ cookiecutter.use_docker }}'.lower() == 'n': if '{{ cookiecutter.use_docker }}'.lower() == 'n':
remove_docker_files() remove_docker_files()
remove_paas_files() 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': if '{{ cookiecutter.js_task_runner}}'.lower() == 'gulp':
remove_grunt_files() remove_grunt_files()
@ -278,6 +273,9 @@ def main():
if '{{ cookiecutter.use_celery }}'.lower() == 'n': if '{{ cookiecutter.use_celery }}'.lower() == 'n':
remove_celery_app() remove_celery_app()
if '{{ cookiecutter.use_travisci }}'.lower() == 'n':
remove_dottravisyml_file()
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View File

@ -11,6 +11,9 @@ project_slug = '{{ cookiecutter.project_slug }}'
if hasattr(project_slug, 'isidentifier'): if hasattr(project_slug, 'isidentifier'):
assert project_slug.isidentifier(), "'{}' project slug is not a valid Python identifier.".format(project_slug) 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() using_docker = '{{ cookiecutter.use_docker }}'.lower()
if using_docker == 'n': if using_docker == 'n':
TERMINATOR = "\x1b[0m" TERMINATOR = "\x1b[0m"

View File

@ -1,11 +1,17 @@
cookiecutter==1.6.0 cookiecutter==1.6.0
flake8==3.5.0 # pyup: != 2.6.0
sh==1.12.14 sh==1.12.14
binaryornot==0.4.4 binaryornot==0.4.4
# Testing
pytest==3.3.2 # Code quality
# ------------------------------------------------------------------------------
flake8==3.5.0
pycodestyle==2.3.1 pycodestyle==2.3.1
pyflakes==1.6.0 pyflakes==1.6.0
# Testing
# ------------------------------------------------------------------------------
tox==2.9.1 tox==2.9.1
pytest==3.4.2
pytest-cookies==0.3.0 pytest-cookies==0.3.0

View File

@ -1,2 +0,0 @@
# These requirements prevented an upgrade to Django 1.11.
django-autoslug==1.9.3

View File

@ -10,7 +10,7 @@ except ImportError:
# Our version ALWAYS matches the version of Django we support # 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. # 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': if sys.argv[-1] == 'tag':
os.system('git tag -a %s -m "version %s"' % (version, version)) os.system('git tag -a %s -m "version %s"' % (version, version))
@ -34,7 +34,7 @@ setup(
classifiers=[ classifiers=[
'Development Status :: 4 - Beta', 'Development Status :: 4 - Beta',
'Environment :: Console', 'Environment :: Console',
'Framework :: Django :: 1.11', 'Framework :: Django :: 2.0',
'Intended Audience :: Developers', 'Intended Audience :: Developers',
'Natural Language :: English', 'Natural Language :: English',
'License :: OSI Approved :: BSD License', 'License :: OSI Approved :: BSD License',
@ -42,7 +42,6 @@ setup(
'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: PyPy',
'Topic :: Software Development', 'Topic :: Software Development',
], ],
keywords=( keywords=(

View File

@ -12,10 +12,13 @@ cd .cache/docker
# create the project using the default settings in cookiecutter.json # create the project using the default settings in cookiecutter.json
cookiecutter ../../ --no-input --overwrite-if-exists use_docker=y js_task_runner=None 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 # run the project's tests
docker-compose -f local.yml run django python manage.py test 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 # 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; } 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 django python manage.py makemessages

View File

@ -3,10 +3,5 @@ skipsdist = true
envlist = py36 envlist = py36
[testenv] [testenv]
passenv = LC_ALL, LANG, HOME deps = -rrequirements.txt
deps = commands = pytest {posargs:./tests}
binaryornot
flake8==2.5.5
pytest-cookies
sh
commands = py.test {posargs:tests}

View File

@ -92,7 +92,7 @@ module.exports = function (grunt) {
processors: [ processors: [
require('pixrem')(), // add fallbacks for rem units require('pixrem')(), // add fallbacks for rem units
require('autoprefixer-core')({browsers: [ require('autoprefixer')({browsers: [
'Android 2.3', 'Android 2.3',
'Android >= 4', 'Android >= 4',
'Chrome >= 20', 'Chrome >= 20',

View File

@ -1,7 +1,18 @@
FROM python:3.6 FROM python:3.6-alpine
ENV PYTHONUNBUFFERED 1 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 # Requirements have to be pulled and installed here, otherwise caching won't work
COPY ./requirements /requirements COPY ./requirements /requirements
RUN pip install -r /requirements/local.txt RUN pip install -r /requirements/local.txt

View File

@ -1,4 +1,4 @@
#!/usr/bin/env bash #!/bin/sh
set -o errexit set -o errexit
set -o pipefail set -o pipefail

View File

@ -1,4 +1,4 @@
#!/usr/bin/env bash #!/bin/sh
set -o errexit set -o errexit
set -o pipefail set -o pipefail

View File

@ -1,4 +1,4 @@
#!/usr/bin/env bash #!/bin/sh
set -o errexit set -o errexit
set -o pipefail set -o pipefail

View File

@ -1,9 +1,18 @@
FROM python:3.6 FROM python:3.6-alpine
ENV PYTHONUNBUFFERED 1 ENV PYTHONUNBUFFERED 1
RUN groupadd -r django \ RUN apk update \
&& useradd -r -g django django # 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 # Requirements have to be pulled and installed here, otherwise caching won't work
COPY ./requirements /requirements COPY ./requirements /requirements

View File

@ -1,4 +1,4 @@
#!/usr/bin/env bash #!/bin/sh
set -o errexit set -o errexit
set -o pipefail set -o pipefail

View File

@ -1,4 +1,4 @@
#!/usr/bin/env bash #!/bin/sh
set -o errexit set -o errexit
set -o pipefail set -o pipefail

View File

@ -1,4 +1,4 @@
#!/usr/bin/env bash #!/bin/sh
set -o errexit set -o errexit
set -o pipefail set -o pipefail
@ -25,7 +25,7 @@ export DATABASE_URL=postgres://$POSTGRES_USER:$POSTGRES_PASSWORD@postgres:5432/$
export CELERY_BROKER_URL=$REDIS_URL/0 export CELERY_BROKER_URL=$REDIS_URL/0
{% endif %} {% endif %}
function postgres_ready(){ postgres_ready() {
python << END python << END
import sys import sys
import psycopg2 import psycopg2

View File

@ -1,4 +1,4 @@
#!/usr/bin/env bash #!/bin/sh
set -o errexit set -o errexit
set -o pipefail set -o pipefail
@ -6,4 +6,4 @@ set -o nounset
python /app/manage.py collectstatic --noinput 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

View File

@ -1,232 +1,119 @@
""" """
Base settings for {{cookiecutter.project_name}} project. Base settings to build other settings files upon.
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/
""" """
import environ import environ
ROOT_DIR = environ.Path(__file__) - 3 # ({{ cookiecutter.project_slug }}/config/settings/base.py - 3 = {{ cookiecutter.project_slug }}/) 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 }}') APPS_DIR = ROOT_DIR.path('{{ cookiecutter.project_slug }}')
# Load operating system environment variables and then prepare to use them
env = environ.Env() env = environ.Env()
# .env file, should load only in development environment
READ_DOT_ENV_FILE = env.bool('DJANGO_READ_DOT_ENV_FILE', default=False) READ_DOT_ENV_FILE = env.bool('DJANGO_READ_DOT_ENV_FILE', default=False)
if READ_DOT_ENV_FILE: if READ_DOT_ENV_FILE:
# Operating System Environment variables have precedence over variables defined in the .env file, # OS environment variables take precedence over variables from .env
# that is to say variables from the .env files will only be used if not defined env.read_env(str(ROOT_DIR.path('.env')))
# 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')
# 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 = [ DJANGO_APPS = [
# Default Django apps:
'django.contrib.auth', 'django.contrib.auth',
'django.contrib.contenttypes', 'django.contrib.contenttypes',
'django.contrib.sessions', 'django.contrib.sessions',
'django.contrib.sites', 'django.contrib.sites',
'django.contrib.messages', 'django.contrib.messages',
'django.contrib.staticfiles', 'django.contrib.staticfiles',
# 'django.contrib.humanize', # Handy template tags
# Useful template tags:
# 'django.contrib.humanize',
# Admin
'django.contrib.admin', 'django.contrib.admin',
] ]
THIRD_PARTY_APPS = [ THIRD_PARTY_APPS = [
'crispy_forms', # Form layouts 'crispy_forms',
'allauth', # registration
'allauth.account', # registration
'allauth.socialaccount', # registration
]
# Apps specific for this project go here. 'allauth',
'allauth.account',
'allauth.socialaccount',
]
LOCAL_APPS = [ LOCAL_APPS = [
# custom users app
'{{ cookiecutter.project_slug }}.users.apps.UsersConfig', '{{ cookiecutter.project_slug }}.users.apps.UsersConfig',
# Your stuff: custom apps go here # Your stuff: custom apps go here
] ]
# https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps
# See: https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps
INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS
# MIDDLEWARE CONFIGURATION # MIGRATIONS
# ------------------------------------------------------------------------------
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
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# https://docs.djangoproject.com/en/dev/ref/settings/#migration-modules
MIGRATION_MODULES = { MIGRATION_MODULES = {
'sites': '{{ cookiecutter.project_slug }}.contrib.sites.migrations' 'sites': '{{ cookiecutter.project_slug }}.contrib.sites.migrations'
} }
# DEBUG # AUTHENTICATION
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# See: https://docs.djangoproject.com/en/dev/ref/settings/#debug # https://docs.djangoproject.com/en/dev/ref/settings/#authentication-backends
DEBUG = env.bool('DJANGO_DEBUG', False) AUTHENTICATION_BACKENDS = [
'django.contrib.auth.backends.ModelBackend',
# FIXTURE CONFIGURATION 'allauth.account.auth_backends.AuthenticationBackend',
# ------------------------------------------------------------------------------
# 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/#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 # PASSWORDS
MANAGERS = ADMINS
# DATABASE CONFIGURATION
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# See: https://docs.djangoproject.com/en/dev/ref/settings/#databases # https://docs.djangoproject.com/en/dev/ref/settings/#password-hashers
# Uses django-environ to accept uri format
# See: https://django-environ.readthedocs.io/en/latest/#supported-types
DATABASES = {
'default': env.db('DATABASE_URL', default='postgres://{% if cookiecutter.windows == 'y' %}localhost{% endif %}/{{cookiecutter.project_slug}}'),
}
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
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.Argon2PasswordHasher',
'django.contrib.auth.hashers.PBKDF2PasswordHasher', 'django.contrib.auth.hashers.PBKDF2PasswordHasher',
'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher', 'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
'django.contrib.auth.hashers.BCryptSHA256PasswordHasher', 'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
'django.contrib.auth.hashers.BCryptPasswordHasher', 'django.contrib.auth.hashers.BCryptPasswordHasher',
] ]
# PASSWORD VALIDATION
# https://docs.djangoproject.com/en/dev/ref/settings/#auth-password-validators # https://docs.djangoproject.com/en/dev/ref/settings/#auth-password-validators
# ------------------------------------------------------------------------------
AUTH_PASSWORD_VALIDATORS = [ AUTH_PASSWORD_VALIDATORS = [
{ {
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
@ -242,50 +129,142 @@ AUTH_PASSWORD_VALIDATORS = [
}, },
] ]
# AUTHENTICATION CONFIGURATION # MIDDLEWARE
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
AUTHENTICATION_BACKENDS = [ # https://docs.djangoproject.com/en/dev/ref/settings/#middleware
'django.contrib.auth.backends.ModelBackend', MIDDLEWARE = [
'allauth.account.auth_backends.AuthenticationBackend', '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 # STATIC
ACCOUNT_AUTHENTICATION_METHOD = 'username' # ------------------------------------------------------------------------------
ACCOUNT_EMAIL_REQUIRED = True # https://docs.djangoproject.com/en/dev/ref/settings/#static-root
ACCOUNT_EMAIL_VERIFICATION = 'mandatory' 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) # MEDIA
ACCOUNT_ADAPTER = '{{cookiecutter.project_slug}}.users.adapters.AccountAdapter' # ------------------------------------------------------------------------------
SOCIALACCOUNT_ADAPTER = '{{cookiecutter.project_slug}}.users.adapters.SocialAccountAdapter' # 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 # TEMPLATES
# Select the correct user model # ------------------------------------------------------------------------------
AUTH_USER_MODEL = 'users.User' # https://docs.djangoproject.com/en/dev/ref/settings/#templates
LOGIN_REDIRECT_URL = 'users:redirect' TEMPLATES = [
LOGIN_URL = 'account_login' {
# 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 # FIXTURES
AUTOSLUG_SLUGIFY_FUNCTION = 'slugify.slugify' # ------------------------------------------------------------------------------
{% if cookiecutter.use_celery == 'y' %} # https://docs.djangoproject.com/en/dev/ref/settings/#fixture-dirs
########## CELERY 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'] 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://') 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://': if CELERY_BROKER_URL == 'django://':
CELERY_RESULT_BACKEND = 'redis://' CELERY_RESULT_BACKEND = 'redis://'
else: else:
CELERY_RESULT_BACKEND = CELERY_BROKER_URL CELERY_RESULT_BACKEND = CELERY_BROKER_URL
########## END CELERY # http://docs.celeryproject.org/en/latest/userguide/configuration.html#std:setting-accept_content
{% endif %} 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'
{%- 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 # django-compressor
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# https://django-compressor.readthedocs.io/en/latest/quickstart/#installation
INSTALLED_APPS += ['compressor'] INSTALLED_APPS += ['compressor']
STATICFILES_FINDERS += ['compressor.finders.CompressorFinder'] STATICFILES_FINDERS += ['compressor.finders.CompressorFinder']
{%- endif %} {%- endif %}
# Your stuff...
# 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
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------

View File

@ -1,47 +1,21 @@
"""
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 from .base import * # noqa
from .base import env
# DEBUG # GENERAL
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# https://docs.djangoproject.com/en/dev/ref/settings/#debug
DEBUG = env.bool('DJANGO_DEBUG', default=True) DEBUG = env.bool('DJANGO_DEBUG', default=True)
TEMPLATES[0]['OPTIONS']['debug'] = DEBUG # https://docs.djangoproject.com/en/dev/ref/settings/#secret-key
# 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!!!') 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",
]
# Mail settings # CACHES
# ------------------------------------------------------------------------------
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
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# https://docs.djangoproject.com/en/dev/ref/settings/#caches
CACHES = { CACHES = {
'default': { 'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
@ -49,40 +23,62 @@ CACHES = {
} }
} }
# TEMPLATES
# ------------------------------------------------------------------------------
# https://docs.djangoproject.com/en/dev/ref/settings/#templates
TEMPLATES[0]['OPTIONS']['debug'] = DEBUG # noqa F405
# 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 # django-debug-toolbar
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
MIDDLEWARE += ['debug_toolbar.middleware.DebugToolbarMiddleware', ] # 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
INTERNAL_IPS = ['127.0.0.1', '10.0.2.2', ] MIDDLEWARE += ['debug_toolbar.middleware.DebugToolbarMiddleware'] # noqa F405
{% if cookiecutter.use_docker == 'y' %} # https://django-debug-toolbar.readthedocs.io/en/latest/configuration.html#debug-toolbar-config
{# [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':
hostname, _, ips = socket.gethostbyname_ex(socket.gethostname())
INTERNAL_IPS += [ip[:-1] + '1' for ip in ips]
{% endif %}
DEBUG_TOOLBAR_CONFIG = { DEBUG_TOOLBAR_CONFIG = {
'DISABLE_PANELS': [ 'DISABLE_PANELS': [
'debug_toolbar.panels.redirects.RedirectsPanel', 'debug_toolbar.panels.redirects.RedirectsPanel',
], ],
'SHOW_TEMPLATE_CONTEXT': True, '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':
hostname, _, ips = socket.gethostbyname_ex(socket.gethostname())
INTERNAL_IPS += [ip[:-1] + '1' for ip in ips]
{%- endif %}
# django-extensions # django-extensions
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
INSTALLED_APPS += ['django_extensions', ] # https://django-extensions.readthedocs.io/en/latest/installation_instructions.html#configuration
INSTALLED_APPS += ['django_extensions'] # noqa F405
{% if cookiecutter.use_celery == 'y' -%}
# TESTING # Celery
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
TEST_RUNNER = 'django.test.runner.DiscoverRunner' # http://docs.celeryproject.org/en/latest/userguide/configuration.html#std:setting-task_always_eager
{% if cookiecutter.use_celery == 'y' %}
########## CELERY
# In development, all tasks will be executed locally by blocking until the task returns
CELERY_ALWAYS_EAGER = True CELERY_ALWAYS_EAGER = True
########## END CELERY
{% endif %} {%- endif %}
# Your local stuff: Below this line define 3rd party library settings # Your stuff...
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------

View File

@ -1,203 +1,190 @@
"""
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 import logging
{% endif %}
from .base import * # noqa from .base import * # noqa
from .base import env
# SECRET CONFIGURATION # GENERAL
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# See: https://docs.djangoproject.com/en/dev/ref/settings/#secret-key # https://docs.djangoproject.com/en/dev/ref/settings/#secret-key
# Raises ImproperlyConfigured exception if DJANGO_SECRET_KEY not in os.environ
SECRET_KEY = env('DJANGO_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 }}'])
# DATABASES
# 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 DATABASES['default'] = env.db('DATABASE_URL') # noqa F405
# and https://docs.djangoproject.com/en/dev/howto/deployment/checklist/#run-manage-py-check-deploy DATABASES['default']['ATOMIC_REQUESTS'] = True # noqa F405
DATABASES['default']['CONN_MAX_AGE'] = env.int('CONN_MAX_AGE', default=60) # noqa F405
# set this to 60 seconds and then to 518400 when you can prove it works # CACHES
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
# 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' -%}
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}} <noreply@{{cookiecutter.domain_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('DJANGO_MAILGUN_API_KEY'),
'MAILGUN_SENDER_DOMAIN': env('MAILGUN_SENDER_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', ]),
]
{% 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
# CACHING
# ------------------------------------------------------------------------------
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 = { CACHES = {
'default': { 'default': {
'BACKEND': 'django_redis.cache.RedisCache', 'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': REDIS_LOCATION, 'LOCATION': f'{env("REDIS_URL", default="redis://127.0.0.1:6379")}/{0}',
'OPTIONS': { 'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient', 'CLIENT_CLASS': 'django_redis.client.DefaultClient',
'IGNORE_EXCEPTIONS': True, # mimics memcache behavior. # Mimicing memcache behavior.
# http://niwinz.github.io/django-redis/latest/#_memcached_exceptions_behavior # http://niwinz.github.io/django-redis/latest/#_memcached_exceptions_behavior
'IGNORE_EXCEPTIONS': True,
} }
} }
} }
{% if cookiecutter.use_sentry_for_error_reporting == 'y' %} # SECURITY
# Sentry Configuration # ------------------------------------------------------------------------------
# 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'] # 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
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': f'max-age={_AWS_EXPIRY}, s-maxage={_AWS_EXPIRY}, must-revalidate',
}
# 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 = f'https://s3.amazonaws.com/{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 = 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'] = [ # noqa F405
(
'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}} <noreply@{{cookiecutter.domain_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'] # noqa F405
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'] # noqa F405
{% if cookiecutter.use_whitenoise == 'y' -%}
# WhiteNoise
# ------------------------------------------------------------------------------
# http://whitenoise.evans.io/en/latest/django.html#enable-whitenoise
MIDDLEWARE = ['whitenoise.middleware.WhiteNoiseMiddleware'] + MIDDLEWARE # noqa F405
{%- 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 # noqa F405
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'] # noqa F405
MIDDLEWARE = ['raven.contrib.django.raven_compat.middleware.SentryResponseErrorIdMiddleware'] + MIDDLEWARE
# Sentry
# ------------------------------------------------------------------------------
SENTRY_DSN = env('DJANGO_SENTRY_DSN') SENTRY_DSN = env('DJANGO_SENTRY_DSN')
SENTRY_CLIENT = env('DJANGO_SENTRY_CLIENT', default='raven.contrib.django.raven_compat.DjangoClient') SENTRY_CLIENT = env('DJANGO_SENTRY_CLIENT', default='raven.contrib.django.raven_compat.DjangoClient')
LOGGING = { LOGGING = {
@ -205,7 +192,7 @@ LOGGING = {
'disable_existing_loggers': True, 'disable_existing_loggers': True,
'root': { 'root': {
'level': 'WARNING', 'level': 'WARNING',
'handlers': ['sentry', ], 'handlers': ['sentry'],
}, },
'formatters': { 'formatters': {
'verbose': { 'verbose': {
@ -227,38 +214,39 @@ LOGGING = {
'loggers': { 'loggers': {
'django.db.backends': { 'django.db.backends': {
'level': 'ERROR', 'level': 'ERROR',
'handlers': ['console', ], 'handlers': ['console'],
'propagate': False, 'propagate': False,
}, },
'raven': { 'raven': {
'level': 'DEBUG', 'level': 'DEBUG',
'handlers': ['console', ], 'handlers': ['console'],
'propagate': False, 'propagate': False,
}, },
'sentry.errors': { 'sentry.errors': {
'level': 'DEBUG', 'level': 'DEBUG',
'handlers': ['console', ], 'handlers': ['console'],
'propagate': False, 'propagate': False,
}, },
'django.security.DisallowedHost': { 'django.security.DisallowedHost': {
'level': 'ERROR', 'level': 'ERROR',
'handlers': ['console', 'sentry', ], 'handlers': ['console', 'sentry'],
'propagate': False, 'propagate': False,
}, },
}, },
} }
SENTRY_CELERY_LOGLEVEL = env.int('DJANGO_SENTRY_LOG_LEVEL', logging.INFO) SENTRY_CELERY_LOGLEVEL = env.int('DJANGO_SENTRY_LOG_LEVEL', logging.INFO)
RAVEN_CONFIG = { RAVEN_CONFIG = {
'CELERY_LOGLEVEL': env.int('DJANGO_SENTRY_LOG_LEVEL', logging.INFO), 'CELERY_LOGLEVEL': env.int('DJANGO_SENTRY_LOG_LEVEL', logging.INFO),
'DSN': SENTRY_DSN 'DSN': SENTRY_DSN
} }
{% elif cookiecutter.use_sentry_for_error_reporting == 'n' %} {%- else %}
# LOGGING CONFIGURATION # LOGGING
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# See: https://docs.djangoproject.com/en/dev/ref/settings/#logging # See: https://docs.djangoproject.com/en/dev/ref/settings/#logging
# A sample logging configuration. The only tangible logging # A sample logging configuration. The only tangible logging
# performed by this configuration is to send an email to # 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 # See https://docs.djangoproject.com/en/dev/topics/logging for
# more details on how to customize your logging configuration. # more details on how to customize your logging configuration.
LOGGING = { LOGGING = {
@ -278,7 +266,7 @@ LOGGING = {
'handlers': { 'handlers': {
'mail_admins': { 'mail_admins': {
'level': 'ERROR', 'level': 'ERROR',
'filters': ['require_debug_false', ], 'filters': ['require_debug_false'],
'class': 'django.utils.log.AdminEmailHandler' 'class': 'django.utils.log.AdminEmailHandler'
}, },
'console': { 'console': {
@ -289,20 +277,33 @@ LOGGING = {
}, },
'loggers': { 'loggers': {
'django.request': { 'django.request': {
'handlers': ['mail_admins', ], 'handlers': ['mail_admins'],
'level': 'ERROR', 'level': 'ERROR',
'propagate': True 'propagate': True
}, },
'django.security.DisallowedHost': { 'django.security.DisallowedHost': {
'level': 'ERROR', 'level': 'ERROR',
'handlers': ['console', 'mail_admins', ], 'handlers': ['console', 'mail_admins'],
'propagate': True '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'] # 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...
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------

View File

@ -1,36 +1,22 @@
""" """
Test settings for {{cookiecutter.project_name}} project. With these settings, tests run faster.
- Used to run tests fast on the continuous integration server and locally
""" """
from .base import * # noqa from .base import * # noqa
from .base import env
# GENERAL
# DEBUG
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Turn debug off so tests run faster # https://docs.djangoproject.com/en/dev/ref/settings/#debug
DEBUG = False DEBUG = False
TEMPLATES[0]['OPTIONS']['debug'] = False # https://docs.djangoproject.com/en/dev/ref/settings/#secret-key
# 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!!!') 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' # https://docs.djangoproject.com/en/dev/ref/settings/#caches
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
CACHES = { CACHES = {
'default': { 'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
@ -38,24 +24,35 @@ CACHES = {
} }
} }
# TESTING # PASSWORDS
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
TEST_RUNNER = 'django.test.runner.DiscoverRunner' # https://docs.djangoproject.com/en/dev/ref/settings/#password-hashers
# PASSWORD HASHING
# ------------------------------------------------------------------------------
# Use fast password hasher so tests run faster
PASSWORD_HASHERS = [ PASSWORD_HASHERS = [
'django.contrib.auth.hashers.MD5PasswordHasher', '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']['loaders'] = [ TEMPLATES[0]['OPTIONS']['debug'] = DEBUG # noqa F405
['django.template.loaders.cached.Loader', [ TEMPLATES[0]['OPTIONS']['loaders'] = [ # noqa F405
'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...
# ------------------------------------------------------------------------------

View File

@ -4,6 +4,9 @@ POSTGRES_PASSWORD=!!!SET POSTGRES_PASSWORD!!!
POSTGRES_USER=!!!SET POSTGRES_USER!!! POSTGRES_USER=!!!SET POSTGRES_USER!!!
CONN_MAX_AGE= CONN_MAX_AGE=
# Gunicorn concurrency
WEB_CONCURRENCY=4
# Domain name, used by caddy # Domain name, used by caddy
DOMAIN_NAME={{ cookiecutter.domain_name }} DOMAIN_NAME={{ cookiecutter.domain_name }}
@ -20,9 +23,9 @@ DJANGO_AWS_SECRET_ACCESS_KEY=
DJANGO_AWS_STORAGE_BUCKET_NAME= DJANGO_AWS_STORAGE_BUCKET_NAME=
# Used with email # Used with email
DJANGO_MAILGUN_API_KEY= MAILGUN_API_KEY=
DJANGO_SERVER_EMAIL= DJANGO_SERVER_EMAIL=
MAILGUN_SENDER_DOMAIN= MAILGUN_DOMAIN=
# Security! Better to use DNS for this task, but you can use redirect # Security! Better to use DNS for this task, but you can use redirect
DJANGO_SECURE_SSL_REDIRECT=False DJANGO_SECURE_SSL_REDIRECT=False

View File

@ -0,0 +1,6 @@
Translations
============
Translations will be placed in this folder when running::
python manage.py makemessages

View File

@ -4,22 +4,22 @@
"dependencies": {}, "dependencies": {},
"devDependencies": { "devDependencies": {
{% if cookiecutter.js_task_runner == 'Grunt' %} {% if cookiecutter.js_task_runner == 'Grunt' %}
"autoprefixer-core": "~5.2.1", "autoprefixer": "~8.1.0",
{% if cookiecutter.custom_bootstrap_compilation == 'y' %} {% if cookiecutter.custom_bootstrap_compilation == 'y' %}
"bootstrap": "^4.0.0", "bootstrap": "^4.0.0",
{% endif %} {% endif %}
"connect-livereload": "~0.3.2", "connect-livereload": "~0.6.0",
"cssnano": "~2.1.0", "cssnano": "~3.10.0",
"grunt": "~0.4.5", "grunt": "~1.0.2",
"grunt-bg-shell": "~2.3.1", "grunt-bg-shell": "~2.3.1",
"grunt-contrib-watch": "~0.6.1", "grunt-contrib-watch": "~1.0.0",
"grunt-postcss": "~0.5.5", "grunt-postcss": "~0.9.0",
"grunt-sass": "~1.0.0", "grunt-sass": "~2.1.0",
{% if cookiecutter.custom_bootstrap_compilation == 'y' %} {% if cookiecutter.custom_bootstrap_compilation == 'y' %}
"jquery": "^3.2.1-slim", "jquery": "^3.2.1-slim",
{% endif %} {% endif %}
"load-grunt-tasks": "~3.2.0", "load-grunt-tasks": "~3.2.0",
"pixrem": "~1.3.1", "pixrem": "~4.0.1",
{% if cookiecutter.custom_bootstrap_compilation == 'y' %} {% if cookiecutter.custom_bootstrap_compilation == 'y' %}
"popper.js": "^1.12.3", "popper.js": "^1.12.3",
{% endif %} {% endif %}
@ -31,26 +31,34 @@
"browser-sync": "^2.14.0", "browser-sync": "^2.14.0",
"del": "^2.2.2", "del": "^2.2.2",
"gulp": "^3.9.1", "gulp": "^3.9.1",
"gulp-autoprefixer": "^3.1.1", "gulp-autoprefixer": "^5.0.0",
{% if cookiecutter.custom_bootstrap_compilation == 'y' %} {% if cookiecutter.custom_bootstrap_compilation == 'y' %}
"gulp-concat": "^2.6.1", "gulp-concat": "^2.6.1",
{% endif %} {% endif %}
"gulp-cssnano": "^2.1.2", "gulp-cssnano": "^2.1.2",
"gulp-imagemin": "^3.0.3", "gulp-imagemin": "^4.1.0",
"gulp-pixrem": "^1.0.0", "gulp-pixrem": "^1.0.0",
"gulp-plumber": "^1.1.0", "gulp-plumber": "^1.1.0",
"gulp-rename": "^1.2.2", "gulp-rename": "^1.2.2",
"gulp-sass": "^2.3.2", "gulp-sass": "^3.1.0",
"gulp-uglify": "^2.0.0", "gulp-uglify": "^3.0.0",
"gulp-util": "^3.0.7", "gulp-util": "^3.0.7",
{% if cookiecutter.custom_bootstrap_compilation == 'y' %} {% if cookiecutter.custom_bootstrap_compilation == 'y' %}
"jquery": "^3.2.1-slim", "jquery": "^3.2.1-slim",
"popper.js": "^1.12.3", "popper.js": "^1.12.3",
{% endif %} {% endif %}
"run-sequence": "^1.2.2" "run-sequence": "^2.1.1"
{% endif %} {% endif %}
}, },
"engines": { "engines": {
"node": ">=0.8.0" "node": ">=0.8.0"
},
"scripts": {
{% if cookiecutter.js_task_runner == 'Grunt' %}
"dev": "grunt serve"
{% elif cookiecutter.js_task_runner == 'Gulp' %}
"dev": "gulp"
{% endif %}
} }
} }

View File

@ -1,3 +1,3 @@
# This file is here because many Platforms as a Service look for # This file is expected by Heroku.
# requirements.txt in the root directory of a project.
-r requirements/production.txt -r requirements/production.txt

View File

@ -1,12 +1,5 @@
# 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 # Conservative Django
django==2.0.2 # pyup: < 2.1 django==2.0.3 # pyup: < 2.1
# Configuration # Configuration
django-environ==0.4.4 django-environ==0.4.4
@ -16,7 +9,7 @@ whitenoise==3.3.1
# Forms # Forms
django-crispy-forms==1.7.0 django-crispy-forms==1.7.1
# Models # Models
django-model-utils==3.1.1 django-model-utils==3.1.1
@ -36,7 +29,7 @@ django-allauth==0.35.0
# from http://www.lfd.uci.edu/~gohlke/pythonlibs/#psycopg # from http://www.lfd.uci.edu/~gohlke/pythonlibs/#psycopg
{% else %} {% else %}
# Python-PostgreSQL Database Adapter # Python-PostgreSQL Database Adapter
psycopg2==2.7.4 psycopg2==2.7.4 --no-binary psycopg2
{%- endif %} {%- endif %}
# Unicode slugification # Unicode slugification
@ -46,7 +39,7 @@ awesome-slugify==1.6.5
pytz==2018.3 pytz==2018.3
# Redis support # Redis support
django-redis==4.8.0 django-redis==4.9.0
redis>=2.10.5 redis>=2.10.5
{% if cookiecutter.use_celery == "y" %} {% if cookiecutter.use_celery == "y" %}

View File

@ -4,8 +4,8 @@
coverage==4.5.1 coverage==4.5.1
django-coverage-plugin==1.5.0 django-coverage-plugin==1.5.0
Sphinx==1.7.0 Sphinx==1.7.1
django-extensions==1.9.9 django-extensions==2.0.0
Werkzeug==0.14.1 Werkzeug==0.14.1
django-test-plus==1.0.22 django-test-plus==1.0.22
factory-boy==2.10.0 factory-boy==2.10.0

View File

@ -6,7 +6,7 @@
# Python-PostgreSQL Database Adapter # Python-PostgreSQL Database Adapter
# Assuming Windows is used locally, and *nix -- in production. # Assuming Windows is used locally, and *nix -- in production.
# ------------------------------------------------------------ # ------------------------------------------------------------
psycopg2==2.7.4 psycopg2==2.7.4 --no-binary psycopg2
{%- endif %} {%- endif %}
# WSGI Handler # WSGI Handler
@ -16,7 +16,7 @@ gunicorn==19.7.1
# Static and Media Storage # Static and Media Storage
# ------------------------------------------------ # ------------------------------------------------
boto3==1.5.31 boto3==1.6.2 # pyup: update minor
django-storages==1.6.5 django-storages==1.6.5
{% if cookiecutter.use_whitenoise != 'y' -%} {% if cookiecutter.use_whitenoise != 'y' -%}
Collectfast==0.6.0 Collectfast==0.6.0
@ -29,7 +29,7 @@ django-anymail==1.4
{% if cookiecutter.use_sentry_for_error_reporting == "y" -%} {% if cookiecutter.use_sentry_for_error_reporting == "y" -%}
# Raven is the Sentry client # Raven is the Sentry client
# -------------------------- # --------------------------
raven==6.5.0 raven==6.6.0
{%- endif %} {%- endif %}
{% if cookiecutter.use_opbeat == "y" -%} {% if cookiecutter.use_opbeat == "y" -%}

View File

@ -66,7 +66,7 @@ class CeleryConfig(AppConfig):
try: try:
opbeat_register_signal(opbeat_client) opbeat_register_signal(opbeat_client)
except Exception as e: 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: if 'opbeat.contrib.django' in settings.INSTALLED_APPS:
opbeat_register_handlers() opbeat_register_handlers()
@ -75,7 +75,7 @@ class CeleryConfig(AppConfig):
@app.task(bind=True) @app.task(bind=True)
def debug_task(self): def debug_task(self):
print('Request: {0!r}'.format(self.request)) # pragma: no cover print(f'Request: {self.request!r}') # pragma: no cover
{% else %} {% else %}
# Use this as a starting point for your project with celery. # Use this as a starting point for your project with celery.
# If you are not using celery, you can remove this app # If you are not using celery, you can remove this app

View File

@ -22,7 +22,7 @@
<!-- Your stuff: Third-party CSS libraries go here --> <!-- Your stuff: Third-party CSS libraries go here -->
{% endraw %}{% if cookiecutter.use_compressor == "y" %}{% raw %}{% compress css %}{% endraw %}{% endif %}{% raw %} {% endraw %}{% if cookiecutter.use_compressor == "y" %}{% raw %}{% compress css %}{% endraw %}{% endif %}{% raw %}
<!-- This file stores project-specific CSS --> <!-- This file stores project-specific CSS -->
{% endraw %}{% if cookiecutter.js_task_runner == "Gulp" %}{% raw %} {% endraw %}{% if cookiecutter.js_task_runner == "Gulp" and cookiecutter.use_compressor == "n" %}{% raw %}
<link href="{% static 'css/project.min.css' %}" rel="stylesheet"> <link href="{% static 'css/project.min.css' %}" rel="stylesheet">
{% endraw %}{% else %}{% raw %} {% endraw %}{% else %}{% raw %}
<link href="{% static 'css/project.css' %}" rel="stylesheet"> <link href="{% static 'css/project.css' %}" rel="stylesheet">

View File

@ -10,4 +10,7 @@ class UsersConfig(AppConfig):
Users system checks Users system checks
Users signal registration Users signal registration
""" """
pass try:
import users.signals # noqa F401
except ImportError:
pass

View File

@ -1,11 +1,9 @@
from django.contrib.auth.models import AbstractUser from django.contrib.auth.models import AbstractUser
from django.db import models from django.db import models
from django.urls import reverse from django.urls import reverse
from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@python_2_unicode_compatible
class User(AbstractUser): class User(AbstractUser):
# First Name and Last Name do not cover name patterns # First Name and Last Name do not cover name patterns

View File

@ -2,8 +2,8 @@ import factory
class UserFactory(factory.django.DjangoModelFactory): class UserFactory(factory.django.DjangoModelFactory):
username = factory.Sequence(lambda n: 'user-{0}'.format(n)) username = factory.Sequence(lambda n: f'user-{n}')
email = factory.Sequence(lambda n: 'user-{0}@example.com'.format(n)) email = factory.Sequence(lambda n: f'user-{n}@example.com')
password = factory.PostGenerationMethodCall('set_password', 'password') password = factory.PostGenerationMethodCall('set_password', 'password')
class Meta: class Meta:

View File

@ -14,14 +14,14 @@ urlpatterns = [
view=views.UserRedirectView.as_view(), view=views.UserRedirectView.as_view(),
name='redirect' name='redirect'
), ),
url(
regex=r'^(?P<username>[\w.@+-]+)/$',
view=views.UserDetailView.as_view(),
name='detail'
),
url( url(
regex=r'^~update/$', regex=r'^~update/$',
view=views.UserUpdateView.as_view(), view=views.UserUpdateView.as_view(),
name='update' name='update'
), ),
url(
regex=r'^(?P<username>[\w.@+-]+)/$',
view=views.UserDetailView.as_view(),
name='detail'
),
] ]