Merge branch 'master' into conditional-redis-merge

This commit is contained in:
Bruno Alla 2019-03-11 20:53:36 +00:00
commit ae27ef3fae
39 changed files with 500 additions and 277 deletions

View File

@ -17,7 +17,5 @@ about: Report a bug
[//]: # (Any or all of the following:) [//]: # (Any or all of the following:)
[//]: # (* Host system configuration: OS, Docker & friends' versions etc.) [//]: # (* Host system configuration: OS, Docker & friends' versions etc.)
[//]: # (* Project generation options) [//]: # (* Replay file https://cookiecutter.readthedocs.io/en/latest/advanced/replay.html)
[//]: # (* Logs) [//]: # (* Logs)

View File

@ -57,7 +57,9 @@ Listed in alphabetical order.
Andrew Mikhnevich `@zcho`_ Andrew Mikhnevich `@zcho`_
Andy Rose Andy Rose
Anna Callahan `@jazztpt`_ Anna Callahan `@jazztpt`_
Anna Sidwell `@takkaria`_
Antonia Blair `@antoniablair`_ @antoniablairart Antonia Blair `@antoniablair`_ @antoniablairart
Anuj Bansal `@ahhda`_
Arcuri Davide `@dadokkio`_ Arcuri Davide `@dadokkio`_
Areski Belaid `@areski`_ Areski Belaid `@areski`_
Ashley Camba Ashley Camba
@ -69,7 +71,9 @@ Listed in alphabetical order.
Bo Lopker `@blopker`_ Bo Lopker `@blopker`_
Bouke Haarsma Bouke Haarsma
Brent Payne `@brentpayne`_ @brentpayne Brent Payne `@brentpayne`_ @brentpayne
Bartek `@btknu`
Burhan Khalid            `@burhan`_                   @burhan Burhan Khalid            `@burhan`_                   @burhan
Carl Johnson `@carlmjohnson`_ @carlmjohnson
Catherine Devlin `@catherinedevlin`_ Catherine Devlin `@catherinedevlin`_
Cédric Gaspoz `@cgaspoz`_ Cédric Gaspoz `@cgaspoz`_
Charlie Smith `@chuckus`_ Charlie Smith `@chuckus`_
@ -78,6 +82,7 @@ Listed in alphabetical order.
Chris Franklin `@hairychris`_ Chris Franklin `@hairychris`_
Chris Pappalardo `@ChrisPappalardo`_ Chris Pappalardo `@ChrisPappalardo`_
Christopher Clarke `@chrisdev`_ Christopher Clarke `@chrisdev`_
Cole Mackenzie `@cmackenzie1`_
Collederas `@Collederas`_ Collederas `@Collederas`_
Cristian Vargas `@cdvv7788`_ Cristian Vargas `@cdvv7788`_
Cullen Rhodes `@c-rhodes`_ Cullen Rhodes `@c-rhodes`_
@ -85,10 +90,12 @@ Listed in alphabetical order.
Daniel Hepper `@dhepper`_ @danielhepper Daniel Hepper `@dhepper`_ @danielhepper
Daniele Tricoli `@eriol`_ Daniele Tricoli `@eriol`_
David Díaz `@ddiazpinto`_ @DavidDiazPinto David Díaz `@ddiazpinto`_ @DavidDiazPinto
Davit Tovmasyan `@davitovmasyan`_
Davur Clementsen `@dsclementsen`_ @davur Davur Clementsen `@dsclementsen`_ @davur
Delio Castillo `@jangeador`_ @jangeador Delio Castillo `@jangeador`_ @jangeador
Denis Orehovsky `@apirobot`_ Denis Orehovsky `@apirobot`_
Dónal Adams `@epileptic-fish`_ Dónal Adams `@epileptic-fish`_
Diane Chen `@purplediane`_ @purplediane88
Dong Huynh `@trungdong`_ Dong Huynh `@trungdong`_
Emanuel Calso `@bloodpet`_ @bloodpet Emanuel Calso `@bloodpet`_ @bloodpet
Eraldo Energy `@eraldo`_ Eraldo Energy `@eraldo`_
@ -99,11 +106,15 @@ Listed in alphabetical order.
Garry Polley `@garrypolley`_ Garry Polley `@garrypolley`_
Hamish Durkin `@durkode`_ Hamish Durkin `@durkode`_
Harry Percival `@hjwp`_ Harry Percival `@hjwp`_
Hendrik Schneider `@hendrikschneider`_
Henrique G. G. Pereira `@ikkebr`_ Henrique G. G. Pereira `@ikkebr`_
Ian Lee `@IanLee1521`_ Ian Lee `@IanLee1521`_
Irfan Ahmad `@erfaan`_ @erfaan
Jan Van Bruggen `@jvanbrug`_ Jan Van Bruggen `@jvanbrug`_
Jens Nilsson `@phiberjenz`_ Jens Nilsson `@phiberjenz`_
Jerome Leclanche `@jleclanche`_ @Adys
Jimmy Gitonga `@afrowave`_ @afrowave Jimmy Gitonga `@afrowave`_ @afrowave
John Cass `@jcass77`_ @cass_john
Julien Almarcha `@sladinji`_ Julien Almarcha `@sladinji`_
Julio Castillo `@juliocc`_ Julio Castillo `@juliocc`_
Kaido Kert `@kaidokert`_ Kaido Kert `@kaidokert`_
@ -115,6 +126,7 @@ Listed in alphabetical order.
Krzysztof Szumny `@noisy`_ Krzysztof Szumny `@noisy`_
Krzysztof Żuraw `@krzysztofzuraw`_ Krzysztof Żuraw `@krzysztofzuraw`_
Leonardo Jimenez `@xpostudio4`_ Leonardo Jimenez `@xpostudio4`_
Leo Zhou `@glasslion`_
Lin Xianyi `@iynaix`_ Lin Xianyi `@iynaix`_
Luis Nell `@originell`_ Luis Nell `@originell`_
Lukas Klein Lukas Klein
@ -122,6 +134,7 @@ Listed in alphabetical order.
Malik Sulaimanov `@flyudvik`_ @flyudvik Malik Sulaimanov `@flyudvik`_ @flyudvik
Martin Blech Martin Blech
Martin Saizar `@msaizar`_ Martin Saizar `@msaizar`_
Mateusz Ostaszewski `@mostaszewski`_
Mathijs Hoogland `@MathijsHoogland`_ Mathijs Hoogland `@MathijsHoogland`_
Matt Braymer-Hayes `@mattayes`_ @mattayes Matt Braymer-Hayes `@mattayes`_ @mattayes
Matt Linares Matt Linares
@ -135,6 +148,7 @@ Listed in alphabetical order.
Pablo `@oubiga`_ Pablo `@oubiga`_
Parbhat Puri `@parbhat`_ Parbhat Puri `@parbhat`_
Peter Bittner `@bittner`_ Peter Bittner `@bittner`_
Peter Coles `@mrcoles`_
Pierre Chiquet `@pchiquet`_ Pierre Chiquet `@pchiquet`_
Raphael Pierzina `@hackebrot`_ Raphael Pierzina `@hackebrot`_
Raony Guimarães Corrêa `@raonyguimaraes`_ Raony Guimarães Corrêa `@raonyguimaraes`_
@ -157,12 +171,17 @@ Listed in alphabetical order.
Tom Atkins `@knitatoms`_ Tom Atkins `@knitatoms`_
Tom Offermann Tom Offermann
Travis McNeill `@Travistock`_ @tavistock_esq Travis McNeill `@Travistock`_ @tavistock_esq
Tubo Shi `@Tubo`_
Umair Ashraf `@umrashrf`_ @fabumair
Vitaly Babiy Vitaly Babiy
Vivian Guillen `@viviangb`_ Vivian Guillen `@viviangb`_
Will Farley `@goldhand`_ @g01dhand Will Farley `@goldhand`_ @g01dhand
William Archinal `@archinal`_ William Archinal `@archinal`_
Yaroslav Halchenko Yaroslav Halchenko
Denis Bobrov `@delneg`_ Denis Bobrov `@delneg`_
Philipp Matthies `@canonnervio`_
Vadim Iskuchekov `@Egregors`_ @egregors
Keith Bailey `@keithjeb`_
========================== ============================ ============== ========================== ============================ ==============
.. _@a7p: https://github.com/a7p .. _@a7p: https://github.com/a7p
@ -185,6 +204,7 @@ Listed in alphabetical order.
.. _@burhan: https://github.com/burhan .. _@burhan: https://github.com/burhan
.. _@c-rhodes: https://github.com/c-rhodes .. _@c-rhodes: https://github.com/c-rhodes
.. _@caffodian: https://github.com/caffodian .. _@caffodian: https://github.com/caffodian
.. _@carlmjohnson: https://github.com/carlmjohnson
.. _@catherinedevlin: https://github.com/catherinedevlin .. _@catherinedevlin: https://github.com/catherinedevlin
.. _@ccurvey: https://github.com/ccurvey .. _@ccurvey: https://github.com/ccurvey
.. _@cdvv7788: https://github.com/cdvv7788 .. _@cdvv7788: https://github.com/cdvv7788
@ -192,7 +212,9 @@ Listed in alphabetical order.
.. _@chrisdev: https://github.com/chrisdev .. _@chrisdev: https://github.com/chrisdev
.. _@ChrisPappalardo: https://github.com/ChrisPappalardo .. _@ChrisPappalardo: https://github.com/ChrisPappalardo
.. _@chuckus: https://github.com/chuckus .. _@chuckus: https://github.com/chuckus
.. _@cmackenzie1: https://github.com/cmackenzie1
.. _@Collederas: https://github.com/Collederas .. _@Collederas: https://github.com/Collederas
.. _@davitovmasyan: https://github.com/davitovmasyan
.. _@ddiazpinto: https://github.com/ddiazpinto .. _@ddiazpinto: https://github.com/ddiazpinto
.. _@dezoito: https://github.com/dezoito .. _@dezoito: https://github.com/dezoito
.. _@dhepper: https://github.com/dhepper .. _@dhepper: https://github.com/dhepper
@ -201,19 +223,23 @@ Listed in alphabetical order.
.. _@durkode: https://github.com/durkode .. _@durkode: https://github.com/durkode
.. _@epileptic-fish: https://gihub.com/epileptic-fish .. _@epileptic-fish: https://gihub.com/epileptic-fish
.. _@eraldo: https://github.com/eraldo .. _@eraldo: https://github.com/eraldo
.. _@erfaan: https://github.com/erfaan
.. _@eriol: https://github.com/eriol .. _@eriol: https://github.com/eriol
.. _@eyadsibai: https://github.com/eyadsibai .. _@eyadsibai: https://github.com/eyadsibai
.. _@flyudvik: https://github.com/flyudvik .. _@flyudvik: https://github.com/flyudvik
.. _@garry-cairns: https://github.com/garry-cairns .. _@garry-cairns: https://github.com/garry-cairns
.. _@garrypolley: https://github.com/garrypolley .. _@garrypolley: https://github.com/garrypolley
.. _@goldhand: https://github.com/goldhand .. _@goldhand: https://github.com/goldhand
.. _@glasslion: https://github.com/glasslion
.. _@hackebrot: https://github.com/hackebrot .. _@hackebrot: https://github.com/hackebrot
.. _@hairychris: https://github.com/hairychris .. _@hairychris: https://github.com/hairychris
.. _@hendrikschneider: https://github.com/hendrikschneider
.. _@hjwp: https://github.com/hjwp .. _@hjwp: https://github.com/hjwp
.. _@IanLee1521: https://github.com/IanLee1521 .. _@IanLee1521: https://github.com/IanLee1521
.. _@ikkebr: https://github.com/ikkebr .. _@ikkebr: https://github.com/ikkebr
.. _@iynaix: https://github.com/iynaix .. _@iynaix: https://github.com/iynaix
.. _@jazztpt: https://github.com/jazztpt .. _@jazztpt: https://github.com/jazztpt
.. _@jleclanche: https://github.com/jleclanche
.. _@juliocc: https://github.com/juliocc .. _@juliocc: https://github.com/juliocc
.. _@jvanbrug: https://github.com/jvanbrug .. _@jvanbrug: https://github.com/jvanbrug
.. _@ka7eh: https://github.com/ka7eh .. _@ka7eh: https://github.com/ka7eh
@ -226,6 +252,7 @@ Listed in alphabetical order.
.. _@MathijsHoogland: https://github.com/MathijsHoogland .. _@MathijsHoogland: https://github.com/MathijsHoogland
.. _@mattayes: https://github.com/mattayes .. _@mattayes: https://github.com/mattayes
.. _@menzenski: https://github.com/menzenski .. _@menzenski: https://github.com/menzenski
.. _@mostaszewski: https://github.com/mostaszewski
.. _@mfwarren: https://github.com/mfwarren .. _@mfwarren: https://github.com/mfwarren
.. _@mimischi: https://github.com/mimischi .. _@mimischi: https://github.com/mimischi
.. _@mjsisley: https://github.com/mjsisley .. _@mjsisley: https://github.com/mjsisley
@ -247,9 +274,11 @@ Listed in alphabetical order.
.. _@ssteinerX: https://github.com/ssteinerx .. _@ssteinerX: https://github.com/ssteinerx
.. _@stepmr: https://github.com/stepmr .. _@stepmr: https://github.com/stepmr
.. _@suledev: https://github.com/suledev .. _@suledev: https://github.com/suledev
.. _@takkaria: https://github.com/takkaria
.. _@timfreund: https://github.com/timfreund .. _@timfreund: https://github.com/timfreund
.. _@Travistock: https://github.com/Tavistock .. _@Travistock: https://github.com/Tavistock
.. _@trungdong: https://github.com/trungdong .. _@trungdong: https://github.com/trungdong
.. _@Tubo: https://github.com/tubo
.. _@viviangb: https://github.com/viviangb .. _@viviangb: https://github.com/viviangb
.. _@xpostudio4: https://github.com/xpostudio4 .. _@xpostudio4: https://github.com/xpostudio4
.. _@yunti: https://github.com/yunti .. _@yunti: https://github.com/yunti
@ -267,6 +296,11 @@ Listed in alphabetical order.
.. _@afrowave: https://github.com/afrowave .. _@afrowave: https://github.com/afrowave
.. _@pchiquet: https://github.com/pchiquet .. _@pchiquet: https://github.com/pchiquet
.. _@delneg: https://github.com/delneg .. _@delneg: https://github.com/delneg
.. _@purplediane: https://github.com/purplediane
.. _@umrashrf: https://github.com/umrashrf
.. _@ahhda: https://github.com/ahhda
.. _@keithjeb: https://github.com/keithjeb
.. _@btknu: https://github.com/btknu
Special Thanks Special Thanks
~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~

View File

@ -28,8 +28,6 @@ production-ready Django projects quickly.
* If you have problems with Cookiecutter Django, please open issues_ don't send * If you have problems with Cookiecutter Django, please open issues_ don't send
emails to the maintainers. emails to the maintainers.
.. _cookiecutter: https://github.com/audreyr/cookiecutter
.. _Troubleshooting: https://cookiecutter-django.readthedocs.io/en/latest/troubleshooting.html .. _Troubleshooting: https://cookiecutter-django.readthedocs.io/en/latest/troubleshooting.html
.. _528: https://github.com/pydanny/cookiecutter-django/issues/528#issuecomment-212650373 .. _528: https://github.com/pydanny/cookiecutter-django/issues/528#issuecomment-212650373
@ -41,13 +39,13 @@ 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 (`maintained Foundation fork`_ also available) * Twitter Bootstrap_ v4.1.1 (`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
* Registration via django-allauth_ * Registration via django-allauth_
* Comes with custom user model ready to go * Comes with custom user model ready to go
* Grunt build for compass and livereload * Optional custom static build using Gulp and livereload
* Send emails via Anymail_ (using Mailgun_ by default, but switchable) * Send emails via Anymail_ (using Mailgun_ by default, but switchable)
* Media storage using Amazon S3 * Media storage using Amazon S3
* Docker support using docker-compose_ for development and production (using Caddy_ with LetsEncrypt_ support) * Docker support using docker-compose_ for development and production (using Caddy_ with LetsEncrypt_ support)
@ -180,10 +178,9 @@ Answer the prompts with your own desired options_. For example::
7 - 9.3 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 - None
2 - Grunt 2 - Gulp
3 - None Choose from 1, 2 [1]: 1
Choose from 1, 2, 3, 4 [1]: 1
custom_bootstrap_compilation [n]: n custom_bootstrap_compilation [n]: n
Select open_source_license: Select open_source_license:
1 - MIT 1 - MIT

View File

@ -1,6 +1,6 @@
{ {
"project_name": "My Awesome Project", "project_name": "My Awesome Project",
"project_slug": "{{ cookiecutter.project_name.lower()|replace(' ', '_')|replace('-', '_') }}", "project_slug": "{{ cookiecutter.project_name.lower()|replace(' ', '_')|replace('-', '_')|replace('.', '_')|trim() }}",
"description": "Behold My Awesome Project!", "description": "Behold My Awesome Project!",
"author_name": "Daniel Roy Greenfeld", "author_name": "Daniel Roy Greenfeld",
"domain_name": "example.com", "domain_name": "example.com",
@ -18,6 +18,7 @@
"use_pycharm": "n", "use_pycharm": "n",
"use_docker": "n", "use_docker": "n",
"postgresql_version": [ "postgresql_version": [
"10.5",
"10.4", "10.4",
"10.3", "10.3",
"10.2", "10.2",

0
docs/_static/.gitkeep vendored Normal file
View File

View File

@ -10,6 +10,8 @@ Run these commands to deploy the project to Heroku:
heroku create --buildpack https://github.com/heroku/heroku-buildpack-python heroku create --buildpack https://github.com/heroku/heroku-buildpack-python
heroku addons:create heroku-postgresql:hobby-dev heroku addons:create heroku-postgresql:hobby-dev
# On Windows use double quotes for the time zone, e.g.
# heroku pg:backups schedule --at "02:00 America/Los_Angeles" DATABASE_URL
heroku pg:backups schedule --at '02:00 America/Los_Angeles' DATABASE_URL heroku pg:backups schedule --at '02:00 America/Los_Angeles' DATABASE_URL
heroku pg:promote DATABASE_URL heroku pg:promote DATABASE_URL
@ -21,17 +23,27 @@ Run these commands to deploy the project to Heroku:
heroku addons:create sentry:f1 heroku addons:create sentry:f1
heroku config:set PYTHONHASHSEED=random heroku config:set PYTHONHASHSEED=random
heroku config:set WEB_CONCURRENCY=4 heroku config:set WEB_CONCURRENCY=4
heroku config:set DJANGO_DEBUG=False heroku config:set DJANGO_DEBUG=False
heroku config:set DJANGO_SETTINGS_MODULE=config.settings.production heroku config:set DJANGO_SETTINGS_MODULE=config.settings.production
heroku config:set DJANGO_SECRET_KEY="$(openssl rand -base64 64)" heroku config:set DJANGO_SECRET_KEY="$(openssl rand -base64 64)"
# Generating a 32 character-long random string without any of the visually similiar characters "IOl01": # 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_ADMIN_URL="$(openssl rand -base64 4096 | tr -dc 'A-HJ-NP-Za-km-z2-9' | head -c 32)/"
heroku config:set DJANGO_ALLOWED_HOSTS= # Set this to your Heroku app url, e.g. 'bionic-beaver-28392.herokuapp.com'
# Set this to your Heroku app url, e.g. 'bionic-beaver-28392.herokuapp.com'
heroku config:set DJANGO_AWS_ACCESS_KEY_ID= # Assign with AWS_ACCESS_KEY_ID heroku config:set DJANGO_ALLOWED_HOSTS=
heroku config:set DJANGO_AWS_SECRET_ACCESS_KEY= # Assign with AWS_SECRET_ACCESS_KEY
heroku config:set DJANGO_AWS_STORAGE_BUCKET_NAME= # Assign with AWS_STORAGE_BUCKET_NAME # Assign with AWS_ACCESS_KEY_ID
heroku config:set DJANGO_AWS_ACCESS_KEY_ID=
# Assign with AWS_SECRET_ACCESS_KEY
heroku config:set DJANGO_AWS_SECRET_ACCESS_KEY=
# Assign with AWS_STORAGE_BUCKET_NAME
heroku config:set DJANGO_AWS_STORAGE_BUCKET_NAME=
git push heroku master git push heroku master

View File

@ -59,7 +59,7 @@ SSL (Secure Sockets Layer) is a standard security technology for establishing an
It is always better to deploy a site behind HTTPS and will become crucial as the web services extend to the IoT (Internet of Things). For this reason, we have set up a number of security defaults to help make your website secure: It is always better to deploy a site behind HTTPS and will become crucial as the web services extend to the IoT (Internet of Things). For this reason, we have set up a number of security defaults to help make your website secure:
* If you are not using a subdomain of the domain name set in the project, then remember to put the your staging/production IP address in the ``DJANGO_ALLOWED_HOSTS`` environment variable (see :ref:`settings`) before you deploy your website. Failure to do this will mean you will not have access to your website through the HTTP protocol. * If you are not using a subdomain of the domain name set in the project, then remember to put your staging/production IP address in the ``DJANGO_ALLOWED_HOSTS`` environment variable (see :ref:`settings`) before you deploy your website. Failure to do this will mean you will not have access to your website through the HTTP protocol.
* Access to the Django admin is set up by default to require HTTPS in production or once *live*. * Access to the Django admin is set up by default to require HTTPS in production or once *live*.

View File

@ -171,6 +171,16 @@ When developing locally you can go with MailHog_ for email testing provided ``us
.. _Mailhog: https://github.com/mailhog/MailHog/ .. _Mailhog: https://github.com/mailhog/MailHog/
.. _`CeleryTasks`:
Celery tasks in local development
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When not using docker Celery tasks are set to run in Eager mode, so that a full stack is not needed. When using docker the task
scheduler will be used by default.
If you need tasks to be executed on the main thread during development set CELERY_TASK_ALWAYS_EAGER = True in config/settings/local.py.
Possible uses could be for testing, or ease of profiling with DJDT.
.. _`CeleryFlower`: .. _`CeleryFlower`:

View File

@ -9,23 +9,54 @@ Setting Up Development Environment
Make sure to have the following on your host: Make sure to have the following on your host:
* virtualenv_; * Python 3.6
* pip; * PostgreSQL_.
* PostgreSQL. * Redis_, if using Celery
First things first. First things first.
#. `Create a virtualenv`_. #. Create a virtualenv: ::
#. Activate the virtualenv you have just created. $ python3.6 -m venv <virtual env path>
#. Activate the virtualenv you have just created: ::
$ source <virtual env path>/bin/activate
#. Install development requirements: :: #. Install development requirements: ::
$ pip install -r requirements/local.txt $ pip install -r requirements/local.txt
#. Create a new PostgreSQL database (note: if this is the first time a database is created on your machine you might need to alter a localhost-related entry in your ``pg_hba.conf`` so as to utilize ``trust`` policy): :: #. Create a new PostgreSQL database using createdb_: ::
$ createdb <what you've entered as the project_slug at setup stage> $ createdb <what you have entered as the project_slug at setup stage> -U postgres --password <password>
.. note::
if this is the first time a database is created on your machine you might need an
`initial PostgreSQL set up`_ to allow local connections & set a password for
the ``postgres`` user. The `postgres documentation`_ explains the syntax of the config file
that you need to change.
#. Set the environment variables for your database(s): ::
$ export DATABASE_URL=postgres://postgres:<password>@127.0.0.1:5432/<DB name given to createdb>
# Optional: set broker URL if using Celery
$ export CELERY_BROKER_URL=redis://localhost:6379/0
.. note::
Check out the :ref:`settings` page for a comprehensive list of the environments variables.
.. seealso::
To help setting up your environment variables, you have a few options:
* create an ``.env`` file in the root of your project and define all the variables you need in it.
Then you just need to have ``DJANGO_READ_DOT_ENV_FILE=True`` in your machine and all the variables
will be read.
* Use a local environment manager like `direnv`_
#. Apply migrations: :: #. Apply migrations: ::
@ -35,8 +66,12 @@ First things first.
$ python manage.py runserver 0.0.0.0:8000 $ python manage.py runserver 0.0.0.0:8000
.. _virtualenv: http://docs.python-guide.org/en/latest/dev/virtualenvs/ .. _PostgreSQL: https://www.postgresql.org/download/
.. _`Create a virtualenv`: https://virtualenv.pypa.io/en/stable/userguide/ .. _Redis: https://redis.io/download
.. _createdb: https://www.postgresql.org/docs/current/static/app-createdb.html
.. _initial PostgreSQL set up: http://suite.opengeo.org/docs/latest/dataadmin/pgGettingStarted/firstconnect.html
.. _postgres documentation: https://www.postgresql.org/docs/current/static/auth-pg-hba-conf.html
.. _direnv: https://direnv.net/
Setup Email Backend Setup Email Backend
@ -69,9 +104,7 @@ For instance, one of the packages we depend upon, ``django-allauth`` sends verif
Now you have your own mail server running locally, ready to receive whatever you send it. Now you have your own mail server running locally, ready to receive whatever you send it.
.. _MailHog: https://github.com/mailhog/MailHog/ .. _`Download the latest MailHog release`: https://github.com/mailhog/MailHog
.. _`properly configured`: https://docs.djangoproject.com/en/dev/topics/email/#smtp-backend
Console Console
~~~~~~~ ~~~~~~~
@ -85,14 +118,21 @@ In production, we have Mailgun_ configured to have your back!
.. _Mailgun: https://www.mailgun.com/ .. _Mailgun: https://www.mailgun.com/
Celery
------
If the project is configured to use Celery as a task scheduler then by default tasks are set to run on the main thread
when developing locally. If you have the appropriate setup on your local machine then set
CELERY_TASK_ALWAYS_EAGER = False
in /config/settings/local.py
Sass Compilation & Live Reloading Sass Compilation & Live Reloading
--------------------------------- ---------------------------------
If youd like to take advantage of live reloading and Sass / Compass CSS compilation you can do so with a little bit of preparation_. If youd like to take advantage of live reloading and Sass compilation you can do so with a little
bit of preparation, see :ref:`sass-compilation-live-reload`.
.. _`Download the latest MailHog release`: https://github.com/mailhog/MailHog/releases
.. _preparation: https://cookiecutter-django.readthedocs.io/en/latest/live-reloading-and-sass-compilation.html
Summary Summary
------- -------

View File

@ -17,7 +17,7 @@ Contents:
developing-locally-docker developing-locally-docker
settings settings
linters linters
live-reloading-and-sass-compilation testing
deployment-on-pythonanywhere deployment-on-pythonanywhere
deployment-on-heroku deployment-on-heroku
deployment-with-docker deployment-with-docker

View File

@ -1,17 +0,0 @@
PostgreSQL Installation Basics
==============================
.. index:: pip, virtualenv, PostgreSQL
The steps below will get you up and running with PostgreSQL. This assumes you have pip and virtualenv_ installed.
.. _virtualenv: http://docs.python-guide.org/en/latest/dev/virtualenvs/
On Mac
Install PostgreSQLapp_ from the browser and move PostGresSQL into your applications folder. Then install PostgreSQL from HomeBrew_.
$ brew install postgres
.. _PostgreSQLapp: http://postgresapp.com/
.. _HomeBrew: http://brew.sh/

View File

@ -5,9 +5,9 @@ Linters
flake8 flake8
------- ------
To run flake8: To run flake8: ::
$ flake8 $ flake8
@ -19,7 +19,7 @@ The config for flake8 is located in setup.cfg. It specifies:
pylint pylint
------ ------
This is included in flake8's checks, but you can also run it separately to see a more detailed report: This is included in flake8's checks, but you can also run it separately to see a more detailed report: ::
$ pylint <python files that you wish to lint> $ pylint <python files that you wish to lint>
@ -31,9 +31,9 @@ The config for pylint is located in .pylintrc. It specifies:
* max-parents=13 * max-parents=13
pycodestyle pycodestyle
----- -----------
This is included in flake8's checks, but you can also run it separately to see a more detailed report: This is included in flake8's checks, but you can also run it separately to see a more detailed report: ::
$ pycodestyle <python files that you wish to lint> $ pycodestyle <python files that you wish to lint>

View File

@ -1,24 +1,24 @@
.. _sass-compilation-live-reload:
Sass Compilation & Live Reloading Sass Compilation & Live Reloading
================================= =================================
If you'd like to take advantage of live reloading and Sass / Compass CSS compilation you can do so with a little bit of prep work. If you'd like to take advantage of `live reload`_ and Sass compilation:
Make sure that nodejs_ is installed. Then in the project root run:: - Make sure that nodejs_ is installed. Then in the project root run::
$ npm install $ npm install
.. _nodejs: http://nodejs.org/download/ .. _nodejs: http://nodejs.org/download/
If you don't already have it, install `compass` (doesn't hurt if you run this command twice):: - Now you just need::
gem install compass
Now you just need::
$ npm run dev $ 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.
When changing your Sass files, they will be automatically recompiled and change will be reflected in your browser without refreshing.
To get live reloading to work you'll probably need to install an `appropriate browser extension`_ To get live reloading to work you'll probably need to install an `appropriate browser extension`_
.. _live reload: http://livereload.com/
.. _appropriate browser extension: http://livereload.com/extensions/ .. _appropriate browser extension: http://livereload.com/extensions/

View File

@ -93,7 +93,8 @@ use_travisci:
keep_local_envs_in_vcs: keep_local_envs_in_vcs:
Indicates whether the project's ``.envs/.local/`` should be kept in VCS Indicates whether the project's ``.envs/.local/`` should be kept in VCS
(comes in handy when working in teams where local environment reproducibility (comes in handy when working in teams where local environment reproducibility
is strongly encouraged). is strongly encouraged).
Note: .env(s) are only utilized when Docker Compose and/or Heroku support is enabled.
debug: debug:
Indicates whether the project should be configured for debugging. Indicates whether the project should be configured for debugging.

View File

@ -1,7 +1,7 @@
.. _settings: .. _settings:
Settings Settings
========== ========
This project relies extensively on environment settings which **will not work with Apache/mod_wsgi setups**. It has been deployed successfully with both Gunicorn/Nginx and even uWSGI/Nginx. This project relies extensively on environment settings which **will not work with Apache/mod_wsgi setups**. It has been deployed successfully with both Gunicorn/Nginx and even uWSGI/Nginx.
@ -18,11 +18,10 @@ DJANGO_READ_DOT_ENV_FILE READ_DOT_ENV_FILE False
======================================= =========================== ============================================== ====================================================================== ======================================= =========================== ============================================== ======================================================================
Environment Variable Django Setting Development Default Production Default Environment Variable Django Setting Development Default Production Default
======================================= =========================== ============================================== ====================================================================== ======================================= =========================== ============================================== ======================================================================
DATABASE_URL DATABASES auto w/ Docker; postgres://project_slug w/o raises error
DJANGO_ADMIN_URL n/a 'admin/' raises error DJANGO_ADMIN_URL n/a 'admin/' raises error
DJANGO_CACHES CACHES (default) locmem redis
DJANGO_DATABASES DATABASES (default) See code See code
DJANGO_DEBUG DEBUG True False DJANGO_DEBUG DEBUG True False
DJANGO_SECRET_KEY SECRET_KEY !!!SET DJANGO_SECRET_KEY!!! raises error DJANGO_SECRET_KEY SECRET_KEY auto-generated raises error
DJANGO_SECURE_BROWSER_XSS_FILTER SECURE_BROWSER_XSS_FILTER n/a True DJANGO_SECURE_BROWSER_XSS_FILTER SECURE_BROWSER_XSS_FILTER n/a True
DJANGO_SECURE_SSL_REDIRECT SECURE_SSL_REDIRECT n/a True DJANGO_SECURE_SSL_REDIRECT SECURE_SSL_REDIRECT n/a True
DJANGO_SECURE_CONTENT_TYPE_NOSNIFF SECURE_CONTENT_TYPE_NOSNIFF n/a True DJANGO_SECURE_CONTENT_TYPE_NOSNIFF SECURE_CONTENT_TYPE_NOSNIFF n/a True
@ -41,6 +40,7 @@ The following table lists settings and their defaults for third-party applicatio
======================================= =========================== ============================================== ====================================================================== ======================================= =========================== ============================================== ======================================================================
Environment Variable Django Setting Development Default Production Default Environment Variable Django Setting Development Default Production Default
======================================= =========================== ============================================== ====================================================================== ======================================= =========================== ============================================== ======================================================================
CELERY_BROKER_URL CELERY_BROKER_URL auto w/ Docker; raises error w/o raises error
DJANGO_AWS_ACCESS_KEY_ID AWS_ACCESS_KEY_ID n/a raises error DJANGO_AWS_ACCESS_KEY_ID AWS_ACCESS_KEY_ID n/a raises error
DJANGO_AWS_SECRET_ACCESS_KEY AWS_SECRET_ACCESS_KEY n/a raises error DJANGO_AWS_SECRET_ACCESS_KEY AWS_SECRET_ACCESS_KEY n/a raises error
DJANGO_AWS_STORAGE_BUCKET_NAME AWS_STORAGE_BUCKET_NAME n/a raises error DJANGO_AWS_STORAGE_BUCKET_NAME AWS_STORAGE_BUCKET_NAME n/a raises error
@ -49,8 +49,6 @@ DJANGO_SENTRY_CLIENT SENTRY_CLIENT n/a
DJANGO_SENTRY_LOG_LEVEL SENTRY_LOG_LEVEL n/a logging.INFO DJANGO_SENTRY_LOG_LEVEL SENTRY_LOG_LEVEL n/a logging.INFO
MAILGUN_API_KEY MAILGUN_ACCESS_KEY n/a raises error MAILGUN_API_KEY MAILGUN_ACCESS_KEY n/a raises error
MAILGUN_DOMAIN MAILGUN_SENDER_DOMAIN n/a raises error MAILGUN_DOMAIN MAILGUN_SENDER_DOMAIN n/a raises error
NEW_RELIC_APP_NAME NEW_RELIC_APP_NAME n/a raises error
NEW_RELIC_LICENSE_KEY NEW_RELIC_LICENSE_KEY n/a raises error
======================================= =========================== ============================================== ====================================================================== ======================================= =========================== ============================================== ======================================================================
-------------------------- --------------------------

56
docs/testing.rst Normal file
View File

@ -0,0 +1,56 @@
.. _testing:
Testing
========
We encourage users to build application tests. As best practice, this should be done immediately after documentation of the application being built, before starting on any coding.
Pytest
------
This project uses the Pytest_, a framework for easily building simple and scalable tests.
After you have set up to `develop locally`_, run the following commands to make sure the testing environment is ready: ::
$ pytest
You will get a readout of the `users` app that has already been set up with tests. If you do not want to run the `pytest` on the entire project, you can target a particular app by typing in its location: ::
$ pytest <path-to-app-in-project/app>
If you set up your project to `develop locally with docker`_, run the following command: ::
$ docker-compose -f local.yml run django pytest
Targetting particular apps for testing in ``docker`` follows a similar pattern as previously shown above.
Coverage
--------
You should build your tests to provide the highest level of **code coverage**. You can run the ``pytest`` with code ``coverage`` by typing in the following command: ::
$ docker-compose -f local.yml run django coverage run -m pytest
Once the tests are complete, in order to see the code coverage, run the following command: ::
$ docker-compose -f local.yml run django coverage report
.. note::
At the root of the project folder, you will find the `pytest.ini` file. You can use this to customize_ the ``pytest`` to your liking.
There is also the `.coveragerc`. This is the configuration file for the ``coverage`` tool. You can find out more about `configuring`_ ``coverage``.
.. seealso::
For unit tests, run: ::
$ python manage.py test
Since this is a fresh install, and there are no tests built using the Python `unittest`_ library yet, you should get feedback that says there were no tests carried out.
.. _Pytest: https://docs.pytest.org/en/latest/example/simple.html
.. _develop locally: ../developing-locally.rst
.. _develop locally with docker: ..../developing-locally-docker.rst
.. _customize: https://docs.pytest.org/en/latest/customize.html
.. _unittest: https://docs.python.org/3/library/unittest.html#module-unittest
.. _configuring: https://coverage.readthedocs.io/en/v4.5.x/config.html

View File

@ -9,4 +9,7 @@ This page contains some advice about errors and problems commonly encountered du
#. Internal server error on user registration: make sure you have configured the mail backend (e.g. Mailgun) by adding the API key and sender domain #. Internal server error on user registration: make sure you have configured the mail backend (e.g. Mailgun) by adding the API key and sender domain
#. New apps not getting created in project root: This is the expected behavior, because cookiecutter-django does not change the way that django startapp works, you'll have to fix this manually (see `#1725`_)
.. _#528: https://github.com/pydanny/cookiecutter-django/issues/528#issuecomment-212650373 .. _#528: https://github.com/pydanny/cookiecutter-django/issues/528#issuecomment-212650373
.. _#1725: https://github.com/pydanny/cookiecutter-django/issues/1725#issuecomment-407493176

View File

@ -32,7 +32,10 @@ DEBUG_VALUE = "debug"
def remove_open_source_files(): def remove_open_source_files():
file_names = ["CONTRIBUTORS.txt"] file_names = [
"CONTRIBUTORS.txt",
"LICENSE",
]
for file_name in file_names: for file_name in file_names:
os.remove(file_name) os.remove(file_name)
@ -61,9 +64,16 @@ def remove_docker_files():
os.remove(file_name) os.remove(file_name)
def remove_utility_files():
shutil.rmtree("utility")
def remove_heroku_files(): def remove_heroku_files():
file_names = ["Procfile", "runtime.txt", "requirements.txt"] file_names = ["Procfile", "runtime.txt", "requirements.txt"]
for file_name in file_names: for file_name in file_names:
if file_name == "requirements.txt" and "{{ cookiecutter.use_travisci }}".lower() == "y":
# don't remove the file if we are using travisci but not using heroku
continue
os.remove(file_name) os.remove(file_name)
@ -111,9 +121,11 @@ def generate_random_string(
if using_ascii_letters: if using_ascii_letters:
symbols += string.ascii_letters symbols += string.ascii_letters
if using_punctuation: if using_punctuation:
symbols += string.punctuation.replace('"', "").replace("'", "").replace( all_punctuation = set(string.punctuation)
"\\", "" # These symbols can cause issues in environment variables
) unsuitable = {"'", '"', "\\", "$"}
suitable = all_punctuation.difference(unsuitable)
symbols += "".join(suitable)
return "".join([random.choice(symbols) for _ in range(length)]) return "".join([random.choice(symbols) for _ in range(length)])
@ -275,7 +287,9 @@ def main():
if "{{ cookiecutter.use_pycharm }}".lower() == "n": if "{{ cookiecutter.use_pycharm }}".lower() == "n":
remove_pycharm_files() remove_pycharm_files()
if "{{ cookiecutter.use_docker }}".lower() == "n": if "{{ cookiecutter.use_docker }}".lower() == "y":
remove_utility_files()
else:
remove_docker_files() remove_docker_files()
if "{{ cookiecutter.use_heroku }}".lower() == "n": if "{{ cookiecutter.use_heroku }}".lower() == "n":

View File

@ -4,10 +4,11 @@ binaryornot==0.4.4
# Code quality # Code quality
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
flake8==3.5.0 flake8==3.7.6
# Testing # Testing
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
tox==3.0.0 tox==3.6.1
pytest==3.6.2 pytest==4.3.0
pytest-cookies==0.3.0 pytest-cookies==0.3.0
pyyaml==3.13

View File

@ -1,6 +1,7 @@
import os import os
import re import re
import sh import sh
import yaml
import pytest import pytest
from binaryornot.check import is_binary from binaryornot.check import is_binary
@ -85,3 +86,19 @@ def test_flake8_compliance(cookies):
sh.flake8(str(result.project)) sh.flake8(str(result.project))
except sh.ErrorReturnCode as e: except sh.ErrorReturnCode as e:
pytest.fail(e) pytest.fail(e)
def test_travis_invokes_pytest(cookies, context):
context.update({"use_travisci": "y"})
result = cookies.bake(extra_context=context)
assert result.exit_code == 0
assert result.exception is None
assert result.project.basename == context["project_slug"]
assert result.project.isdir()
with open(f'{result.project}/.travis.yml', 'r') as travis_yml:
try:
assert yaml.load(travis_yml)['script'] == ['pytest']
except yaml.YAMLError as e:
pytest.fail(e)

View File

@ -14,8 +14,11 @@ cd .cache/docker
cookiecutter ../../ --no-input --overwrite-if-exists use_docker=y cookiecutter ../../ --no-input --overwrite-if-exists use_docker=y
cd my_awesome_project cd my_awesome_project
# run the project's type checks
docker-compose -f local.yml run django mypy 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 pytest
# 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; }

View File

@ -1,6 +1,7 @@
# General # General
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
USE_DOCKER=yes USE_DOCKER=yes
IPYTHONDIR=/app/.ipython
{%- if cookiecutter.use_celery == 'y' %} {%- if cookiecutter.use_celery == 'y' %}
# Redis # Redis

View File

@ -333,6 +333,7 @@ tags
[Ss]cripts [Ss]cripts
pyvenv.cfg pyvenv.cfg
pip-selfcheck.json pip-selfcheck.json
.env
{% endif %} {% endif %}
### Project template ### Project template
@ -342,3 +343,7 @@ MailHog
{{ cookiecutter.project_slug }}/media/ {{ cookiecutter.project_slug }}/media/
.pytest_cache/ .pytest_cache/
{% if cookiecutter.use_docker == 'y' %}
.ipython/
{%- endif %}

View File

@ -9,3 +9,7 @@ before_install:
language: python language: python
python: python:
- "3.6" - "3.6"
install:
- pip install -r requirements/local.txt
script:
- "pytest"

View File

@ -32,12 +32,21 @@ Setting Up Your Users
For convenience, you can keep your normal user logged in on Chrome and your superuser logged in on Firefox (or similar), so that you can see how the site behaves for both kinds of users. For convenience, you can keep your normal user logged in on Chrome and your superuser logged in on Firefox (or similar), so that you can see how the site behaves for both kinds of users.
Type checks
^^^^^^^^^^^
Running type checks with mypy:
::
$ mypy {{cookiecutter.project_slug}}
Test coverage Test coverage
^^^^^^^^^^^^^ ^^^^^^^^^^^^^
To run the tests, check your test coverage, and generate an HTML coverage report:: To run the tests, check your test coverage, and generate an HTML coverage report::
$ coverage run manage.py test $ coverage run -m pytest
$ coverage html $ coverage html
$ open htmlcov/index.html $ open htmlcov/index.html
@ -46,7 +55,7 @@ Running tests with py.test
:: ::
$ py.test $ pytest
Live reloading and Sass CSS compilation Live reloading and Sass CSS compilation
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -86,16 +95,25 @@ With MailHog running, to view messages that are sent by your application, open y
{% else %} {% else %}
In development, it is often nice to be able to see emails that are being sent from your application. If you choose to use `MailHog`_ when generating the project a local SMTP server with a web interface will be available. In development, it is often nice to be able to see emails that are being sent from your application. If you choose to use `MailHog`_ when generating the project a local SMTP server with a web interface will be available.
To start the service, make sure you have nodejs installed, and then type the following:: #. `Download the latest MailHog release`_ for your OS.
$ npm install #. Rename the build to ``MailHog``.
$ grunt serve
(After the first run you only need to type ``grunt serve``) This will start an email server that listens on ``127.0.0.1:1025`` in addition to starting your Django project and a watch task for live reload. #. Copy the file to the project root.
To view messages that are sent by your application, open your browser and go to ``http://127.0.0.1:8025`` #. Make it executable: ::
The email server will exit when you exit the Grunt task on the CLI with Ctrl+C. $ chmod +x MailHog
#. Spin up another terminal window and start it there: ::
./MailHog
#. Check out `<http://127.0.0.1:8025/>`_ to see how it goes.
Now you have your own mail server running locally, ready to receive whatever you send it.
.. _`Download the latest MailHog release`: https://github.com/mailhog/MailHog/releases
{% endif %} {% endif %}
.. _mailhog: https://github.com/mailhog/MailHog .. _mailhog: https://github.com/mailhog/MailHog
{% endif %} {% endif %}
@ -138,7 +156,7 @@ Custom Bootstrap Compilation
^^^^^^ ^^^^^^
The generated CSS is set up with automatic Bootstrap recompilation with variables of your choice. The generated CSS is set up with automatic Bootstrap recompilation with variables of your choice.
Bootstrap v4 is installed using npm and customised by tweaking your variables in ``static/sass/custom_bootstrap_vars``. Bootstrap v4.1.1 is installed using npm and customised by tweaking your variables in ``static/sass/custom_bootstrap_vars``.
You can find a list of available variables `in the bootstrap source`_, or get explanations on them in the `Bootstrap docs`_. You can find a list of available variables `in the bootstrap source`_, or get explanations on them in the `Bootstrap docs`_.
@ -147,6 +165,6 @@ Bootstrap's javascript as well as its dependencies is concatenated into a single
{% endif %} {% endif %}
.. _in the bootstrap source: https://github.com/twbs/bootstrap/blob/v4-dev/scss/_variables.scss .. _in the bootstrap source: https://github.com/twbs/bootstrap/blob/v4-dev/scss/_variables.scss
.. _Bootstrap docs: https://getbootstrap.com/docs/4.0/getting-started/theming/ .. _Bootstrap docs: https://getbootstrap.com/docs/4.1/getting-started/theming/
{% endif %} {% endif %}

View File

@ -1,5 +1,5 @@
www.{% raw %}{$DOMAIN_NAME}{% endraw %} { www.{% raw %}{$DOMAIN_NAME}{% endraw %} {
redir https://{{cookiecutter.domain_name}} redir https://{% raw %}{$DOMAIN_NAME}{% endraw %}
} }
{% raw %}{$DOMAIN_NAME}{% endraw %} { {% raw %}{$DOMAIN_NAME}{% endraw %} {
@ -7,6 +7,7 @@ www.{% raw %}{$DOMAIN_NAME}{% endraw %} {
header_upstream Host {host} header_upstream Host {host}
header_upstream X-Real-IP {remote} header_upstream X-Real-IP {remote}
header_upstream X-Forwarded-Proto {scheme} header_upstream X-Forwarded-Proto {scheme}
header_upstream X-CSRFToken {~csrftoken}
} }
log stdout log stdout
errors stdout errors stdout

View File

@ -209,6 +209,17 @@ FIXTURE_DIRS = (
str(APPS_DIR.path('fixtures')), str(APPS_DIR.path('fixtures')),
) )
# SECURITY
# ------------------------------------------------------------------------------
# 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-httponly
CSRF_COOKIE_HTTPONLY = 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'
# EMAIL # EMAIL
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# https://docs.djangoproject.com/en/dev/ref/settings/#email-backend # https://docs.djangoproject.com/en/dev/ref/settings/#email-backend

View File

@ -76,8 +76,10 @@ INSTALLED_APPS += ['django_extensions'] # noqa F405
# Celery # Celery
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
{% if cookiecutter.use_docker == 'n' -%}
# http://docs.celeryproject.org/en/latest/userguide/configuration.html#task-always-eager # http://docs.celeryproject.org/en/latest/userguide/configuration.html#task-always-eager
CELERY_TASK_ALWAYS_EAGER = True CELERY_TASK_ALWAYS_EAGER = True
{%- endif %}
# http://docs.celeryproject.org/en/latest/userguide/configuration.html#task-eager-propagates # http://docs.celeryproject.org/en/latest/userguide/configuration.html#task-eager-propagates
CELERY_TASK_EAGER_PROPAGATES = True CELERY_TASK_EAGER_PROPAGATES = True

View File

@ -41,12 +41,8 @@ SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
SECURE_SSL_REDIRECT = env.bool('DJANGO_SECURE_SSL_REDIRECT', default=True) SECURE_SSL_REDIRECT = env.bool('DJANGO_SECURE_SSL_REDIRECT', default=True)
# https://docs.djangoproject.com/en/dev/ref/settings/#session-cookie-secure # https://docs.djangoproject.com/en/dev/ref/settings/#session-cookie-secure
SESSION_COOKIE_SECURE = True 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 # https://docs.djangoproject.com/en/dev/ref/settings/#csrf-cookie-secure
CSRF_COOKIE_SECURE = True 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/topics/security/#ssl-https
# https://docs.djangoproject.com/en/dev/ref/settings/#secure-hsts-seconds # 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 # TODO: set this to 60 seconds first and then to 518400 once you prove the former works
@ -57,10 +53,6 @@ SECURE_HSTS_INCLUDE_SUBDOMAINS = env.bool('DJANGO_SECURE_HSTS_INCLUDE_SUBDOMAINS
SECURE_HSTS_PRELOAD = env.bool('DJANGO_SECURE_HSTS_PRELOAD', default=True) SECURE_HSTS_PRELOAD = env.bool('DJANGO_SECURE_HSTS_PRELOAD', default=True)
# https://docs.djangoproject.com/en/dev/ref/middleware/#x-content-type-options-nosniff # 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) 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 # STORAGES
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@ -73,8 +65,6 @@ AWS_SECRET_ACCESS_KEY = env('DJANGO_AWS_SECRET_ACCESS_KEY')
# https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#settings # https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#settings
AWS_STORAGE_BUCKET_NAME = env('DJANGO_AWS_STORAGE_BUCKET_NAME') AWS_STORAGE_BUCKET_NAME = env('DJANGO_AWS_STORAGE_BUCKET_NAME')
# https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#settings # 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 AWS_QUERYSTRING_AUTH = False
# DO NOT change these unless you know what you're doing. # DO NOT change these unless you know what you're doing.
_AWS_EXPIRY = 60 * 60 * 24 * 7 _AWS_EXPIRY = 60 * 60 * 24 * 7
@ -88,23 +78,33 @@ AWS_S3_OBJECT_PARAMETERS = {
{% if cookiecutter.use_whitenoise == 'y' -%} {% if cookiecutter.use_whitenoise == 'y' -%}
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage' STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
{%- else %} {%- else %}
STATICFILES_STORAGE = 'config.settings.production.StaticRootS3BotoStorage' STATICFILES_STORAGE = 'config.settings.production.StaticRootS3Boto3Storage'
STATIC_URL = f'https://s3.amazonaws.com/{AWS_STORAGE_BUCKET_NAME}/static/' STATIC_URL = f'https://{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com/static/'
{%- endif %} {%- endif %}
# MEDIA # MEDIA
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
{% if cookiecutter.use_whitenoise == 'y' -%} {% if cookiecutter.use_whitenoise == 'y' -%}
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage' DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
MEDIA_URL = f'https://s3.amazonaws.com/{AWS_STORAGE_BUCKET_NAME}/' MEDIA_URL = f'https://{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com/'
{%- else %} {%- else %}
# region http://stackoverflow.com/questions/10390244/ # region http://stackoverflow.com/questions/10390244/
# Full-fledge class: https://stackoverflow.com/a/18046120/104731
from storages.backends.s3boto3 import S3Boto3Storage # noqa E402 from storages.backends.s3boto3 import S3Boto3Storage # noqa E402
StaticRootS3BotoStorage = lambda: S3Boto3Storage(location='static') # noqa
MediaRootS3BotoStorage = lambda: S3Boto3Storage(location='media', file_overwrite=False) # noqa
class StaticRootS3Boto3Storage(S3Boto3Storage):
location = 'static'
class MediaRootS3Boto3Storage(S3Boto3Storage):
location = 'media'
file_overwrite = False
# endregion # endregion
DEFAULT_FILE_STORAGE = 'config.settings.production.MediaRootS3BotoStorage' DEFAULT_FILE_STORAGE = 'config.settings.production.MediaRootS3Boto3Storage'
MEDIA_URL = f'https://s3.amazonaws.com/{AWS_STORAGE_BUCKET_NAME}/media/' MEDIA_URL = f'https://{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com/media/'
{%- endif %} {%- endif %}
# TEMPLATES # TEMPLATES
@ -156,7 +156,7 @@ INSTALLED_APPS += ['gunicorn'] # noqa F405
# WhiteNoise # WhiteNoise
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# http://whitenoise.evans.io/en/latest/django.html#enable-whitenoise # http://whitenoise.evans.io/en/latest/django.html#enable-whitenoise
MIDDLEWARE = ['whitenoise.middleware.WhiteNoiseMiddleware'] + MIDDLEWARE # noqa F405 MIDDLEWARE.insert(1, 'whitenoise.middleware.WhiteNoiseMiddleware') # noqa F405
{% endif %} {% endif %}
{%- if cookiecutter.use_compressor == 'y' -%} {%- if cookiecutter.use_compressor == 'y' -%}

View File

@ -1,63 +1,70 @@
////////////////////////////////
// Setup
////////////////////////////////
//////////////////////////////// // Gulp and package
//Setup// const { src, dest, parallel, series, watch } = require('gulp')
//////////////////////////////// const pjson = require('./package.json')
// Plugins // Plugins
var gulp = require('gulp'), const autoprefixer = require('autoprefixer')
pjson = require('./package.json'), const browserSync = require('browser-sync').create()
gutil = require('gulp-util'), {% if cookiecutter.custom_bootstrap_compilation == 'y' %}
sass = require('gulp-sass'), const concat = require('gulp-concat')
autoprefixer = require('gulp-autoprefixer'), {% endif %}
cssnano = require('gulp-cssnano'), const cssnano = require ('cssnano')
{% if cookiecutter.custom_bootstrap_compilation == 'y' %} const imagemin = require('gulp-imagemin')
concat = require('gulp-concat'), const pixrem = require('pixrem')
{% endif %} const plumber = require('gulp-plumber')
rename = require('gulp-rename'), const postcss = require('gulp-postcss')
del = require('del'), const reload = browserSync.reload
plumber = require('gulp-plumber'), const rename = require('gulp-rename')
pixrem = require('gulp-pixrem'), const sass = require('gulp-sass')
uglify = require('gulp-uglify'), const spawn = require('child_process').spawn
imagemin = require('gulp-imagemin'), const uglify = require('gulp-uglify-es').default
spawn = require('child_process').spawn,
runSequence = require('run-sequence'),
browserSync = require('browser-sync').create(),
reload = browserSync.reload;
// Relative paths function // Relative paths function
var pathsConfig = function (appName) { function pathsConfig(appName) {
this.app = "./" + (appName || pjson.name); this.app = `./${pjson.name}`
var vendorsRoot = 'node_modules/'; const vendorsRoot = 'node_modules'
return { return {
{% if cookiecutter.custom_bootstrap_compilation == 'y' %} {% if cookiecutter.custom_bootstrap_compilation == 'y' %}
bootstrapSass: vendorsRoot + '/bootstrap/scss', bootstrapSass: `${vendorsRoot}/bootstrap/scss`,
vendorsJs: [ vendorsJs: [
vendorsRoot + 'jquery/dist/jquery.slim.js', `${vendorsRoot}/jquery/dist/jquery.slim.js`,
vendorsRoot + 'popper.js/dist/umd/popper.js', `${vendorsRoot}/popper.js/dist/umd/popper.js`,
vendorsRoot + 'bootstrap/dist/js/bootstrap.js' `${vendorsRoot}/bootstrap/dist/js/bootstrap.js`,
], ],
{% endif %} {% endif %}
app: this.app, app: this.app,
templates: this.app + '/templates', templates: `${this.app}/templates`,
css: this.app + '/static/css', css: `${this.app}/static/css`,
sass: this.app + '/static/sass', sass: `${this.app}/static/sass`,
fonts: this.app + '/static/fonts', fonts: `${this.app}/static/fonts`,
images: this.app + '/static/images', images: `${this.app}/static/images`,
js: this.app + '/static/js' js: `${this.app}/static/js`,
} }
}; }
var paths = pathsConfig(); var paths = pathsConfig()
//////////////////////////////// ////////////////////////////////
//Tasks// // Tasks
//////////////////////////////// ////////////////////////////////
// Styles autoprefixing and minification // Styles autoprefixing and minification
gulp.task('styles', function() { function styles() {
return gulp.src(paths.sass + '/project.scss') var processCss = [
autoprefixer(), // adds vendor prefixes
pixrem(), // add fallbacks for rem units
]
var minifyCss = [
cssnano({ preset: 'default' }) // minify result
]
return src(`${paths.sass}/project.scss`)
.pipe(sass({ .pipe(sass({
includePaths: [ includePaths: [
{% if cookiecutter.custom_bootstrap_compilation == 'y' %} {% if cookiecutter.custom_bootstrap_compilation == 'y' %}
@ -67,72 +74,86 @@ gulp.task('styles', function() {
] ]
}).on('error', sass.logError)) }).on('error', sass.logError))
.pipe(plumber()) // Checks for errors .pipe(plumber()) // Checks for errors
.pipe(autoprefixer({browsers: ['last 2 versions']})) // Adds vendor prefixes .pipe(postcss(processCss))
.pipe(pixrem()) // add fallbacks for rem units .pipe(dest(paths.css))
.pipe(gulp.dest(paths.css))
.pipe(rename({ suffix: '.min' })) .pipe(rename({ suffix: '.min' }))
.pipe(cssnano()) // Minifies the result .pipe(postcss(minifyCss)) // Minifies the result
.pipe(gulp.dest(paths.css)); .pipe(dest(paths.css))
}); }
// Javascript minification // Javascript minification
gulp.task('scripts', function() { function scripts() {
return gulp.src(paths.js + '/project.js') return src(`${paths.js}/project.js`)
.pipe(plumber()) // Checks for errors .pipe(plumber()) // Checks for errors
.pipe(uglify()) // Minifies the js .pipe(uglify()) // Minifies the js
.pipe(rename({ suffix: '.min' })) .pipe(rename({ suffix: '.min' }))
.pipe(gulp.dest(paths.js)); .pipe(dest(paths.js))
}); }
{% if cookiecutter.custom_bootstrap_compilation == 'y' %} {% if cookiecutter.custom_bootstrap_compilation == 'y' %}
// Vendor Javascript minification // Vendor Javascript minification
gulp.task('vendor-scripts', function() { function vendorScripts() {
return gulp.src(paths.vendorsJs) return src(paths.vendorsJs)
.pipe(concat('vendors.js')) .pipe(concat('vendors.js'))
.pipe(gulp.dest(paths.js)) .pipe(dest(paths.js))
.pipe(plumber()) // Checks for errors .pipe(plumber()) // Checks for errors
.pipe(uglify()) // Minifies the js .pipe(uglify()) // Minifies the js
.pipe(rename({ suffix: '.min' })) .pipe(rename({ suffix: '.min' }))
.pipe(gulp.dest(paths.js)); .pipe(dest(paths.js))
}); }
{% endif %} {% endif %}
// Image compression // Image compression
gulp.task('imgCompression', function(){ function imgCompression() {
return gulp.src(paths.images + '/*') return src(`${paths.images}/*`)
.pipe(imagemin()) // Compresses PNG, JPEG, GIF and SVG images .pipe(imagemin()) // Compresses PNG, JPEG, GIF and SVG images
.pipe(gulp.dest(paths.images)) .pipe(dest(paths.images))
}); }
// Run django server // Run django server
gulp.task('runServer', function(cb) { function runServer(cb) {
var cmd = spawn('python', ['manage.py', 'runserver'], {stdio: 'inherit'}); var cmd = spawn('python', ['manage.py', 'runserver'], {stdio: 'inherit'})
cmd.on('close', function(code) { cmd.on('close', function(code) {
console.log('runServer exited with code ' + code); console.log('runServer exited with code ' + code)
cb(code); cb(code)
}); })
}); }
// Browser sync server for live reload // Browser sync server for live reload
gulp.task('browserSync', function() { function initBrowserSync() {
browserSync.init( browserSync.init(
[paths.css + "/*.css", paths.js + "*.js", paths.templates + '*.html'], { [
proxy: "localhost:8000" `${paths.css}/*.css`,
}); `${paths.js}/*.js`,
}); `${paths.templates}/*.html`
], {
proxy: "localhost:8000"
}
)
}
// Watch // Watch
gulp.task('watch', function() { function watchPaths() {
watch(`${paths.sass}/*.scss`, styles)
watch(`${paths.templates}/**/*.html`).on("change", reload)
watch([`${paths.js}/*.js`, `!${paths.js}/*.min.js`], scripts).on("change", reload)
}
gulp.watch(paths.sass + '/*.scss', ['styles']); // Generate all assets
gulp.watch(paths.js + '/*.js', ['scripts']).on("change", reload); const generateAssets = parallel(
gulp.watch(paths.images + '/*', ['imgCompression']); styles,
gulp.watch(paths.templates + '/**/*.html').on("change", reload); scripts,
{% if cookiecutter.custom_bootstrap_compilation == 'y' %}vendorScripts,{% endif %}
imgCompression
)
}); // Set up dev environment
const dev = parallel(
runServer,
initBrowserSync,
watchPaths
)
// Default task exports.default = series(generateAssets, dev)
gulp.task('default', function() { exports["generate-assets"] = generateAssets
runSequence(['styles', 'scripts', {% if cookiecutter.custom_bootstrap_compilation == 'y' %}'vendor-scripts', {% endif %}'imgCompression'], ['runServer', 'browserSync', 'watch']); exports["dev"] = dev
});

View File

@ -3,38 +3,35 @@
"version": "{{ cookiecutter.version }}", "version": "{{ cookiecutter.version }}",
"dependencies": {}, "dependencies": {},
"devDependencies": { "devDependencies": {
{% if cookiecutter.js_task_runner == 'Gulp' %} {% if cookiecutter.js_task_runner == 'Gulp' -%}
{% if cookiecutter.custom_bootstrap_compilation == 'y' %} {% if cookiecutter.custom_bootstrap_compilation == 'y' -%}
"bootstrap": "^4.0.0", "bootstrap": "4.1.1",
{% endif %}
"browser-sync": "^2.14.0",
"del": "^2.2.2",
"gulp": "^3.9.1",
"gulp-autoprefixer": "^5.0.0",
{% if cookiecutter.custom_bootstrap_compilation == 'y' %}
"gulp-concat": "^2.6.1", "gulp-concat": "^2.6.1",
{% endif %} "jquery": "3.3.1",
"gulp-cssnano": "^2.1.2", "popper.js": "1.14.3",
"gulp-imagemin": "^4.1.0", {% endif -%}
"gulp-pixrem": "^1.0.0", "autoprefixer": "^9.4.7",
"gulp-plumber": "^1.1.0", "browser-sync": "^2.14.0",
"cssnano": "^4.1.10",
"gulp": "^4.0.0",
"gulp-imagemin": "^5.0.3",
"gulp-plumber": "^1.2.1",
"gulp-postcss": "^8.0.0",
"gulp-rename": "^1.2.2", "gulp-rename": "^1.2.2",
"gulp-sass": "^3.1.0", "gulp-sass": "^4.0.2",
"gulp-uglify": "^3.0.0", "gulp-uglify-es": "^1.0.4",
"gulp-util": "^3.0.7", "pixrem": "^5.0.0"
{% if cookiecutter.custom_bootstrap_compilation == 'y' %} {%- endif %}
"jquery": "^3.2.1-slim",
"popper.js": "^1.12.3",
{% endif %}
"run-sequence": "^2.1.1"
{% endif %}
}, },
"engines": { "engines": {
"node": ">=0.8.0" "node": ">=8"
}, },
"browserslist": [
"last 2 versions"
],
"scripts": { "scripts": {
{% if cookiecutter.js_task_runner == 'Gulp' %} {% if cookiecutter.js_task_runner == 'Gulp' -%}
"dev": "gulp" "dev": "gulp"
{% endif %} {%- endif %}
} }
} }

View File

@ -1,16 +1,16 @@
pytz==2018.4 # https://github.com/stub42/pytz pytz==2018.9 # https://github.com/stub42/pytz
python-slugify==1.2.5 # https://github.com/un33k/python-slugify python-slugify==2.0.1 # https://github.com/un33k/python-slugify
Pillow==5.1.0 # https://github.com/python-pillow/Pillow Pillow==5.4.1 # https://github.com/python-pillow/Pillow
{%- if cookiecutter.use_compressor == "y" %} {%- if cookiecutter.use_compressor == "y" %}
rcssmin==1.0.6{% if cookiecutter.windows == 'y' %} --install-option="--without-c-extensions"{% endif %} # https://github.com/ndparker/rcssmin rcssmin==1.0.6{% if cookiecutter.windows == 'y' %} --install-option="--without-c-extensions"{% endif %} # https://github.com/ndparker/rcssmin
{%- endif %} {%- endif %}
argon2-cffi==18.1.0 # https://github.com/hynek/argon2_cffi argon2-cffi==19.1.0 # https://github.com/hynek/argon2_cffi
{%- if cookiecutter.use_whitenoise == 'y' %} {%- if cookiecutter.use_whitenoise == 'y' %}
whitenoise==3.3.1 # https://github.com/evansd/whitenoise whitenoise==4.1.2 # https://github.com/evansd/whitenoise
{%- endif %} {%- endif %}
redis>=2.10.5 # https://github.com/antirez/redis redis>=2.10.6, < 3 # pyup: < 3 # https://github.com/antirez/redis
{%- if cookiecutter.use_celery == "y" %} {%- if cookiecutter.use_celery == "y" %}
celery==4.2.0 # pyup: <5.0 # https://github.com/celery/celery celery==4.2.1 # pyup: < 5.0 # https://github.com/celery/celery
{%- if cookiecutter.use_docker == 'y' %} {%- if cookiecutter.use_docker == 'y' %}
flower==0.9.2 # https://github.com/mher/flower flower==0.9.2 # https://github.com/mher/flower
{%- endif %} {%- endif %}
@ -18,16 +18,16 @@ flower==0.9.2 # https://github.com/mher/flower
# Django # Django
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
django==2.0.6 # pyup: < 2.1 # https://www.djangoproject.com/ django==2.0.13 # pyup: < 2.1 # https://www.djangoproject.com/
django-environ==0.4.5 # https://github.com/joke2k/django-environ django-environ==0.4.5 # https://github.com/joke2k/django-environ
django-model-utils==3.1.2 # https://github.com/jazzband/django-model-utils django-model-utils==3.1.2 # https://github.com/jazzband/django-model-utils
django-allauth==0.36.0 # https://github.com/pennersr/django-allauth django-allauth==0.38.0 # https://github.com/pennersr/django-allauth
django-crispy-forms==1.7.2 # https://github.com/django-crispy-forms/django-crispy-forms django-crispy-forms==1.7.2 # https://github.com/django-crispy-forms/django-crispy-forms
{%- if cookiecutter.use_compressor == "y" %} {%- if cookiecutter.use_compressor == "y" %}
django-compressor==2.2 # https://github.com/django-compressor/django-compressor django-compressor==2.2 # https://github.com/django-compressor/django-compressor
{%- endif %} {%- endif %}
django-redis==4.9.0 # https://github.com/niwinz/django-redis django-redis==4.10.0 # https://github.com/niwinz/django-redis
# Django REST Framework # Django REST Framework
djangorestframework==3.8.2 # https://github.com/encode/django-rest-framework djangorestframework==3.9.1 # https://github.com/encode/django-rest-framework
coreapi==2.3.3 # https://github.com/core-api/python-client coreapi==2.3.3 # https://github.com/core-api/python-client

View File

@ -2,28 +2,29 @@
Werkzeug==0.14.1 # https://github.com/pallets/werkzeug Werkzeug==0.14.1 # https://github.com/pallets/werkzeug
ipdb==0.11 # https://github.com/gotcha/ipdb ipdb==0.11 # https://github.com/gotcha/ipdb
Sphinx==1.7.5 # https://github.com/sphinx-doc/sphinx Sphinx==1.8.4 # https://github.com/sphinx-doc/sphinx
{%- if cookiecutter.use_docker == 'y' %} {%- if cookiecutter.use_docker == 'y' %}
psycopg2==2.7.4 --no-binary psycopg2 # https://github.com/psycopg/psycopg2 psycopg2==2.7.4 --no-binary psycopg2 # https://github.com/psycopg/psycopg2
{%- else %} {%- else %}
psycopg2-binary==2.7.5 # https://github.com/psycopg/psycopg2 psycopg2-binary==2.7.7 # https://github.com/psycopg/psycopg2
{%- endif %} {%- endif %}
# Testing # Testing
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
pytest==3.6.2 # https://github.com/pytest-dev/pytest mypy==0.670 # https://github.com/python/mypy
pytest-sugar==0.9.1 # https://github.com/Frozenball/pytest-sugar pytest==4.2.0 # https://github.com/pytest-dev/pytest
pytest-sugar==0.9.2 # https://github.com/Frozenball/pytest-sugar
# Code quality # Code quality
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
flake8==3.5.0 # https://github.com/PyCQA/flake8 flake8==3.7.5 # https://github.com/PyCQA/flake8
coverage==4.5.1 # https://github.com/nedbat/coveragepy coverage==4.5.2 # https://github.com/nedbat/coveragepy
# Django # Django
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
factory-boy==2.11.1 # https://github.com/FactoryBoy/factory_boy factory-boy==2.11.1 # https://github.com/FactoryBoy/factory_boy
django-debug-toolbar==1.9.1 # https://github.com/jazzband/django-debug-toolbar django-debug-toolbar==1.11 # https://github.com/jazzband/django-debug-toolbar
django-extensions==2.0.7 # https://github.com/django-extensions/django-extensions django-extensions==2.1.5 # https://github.com/django-extensions/django-extensions
django-coverage-plugin==1.5.0 # https://github.com/nedbat/django_coverage_plugin django-coverage-plugin==1.6.0 # https://github.com/nedbat/django_coverage_plugin
pytest-django==3.3.2 # https://github.com/pytest-dev/pytest-django pytest-django==3.4.7 # https://github.com/pytest-dev/pytest-django

View File

@ -2,16 +2,16 @@
-r ./base.txt -r ./base.txt
gunicorn==19.8.1 # https://github.com/benoitc/gunicorn gunicorn==19.9.0 # https://github.com/benoitc/gunicorn
psycopg2==2.7.4 --no-binary psycopg2 # https://github.com/psycopg/psycopg2 psycopg2==2.7.4 --no-binary psycopg2 # https://github.com/psycopg/psycopg2
{%- if cookiecutter.use_whitenoise == 'n' %} {%- if cookiecutter.use_whitenoise == 'n' %}
Collectfast==0.6.2 # https://github.com/antonagestam/collectfast Collectfast==0.6.2 # https://github.com/antonagestam/collectfast
{%- endif %} {%- endif %}
{%- if cookiecutter.use_sentry == "y" %} {%- if cookiecutter.use_sentry == "y" %}
raven==6.9.0 # https://github.com/getsentry/raven-python raven==6.10.0 # https://github.com/getsentry/raven-python
{%- endif %} {%- endif %}
# Django # Django
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
django-storages[boto3]==1.6.6 # https://github.com/jschneier/django-storages django-storages[boto3]==1.7.1 # https://github.com/jschneier/django-storages
django-anymail[mailgun]==3.0 # https://github.com/anymail/django-anymail django-anymail[mailgun]==5.0 # https://github.com/anymail/django-anymail

View File

@ -1 +1 @@
python-3.6.5 python-3.6.6

View File

@ -5,3 +5,17 @@ exclude = .tox,.git,*/migrations/*,*/static/CACHE/*,docs,node_modules
[pycodestyle] [pycodestyle]
max-line-length = 120 max-line-length = 120
exclude = .tox,.git,*/migrations/*,*/static/CACHE/*,docs,node_modules exclude = .tox,.git,*/migrations/*,*/static/CACHE/*,docs,node_modules
[mypy]
python_version = 3.6
check_untyped_defs = True
ignore_errors = False
ignore_missing_imports = True
strict_optional = True
warn_unused_ignores = True
warn_redundant_casts = True
warn_unused_configs = True
[mypy-*.migrations.*]
# Django migrations should not produce any errors:
ignore_errors = True

View File

@ -1,21 +1 @@
/* Project specific Javascript goes here. */ /* Project specific Javascript goes here. */
/*
Formatting hack to get around crispy-forms unfortunate hardcoding
in helpers.FormHelper:
if template_pack == 'bootstrap4':
grid_colum_matcher = re.compile('\w*col-(xs|sm|md|lg|xl)-\d+\w*')
using_grid_layout = (grid_colum_matcher.match(self.label_class) or
grid_colum_matcher.match(self.field_class))
if using_grid_layout:
items['using_grid_layout'] = True
Issues with the above approach:
1. Fragile: Assumes Bootstrap 4's API doesn't change (it does)
2. Unforgiving: Doesn't allow for any variation in template design
3. Really Unforgiving: No way to override this behavior
4. Undocumented: No mention in the documentation, or it's too hard for me to find
*/
$('.form-group').removeClass('row');

View File

@ -11,6 +11,11 @@ if not settings.configured:
app = Celery('{{cookiecutter.project_slug}}') app = Celery('{{cookiecutter.project_slug}}')
# Using a string here means the worker will not have to
# pickle the object when using Windows.
# - namespace='CELERY' means all celery-related configuration keys
# should have a `CELERY_` prefix.
app.config_from_object('django.conf:settings', namespace='CELERY')
class CeleryAppConfig(AppConfig): class CeleryAppConfig(AppConfig):
@ -18,11 +23,6 @@ class CeleryAppConfig(AppConfig):
verbose_name = 'Celery Config' verbose_name = 'Celery Config'
def ready(self): def ready(self):
# Using a string here means the worker will not have to
# pickle the object when using Windows.
# - namespace='CELERY' means all celery-related configuration keys
# should have a `CELERY_` prefix.
app.config_from_object('django.conf:settings', namespace='CELERY')
installed_apps = [app_config.name for app_config in apps.get_app_configs()] installed_apps = [app_config.name for app_config in apps.get_app_configs()]
app.autodiscover_tasks(lambda: installed_apps, force=True) app.autodiscover_tasks(lambda: installed_apps, force=True)

View File

@ -17,8 +17,8 @@
{% block css %} {% block css %}
{% endraw %}{% if cookiecutter.custom_bootstrap_compilation == "n" %}{% raw %} {% endraw %}{% if cookiecutter.custom_bootstrap_compilation == "n" %}{% raw %}
<!-- Latest compiled and minified Bootstrap 4 beta CSS --> <!-- Latest compiled and minified Bootstrap 4.1.1 CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous"> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" integrity="sha384-WskhaSGFgHYWDcbwN70/dfYBj47jz9qbsMId/iRN3ewGhXQFZCSftd1LZCfmhktB" crossorigin="anonymous">
{% endraw %}{% endif %}{% raw %} {% endraw %}{% endif %}{% raw %}
<!-- Your stuff: Third-party CSS libraries go here --> <!-- Your stuff: Third-party CSS libraries go here -->
@ -36,7 +36,7 @@
<body> <body>
<div class="m-b-1"> <div class="mb-1">
<nav class="navbar navbar-expand-md navbar-light bg-light"> <nav class="navbar navbar-expand-md navbar-light bg-light">
<button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"> <button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span> <span class="navbar-toggler-icon"></span>
@ -102,10 +102,10 @@
<script src="{% static 'js/vendors.js' %}"></script> <script src="{% static 'js/vendors.js' %}"></script>
{% endraw %}{% if cookiecutter.use_compressor == "y" %}{% raw %}{% endcompress %}{% endraw %}{% endif %}{% raw %} {% endraw %}{% if cookiecutter.use_compressor == "y" %}{% raw %}{% endcompress %}{% endraw %}{% endif %}{% raw %}
{% endraw %}{% else %}{% raw %} {% endraw %}{% else %}{% raw %}
<!-- Required by Bootstrap v4 beta --> <!-- Required by Bootstrap v4.1.1 -->
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script> <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js" integrity="sha384-b/U6ypiBEHpOf/4+1nzFpr53nxSS+GLCkfwBdFNTxtclqqenISfwAzpKaMNFNmj4" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js" integrity="sha384-h0AbiXch4ZDo7tp9hKZ4TsHbi047NrKGLO3SEJAg45jXxnGIfYzk4Si90RDIqNm1" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js" integrity="sha384-smHYKdLADwkXOn1EmN1qk/HfnUcbVRZyYmZ4qpPea6sjB/pTJ0euyQp0Mk8ck+5T" crossorigin="anonymous"></script>
<!-- Your stuff: Third-party javascript libraries go here --> <!-- Your stuff: Third-party javascript libraries go here -->
{% endraw %}{% endif %}{% raw %} {% endraw %}{% endif %}{% raw %}