mirror of
https://github.com/cookiecutter/cookiecutter-django.git
synced 2024-11-24 02:24:07 +03:00
commit
c4479031e9
12
.github/FUNDING.yml
vendored
Normal file
12
.github/FUNDING.yml
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
# These are supported funding model platforms
|
||||||
|
|
||||||
|
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||||
|
patreon: danielroygreenfeld
|
||||||
|
open_collective: # Replace with a single Open Collective username
|
||||||
|
ko_fi: # Replace with a single Ko-fi username
|
||||||
|
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||||
|
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||||
|
liberapay: # Replace with a single Liberapay username
|
||||||
|
issuehunt: # Replace with a single IssueHunt username
|
||||||
|
otechie: # Replace with a single Otechie username
|
||||||
|
custom: ['https://www.patreon.com/browniebroke']
|
17
.pyup.yml
Normal file
17
.pyup.yml
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
# configure updates globally
|
||||||
|
# default: all
|
||||||
|
# allowed: all, insecure, False
|
||||||
|
update: all
|
||||||
|
|
||||||
|
# configure dependency pinning globally
|
||||||
|
# default: True
|
||||||
|
# allowed: True, False
|
||||||
|
pin: True
|
||||||
|
|
||||||
|
# Specify requirement files by hand, pyup seems to struggle to
|
||||||
|
# find the ones in the project_slug folder
|
||||||
|
requirements:
|
||||||
|
- "requirements.txt"
|
||||||
|
- "{{cookiecutter.project_slug}}/requirements/base.txt"
|
||||||
|
- "{{cookiecutter.project_slug}}/requirements/local.txt"
|
||||||
|
- "{{cookiecutter.project_slug}}/requirements/production.txt"
|
31
.travis.yml
31
.travis.yml
|
@ -1,22 +1,37 @@
|
||||||
sudo: required
|
dist: xenial
|
||||||
|
|
||||||
services:
|
services:
|
||||||
- docker
|
- docker
|
||||||
|
|
||||||
language: python
|
language: python
|
||||||
|
|
||||||
python: 3.6
|
python: 3.7
|
||||||
|
|
||||||
env:
|
|
||||||
- TOX_ENV=py36
|
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- docker-compose -v
|
- docker-compose -v
|
||||||
- docker -v
|
- docker -v
|
||||||
|
|
||||||
script:
|
matrix:
|
||||||
- tox -e $TOX_ENV
|
include:
|
||||||
- sh tests/test_docker.sh
|
- name: Test results
|
||||||
|
script: tox -e py37
|
||||||
|
- name: Run flake8 on result
|
||||||
|
script: tox -e flake8
|
||||||
|
- name: Run black on result
|
||||||
|
script: tox -e black
|
||||||
|
- name: Black template
|
||||||
|
script: tox -e black-template
|
||||||
|
- name: Basic Docker
|
||||||
|
script: sh tests/test_docker.sh
|
||||||
|
- name: Docker with Celery
|
||||||
|
script: sh tests/test_docker.sh use_celery=y
|
||||||
|
- name: Bare metal
|
||||||
|
script: sh tests/test_bare.sh use_celery=y use_compressor=y
|
||||||
|
services:
|
||||||
|
- postgresql
|
||||||
|
- redis-server
|
||||||
|
env:
|
||||||
|
- CELERY_BROKER_URL=redis://localhost:6379/0
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- pip install tox
|
- pip install tox
|
||||||
|
|
254
CHANGELOG.md
254
CHANGELOG.md
|
@ -1,6 +1,258 @@
|
||||||
# Change Log
|
# Change Log
|
||||||
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/).
|
|
||||||
|
## [2020-01-23]
|
||||||
|
### Changed
|
||||||
|
- Fix UserFactory to set the password if provided (@BoPeng)
|
||||||
|
- Update documentation files with latest Sphinx (@howiezhao)
|
||||||
|
|
||||||
|
## [2020-01-12]
|
||||||
|
### Changed
|
||||||
|
- Fix mypy setup and added django-stubs (@danifus)
|
||||||
|
- Add Gitlab CI as option (@ikhomutov)
|
||||||
|
|
||||||
|
## [2020-01-11]
|
||||||
|
### Changed
|
||||||
|
- Speed up & reduce size for production Django image (@maxp)
|
||||||
|
- Bumped runtime version for Heroku (@Isaac12x)
|
||||||
|
- Added Debian 10 (Buster) OS dependencies (@ddiazpinto)
|
||||||
|
- Update Traefik to v2 (@blaxpy)
|
||||||
|
- Switched Docker images from Alpine based to Debian based (@trungdong)
|
||||||
|
|
||||||
|
## [2019-10-06]
|
||||||
|
### Changed
|
||||||
|
- Default Python version is now 3.7 (@nicolas471)
|
||||||
|
|
||||||
|
## [2019-10-04]
|
||||||
|
### Fixed
|
||||||
|
- Fix static files handling on GCP (@caioariede)
|
||||||
|
|
||||||
|
## [2019-10-03]
|
||||||
|
### Fixed
|
||||||
|
- Fix incompatible combination between Whitenoise and no cloud provider (@caioariede)
|
||||||
|
|
||||||
|
## [2019-07-09]
|
||||||
|
### Fixed
|
||||||
|
- Always use test settings in pytest (@danihodovic)
|
||||||
|
- Remove gunicorn from `INSTALLED_APPS` (@danihodovic)
|
||||||
|
- Remove `EMAIL_HOST` and `EMAIL_PORT` with locmem backend (@danihodovic)
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Add `EMAIL_TIMEOUT` (@danihodovic)
|
||||||
|
|
||||||
|
## [2019-06-22]
|
||||||
|
### Fixed
|
||||||
|
- Remove redundant template debug setting (@danihodovic)
|
||||||
|
|
||||||
|
## [2019-06-19]
|
||||||
|
### Fixed
|
||||||
|
- Fix removal carriage returns in docker scripts (@timclaessens)
|
||||||
|
|
||||||
|
## [2019-06-15]
|
||||||
|
### Fixed
|
||||||
|
- Issue with Pycharm setup for running things in Docker compose (@foarsitter)
|
||||||
|
|
||||||
|
## [2019-06-06]
|
||||||
|
### Changed
|
||||||
|
- Update generated Travis config (@browniebroke)
|
||||||
|
|
||||||
|
## [2019-06-03]
|
||||||
|
### Added
|
||||||
|
- Installed `django-celery-beat` to keep scheduled tasks in DB (@keyvanm)
|
||||||
|
|
||||||
|
## [2019-05-28]
|
||||||
|
### Changed
|
||||||
|
- Use GCP acronym rather than inconsistent GCE/GCS (@tanoabeleyra)
|
||||||
|
|
||||||
|
## [2019-05-27]
|
||||||
|
### Changed
|
||||||
|
- Made cloud provider optional (@tanoabeleyra)
|
||||||
|
- Updated to Django 2.2.1 (@browniebroke)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Celery worker-related setting names (@browniebroke)
|
||||||
|
|
||||||
|
## [2019-05-18]
|
||||||
|
### Removed
|
||||||
|
- Remove the user list view (@browniebroke)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Static storage default ACL (@browniebroke)
|
||||||
|
|
||||||
|
## [2019-05-17]
|
||||||
|
### Fixed
|
||||||
|
- Added `LocaleMiddleware` to the list of middlewares (@tanoabeleyra)
|
||||||
|
- Added `LOCALE_PATH` to settings (@tanoabeleyra)
|
||||||
|
|
||||||
|
## [2019-05-16]
|
||||||
|
### Changed
|
||||||
|
- Users app to have a translated verbose name (@tanoabeleyra)
|
||||||
|
- Logging configuration for local (@browniebroke)
|
||||||
|
|
||||||
|
## [2019-05-08]
|
||||||
|
### Changed
|
||||||
|
- Upgraded to Django 2.1 (@browniebroke)
|
||||||
|
|
||||||
|
## [2019-04-07]
|
||||||
|
### Added
|
||||||
|
- Support for Google Cloud Storage (@ahhda)
|
||||||
|
|
||||||
|
## [2019-04-03]
|
||||||
|
### Added
|
||||||
|
- Command to backup Db to AWS S3 (@foarsitter)
|
||||||
|
|
||||||
|
## [2019-03-25]
|
||||||
|
### Added
|
||||||
|
- Node image to run Gulp with Docker (@browniebroke)
|
||||||
|
|
||||||
|
## [2019-03-19]
|
||||||
|
### Changed
|
||||||
|
- Replaced Caddy with Traefik (@demestav)
|
||||||
|
|
||||||
|
## [2019-03-11]
|
||||||
|
### Changed
|
||||||
|
- Sentry integration from Raven to Sentry-SDK (@gfabricio)
|
||||||
|
- Made Redis config conditional on Celery locally (@demestav)
|
||||||
|
|
||||||
|
## [2019-03-11]
|
||||||
|
### Added
|
||||||
|
- Automatic migrations on Heroku (@yunti)
|
||||||
|
|
||||||
|
## [2019-03-06]
|
||||||
|
### Fixed
|
||||||
|
- Missing script tag in Travis config (@btknu)
|
||||||
|
|
||||||
|
## [2019-03-02]
|
||||||
|
### Changed
|
||||||
|
- Celery eager setting in local setting with Docker (@keithjeb)
|
||||||
|
|
||||||
|
## [2019-03-01]
|
||||||
|
### Updated
|
||||||
|
- All NPM dependencies (@takkaria)
|
||||||
|
|
||||||
|
## [2018-11-13]
|
||||||
|
### Changed
|
||||||
|
- Security settings in Dev (@carlmjohnson)
|
||||||
|
|
||||||
|
## [2018-11-20]
|
||||||
|
### Fixed
|
||||||
|
- Passing the CSRF header from the reverse proxy to Django server for DRF (@hpbruna)
|
||||||
|
|
||||||
|
## [2018-11-12]
|
||||||
|
### Fixed
|
||||||
|
- Initialisation of Celery app (@glasslion)
|
||||||
|
|
||||||
|
## [2018-10-24]
|
||||||
|
### Fixed
|
||||||
|
- Persisting of iPython history between sessions (@davitovmasyan)
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Postgres 10.5 option (@jleclanche)
|
||||||
|
|
||||||
|
## [2018-09-18]
|
||||||
|
### Added
|
||||||
|
- Included `mypy` in dependencies and run it in tests (@apirobot)
|
||||||
|
|
||||||
|
## [2018-09-18]
|
||||||
|
### Fixed
|
||||||
|
- Avoid `$` in environment variables to workaround a bug from django-environ (@browniebroke)
|
||||||
|
|
||||||
|
## [2018-09-16]
|
||||||
|
### Fixed
|
||||||
|
- Bug in ordering of Middleware for production config (@ChrisPappalardo)
|
||||||
|
|
||||||
|
## [2018-09-12]
|
||||||
|
### Fixed
|
||||||
|
- URLs for Static and Media for S3 buckets in regions other than N. Virginia (@umrashrf)
|
||||||
|
|
||||||
|
## [2018-09-09]
|
||||||
|
### Changed
|
||||||
|
- Name of static and media storage classes (@sfdye)
|
||||||
|
|
||||||
|
## [2018-09-01]
|
||||||
|
### Changed
|
||||||
|
- Make static and media storage fully-fledged classes (@erfaan)
|
||||||
|
|
||||||
|
## [2018-08-28]
|
||||||
|
### Fixed
|
||||||
|
- Running tests in docker test script (@apirobot)
|
||||||
|
|
||||||
|
## [2018-07-23]
|
||||||
|
### Changed
|
||||||
|
- Test commands to use pytest (@jcass77)
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
- Some hacks leftovers from Bootstrap v4 beta in `project.js` (@hendrikschneider)
|
||||||
|
|
||||||
|
## [2018-07-12]
|
||||||
|
### Changed
|
||||||
|
- Upgraded to Bootstrap 4.1.1 (@mostaszewski)
|
||||||
|
|
||||||
|
## [2018-06-25]
|
||||||
|
### Added
|
||||||
|
- Flower integration with Docker (@webyneter)
|
||||||
|
|
||||||
|
## [2018-06-25]
|
||||||
|
### Changed
|
||||||
|
- Rewrite user app test to use a pytest style (@webyneter)
|
||||||
|
|
||||||
|
## [2018-06-21]
|
||||||
|
### Added
|
||||||
|
- Extend & update Celery config (@webyneter & @apirobot)
|
||||||
|
|
||||||
|
## [2018-05-25]
|
||||||
|
### Fixed
|
||||||
|
- Build issues due to incompatibility between libressl & openssl (@SassanoM)
|
||||||
|
|
||||||
|
## [2018-05-21]
|
||||||
|
### Changed
|
||||||
|
- Updated Caddy to 0.11 and pin its version (@webyneter)
|
||||||
|
|
||||||
|
## [2018-05-14]
|
||||||
|
### Changed
|
||||||
|
- Replace `awesome-slugify` by `python-slugify` (@hongquan)
|
||||||
|
- Migrate to Django 2.0+ URL style (@saschalalala)
|
||||||
|
|
||||||
|
## [2018-05-05]
|
||||||
|
### Fixed
|
||||||
|
- Postgres backup & restore commands (@webyneter)
|
||||||
|
|
||||||
|
## [2018-04-10]
|
||||||
|
### Changed
|
||||||
|
- Simplify configuration (@danidee10)
|
||||||
|
|
||||||
|
## [2018-04-08]
|
||||||
|
### Added
|
||||||
|
- Adopt Black code style (@pydanny)
|
||||||
|
|
||||||
|
## [2018-03-27]
|
||||||
|
### Fixed
|
||||||
|
- Simplified extra Celery config generated when opted out (@webyneter)
|
||||||
|
|
||||||
|
## [2018-03-21]
|
||||||
|
### Removed
|
||||||
|
- Remove Opbeat support (@sfdye)
|
||||||
|
|
||||||
|
## [2018-03-16]
|
||||||
|
### Fixed
|
||||||
|
- Install `psycopg2-binary` when using Docker locally (@browniebroke)
|
||||||
|
|
||||||
|
## [2018-03-14]
|
||||||
|
### Fixed
|
||||||
|
- Fixed and improved Postgres backup & restore scripts (@webyneter)
|
||||||
|
|
||||||
|
## [2018-03-10]
|
||||||
|
### Changed
|
||||||
|
- Simplify Mailgun setting (@browniebroke)
|
||||||
|
|
||||||
|
## [2018-03-06]
|
||||||
|
### Changed
|
||||||
|
- Convert string formatting to f-strings (@sfdye)
|
||||||
|
|
||||||
|
## [2018-03-01]
|
||||||
|
### Changed
|
||||||
|
- Celery to use JSON serialization by default (@adammsteele)
|
||||||
|
- Use Docker version from Travis to run tests (@browniebroke)
|
||||||
|
|
||||||
## [2018-02-16]
|
## [2018-02-16]
|
||||||
### Changed
|
### Changed
|
||||||
|
|
|
@ -39,9 +39,9 @@ To run all tests using various versions of python in virtualenvs defined in tox.
|
||||||
It is possible to test with a specific version of python. To do this, the command
|
It is possible to test with a specific version of python. To do this, the command
|
||||||
is::
|
is::
|
||||||
|
|
||||||
$ tox -e py36
|
$ tox -e py37
|
||||||
|
|
||||||
This will run py.test with the python3.6 interpreter, for example.
|
This will run py.test with the python3.7 interpreter, for example.
|
||||||
|
|
||||||
To run a particular test with tox for against your current Python version::
|
To run a particular test with tox for against your current Python version::
|
||||||
|
|
||||||
|
|
143
CONTRIBUTORS.rst
143
CONTRIBUTORS.rst
|
@ -7,9 +7,9 @@ Core Developers
|
||||||
These contributors have commit flags for the repository,
|
These contributors have commit flags for the repository,
|
||||||
and are able to accept and merge pull requests.
|
and are able to accept and merge pull requests.
|
||||||
|
|
||||||
=========================== ================ ===========
|
=========================== ================= ===========
|
||||||
Name Github Twitter
|
Name Github Twitter
|
||||||
=========================== ================ ===========
|
=========================== ================= ===========
|
||||||
Daniel Roy Greenfeld `@pydanny`_ @pydanny
|
Daniel Roy Greenfeld `@pydanny`_ @pydanny
|
||||||
Audrey Roy Greenfeld* `@audreyr`_ @audreyr
|
Audrey Roy Greenfeld* `@audreyr`_ @audreyr
|
||||||
Fábio C. Barrionuevo da Luz `@luzfcb`_ @luzfcb
|
Fábio C. Barrionuevo da Luz `@luzfcb`_ @luzfcb
|
||||||
|
@ -19,7 +19,7 @@ Burhan Khalid `@burhan`_ @burhan
|
||||||
Nikita Shupeyko `@webyneter`_ @webyneter
|
Nikita Shupeyko `@webyneter`_ @webyneter
|
||||||
Bruno Alla `@browniebroke`_ @_BrunoAlla
|
Bruno Alla `@browniebroke`_ @_BrunoAlla
|
||||||
Wan Liuyang `@sfdye`_ @sfdye
|
Wan Liuyang `@sfdye`_ @sfdye
|
||||||
=========================== ================ ===========
|
=========================== ================= ===========
|
||||||
|
|
||||||
*Audrey is also the creator of Cookiecutter. Audrey and
|
*Audrey is also the creator of Cookiecutter. Audrey and
|
||||||
Daniel are on the Cookiecutter core team.*
|
Daniel are on the Cookiecutter core team.*
|
||||||
|
@ -42,11 +42,12 @@ Listed in alphabetical order.
|
||||||
Name Github Twitter
|
Name Github Twitter
|
||||||
========================== ============================ ==============
|
========================== ============================ ==============
|
||||||
18 `@dezoito`_
|
18 `@dezoito`_
|
||||||
|
2O4 `@2O4`_
|
||||||
a7p `@a7p`_
|
a7p `@a7p`_
|
||||||
Aaron Eikenberry `@aeikenberry`_
|
Aaron Eikenberry `@aeikenberry`_
|
||||||
Adam Bogdał `@bogdal`_
|
Adam Bogdał `@bogdal`_
|
||||||
Adam Dobrawy `@ad-m`_
|
Adam Dobrawy `@ad-m`_
|
||||||
Adam Steele `@adammsteele`
|
Adam Steele `@adammsteele`_
|
||||||
Agam Dua
|
Agam Dua
|
||||||
Alberto Sanchez `@alb3rto`_
|
Alberto Sanchez `@alb3rto`_
|
||||||
Alex Tsai `@caffodian`_
|
Alex Tsai `@caffodian`_
|
||||||
|
@ -64,15 +65,18 @@ Listed in alphabetical order.
|
||||||
Areski Belaid `@areski`_
|
Areski Belaid `@areski`_
|
||||||
Ashley Camba
|
Ashley Camba
|
||||||
Barclay Gauld `@yunti`_
|
Barclay Gauld `@yunti`_
|
||||||
Ben Warren `@bwarren2`
|
Bartek `@btknu`_
|
||||||
Ben Lopatin
|
Ben Lopatin
|
||||||
|
Ben Warren `@bwarren2`_
|
||||||
Benjamin Abel
|
Benjamin Abel
|
||||||
Bert de Miranda `@bertdemiranda`_
|
Bert de Miranda `@bertdemiranda`_
|
||||||
Bo Lopker `@blopker`_
|
Bo Lopker `@blopker`_
|
||||||
|
Bo Peng `@BoPeng`_
|
||||||
Bouke Haarsma
|
Bouke Haarsma
|
||||||
Brent Payne `@brentpayne`_ @brentpayne
|
Brent Payne `@brentpayne`_ @brentpayne
|
||||||
Bartek `@btknu`
|
Bruce Olivier `@bolivierjr`_
|
||||||
Burhan Khalid `@burhan`_ @burhan
|
Burhan Khalid `@burhan`_ @burhan
|
||||||
|
Caio Ariede `@caioariede`_ @caioariede
|
||||||
Carl Johnson `@carlmjohnson`_ @carlmjohnson
|
Carl Johnson `@carlmjohnson`_ @carlmjohnson
|
||||||
Catherine Devlin `@catherinedevlin`_
|
Catherine Devlin `@catherinedevlin`_
|
||||||
Cédric Gaspoz `@cgaspoz`_
|
Cédric Gaspoz `@cgaspoz`_
|
||||||
|
@ -84,33 +88,49 @@ Listed in alphabetical order.
|
||||||
Christopher Clarke `@chrisdev`_
|
Christopher Clarke `@chrisdev`_
|
||||||
Cole Mackenzie `@cmackenzie1`_
|
Cole Mackenzie `@cmackenzie1`_
|
||||||
Collederas `@Collederas`_
|
Collederas `@Collederas`_
|
||||||
|
Craig Margieson `@cmargieson`_
|
||||||
Cristian Vargas `@cdvv7788`_
|
Cristian Vargas `@cdvv7788`_
|
||||||
Cullen Rhodes `@c-rhodes`_
|
Cullen Rhodes `@c-rhodes`_
|
||||||
|
Curtis St Pierre `@curtisstpierre`_ @cstpierre1388
|
||||||
Dan Shultz `@shultz`_
|
Dan Shultz `@shultz`_
|
||||||
|
Dani Hodovic `@danihodovic`_
|
||||||
Daniel Hepper `@dhepper`_ @danielhepper
|
Daniel Hepper `@dhepper`_ @danielhepper
|
||||||
|
Daniel Hillier `@danifus`_
|
||||||
Daniele Tricoli `@eriol`_
|
Daniele Tricoli `@eriol`_
|
||||||
David Díaz `@ddiazpinto`_ @DavidDiazPinto
|
David Díaz `@ddiazpinto`_ @DavidDiazPinto
|
||||||
Davit Tovmasyan `@davitovmasyan`_
|
Davit Tovmasyan `@davitovmasyan`_
|
||||||
Davur Clementsen `@dsclementsen`_ @davur
|
Davur Clementsen `@dsclementsen`_ @davur
|
||||||
Delio Castillo `@jangeador`_ @jangeador
|
Delio Castillo `@jangeador`_ @jangeador
|
||||||
|
Demetris Stavrou `@demestav`_
|
||||||
|
Denis Bobrov `@delneg`_
|
||||||
Denis Orehovsky `@apirobot`_
|
Denis Orehovsky `@apirobot`_
|
||||||
Dónal Adams `@epileptic-fish`_
|
Denis Savran `@blaxpy`_
|
||||||
Diane Chen `@purplediane`_ @purplediane88
|
Diane Chen `@purplediane`_ @purplediane88
|
||||||
|
Dónal Adams `@epileptic-fish`_
|
||||||
Dong Huynh `@trungdong`_
|
Dong Huynh `@trungdong`_
|
||||||
Emanuel Calso `@bloodpet`_ @bloodpet
|
Emanuel Calso `@bloodpet`_ @bloodpet
|
||||||
Eraldo Energy `@eraldo`_
|
Eraldo Energy `@eraldo`_
|
||||||
Eric Groom `@ericgroom`_
|
Eric Groom `@ericgroom`_
|
||||||
Eyad Al Sibai `@eyadsibai`_
|
Eyad Al Sibai `@eyadsibai`_
|
||||||
Felipe Arruda `@arruda`_
|
Felipe Arruda `@arruda`_
|
||||||
|
Florian Idelberger `@step21`_ @windrush
|
||||||
Garry Cairns `@garry-cairns`_
|
Garry Cairns `@garry-cairns`_
|
||||||
Garry Polley `@garrypolley`_
|
Garry Polley `@garrypolley`_
|
||||||
|
Gilbishkosma `@Gilbishkosma`_
|
||||||
Hamish Durkin `@durkode`_
|
Hamish Durkin `@durkode`_
|
||||||
|
Hana Quadara `@hanaquadara`_
|
||||||
|
Harry Moreno `@morenoh149`_ @morenoh149
|
||||||
Harry Percival `@hjwp`_
|
Harry Percival `@hjwp`_
|
||||||
Hendrik Schneider `@hendrikschneider`_
|
Hendrik Schneider `@hendrikschneider`_
|
||||||
Henrique G. G. Pereira `@ikkebr`_
|
Henrique G. G. Pereira `@ikkebr`_
|
||||||
|
Howie Zhao `@howiezhao`_
|
||||||
Ian Lee `@IanLee1521`_
|
Ian Lee `@IanLee1521`_
|
||||||
Irfan Ahmad `@erfaan`_ @erfaan
|
Irfan Ahmad `@erfaan`_ @erfaan
|
||||||
|
Isaac12x `@Isaac12x`_
|
||||||
|
Ivan Khomutov `@ikhomutov`_
|
||||||
Jan Van Bruggen `@jvanbrug`_
|
Jan Van Bruggen `@jvanbrug`_
|
||||||
|
Jelmer Draaijer `@foarsitter`_
|
||||||
|
Jerome Caisip `@jeromecaisip`_
|
||||||
Jens Nilsson `@phiberjenz`_
|
Jens Nilsson `@phiberjenz`_
|
||||||
Jerome Leclanche `@jleclanche`_ @Adys
|
Jerome Leclanche `@jleclanche`_ @Adys
|
||||||
Jimmy Gitonga `@afrowave`_ @afrowave
|
Jimmy Gitonga `@afrowave`_ @afrowave
|
||||||
|
@ -120,13 +140,16 @@ Listed in alphabetical order.
|
||||||
Kaido Kert `@kaidokert`_
|
Kaido Kert `@kaidokert`_
|
||||||
kappataumu `@kappataumu`_ @kappataumu
|
kappataumu `@kappataumu`_ @kappataumu
|
||||||
Kaveh `@ka7eh`_
|
Kaveh `@ka7eh`_
|
||||||
|
Keith Bailey `@keithjeb`_
|
||||||
|
Keith Webber `@townie`_
|
||||||
Kevin A. Stone
|
Kevin A. Stone
|
||||||
Kevin Ndung'u `@kevgathuku`_
|
Kevin Ndung'u `@kevgathuku`_
|
||||||
Keith Webber `@townie`_
|
Keyvan Mosharraf `@keyvanm`_
|
||||||
Krzysztof Szumny `@noisy`_
|
Krzysztof Szumny `@noisy`_
|
||||||
Krzysztof Żuraw `@krzysztofzuraw`_
|
Krzysztof Żuraw `@krzysztofzuraw`_
|
||||||
Leonardo Jimenez `@xpostudio4`_
|
Leo won `@leollon`_
|
||||||
Leo Zhou `@glasslion`_
|
Leo Zhou `@glasslion`_
|
||||||
|
Leonardo Jimenez `@xpostudio4`_
|
||||||
Lin Xianyi `@iynaix`_
|
Lin Xianyi `@iynaix`_
|
||||||
Luis Nell `@originell`_
|
Luis Nell `@originell`_
|
||||||
Lukas Klein
|
Lukas Klein
|
||||||
|
@ -137,6 +160,7 @@ Listed in alphabetical order.
|
||||||
Mateusz Ostaszewski `@mostaszewski`_
|
Mateusz Ostaszewski `@mostaszewski`_
|
||||||
Mathijs Hoogland `@MathijsHoogland`_
|
Mathijs Hoogland `@MathijsHoogland`_
|
||||||
Matt Braymer-Hayes `@mattayes`_ @mattayes
|
Matt Braymer-Hayes `@mattayes`_ @mattayes
|
||||||
|
Matt Knapper `@mknapper1`_
|
||||||
Matt Linares
|
Matt Linares
|
||||||
Matt Menzenski `@menzenski`_
|
Matt Menzenski `@menzenski`_
|
||||||
Matt Warren `@mfwarren`_
|
Matt Warren `@mfwarren`_
|
||||||
|
@ -144,66 +168,86 @@ Listed in alphabetical order.
|
||||||
Meghan Heintz `@dot2dotseurat`_
|
Meghan Heintz `@dot2dotseurat`_
|
||||||
Mesut Yılmaz `@myilmaz`_
|
Mesut Yılmaz `@myilmaz`_
|
||||||
Michael Gecht `@mimischi`_ @_mischi
|
Michael Gecht `@mimischi`_ @_mischi
|
||||||
|
Michael Samoylov `@msamoylov`_
|
||||||
|
Min ho Kim `@minho42`_
|
||||||
mozillazg `@mozillazg`_
|
mozillazg `@mozillazg`_
|
||||||
|
Nico Stefani `@nicolas471`_ @moby_dick91
|
||||||
|
Oleg Russkin `@rolep`_
|
||||||
Pablo `@oubiga`_
|
Pablo `@oubiga`_
|
||||||
Parbhat Puri `@parbhat`_
|
Parbhat Puri `@parbhat`_
|
||||||
Peter Bittner `@bittner`_
|
Peter Bittner `@bittner`_
|
||||||
Peter Coles `@mrcoles`_
|
Peter Coles `@mrcoles`_
|
||||||
|
Philipp Matthies `@canonnervio`_
|
||||||
Pierre Chiquet `@pchiquet`_
|
Pierre Chiquet `@pchiquet`_
|
||||||
Raphael Pierzina `@hackebrot`_
|
|
||||||
Raony Guimarães Corrêa `@raonyguimaraes`_
|
Raony Guimarães Corrêa `@raonyguimaraes`_
|
||||||
|
Raphael Pierzina `@hackebrot`_
|
||||||
Reggie Riser `@reggieriser`_
|
Reggie Riser `@reggieriser`_
|
||||||
René Muhl `@rm--`_
|
René Muhl `@rm--`_
|
||||||
Roman Afanaskin `@siauPatrick`_
|
Roman Afanaskin `@siauPatrick`_
|
||||||
Roman Osipenko `@romanosipenko`_
|
Roman Osipenko `@romanosipenko`_
|
||||||
Russell Davies
|
Russell Davies
|
||||||
Sascha `@saschalalala` @saschalalala
|
|
||||||
Sam Collins `@MightySCollins`_
|
Sam Collins `@MightySCollins`_
|
||||||
|
Sascha `@saschalalala`_ @saschalalala
|
||||||
Shupeyko Nikita `@webyneter`_
|
Shupeyko Nikita `@webyneter`_
|
||||||
Sławek Ehlert `@slafs`_
|
Sławek Ehlert `@slafs`_
|
||||||
Srinivas Nyayapati `@shireenrao`_
|
Srinivas Nyayapati `@shireenrao`_
|
||||||
stepmr `@stepmr`_
|
stepmr `@stepmr`_
|
||||||
Steve Steiner `@ssteinerX`_
|
Steve Steiner `@ssteinerX`_
|
||||||
Sule Marshall `@suledev`_
|
Sule Marshall `@suledev`_
|
||||||
|
Tano Abeleyra `@tanoabeleyra`_
|
||||||
Taylor Baldwin
|
Taylor Baldwin
|
||||||
Théo Segonds `@show0k`_
|
Théo Segonds `@show0k`_
|
||||||
|
Tim Claessens `@timclaessens`_
|
||||||
Tim Freund `@timfreund`_
|
Tim Freund `@timfreund`_
|
||||||
Tom Atkins `@knitatoms`_
|
Tom Atkins `@knitatoms`_
|
||||||
Tom Offermann
|
Tom Offermann
|
||||||
Travis McNeill `@Travistock`_ @tavistock_esq
|
Travis McNeill `@Travistock`_ @tavistock_esq
|
||||||
Tubo Shi `@Tubo`_
|
Tubo Shi `@Tubo`_
|
||||||
Umair Ashraf `@umrashrf`_ @fabumair
|
Umair Ashraf `@umrashrf`_ @fabumair
|
||||||
|
Vadim Iskuchekov `@Egregors`_ @egregors
|
||||||
Vitaly Babiy
|
Vitaly Babiy
|
||||||
Vivian Guillen `@viviangb`_
|
Vivian Guillen `@viviangb`_
|
||||||
|
Vlad Doster `@vladdoster`_
|
||||||
Will Farley `@goldhand`_ @g01dhand
|
Will Farley `@goldhand`_ @g01dhand
|
||||||
William Archinal `@archinal`_
|
William Archinal `@archinal`_
|
||||||
|
Xaver Y.R. Chen `@yrchen`_ @yrchen
|
||||||
Yaroslav Halchenko
|
Yaroslav Halchenko
|
||||||
Denis Bobrov `@delneg`_
|
Yuchen Xie `@mapx`_
|
||||||
Philipp Matthies `@canonnervio`_
|
|
||||||
Vadim Iskuchekov `@Egregors`_ @egregors
|
|
||||||
Keith Bailey `@keithjeb`_
|
|
||||||
========================== ============================ ==============
|
========================== ============================ ==============
|
||||||
|
|
||||||
.. _@a7p: https://github.com/a7p
|
.. _@a7p: https://github.com/a7p
|
||||||
|
.. _@2O4: https://github.com/2O4
|
||||||
.. _@ad-m: https://github.com/ad-m
|
.. _@ad-m: https://github.com/ad-m
|
||||||
.. _@adammsteele: https://github.com/adammsteele
|
.. _@adammsteele: https://github.com/adammsteele
|
||||||
.. _@aeikenberry: https://github.com/aeikenberry
|
.. _@aeikenberry: https://github.com/aeikenberry
|
||||||
|
.. _@afrowave: https://github.com/afrowave
|
||||||
|
.. _@ahhda: https://github.com/ahhda
|
||||||
.. _@alb3rto: https://github.com/alb3rto
|
.. _@alb3rto: https://github.com/alb3rto
|
||||||
.. _@ameistad: https://github.com/ameistad
|
.. _@ameistad: https://github.com/ameistad
|
||||||
.. _@amjith: https://github.com/amjith
|
.. _@amjith: https://github.com/amjith
|
||||||
.. _@andor-pierdelacabeza: https://github.com/andor-pierdelacabeza
|
.. _@andor-pierdelacabeza: https://github.com/andor-pierdelacabeza
|
||||||
|
.. _@andresgz: https://github.com/andresgz
|
||||||
.. _@antoniablair: https://github.com/antoniablair
|
.. _@antoniablair: https://github.com/antoniablair
|
||||||
.. _@apirobot: https://github.com/apirobot
|
.. _@apirobot: https://github.com/apirobot
|
||||||
.. _@archinal: https://github.com/archinal
|
.. _@archinal: https://github.com/archinal
|
||||||
.. _@areski: https://github.com/areski
|
.. _@areski: https://github.com/areski
|
||||||
.. _@arruda: https://github.com/arruda
|
.. _@arruda: https://github.com/arruda
|
||||||
|
.. _@bertdemiranda: https://github.com/bertdemiranda
|
||||||
.. _@bittner: https://github.com/bittner
|
.. _@bittner: https://github.com/bittner
|
||||||
|
.. _@blaxpy: https://github.com/blaxpy
|
||||||
.. _@bloodpet: https://github.com/bloodpet
|
.. _@bloodpet: https://github.com/bloodpet
|
||||||
.. _@blopker: https://github.com/blopker
|
.. _@blopker: https://github.com/blopker
|
||||||
.. _@bogdal: https://github.com/bogdal
|
.. _@bogdal: https://github.com/bogdal
|
||||||
|
.. _@bolivierjr: https://github.com/bolivierjr
|
||||||
|
.. _@BoPeng: https://github.com/BoPeng
|
||||||
|
.. _@brentpayne: https://github.com/brentpayne
|
||||||
|
.. _@btknu: https://github.com/btknu
|
||||||
.. _@burhan: https://github.com/burhan
|
.. _@burhan: https://github.com/burhan
|
||||||
|
.. _@bwarren2: https://github.com/bwarren2
|
||||||
.. _@c-rhodes: https://github.com/c-rhodes
|
.. _@c-rhodes: https://github.com/c-rhodes
|
||||||
.. _@caffodian: https://github.com/caffodian
|
.. _@caffodian: https://github.com/caffodian
|
||||||
|
.. _@canonnervio: https://github.com/canonnervio
|
||||||
|
.. _@caioariede: https://github.com/caioariede
|
||||||
.. _@carlmjohnson: https://github.com/carlmjohnson
|
.. _@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
|
||||||
|
@ -213,94 +257,119 @@ Listed in alphabetical order.
|
||||||
.. _@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
|
.. _@cmackenzie1: https://github.com/cmackenzie1
|
||||||
|
.. _@cmargieson: https://github.com/cmargieson
|
||||||
.. _@Collederas: https://github.com/Collederas
|
.. _@Collederas: https://github.com/Collederas
|
||||||
|
.. _@curtisstpierre: https://github.com/curtisstpierre
|
||||||
|
.. _@dadokkio: https://github.com/dadokkio
|
||||||
|
.. _@danihodovic: https://github.com/danihodovic
|
||||||
|
.. _@danifus: https://github.com/danifus
|
||||||
.. _@davitovmasyan: https://github.com/davitovmasyan
|
.. _@davitovmasyan: https://github.com/davitovmasyan
|
||||||
.. _@ddiazpinto: https://github.com/ddiazpinto
|
.. _@ddiazpinto: https://github.com/ddiazpinto
|
||||||
|
.. _@delneg: https://github.com/delneg
|
||||||
|
.. _@demestav: https://github.com/demestav
|
||||||
.. _@dezoito: https://github.com/dezoito
|
.. _@dezoito: https://github.com/dezoito
|
||||||
.. _@dhepper: https://github.com/dhepper
|
.. _@dhepper: https://github.com/dhepper
|
||||||
.. _@dot2dotseurat: https://github.com/dot2dotseurat
|
.. _@dot2dotseurat: https://github.com/dot2dotseurat
|
||||||
.. _@dsclementsen: https://github.com/dsclementsen
|
.. _@dsclementsen: https://github.com/dsclementsen
|
||||||
.. _@durkode: https://github.com/durkode
|
.. _@durkode: https://github.com/durkode
|
||||||
|
.. _@Egregors: https://github.com/Egregors
|
||||||
.. _@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
|
.. _@erfaan: https://github.com/erfaan
|
||||||
|
.. _@ericgroom: https://github.com/ericgroom
|
||||||
.. _@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
|
||||||
|
.. _@foarsitter: https://github.com/foarsitter
|
||||||
.. _@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
|
.. _@Gilbishkosma: https://github.com/Gilbishkosma
|
||||||
.. _@glasslion: https://github.com/glasslion
|
.. _@glasslion: https://github.com/glasslion
|
||||||
|
.. _@goldhand: https://github.com/goldhand
|
||||||
.. _@hackebrot: https://github.com/hackebrot
|
.. _@hackebrot: https://github.com/hackebrot
|
||||||
.. _@hairychris: https://github.com/hairychris
|
.. _@hairychris: https://github.com/hairychris
|
||||||
|
.. _@hanaquadara: https://github.com/hanaquadara
|
||||||
.. _@hendrikschneider: https://github.com/hendrikschneider
|
.. _@hendrikschneider: https://github.com/hendrikschneider
|
||||||
.. _@hjwp: https://github.com/hjwp
|
.. _@hjwp: https://github.com/hjwp
|
||||||
|
.. _@howiezhao: https://github.com/howiezhao
|
||||||
.. _@IanLee1521: https://github.com/IanLee1521
|
.. _@IanLee1521: https://github.com/IanLee1521
|
||||||
|
.. _@ikhomutov: https://github.com/ikhomutov
|
||||||
.. _@ikkebr: https://github.com/ikkebr
|
.. _@ikkebr: https://github.com/ikkebr
|
||||||
|
.. _@Isaac12x: https://github.com/Isaac12x
|
||||||
.. _@iynaix: https://github.com/iynaix
|
.. _@iynaix: https://github.com/iynaix
|
||||||
|
.. _@jangeador: https://github.com/jangeador
|
||||||
.. _@jazztpt: https://github.com/jazztpt
|
.. _@jazztpt: https://github.com/jazztpt
|
||||||
|
.. _@jcass77: https://github.com/jcass77
|
||||||
|
.. _@jeromecaisip: https://github.com/jeromecaisip
|
||||||
.. _@jleclanche: https://github.com/jleclanche
|
.. _@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
|
||||||
.. _@kaidokert: https://github.com/kaidokert
|
.. _@kaidokert: https://github.com/kaidokert
|
||||||
.. _@kappataumu: https://github.com/kappataumu
|
.. _@kappataumu: https://github.com/kappataumu
|
||||||
|
.. _@keithjeb: https://github.com/keithjeb
|
||||||
.. _@kevgathuku: https://github.com/kevgathuku
|
.. _@kevgathuku: https://github.com/kevgathuku
|
||||||
|
.. _@keyvanm: https://github.com/keyvanm
|
||||||
.. _@knitatoms: https://github.com/knitatoms
|
.. _@knitatoms: https://github.com/knitatoms
|
||||||
.. _@krzysztofzuraw: https://github.com/krzysztofzuraw
|
.. _@krzysztofzuraw: https://github.com/krzysztofzuraw
|
||||||
.. _@msaizar: https://github.com/msaizar
|
.. _@leollon: https://github.com/leollon
|
||||||
.. _@MathijsHoogland: https://github.com/MathijsHoogland
|
.. _@MathijsHoogland: https://github.com/MathijsHoogland
|
||||||
|
.. _@mapx: https://github.com/mapx
|
||||||
.. _@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
|
||||||
|
.. _@MightySCollins: https://github.com/MightySCollins
|
||||||
.. _@mimischi: https://github.com/mimischi
|
.. _@mimischi: https://github.com/mimischi
|
||||||
|
.. _@minho42: https://github.com/minho42
|
||||||
.. _@mjsisley: https://github.com/mjsisley
|
.. _@mjsisley: https://github.com/mjsisley
|
||||||
.. _@myilmaz: https://github.com/myilmaz
|
.. _@mknapper1: https://github.com/mknapper1
|
||||||
|
.. _@morenoh149: https://github.com/morenoh149
|
||||||
|
.. _@mostaszewski: https://github.com/mostaszewski
|
||||||
.. _@mozillazg: https://github.com/mozillazg
|
.. _@mozillazg: https://github.com/mozillazg
|
||||||
|
.. _@mrcoles: https://github.com/mrcoles
|
||||||
|
.. _@msaizar: https://github.com/msaizar
|
||||||
|
.. _@msamoylov: https://github.com/msamoylov
|
||||||
|
.. _@myilmaz: https://github.com/myilmaz
|
||||||
|
.. _@nicolas471: https://github.com/nicolas471
|
||||||
.. _@noisy: https://github.com/noisy
|
.. _@noisy: https://github.com/noisy
|
||||||
.. _@originell: https://github.com/originell
|
.. _@originell: https://github.com/originell
|
||||||
.. _@oubiga: https://github.com/oubiga
|
.. _@oubiga: https://github.com/oubiga
|
||||||
.. _@parbhat: https://github.com/parbhat
|
.. _@parbhat: https://github.com/parbhat
|
||||||
|
.. _@pchiquet: https://github.com/pchiquet
|
||||||
|
.. _@phiberjenz: https://github.com/phiberjenz
|
||||||
|
.. _@purplediane: https://github.com/purplediane
|
||||||
.. _@raonyguimaraes: https://github.com/raonyguimaraes
|
.. _@raonyguimaraes: https://github.com/raonyguimaraes
|
||||||
.. _@reggieriser: https://github.com/reggieriser
|
.. _@reggieriser: https://github.com/reggieriser
|
||||||
.. _@rm--: https://github.com/rm--
|
.. _@rm--: https://github.com/rm--
|
||||||
|
.. _@rolep: https://github.com/rolep
|
||||||
.. _@romanosipenko: https://github.com/romanosipenko
|
.. _@romanosipenko: https://github.com/romanosipenko
|
||||||
|
.. _@saschalalala: https://github.com/saschalalala
|
||||||
.. _@shireenrao: https://github.com/shireenrao
|
.. _@shireenrao: https://github.com/shireenrao
|
||||||
.. _@show0k: https://github.com/show0k
|
.. _@show0k: https://github.com/show0k
|
||||||
.. _@shultz: https://github.com/shultz
|
.. _@shultz: https://github.com/shultz
|
||||||
.. _@siauPatrick: https://github.com/siauPatrick
|
.. _@siauPatrick: https://github.com/siauPatrick
|
||||||
|
.. _@sladinji: https://github.com/sladinji
|
||||||
.. _@slafs: https://github.com/slafs
|
.. _@slafs: https://github.com/slafs
|
||||||
.. _@ssteinerX: https://github.com/ssteinerx
|
.. _@ssteinerX: https://github.com/ssteinerx
|
||||||
|
.. _@step21: https://github.com/step21
|
||||||
.. _@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
|
.. _@takkaria: https://github.com/takkaria
|
||||||
|
.. _@tanoabeleyra: https://github.com/tanoabeleyra
|
||||||
|
.. _@timclaessens: https://github.com/timclaessens
|
||||||
.. _@timfreund: https://github.com/timfreund
|
.. _@timfreund: https://github.com/timfreund
|
||||||
|
.. _@townie: https://github.com/townie
|
||||||
.. _@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
|
.. _@Tubo: https://github.com/tubo
|
||||||
|
.. _@umrashrf: https://github.com/umrashrf
|
||||||
.. _@viviangb: https://github.com/viviangb
|
.. _@viviangb: https://github.com/viviangb
|
||||||
|
.. _@vladdoster: https://github.com/vladdoster
|
||||||
.. _@xpostudio4: https://github.com/xpostudio4
|
.. _@xpostudio4: https://github.com/xpostudio4
|
||||||
|
.. _@yrchen: https://github.com/yrchen
|
||||||
.. _@yunti: https://github.com/yunti
|
.. _@yunti: https://github.com/yunti
|
||||||
.. _@zcho: https://github.com/zcho
|
.. _@zcho: https://github.com/zcho
|
||||||
.. _@phiberjenz: https://github.com/phiberjenz
|
|
||||||
.. _@sladinji: https://github.com/sladinji
|
|
||||||
.. _@andresgz: https://github.com/andresgz
|
|
||||||
.. _@jangeador: https://github.com/jangeador
|
|
||||||
.. _@townie: https://github.com/townie
|
|
||||||
.. _@MightySCollins: https://github.com/MightySCollins
|
|
||||||
.. _@dadokkio: https://github.com/dadokkio
|
|
||||||
.. _@bwarren2: https://github.com/bwarren2
|
|
||||||
.. _@bertdemiranda: https://github.com/bertdemiranda
|
|
||||||
.. _@brentpayne: https://github.com/brentpayne
|
|
||||||
.. _@afrowave: https://github.com/afrowave
|
|
||||||
.. _@pchiquet: https://github.com/pchiquet
|
|
||||||
.. _@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
|
||||||
~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
53
README.rst
53
README.rst
|
@ -9,8 +9,8 @@ Cookiecutter Django
|
||||||
:target: https://pyup.io/repos/github/pydanny/cookiecutter-django/
|
:target: https://pyup.io/repos/github/pydanny/cookiecutter-django/
|
||||||
:alt: Updates
|
:alt: Updates
|
||||||
|
|
||||||
.. image:: https://badges.gitter.im/Join Chat.svg
|
.. image:: https://img.shields.io/badge/cookiecutter-Join%20on%20Slack-green?style=flat&logo=slack
|
||||||
:target: https://gitter.im/pydanny/cookiecutter-django?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
|
:target: https://join.slack.com/t/cookie-cutter/shared_invite/enQtNzI0Mzg5NjE5Nzk5LTRlYWI2YTZhYmQ4YmU1Y2Q2NmE1ZjkwOGM0NDQyNTIwY2M4ZTgyNDVkNjMxMDdhZGI5ZGE5YmJjM2M3ODJlY2U
|
||||||
|
|
||||||
.. image:: https://www.codetriage.com/pydanny/cookiecutter-django/badges/users.svg
|
.. image:: https://www.codetriage.com/pydanny/cookiecutter-django/badges/users.svg
|
||||||
:target: https://www.codetriage.com/pydanny/cookiecutter-django
|
:target: https://www.codetriage.com/pydanny/cookiecutter-django
|
||||||
|
@ -36,10 +36,10 @@ production-ready Django projects quickly.
|
||||||
Features
|
Features
|
||||||
---------
|
---------
|
||||||
|
|
||||||
* For Django 2.0
|
* For Django 2.2
|
||||||
* Works with Python 3.6
|
* Works with Python 3.7
|
||||||
* Renders Django projects with 100% starting test coverage
|
* Renders Django projects with 100% starting test coverage
|
||||||
* Twitter Bootstrap_ v4.1.1 (`maintained Foundation fork`_ also available)
|
* Twitter Bootstrap_ v4 (`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
|
||||||
|
@ -47,12 +47,13 @@ Features
|
||||||
* Comes with custom user model ready to go
|
* Comes with custom user model ready to go
|
||||||
* Optional custom static build using Gulp 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 or Google Cloud Storage
|
||||||
* Docker support using docker-compose_ for development and production (using Caddy_ with LetsEncrypt_ support)
|
* Docker support using docker-compose_ for development and production (using Traefik_ with LetsEncrypt_ support)
|
||||||
* Procfile_ for deploying to Heroku
|
* Procfile_ for deploying to Heroku
|
||||||
* Instructions for deploying to PythonAnywhere_
|
* Instructions for deploying to PythonAnywhere_
|
||||||
* Run tests with unittest or py.test
|
* Run tests with unittest or pytest
|
||||||
* Customizable PostgreSQL version
|
* Customizable PostgreSQL version
|
||||||
|
* Default integration with pre-commit_ for identifying simple issues before submission to code review
|
||||||
|
|
||||||
.. _`maintained Foundation fork`: https://github.com/Parbhat/cookiecutter-django-foundation
|
.. _`maintained Foundation fork`: https://github.com/Parbhat/cookiecutter-django-foundation
|
||||||
|
|
||||||
|
@ -62,7 +63,7 @@ Optional Integrations
|
||||||
|
|
||||||
*These features can be enabled during initial project setup.*
|
*These features can be enabled during initial project setup.*
|
||||||
|
|
||||||
* Serve static files from Amazon S3 or Whitenoise_
|
* Serve static files from Amazon S3, Google Cloud Storage or Whitenoise_
|
||||||
* Configuration for Celery_ and Flower_ (the latter in Docker setup only)
|
* Configuration for Celery_ and Flower_ (the latter in Docker setup only)
|
||||||
* Integration with MailHog_ for local email testing
|
* Integration with MailHog_ for local email testing
|
||||||
* Integration with Sentry_ for error logging
|
* Integration with Sentry_ for error logging
|
||||||
|
@ -82,15 +83,16 @@ Optional Integrations
|
||||||
.. _Sentry: https://sentry.io/welcome/
|
.. _Sentry: https://sentry.io/welcome/
|
||||||
.. _docker-compose: https://github.com/docker/compose
|
.. _docker-compose: https://github.com/docker/compose
|
||||||
.. _PythonAnywhere: https://www.pythonanywhere.com/
|
.. _PythonAnywhere: https://www.pythonanywhere.com/
|
||||||
.. _Caddy: https://caddyserver.com/
|
.. _Traefik: https://traefik.io/
|
||||||
.. _LetsEncrypt: https://letsencrypt.org/
|
.. _LetsEncrypt: https://letsencrypt.org/
|
||||||
|
.. _pre-commit: https://github.com/pre-commit/pre-commit
|
||||||
|
|
||||||
Constraints
|
Constraints
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
* Only maintained 3rd party libraries are used.
|
* Only maintained 3rd party libraries are used.
|
||||||
* Uses PostgreSQL everywhere (9.2+)
|
* Uses PostgreSQL everywhere (9.4 - 11.3)
|
||||||
* Environment variables for configuration (This won't work with Apache/mod_wsgi except on AWS ELB).
|
* Environment variables for configuration (This won't work with Apache/mod_wsgi).
|
||||||
|
|
||||||
Support this Project!
|
Support this Project!
|
||||||
----------------------
|
----------------------
|
||||||
|
@ -106,7 +108,7 @@ Projects that provide financial support to the maintainers:
|
||||||
Two Scoops of Django 1.11
|
Two Scoops of Django 1.11
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
.. image:: https://cdn.shopify.com/s/files/1/0304/6901/products/tsd-111-alpha_medium.jpg?v=1499531513
|
.. image:: https://cdn.shopify.com/s/files/1/0304/6901/products/2017-06-29-tsd11-sticker-02.png
|
||||||
: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
|
||||||
|
@ -155,7 +157,7 @@ Answer the prompts with your own desired options_. For example::
|
||||||
project_slug [reddit_clone]: reddit
|
project_slug [reddit_clone]: reddit
|
||||||
author_name [Daniel Roy Greenfeld]: Daniel Greenfeld
|
author_name [Daniel Roy Greenfeld]: Daniel Greenfeld
|
||||||
email [you@example.com]: pydanny@gmail.com
|
email [you@example.com]: pydanny@gmail.com
|
||||||
description [A short description of the project.]: A reddit clone.
|
description [Behold My Awesome Project!]: A reddit clone.
|
||||||
domain_name [example.com]: myreddit.com
|
domain_name [example.com]: myreddit.com
|
||||||
version [0.1.0]: 0.0.1
|
version [0.1.0]: 0.0.1
|
||||||
timezone [UTC]: America/Los_Angeles
|
timezone [UTC]: America/Los_Angeles
|
||||||
|
@ -169,18 +171,21 @@ 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.3
|
1 - 11.3
|
||||||
2 - 10.2
|
2 - 10.8
|
||||||
3 - 10.1
|
3 - 9.6
|
||||||
4 - 9.6
|
4 - 9.5
|
||||||
5 - 9.5
|
5 - 9.4
|
||||||
6 - 9.4
|
Choose from 1, 2, 3, 4, 5 [1]: 1
|
||||||
7 - 9.3
|
|
||||||
Choose from 1, 2, 3, 4 [1]: 1
|
|
||||||
Select js_task_runner:
|
Select js_task_runner:
|
||||||
1 - None
|
1 - None
|
||||||
2 - Gulp
|
2 - Gulp
|
||||||
Choose from 1, 2 [1]: 1
|
Choose from 1, 2 [1]: 1
|
||||||
|
Select cloud_provider:
|
||||||
|
1 - AWS
|
||||||
|
2 - GCP
|
||||||
|
3 - None
|
||||||
|
Choose from 1, 2, 3 [1]: 1
|
||||||
custom_bootstrap_compilation [n]: n
|
custom_bootstrap_compilation [n]: n
|
||||||
Select open_source_license:
|
Select open_source_license:
|
||||||
1 - MIT
|
1 - MIT
|
||||||
|
@ -221,11 +226,11 @@ Community
|
||||||
|
|
||||||
* Have questions? **Before you ask questions anywhere else**, please post your question on `Stack Overflow`_ under the *cookiecutter-django* tag. We check there periodically for questions.
|
* Have questions? **Before you ask questions anywhere else**, please post your question on `Stack Overflow`_ under the *cookiecutter-django* tag. We check there periodically for questions.
|
||||||
* If you think you found a bug or want to request a feature, please open an issue_.
|
* If you think you found a bug or want to request a feature, please open an issue_.
|
||||||
* For anything else, you can chat with us on `Gitter`_.
|
* For anything else, you can chat with us on `Slack`_.
|
||||||
|
|
||||||
.. _`Stack Overflow`: http://stackoverflow.com/questions/tagged/cookiecutter-django
|
.. _`Stack Overflow`: http://stackoverflow.com/questions/tagged/cookiecutter-django
|
||||||
.. _`issue`: https://github.com/pydanny/cookiecutter-django/issues
|
.. _`issue`: https://github.com/pydanny/cookiecutter-django/issues
|
||||||
.. _`Gitter`: https://gitter.im/pydanny/cookiecutter-django?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
|
.. _`Slack`: https://join.slack.com/t/cookie-cutter/shared_invite/enQtNzI0Mzg5NjE5Nzk5LTRlYWI2YTZhYmQ4YmU1Y2Q2NmE1ZjkwOGM0NDQyNTIwY2M4ZTgyNDVkNjMxMDdhZGI5ZGE5YmJjM2M3ODJlY2U
|
||||||
|
|
||||||
For Readers of Two Scoops of Django
|
For Readers of Two Scoops of Django
|
||||||
--------------------------------------------
|
--------------------------------------------
|
||||||
|
|
|
@ -18,20 +18,22 @@
|
||||||
"use_pycharm": "n",
|
"use_pycharm": "n",
|
||||||
"use_docker": "n",
|
"use_docker": "n",
|
||||||
"postgresql_version": [
|
"postgresql_version": [
|
||||||
"10.5",
|
"11.3",
|
||||||
"10.4",
|
"10.8",
|
||||||
"10.3",
|
|
||||||
"10.2",
|
|
||||||
"10.1",
|
|
||||||
"9.6",
|
"9.6",
|
||||||
"9.5",
|
"9.5",
|
||||||
"9.4",
|
"9.4"
|
||||||
"9.3"
|
|
||||||
],
|
],
|
||||||
"js_task_runner": [
|
"js_task_runner": [
|
||||||
"None",
|
"None",
|
||||||
"Gulp"
|
"Gulp"
|
||||||
],
|
],
|
||||||
|
"cloud_provider": [
|
||||||
|
"AWS",
|
||||||
|
"GCP",
|
||||||
|
"None"
|
||||||
|
],
|
||||||
|
"use_drf": "n",
|
||||||
"custom_bootstrap_compilation": "n",
|
"custom_bootstrap_compilation": "n",
|
||||||
"use_compressor": "n",
|
"use_compressor": "n",
|
||||||
"use_celery": "n",
|
"use_celery": "n",
|
||||||
|
@ -39,7 +41,11 @@
|
||||||
"use_sentry": "n",
|
"use_sentry": "n",
|
||||||
"use_whitenoise": "n",
|
"use_whitenoise": "n",
|
||||||
"use_heroku": "n",
|
"use_heroku": "n",
|
||||||
"use_travisci": "n",
|
"ci_tool": [
|
||||||
|
"None",
|
||||||
|
"Travis",
|
||||||
|
"Gitlab"
|
||||||
|
],
|
||||||
"keep_local_envs_in_vcs": "y",
|
"keep_local_envs_in_vcs": "y",
|
||||||
|
|
||||||
"debug": "n"
|
"debug": "n"
|
||||||
|
|
|
@ -42,7 +42,7 @@ master_doc = "index"
|
||||||
|
|
||||||
# General information about the project.
|
# General information about the project.
|
||||||
project = "Cookiecutter Django"
|
project = "Cookiecutter Django"
|
||||||
copyright = "2013-2018, Daniel Roy Greenfeld".format(now.year)
|
copyright = "2013-{}, Daniel Roy Greenfeld".format(now.year)
|
||||||
|
|
||||||
# The version info for the project you're documenting, acts as replacement for
|
# The version info for the project you're documenting, acts as replacement for
|
||||||
# |version| and |release|, also used in various other places throughout the
|
# |version| and |release|, also used in various other places throughout the
|
||||||
|
|
|
@ -3,6 +3,9 @@ Deployment on Heroku
|
||||||
|
|
||||||
.. index:: Heroku
|
.. index:: Heroku
|
||||||
|
|
||||||
|
Commands to run
|
||||||
|
---------------
|
||||||
|
|
||||||
Run these commands to deploy the project to Heroku:
|
Run these commands to deploy the project to Heroku:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
@ -17,11 +20,8 @@ Run these commands to deploy the project to Heroku:
|
||||||
|
|
||||||
heroku addons:create heroku-redis:hobby-dev
|
heroku addons:create heroku-redis:hobby-dev
|
||||||
|
|
||||||
# If using mailgun:
|
|
||||||
heroku addons:create mailgun:starter
|
heroku addons:create mailgun:starter
|
||||||
|
|
||||||
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
|
||||||
|
@ -30,7 +30,7 @@ Run these commands to deploy the project to Heroku:
|
||||||
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 similar characters "IOl01":
|
||||||
heroku config:set DJANGO_ADMIN_URL="$(openssl rand -base64 4096 | tr -dc 'A-HJ-NP-Za-km-z2-9' | head -c 32)/"
|
heroku config:set DJANGO_ADMIN_URL="$(openssl rand -base64 4096 | tr -dc 'A-HJ-NP-Za-km-z2-9' | head -c 32)/"
|
||||||
|
|
||||||
# Set this to your Heroku app url, e.g. 'bionic-beaver-28392.herokuapp.com'
|
# Set this to your Heroku app url, e.g. 'bionic-beaver-28392.herokuapp.com'
|
||||||
|
@ -52,3 +52,70 @@ Run these commands to deploy the project to Heroku:
|
||||||
heroku run python manage.py check --deploy
|
heroku run python manage.py check --deploy
|
||||||
|
|
||||||
heroku open
|
heroku open
|
||||||
|
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
.. include:: mailgun.rst
|
||||||
|
|
||||||
|
|
||||||
|
Optional actions
|
||||||
|
----------------
|
||||||
|
|
||||||
|
Celery
|
||||||
|
++++++
|
||||||
|
|
||||||
|
Celery requires a few extra environment variables to be ready operational. Also, the worker is created,
|
||||||
|
it's in the ``Procfile``, but is turned off by default:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
# Set the broker URL to Redis
|
||||||
|
heroku config:set CELERY_BROKER_URL=`heroku config:get REDIS_URL`
|
||||||
|
# Scale dyno to 1 instance
|
||||||
|
heroku ps:scale worker=1
|
||||||
|
|
||||||
|
Sentry
|
||||||
|
++++++
|
||||||
|
|
||||||
|
If you're opted for Sentry error tracking, you can either install it through the `Sentry add-on`_:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
heroku addons:create sentry:f1
|
||||||
|
|
||||||
|
|
||||||
|
Or add the DSN for your account, if you already have one:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
heroku config:set SENTRY_DSN=https://xxxx@sentry.io/12345
|
||||||
|
|
||||||
|
.. _Sentry add-on: https://elements.heroku.com/addons/sentry
|
||||||
|
|
||||||
|
|
||||||
|
Gulp & Bootstrap compilation
|
||||||
|
++++++++++++++++++++++++++++
|
||||||
|
|
||||||
|
If you've opted for a custom bootstrap build, you'll most likely need to setup
|
||||||
|
your app to use `multiple buildpacks`_: one for Python & one for Node.js:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
heroku buildpacks:add --index 1 heroku/nodejs
|
||||||
|
|
||||||
|
At time of writing, this should do the trick: during deployment,
|
||||||
|
the Heroku should run ``npm install`` and then ``npm build``,
|
||||||
|
which runs Gulp in cookiecutter-django.
|
||||||
|
|
||||||
|
If things don't work, please refer to the Heroku docs.
|
||||||
|
|
||||||
|
.. _multiple buildpacks: https://devcenter.heroku.com/articles/using-multiple-buildpacks-for-an-app
|
||||||
|
|
||||||
|
About Heroku & Docker
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
Although Heroku has some sort of `Docker support`_, it's not supported by cookiecutter-django.
|
||||||
|
We invite you to follow Heroku documentation about it.
|
||||||
|
|
||||||
|
.. _Docker support: https://devcenter.heroku.com/articles/build-docker-images-heroku-yml
|
||||||
|
|
|
@ -29,13 +29,13 @@ Once you've been through this one-off config, future deployments are much simple
|
||||||
Getting your code and dependencies installed on PythonAnywhere
|
Getting your code and dependencies installed on PythonAnywhere
|
||||||
--------------------------------------------------------------
|
--------------------------------------------------------------
|
||||||
|
|
||||||
Make sure your project is fully commited and pushed up to Bitbucket or Github or wherever it may be. Then, log into your PythonAnywhere account, open up a **Bash** console, clone your repo, and create a virtualenv:
|
Make sure your project is fully committed and pushed up to Bitbucket or Github or wherever it may be. Then, log into your PythonAnywhere account, open up a **Bash** console, clone your repo, and create a virtualenv:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
git clone <my-repo-url> # you can also use hg
|
git clone <my-repo-url> # you can also use hg
|
||||||
cd my-project-name
|
cd my-project-name
|
||||||
mkvirtualenv --python=/usr/bin/python3.6 my-project-name
|
mkvirtualenv --python=/usr/bin/python3.7 my-project-name
|
||||||
pip install -r requirements/production.txt # may take a few minutes
|
pip install -r requirements/production.txt # may take a few minutes
|
||||||
|
|
||||||
|
|
||||||
|
@ -153,7 +153,7 @@ Back on the Web tab, hit **Reload**, and your app should be live!
|
||||||
|
|
||||||
|
|
||||||
**NOTE:** *you may see security warnings until you set up your SSL certificates. If you
|
**NOTE:** *you may see security warnings until you set up your SSL certificates. If you
|
||||||
want to supress them temporarily, set DJANGO_SECURE_SSL_REDIRECT to blank. Follow
|
want to suppress them temporarily, set DJANGO_SECURE_SSL_REDIRECT to blank. Follow
|
||||||
the instructions here to get SSL set up: https://help.pythonanywhere.com/pages/SSLOwnDomains/*
|
the instructions here to get SSL set up: https://help.pythonanywhere.com/pages/SSLOwnDomains/*
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,8 @@ Deployment with Docker
|
||||||
Prerequisites
|
Prerequisites
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
* Docker 1.10+.
|
* Docker 17.05+.
|
||||||
* Docker Compose 1.6+
|
* Docker Compose 1.17+
|
||||||
|
|
||||||
|
|
||||||
Understanding the Docker Compose Setup
|
Understanding the Docker Compose Setup
|
||||||
|
@ -19,7 +19,7 @@ Before you begin, check out the ``production.yml`` file in the root of this proj
|
||||||
* ``django``: your application running behind ``Gunicorn``;
|
* ``django``: your application running behind ``Gunicorn``;
|
||||||
* ``postgres``: PostgreSQL database with the application's relational data;
|
* ``postgres``: PostgreSQL database with the application's relational data;
|
||||||
* ``redis``: Redis instance for caching;
|
* ``redis``: Redis instance for caching;
|
||||||
* ``caddy``: Caddy web server with HTTPS on by default.
|
* ``traefik``: Traefik reverse proxy with HTTPS on by default.
|
||||||
|
|
||||||
Provided you have opted for Celery (via setting ``use_celery`` to ``y``) there are three more services:
|
Provided you have opted for Celery (via setting ``use_celery`` to ``y``) there are three more services:
|
||||||
|
|
||||||
|
@ -35,7 +35,15 @@ Configuring the Stack
|
||||||
|
|
||||||
The majority of services above are configured through the use of environment variables. Just check out :ref:`envs` and you will know the drill.
|
The majority of services above are configured through the use of environment variables. Just check out :ref:`envs` and you will know the drill.
|
||||||
|
|
||||||
To obtain logs and information about crashes in a production setup, make sure that you have access to an external Sentry instance (e.g. by creating an account with `sentry.io`_), and set the ``SENTRY_DSN`` variable.
|
To obtain logs and information about crashes in a production setup, make sure that you have access to an external Sentry instance (e.g. by creating an account with `sentry.io`_), and set the ``SENTRY_DSN`` variable. Logs of level `logging.ERROR` are sent as Sentry events. Therefore, in order to send a Sentry event use:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
import logging
|
||||||
|
logging.error("This event is sent to Sentry", extra={"<example_key>": "<example_value>"})
|
||||||
|
|
||||||
|
The `extra` parameter allows you to send additional information about the context of this error.
|
||||||
|
|
||||||
|
|
||||||
You will probably also need to setup the Mail backend, for example by adding a `Mailgun`_ API key and a `Mailgun`_ sender domain, otherwise, the account creation view will crash and result in a 500 error when the backend attempts to send an email to the account owner.
|
You will probably also need to setup the Mail backend, for example by adding a `Mailgun`_ API key and a `Mailgun`_ sender domain, otherwise, the account creation view will crash and result in a 500 error when the backend attempts to send an email to the account owner.
|
||||||
|
|
||||||
|
@ -43,6 +51,11 @@ You will probably also need to setup the Mail backend, for example by adding a `
|
||||||
.. _Mailgun: https://mailgun.com
|
.. _Mailgun: https://mailgun.com
|
||||||
|
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
.. include:: mailgun.rst
|
||||||
|
|
||||||
|
|
||||||
Optional: Use AWS IAM Role for EC2 instance
|
Optional: Use AWS IAM Role for EC2 instance
|
||||||
-------------------------------------------
|
-------------------------------------------
|
||||||
|
|
||||||
|
@ -63,11 +76,11 @@ It is always better to deploy a site behind HTTPS and will become crucial as the
|
||||||
|
|
||||||
* 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*.
|
||||||
|
|
||||||
The Caddy web server used in the default configuration will get you a valid certificate from Lets Encrypt and update it automatically. All you need to do to enable this is to make sure that your DNS records are pointing to the server Caddy runs on.
|
The Traefik reverse proxy used in the default configuration will get you a valid certificate from Lets Encrypt and update it automatically. All you need to do to enable this is to make sure that your DNS records are pointing to the server Traefik runs on.
|
||||||
|
|
||||||
You can read more about this here at `Automatic HTTPS`_ in the Caddy docs.
|
You can read more about this feature and how to configure it, at `Automatic HTTPS`_ in the Traefik docs.
|
||||||
|
|
||||||
.. _Automatic HTTPS: https://caddyserver.com/docs/automatic-https
|
.. _Automatic HTTPS: https://docs.traefik.io/configuration/acme/
|
||||||
|
|
||||||
|
|
||||||
(Optional) Postgres Data Volume Modifications
|
(Optional) Postgres Data Volume Modifications
|
||||||
|
@ -112,7 +125,7 @@ If you want to scale your application, run::
|
||||||
docker-compose -f production.yml scale django=4
|
docker-compose -f production.yml scale django=4
|
||||||
docker-compose -f production.yml scale celeryworker=2
|
docker-compose -f production.yml scale celeryworker=2
|
||||||
|
|
||||||
.. warning:: don't try to scale ``postgres``, ``celerybeat``, or ``caddy``.
|
.. warning:: don't try to scale ``postgres``, ``celerybeat``, or ``traefik``.
|
||||||
|
|
||||||
To see how your containers are doing run::
|
To see how your containers are doing run::
|
||||||
|
|
||||||
|
@ -139,8 +152,10 @@ If you are using ``supervisor``, you can use this file as a starting point::
|
||||||
Move it to ``/etc/supervisor/conf.d/{{cookiecutter.project_slug}}.conf`` and run::
|
Move it to ``/etc/supervisor/conf.d/{{cookiecutter.project_slug}}.conf`` and run::
|
||||||
|
|
||||||
supervisorctl reread
|
supervisorctl reread
|
||||||
|
supervisorctl update
|
||||||
supervisorctl start {{cookiecutter.project_slug}}
|
supervisorctl start {{cookiecutter.project_slug}}
|
||||||
|
|
||||||
For status check, run::
|
For status check, run::
|
||||||
|
|
||||||
supervisorctl status
|
supervisorctl status
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,12 @@ Getting Up and Running Locally With Docker
|
||||||
The steps below will get you up and running with a local development environment.
|
The steps below will get you up and running with a local development environment.
|
||||||
All of these commands assume you are in the root of your generated project.
|
All of these commands assume you are in the root of your generated project.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
If you're new to Docker, please be aware that some resources are cached system-wide
|
||||||
|
and might reappear if you generate a project multiple times with the same name (e.g.
|
||||||
|
:ref:`this issue with Postgres <docker-postgres-auth-failed>`).
|
||||||
|
|
||||||
|
|
||||||
Prerequisites
|
Prerequisites
|
||||||
-------------
|
-------------
|
||||||
|
@ -17,17 +23,6 @@ Prerequisites
|
||||||
.. _`installation guide`: https://docs.docker.com/compose/install/
|
.. _`installation guide`: https://docs.docker.com/compose/install/
|
||||||
|
|
||||||
|
|
||||||
Attention, Windows Users
|
|
||||||
------------------------
|
|
||||||
|
|
||||||
Currently PostgreSQL (``psycopg2`` python package) is not installed inside Docker containers for Windows users, while it is required by the generated Django project. To fix this, add ``psycopg2`` to the list of requirements inside ``requirements/base.txt``::
|
|
||||||
|
|
||||||
# Python-PostgreSQL Database Adapter
|
|
||||||
psycopg2==2.6.2
|
|
||||||
|
|
||||||
Doing this will prevent the project from being installed in an Windows-only environment (thus without usage of Docker). If you want to use this project without Docker, make sure to remove ``psycopg2`` from the requirements again.
|
|
||||||
|
|
||||||
|
|
||||||
Build the Stack
|
Build the Stack
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
|
@ -105,7 +100,6 @@ The most important thing for us here now is ``env_file`` section enlisting ``./.
|
||||||
│ ├── .django
|
│ ├── .django
|
||||||
│ └── .postgres
|
│ └── .postgres
|
||||||
└── .production
|
└── .production
|
||||||
├── .caddy
|
|
||||||
├── .django
|
├── .django
|
||||||
└── .postgres
|
└── .postgres
|
||||||
|
|
||||||
|
@ -120,7 +114,7 @@ Consider the aforementioned ``.envs/.local/.postgres``: ::
|
||||||
POSTGRES_USER=XgOWtQtJecsAbaIyslwGvFvPawftNaqO
|
POSTGRES_USER=XgOWtQtJecsAbaIyslwGvFvPawftNaqO
|
||||||
POSTGRES_PASSWORD=jSljDz4whHuwO3aJIgVBrqEml5Ycbghorep4uVJ4xjDYQu0LfuTZdctj7y0YcCLu
|
POSTGRES_PASSWORD=jSljDz4whHuwO3aJIgVBrqEml5Ycbghorep4uVJ4xjDYQu0LfuTZdctj7y0YcCLu
|
||||||
|
|
||||||
The three envs we are presented with here are ``POSTGRES_DB``, ``POSTGRES_USER``, and ``POSTGRES_PASSWORD`` (by the way, their values have also been generated for you). You might have figured out already where these definitions will end up; it's all the same with ``django`` and ``caddy`` service container envs.
|
The three envs we are presented with here are ``POSTGRES_DB``, ``POSTGRES_USER``, and ``POSTGRES_PASSWORD`` (by the way, their values have also been generated for you). You might have figured out already where these definitions will end up; it's all the same with ``django`` service container envs.
|
||||||
|
|
||||||
One final touch: should you ever need to merge ``.envs/production/*`` in a single ``.env`` run the ``merge_production_dotenvs_in_dotenv.py``: ::
|
One final touch: should you ever need to merge ``.envs/production/*`` in a single ``.env`` run the ``merge_production_dotenvs_in_dotenv.py``: ::
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ Setting Up Development Environment
|
||||||
|
|
||||||
Make sure to have the following on your host:
|
Make sure to have the following on your host:
|
||||||
|
|
||||||
* Python 3.6
|
* Python 3.7
|
||||||
* PostgreSQL_.
|
* PostgreSQL_.
|
||||||
* Redis_, if using Celery
|
* Redis_, if using Celery
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ First things first.
|
||||||
|
|
||||||
#. Create a virtualenv: ::
|
#. Create a virtualenv: ::
|
||||||
|
|
||||||
$ python3.6 -m venv <virtual env path>
|
$ python3.7 -m venv <virtual env path>
|
||||||
|
|
||||||
#. Activate the virtualenv you have just created: ::
|
#. Activate the virtualenv you have just created: ::
|
||||||
|
|
||||||
|
@ -26,6 +26,12 @@ First things first.
|
||||||
#. Install development requirements: ::
|
#. Install development requirements: ::
|
||||||
|
|
||||||
$ pip install -r requirements/local.txt
|
$ pip install -r requirements/local.txt
|
||||||
|
$ pre-commit install
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
the `pre-commit` exists in the generated project as default.
|
||||||
|
for the details of `pre-commit`, follow the [site of pre-commit](https://pre-commit.com/).
|
||||||
|
|
||||||
#. Create a new PostgreSQL database using createdb_: ::
|
#. Create a new PostgreSQL database using createdb_: ::
|
||||||
|
|
||||||
|
@ -120,12 +126,12 @@ In production, we have Mailgun_ configured to have your back!
|
||||||
|
|
||||||
Celery
|
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
|
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
|
when developing locally. If you have the appropriate setup on your local machine then set the following
|
||||||
|
in ``config/settings/local.py``::
|
||||||
|
|
||||||
CELERY_TASK_ALWAYS_EAGER = False
|
CELERY_TASK_ALWAYS_EAGER = False
|
||||||
|
|
||||||
in /config/settings/local.py
|
|
||||||
|
|
||||||
|
|
||||||
Sass Compilation & Live Reloading
|
Sass Compilation & Live Reloading
|
||||||
|
|
|
@ -85,3 +85,11 @@ You will see something like ::
|
||||||
# ...
|
# ...
|
||||||
ALTER TABLE
|
ALTER TABLE
|
||||||
SUCCESS: The 'my_project' database has been restored from the '/backups/backup_2018_03_13T09_05_07.sql.gz' backup.
|
SUCCESS: The 'my_project' database has been restored from the '/backups/backup_2018_03_13T09_05_07.sql.gz' backup.
|
||||||
|
|
||||||
|
|
||||||
|
Backup to Amazon S3
|
||||||
|
----------------------------------
|
||||||
|
For uploading your backups to Amazon S3 you can use the aws cli container. There is an upload command for uploading the postgres /backups directory recursively and there is a download command for downloading a specific backup. The default S3 environment variables are used. ::
|
||||||
|
|
||||||
|
$ docker-compose -f production.yml run --rm awscli upload
|
||||||
|
$ docker-compose -f production.yml run --rm awscli download backup_2018_03_13T09_05_07.sql.gz
|
||||||
|
|
45
docs/document.rst
Normal file
45
docs/document.rst
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
.. _document:
|
||||||
|
|
||||||
|
Document
|
||||||
|
=========
|
||||||
|
|
||||||
|
This project uses Sphinx_ documentation generator.
|
||||||
|
After you have set up to `develop locally`_, run the following commands to generate the HTML documentation: ::
|
||||||
|
|
||||||
|
$ sphinx-build docs/ docs/_build/html/
|
||||||
|
|
||||||
|
If you set up your project to `develop locally with docker`_, run the following command: ::
|
||||||
|
|
||||||
|
$ docker-compose -f local.yml run --rm django sphinx-build docs/ docs/_build/html/
|
||||||
|
|
||||||
|
Generate API documentation
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
Sphinx can automatically generate documentation from docstrings, to enable this feature, follow these steps:
|
||||||
|
|
||||||
|
1. Add Sphinx extension in ``docs/conf.py`` file, like below: ::
|
||||||
|
|
||||||
|
extensions = [
|
||||||
|
'sphinx.ext.autodoc',
|
||||||
|
]
|
||||||
|
|
||||||
|
2. Uncomment the following lines in the ``docs/conf.py`` file: ::
|
||||||
|
|
||||||
|
# import django
|
||||||
|
# sys.path.insert(0, os.path.abspath('..'))
|
||||||
|
# os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.local")
|
||||||
|
# django.setup()
|
||||||
|
|
||||||
|
3. Run the following command: ::
|
||||||
|
|
||||||
|
$ sphinx-apidoc -f -o ./docs/modules/ ./tpub/ migrations/*
|
||||||
|
|
||||||
|
If you set up your project to `develop locally with docker`_, run the following command: ::
|
||||||
|
|
||||||
|
$ docker-compose -f local.yml run --rm django sphinx-apidoc -f -o ./docs/modules ./tpub/ migrations/*
|
||||||
|
|
||||||
|
4. Regenerate HTML documentation as written above.
|
||||||
|
|
||||||
|
.. _Sphinx: https://www.sphinx-doc.org/en/master/index.html
|
||||||
|
.. _develop locally: ./developing-locally.html
|
||||||
|
.. _develop locally with docker: ./developing-locally-docker.html
|
|
@ -18,6 +18,7 @@ Contents:
|
||||||
settings
|
settings
|
||||||
linters
|
linters
|
||||||
testing
|
testing
|
||||||
|
document
|
||||||
deployment-on-pythonanywhere
|
deployment-on-pythonanywhere
|
||||||
deployment-on-heroku
|
deployment-on-heroku
|
||||||
deployment-with-docker
|
deployment-with-docker
|
||||||
|
|
|
@ -25,7 +25,7 @@ This is included in flake8's checks, but you can also run it separately to see a
|
||||||
|
|
||||||
The config for pylint is located in .pylintrc. It specifies:
|
The config for pylint is located in .pylintrc. It specifies:
|
||||||
|
|
||||||
* Use the pylint_common and pylint_django plugins. If using Celery, also use pylint_celery.
|
* Use the pylint_django plugin. If using Celery, also use pylint_celery.
|
||||||
* Set max line length to 120 chars
|
* Set max line length to 120 chars
|
||||||
* Disable linting messages for missing docstring and invalid name
|
* Disable linting messages for missing docstring and invalid name
|
||||||
* max-parents=13
|
* max-parents=13
|
||||||
|
|
13
docs/mailgun.rst
Normal file
13
docs/mailgun.rst
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
If your email server used to send email isn't configured properly (Mailgun by default),
|
||||||
|
attempting to send an email will cause an Internal Server Error.
|
||||||
|
|
||||||
|
By default, django-allauth is setup to `have emails verifications mandatory`_,
|
||||||
|
which means it'll send a verification email when an unverified user tries to
|
||||||
|
log-in or when someone tries to sign-up.
|
||||||
|
|
||||||
|
This may happen just after you've setup your Mailgun account, which is running in a
|
||||||
|
sandbox subdomain by default. Either add your email to the list of authorized recipients
|
||||||
|
or verify your domain.
|
||||||
|
|
||||||
|
|
||||||
|
.. _have emails verifications mandatory: https://django-allauth.readthedocs.io/en/latest/configuration.html?highlight=ACCOUNT_EMAIL_VERIFICATION
|
|
@ -49,13 +49,11 @@ use_docker:
|
||||||
postgresql_version:
|
postgresql_version:
|
||||||
Select a PostgreSQL_ version to use. The choices are:
|
Select a PostgreSQL_ version to use. The choices are:
|
||||||
|
|
||||||
1. 10.3
|
1. 11.3
|
||||||
2. 10.2
|
2. 10.8
|
||||||
3. 10.1
|
3. 9.6
|
||||||
4. 9.6
|
4. 9.5
|
||||||
5. 9.5
|
5. 9.4
|
||||||
6. 9.4
|
|
||||||
7. 9.3
|
|
||||||
|
|
||||||
js_task_runner:
|
js_task_runner:
|
||||||
Select a JavaScript task runner. The choices are:
|
Select a JavaScript task runner. The choices are:
|
||||||
|
@ -63,6 +61,15 @@ js_task_runner:
|
||||||
1. None
|
1. None
|
||||||
2. Gulp_
|
2. Gulp_
|
||||||
|
|
||||||
|
cloud_provider:
|
||||||
|
Select a cloud provider for static & media files. The choices are:
|
||||||
|
|
||||||
|
1. AWS_
|
||||||
|
2. GCP_
|
||||||
|
3. None
|
||||||
|
|
||||||
|
Note that if you choose no cloud provider, media files won't work.
|
||||||
|
|
||||||
custom_bootstrap_compilation:
|
custom_bootstrap_compilation:
|
||||||
Indicates whether the project should support Bootstrap recompilation
|
Indicates whether the project should support Bootstrap recompilation
|
||||||
via the selected JavaScript task runner's task. This can be useful
|
via the selected JavaScript task runner's task. This can be useful
|
||||||
|
@ -87,8 +94,12 @@ use_heroku:
|
||||||
Indicates whether the project should be configured so as to be deployable
|
Indicates whether the project should be configured so as to be deployable
|
||||||
to Heroku_.
|
to Heroku_.
|
||||||
|
|
||||||
use_travisci:
|
ci_tool:
|
||||||
Indicates whether the project should be configured to use `Travis CI`_.
|
Select a CI tool for running tests. The choices are:
|
||||||
|
|
||||||
|
1. None
|
||||||
|
2. Travis_
|
||||||
|
3. Gitlab_
|
||||||
|
|
||||||
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
|
||||||
|
@ -115,6 +126,9 @@ debug:
|
||||||
|
|
||||||
.. _Gulp: https://github.com/gulpjs/gulp
|
.. _Gulp: https://github.com/gulpjs/gulp
|
||||||
|
|
||||||
|
.. _AWS: https://aws.amazon.com/s3/
|
||||||
|
.. _GCP: https://cloud.google.com/storage/
|
||||||
|
|
||||||
.. _Django Compressor: https://github.com/django-compressor/django-compressor
|
.. _Django Compressor: https://github.com/django-compressor/django-compressor
|
||||||
|
|
||||||
.. _Celery: https://github.com/celery/celery
|
.. _Celery: https://github.com/celery/celery
|
||||||
|
@ -128,3 +142,6 @@ debug:
|
||||||
.. _Heroku: https://github.com/heroku/heroku-buildpack-python
|
.. _Heroku: https://github.com/heroku/heroku-buildpack-python
|
||||||
|
|
||||||
.. _Travis CI: https://travis-ci.org/
|
.. _Travis CI: https://travis-ci.org/
|
||||||
|
|
||||||
|
.. _GitLab CI: https://docs.gitlab.com/ee/ci/
|
||||||
|
|
||||||
|
|
|
@ -44,11 +44,14 @@ CELERY_BROKER_URL CELERY_BROKER_URL auto w/ Dock
|
||||||
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
|
||||||
|
DJANGO_AWS_S3_REGION_NAME AWS_S3_REGION_NAME n/a None
|
||||||
|
DJANGO_GCP_STORAGE_BUCKET_NAME GS_BUCKET_NAME n/a raises error
|
||||||
|
GOOGLE_APPLICATION_CREDENTIALS n/a n/a raises error
|
||||||
SENTRY_DSN SENTRY_DSN n/a raises error
|
SENTRY_DSN SENTRY_DSN n/a raises error
|
||||||
DJANGO_SENTRY_CLIENT SENTRY_CLIENT n/a raven.contrib.django.raven_compat.DjangoClient
|
|
||||||
DJANGO_SENTRY_LOG_LEVEL SENTRY_LOG_LEVEL n/a logging.INFO
|
DJANGO_SENTRY_LOG_LEVEL SENTRY_LOG_LEVEL n/a logging.INFO
|
||||||
MAILGUN_API_KEY MAILGUN_ACCESS_KEY n/a raises error
|
MAILGUN_API_KEY MAILGUN_API_KEY n/a raises error
|
||||||
MAILGUN_DOMAIN MAILGUN_SENDER_DOMAIN n/a raises error
|
MAILGUN_DOMAIN MAILGUN_SENDER_DOMAIN n/a raises error
|
||||||
|
MAILGUN_API_URL n/a n/a "https://api.mailgun.net/v3"
|
||||||
======================================= =========================== ============================================== ======================================================================
|
======================================= =========================== ============================================== ======================================================================
|
||||||
|
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
|
@ -19,20 +19,20 @@ You will get a readout of the `users` app that has already been set up with test
|
||||||
|
|
||||||
If you set up your project to `develop locally with docker`_, run the following command: ::
|
If you set up your project to `develop locally with docker`_, run the following command: ::
|
||||||
|
|
||||||
$ docker-compose -f local.yml run django pytest
|
$ docker-compose -f local.yml run --rm django pytest
|
||||||
|
|
||||||
Targetting particular apps for testing in ``docker`` follows a similar pattern as previously shown above.
|
Targeting particular apps for testing in ``docker`` follows a similar pattern as previously shown above.
|
||||||
|
|
||||||
Coverage
|
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: ::
|
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
|
$ docker-compose -f local.yml run --rm django coverage run -m pytest
|
||||||
|
|
||||||
Once the tests are complete, in order to see the code coverage, run the following command: ::
|
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
|
$ docker-compose -f local.yml run --rm django coverage report
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
|
@ -49,8 +49,8 @@ Once the tests are complete, in order to see the code coverage, run the followin
|
||||||
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.
|
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
|
.. _Pytest: https://docs.pytest.org/en/latest/example/simple.html
|
||||||
.. _develop locally: ../developing-locally.rst
|
.. _develop locally: ./developing-locally.html
|
||||||
.. _develop locally with docker: ..../developing-locally-docker.rst
|
.. _develop locally with docker: ./developing-locally-docker.html
|
||||||
.. _customize: https://docs.pytest.org/en/latest/customize.html
|
.. _customize: https://docs.pytest.org/en/latest/customize.html
|
||||||
.. _unittest: https://docs.python.org/3/library/unittest.html#module-unittest
|
.. _unittest: https://docs.python.org/3/library/unittest.html#module-unittest
|
||||||
.. _configuring: https://coverage.readthedocs.io/en/v4.5.x/config.html
|
.. _configuring: https://coverage.readthedocs.io/en/v4.5.x/config.html
|
|
@ -3,12 +3,48 @@ Troubleshooting
|
||||||
|
|
||||||
This page contains some advice about errors and problems commonly encountered during the development of Cookiecutter Django applications.
|
This page contains some advice about errors and problems commonly encountered during the development of Cookiecutter Django applications.
|
||||||
|
|
||||||
|
Server Error on sign-up/log-in
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
Make sure you have configured the mail backend (e.g. Mailgun) by adding the API key and sender domain
|
||||||
|
|
||||||
|
.. include:: mailgun.rst
|
||||||
|
|
||||||
|
.. _docker-postgres-auth-failed:
|
||||||
|
|
||||||
|
Docker: Postgres authentication failed
|
||||||
|
--------------------------------------
|
||||||
|
|
||||||
|
Examples of logs::
|
||||||
|
|
||||||
|
postgres_1 | 2018-06-07 19:11:23.963 UTC [81] FATAL: password authentication failed for user "pydanny"
|
||||||
|
postgres_1 | 2018-06-07 19:11:23.963 UTC [81] DETAIL: Password does not match for user "pydanny".
|
||||||
|
postgres_1 | Connection matched pg_hba.conf line 95: "host all all all md5"
|
||||||
|
|
||||||
|
If you recreate the project multiple times with the same name, Docker would preserve the volumes for the postgres container between projects. Here is what happens:
|
||||||
|
|
||||||
|
#. You generate the project the first time. The .env postgres file is populated with the random password
|
||||||
|
#. You run the docker-compose and the containers are created. The postgres container creates the database based on the .env file credentials
|
||||||
|
#. You "regenerate" the project with the same name, so the postgres .env file is populated with a new random password
|
||||||
|
#. You run docker-compose. Since the names of the containers are the same, docker will try to start them (not create them from scratch i.e. it won't execute the Dockerfile to recreate the database). When this happens, it tries to start the database based on the new credentials which do not match the ones that the database was created with, and you get the error message above.
|
||||||
|
|
||||||
|
To fix this, you can either:
|
||||||
|
|
||||||
|
- Clear your project-related Docker cache with ``docker-compose -f local.yml down --volumes --rmi all``.
|
||||||
|
- Use the Docker volume sub-commands to find volumes (`ls`_) and remove them (`rm`_).
|
||||||
|
- Use the `prune`_ command to clear system-wide (use with care!).
|
||||||
|
|
||||||
|
.. _ls: https://docs.docker.com/engine/reference/commandline/volume_ls/
|
||||||
|
.. _rm: https://docs.docker.com/engine/reference/commandline/volume_rm/
|
||||||
|
.. _prune: https://docs.docker.com/v17.09/engine/reference/commandline/system_prune/
|
||||||
|
|
||||||
|
Others
|
||||||
|
------
|
||||||
|
|
||||||
#. ``project_slug`` must be a valid Python module name or you will have issues on imports.
|
#. ``project_slug`` must be a valid Python module name or you will have issues on imports.
|
||||||
|
|
||||||
#. ``jinja2.exceptions.TemplateSyntaxError: Encountered unknown tag 'now'.``: please upgrade your cookiecutter version to >= 1.4 (see `#528`_)
|
#. ``jinja2.exceptions.TemplateSyntaxError: Encountered unknown tag 'now'.``: please upgrade your cookiecutter version to >= 1.4 (see `#528`_)
|
||||||
|
|
||||||
#. 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`_)
|
#. 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
|
||||||
|
|
|
@ -32,10 +32,7 @@ DEBUG_VALUE = "debug"
|
||||||
|
|
||||||
|
|
||||||
def remove_open_source_files():
|
def remove_open_source_files():
|
||||||
file_names = [
|
file_names = ["CONTRIBUTORS.txt", "LICENSE"]
|
||||||
"CONTRIBUTORS.txt",
|
|
||||||
"LICENSE",
|
|
||||||
]
|
|
||||||
for file_name in file_names:
|
for file_name in file_names:
|
||||||
os.remove(file_name)
|
os.remove(file_name)
|
||||||
|
|
||||||
|
@ -71,7 +68,10 @@ def remove_utility_files():
|
||||||
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":
|
if (
|
||||||
|
file_name == "requirements.txt"
|
||||||
|
and "{{ cookiecutter.ci_tool }}".lower() == "travis"
|
||||||
|
):
|
||||||
# don't remove the file if we are using travisci but not using heroku
|
# don't remove the file if we are using travisci but not using heroku
|
||||||
continue
|
continue
|
||||||
os.remove(file_name)
|
os.remove(file_name)
|
||||||
|
@ -89,14 +89,26 @@ def remove_packagejson_file():
|
||||||
os.remove(file_name)
|
os.remove(file_name)
|
||||||
|
|
||||||
|
|
||||||
def remove_celery_app():
|
def remove_celery_files():
|
||||||
shutil.rmtree(os.path.join("{{ cookiecutter.project_slug }}", "taskapp"))
|
file_names = [
|
||||||
|
os.path.join("config", "celery_app.py"),
|
||||||
|
os.path.join("{{ cookiecutter.project_slug }}", "users", "tasks.py"),
|
||||||
|
os.path.join(
|
||||||
|
"{{ cookiecutter.project_slug }}", "users", "tests", "test_tasks.py"
|
||||||
|
),
|
||||||
|
]
|
||||||
|
for file_name in file_names:
|
||||||
|
os.remove(file_name)
|
||||||
|
|
||||||
|
|
||||||
def remove_dottravisyml_file():
|
def remove_dottravisyml_file():
|
||||||
os.remove(".travis.yml")
|
os.remove(".travis.yml")
|
||||||
|
|
||||||
|
|
||||||
|
def remove_dotgitlabciyml_file():
|
||||||
|
os.remove(".gitlab-ci.yml")
|
||||||
|
|
||||||
|
|
||||||
def append_to_project_gitignore(path):
|
def append_to_project_gitignore(path):
|
||||||
gitignore_file_path = ".gitignore"
|
gitignore_file_path = ".gitignore"
|
||||||
with open(gitignore_file_path, "a") as gitignore_file:
|
with open(gitignore_file_path, "a") as gitignore_file:
|
||||||
|
@ -183,11 +195,7 @@ def generate_postgres_user(debug=False):
|
||||||
|
|
||||||
|
|
||||||
def set_postgres_user(file_path, value):
|
def set_postgres_user(file_path, value):
|
||||||
postgres_user = set_flag(
|
postgres_user = set_flag(file_path, "!!!SET POSTGRES_USER!!!", value=value)
|
||||||
file_path,
|
|
||||||
"!!!SET POSTGRES_USER!!!",
|
|
||||||
value=value,
|
|
||||||
)
|
|
||||||
return postgres_user
|
return postgres_user
|
||||||
|
|
||||||
|
|
||||||
|
@ -205,9 +213,7 @@ def set_postgres_password(file_path, value=None):
|
||||||
|
|
||||||
def set_celery_flower_user(file_path, value):
|
def set_celery_flower_user(file_path, value):
|
||||||
celery_flower_user = set_flag(
|
celery_flower_user = set_flag(
|
||||||
file_path,
|
file_path, "!!!SET CELERY_FLOWER_USER!!!", value=value
|
||||||
"!!!SET CELERY_FLOWER_USER!!!",
|
|
||||||
value=value,
|
|
||||||
)
|
)
|
||||||
return celery_flower_user
|
return celery_flower_user
|
||||||
|
|
||||||
|
@ -230,11 +236,7 @@ def append_to_gitignore_file(s):
|
||||||
gitignore_file.write(os.linesep)
|
gitignore_file.write(os.linesep)
|
||||||
|
|
||||||
|
|
||||||
def set_flags_in_envs(
|
def set_flags_in_envs(postgres_user, celery_flower_user, debug=False):
|
||||||
postgres_user,
|
|
||||||
celery_flower_user,
|
|
||||||
debug=False,
|
|
||||||
):
|
|
||||||
local_django_envs_path = os.path.join(".envs", ".local", ".django")
|
local_django_envs_path = os.path.join(".envs", ".local", ".django")
|
||||||
production_django_envs_path = os.path.join(".envs", ".production", ".django")
|
production_django_envs_path = os.path.join(".envs", ".production", ".django")
|
||||||
local_postgres_envs_path = os.path.join(".envs", ".local", ".postgres")
|
local_postgres_envs_path = os.path.join(".envs", ".local", ".postgres")
|
||||||
|
@ -244,14 +246,22 @@ def set_flags_in_envs(
|
||||||
set_django_admin_url(production_django_envs_path)
|
set_django_admin_url(production_django_envs_path)
|
||||||
|
|
||||||
set_postgres_user(local_postgres_envs_path, value=postgres_user)
|
set_postgres_user(local_postgres_envs_path, value=postgres_user)
|
||||||
set_postgres_password(local_postgres_envs_path, value=DEBUG_VALUE if debug else None)
|
set_postgres_password(
|
||||||
|
local_postgres_envs_path, value=DEBUG_VALUE if debug else None
|
||||||
|
)
|
||||||
set_postgres_user(production_postgres_envs_path, value=postgres_user)
|
set_postgres_user(production_postgres_envs_path, value=postgres_user)
|
||||||
set_postgres_password(production_postgres_envs_path, value=DEBUG_VALUE if debug else None)
|
set_postgres_password(
|
||||||
|
production_postgres_envs_path, value=DEBUG_VALUE if debug else None
|
||||||
|
)
|
||||||
|
|
||||||
set_celery_flower_user(local_django_envs_path, value=celery_flower_user)
|
set_celery_flower_user(local_django_envs_path, value=celery_flower_user)
|
||||||
set_celery_flower_password(local_django_envs_path, value=DEBUG_VALUE if debug else None)
|
set_celery_flower_password(
|
||||||
|
local_django_envs_path, value=DEBUG_VALUE if debug else None
|
||||||
|
)
|
||||||
set_celery_flower_user(production_django_envs_path, value=celery_flower_user)
|
set_celery_flower_user(production_django_envs_path, value=celery_flower_user)
|
||||||
set_celery_flower_password(production_django_envs_path, value=DEBUG_VALUE if debug else None)
|
set_celery_flower_password(
|
||||||
|
production_django_envs_path, value=DEBUG_VALUE if debug else None
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def set_flags_in_settings_files():
|
def set_flags_in_settings_files():
|
||||||
|
@ -269,6 +279,19 @@ def remove_celery_compose_dirs():
|
||||||
shutil.rmtree(os.path.join("compose", "production", "django", "celery"))
|
shutil.rmtree(os.path.join("compose", "production", "django", "celery"))
|
||||||
|
|
||||||
|
|
||||||
|
def remove_node_dockerfile():
|
||||||
|
shutil.rmtree(os.path.join("compose", "local", "node"))
|
||||||
|
|
||||||
|
|
||||||
|
def remove_aws_dockerfile():
|
||||||
|
shutil.rmtree(os.path.join("compose", "production", "aws"))
|
||||||
|
|
||||||
|
|
||||||
|
def remove_drf_starter_files():
|
||||||
|
os.remove(os.path.join("config", "api_router.py"))
|
||||||
|
shutil.rmtree(os.path.join("{{cookiecutter.project_slug}}", "users", "api"))
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
debug = "{{ cookiecutter.debug }}".lower() == "y"
|
debug = "{{ cookiecutter.debug }}".lower() == "y"
|
||||||
|
|
||||||
|
@ -292,6 +315,12 @@ def main():
|
||||||
else:
|
else:
|
||||||
remove_docker_files()
|
remove_docker_files()
|
||||||
|
|
||||||
|
if (
|
||||||
|
"{{ cookiecutter.use_docker }}".lower() == "y"
|
||||||
|
and "{{ cookiecutter.cloud_provider}}".lower() != "aws"
|
||||||
|
):
|
||||||
|
remove_aws_dockerfile()
|
||||||
|
|
||||||
if "{{ cookiecutter.use_heroku }}".lower() == "n":
|
if "{{ cookiecutter.use_heroku }}".lower() == "n":
|
||||||
remove_heroku_files()
|
remove_heroku_files()
|
||||||
|
|
||||||
|
@ -315,30 +344,29 @@ def main():
|
||||||
if "{{ cookiecutter.js_task_runner}}".lower() == "none":
|
if "{{ cookiecutter.js_task_runner}}".lower() == "none":
|
||||||
remove_gulp_files()
|
remove_gulp_files()
|
||||||
remove_packagejson_file()
|
remove_packagejson_file()
|
||||||
if (
|
if "{{ cookiecutter.use_docker }}".lower() == "y":
|
||||||
"{{ cookiecutter.js_task_runner }}".lower() != "none"
|
remove_node_dockerfile()
|
||||||
and "{{ cookiecutter.use_docker }}".lower() == "y"
|
|
||||||
):
|
if "{{ cookiecutter.cloud_provider}}".lower() == "none":
|
||||||
print(
|
print(
|
||||||
WARNING
|
WARNING + "You chose not to use a cloud provider, "
|
||||||
+ "Docker and {} JS task runner ".format(
|
"media files won't be served in production." + TERMINATOR
|
||||||
"{{ cookiecutter.js_task_runner }}".lower().capitalize()
|
|
||||||
)
|
|
||||||
+ "working together not supported yet. "
|
|
||||||
"You can continue using the generated project like you "
|
|
||||||
"normally would, however you would need to add a JS "
|
|
||||||
"task runner service to your Docker Compose configuration "
|
|
||||||
"manually." + TERMINATOR
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if "{{ cookiecutter.use_celery }}".lower() == "n":
|
if "{{ cookiecutter.use_celery }}".lower() == "n":
|
||||||
remove_celery_app()
|
remove_celery_files()
|
||||||
if "{{ cookiecutter.use_docker }}".lower() == "y":
|
if "{{ cookiecutter.use_docker }}".lower() == "y":
|
||||||
remove_celery_compose_dirs()
|
remove_celery_compose_dirs()
|
||||||
|
|
||||||
if "{{ cookiecutter.use_travisci }}".lower() == "n":
|
if "{{ cookiecutter.ci_tool }}".lower() != "travis":
|
||||||
remove_dottravisyml_file()
|
remove_dottravisyml_file()
|
||||||
|
|
||||||
|
if "{{ cookiecutter.ci_tool }}".lower() != "gitlab":
|
||||||
|
remove_dotgitlabciyml_file()
|
||||||
|
|
||||||
|
if "{{ cookiecutter.use_drf }}".lower() == "n":
|
||||||
|
remove_drf_starter_files()
|
||||||
|
|
||||||
print(SUCCESS + "Project initialized, keep up the good work!" + TERMINATOR)
|
print(SUCCESS + "Project initialized, keep up the good work!" + TERMINATOR)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -18,19 +18,24 @@ SUCCESS = "\x1b[1;32m [SUCCESS]: "
|
||||||
|
|
||||||
project_slug = "{{ cookiecutter.project_slug }}"
|
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(
|
assert (
|
||||||
project_slug
|
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."
|
assert (
|
||||||
|
project_slug == project_slug.lower()
|
||||||
|
), "'{}' project slug should be all lowercase".format(project_slug)
|
||||||
|
|
||||||
|
assert (
|
||||||
|
"\\" not in "{{ cookiecutter.author_name }}"
|
||||||
|
), "Don't include backslashes in author name."
|
||||||
|
|
||||||
if "{{ cookiecutter.use_docker }}".lower() == "n":
|
if "{{ cookiecutter.use_docker }}".lower() == "n":
|
||||||
python_major_version = sys.version_info[0]
|
python_major_version = sys.version_info[0]
|
||||||
if python_major_version == 2:
|
if python_major_version == 2:
|
||||||
print(
|
print(
|
||||||
WARNING + "Cookiecutter Django does not support Python 2. "
|
WARNING + "You're running cookiecutter under Python 2, but the generated "
|
||||||
"Stability is guaranteed with Python 3.6+ only, "
|
"project requires Python 3.7+. Do you want to proceed (y/n)? " + TERMINATOR
|
||||||
"are you sure you want to proceed (y/n)? " + TERMINATOR
|
|
||||||
)
|
)
|
||||||
yes_options, no_options = frozenset(["y"]), frozenset(["n"])
|
yes_options, no_options = frozenset(["y"]), frozenset(["n"])
|
||||||
while True:
|
while True:
|
||||||
|
@ -54,3 +59,12 @@ if "{{ cookiecutter.use_docker }}".lower() == "n":
|
||||||
)
|
)
|
||||||
+ TERMINATOR
|
+ TERMINATOR
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (
|
||||||
|
"{{ cookiecutter.use_whitenoise }}".lower() == "n"
|
||||||
|
and "{{ cookiecutter.cloud_provider }}" == "None"
|
||||||
|
):
|
||||||
|
print(
|
||||||
|
"You should either use Whitenoise or select a Cloud Provider to serve static files"
|
||||||
|
)
|
||||||
|
sys.exit(1)
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
[pytest]
|
[pytest]
|
||||||
|
addopts = -x --tb=short
|
||||||
python_paths = .
|
python_paths = .
|
||||||
norecursedirs = .tox .git */migrations/* */static/* docs venv */{{cookiecutter.project_slug}}/*
|
norecursedirs = .tox .git */migrations/* */static/* docs venv */{{cookiecutter.project_slug}}/*
|
||||||
|
markers =
|
||||||
|
flake8: Run flake8 on all possible template combinations
|
||||||
|
black: Run black on all possible template combinations
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
cookiecutter==1.6.0
|
cookiecutter==1.7.0
|
||||||
sh==1.12.14
|
sh==1.12.14
|
||||||
binaryornot==0.4.4
|
binaryornot==0.4.4
|
||||||
|
|
||||||
# Code quality
|
# Code quality
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
flake8==3.7.6
|
black==19.10b0
|
||||||
|
flake8==3.7.9
|
||||||
|
|
||||||
# Testing
|
# Testing
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
tox==3.6.1
|
tox==3.14.3
|
||||||
pytest==4.3.1
|
pytest==5.3.5
|
||||||
pytest-cookies==0.3.0
|
pytest_cases==1.12.1
|
||||||
pyyaml==5.1
|
pytest-cookies==0.4.0
|
||||||
|
pytest-xdist==1.31.0
|
||||||
|
pyyaml==5.3
|
||||||
|
|
8
setup.py
8
setup.py
|
@ -10,10 +10,10 @@ 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 = "2.0.2"
|
version = "2.2.1"
|
||||||
|
|
||||||
if sys.argv[-1] == "tag":
|
if sys.argv[-1] == "tag":
|
||||||
os.system('git tag -a %s -m "version %s"' % (version, version))
|
os.system(f'git tag -a {version} -m "version {version}"')
|
||||||
os.system("git push --tags")
|
os.system("git push --tags")
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
|
@ -34,13 +34,13 @@ setup(
|
||||||
classifiers=[
|
classifiers=[
|
||||||
"Development Status :: 4 - Beta",
|
"Development Status :: 4 - Beta",
|
||||||
"Environment :: Console",
|
"Environment :: Console",
|
||||||
"Framework :: Django :: 2.0",
|
"Framework :: Django :: 2.2",
|
||||||
"Intended Audience :: Developers",
|
"Intended Audience :: Developers",
|
||||||
"Natural Language :: English",
|
"Natural Language :: English",
|
||||||
"License :: OSI Approved :: BSD License",
|
"License :: OSI Approved :: BSD License",
|
||||||
"Programming Language :: Python",
|
"Programming Language :: Python",
|
||||||
"Programming Language :: Python :: 3",
|
"Programming Language :: Python :: 3",
|
||||||
"Programming Language :: Python :: 3.6",
|
"Programming Language :: Python :: 3.7",
|
||||||
"Programming Language :: Python :: Implementation :: CPython",
|
"Programming Language :: Python :: Implementation :: CPython",
|
||||||
"Topic :: Software Development",
|
"Topic :: Software Development",
|
||||||
],
|
],
|
||||||
|
|
26
tests/test_bare.sh
Executable file
26
tests/test_bare.sh
Executable file
|
@ -0,0 +1,26 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# this is a very simple script that tests the docker configuration for cookiecutter-django
|
||||||
|
# it is meant to be run from the root directory of the repository, eg:
|
||||||
|
# sh tests/test_docker.sh
|
||||||
|
|
||||||
|
set -o errexit
|
||||||
|
|
||||||
|
# install test requirements
|
||||||
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
# create a cache directory
|
||||||
|
mkdir -p .cache/bare
|
||||||
|
cd .cache/bare
|
||||||
|
|
||||||
|
# create the project using the default settings in cookiecutter.json
|
||||||
|
cookiecutter ../../ --no-input --overwrite-if-exists use_docker=n $@
|
||||||
|
cd my_awesome_project
|
||||||
|
|
||||||
|
# Install OS deps
|
||||||
|
sudo utility/install_os_dependencies.sh install
|
||||||
|
|
||||||
|
# Install Python deps
|
||||||
|
pip install -r requirements/local.txt
|
||||||
|
|
||||||
|
# run the project's tests
|
||||||
|
pytest
|
|
@ -1,12 +1,14 @@
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import sh
|
|
||||||
import yaml
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
from cookiecutter.exceptions import FailedHookException
|
||||||
|
from pytest_cases import pytest_fixture_plus
|
||||||
|
import sh
|
||||||
|
import yaml
|
||||||
from binaryornot.check import is_binary
|
from binaryornot.check import is_binary
|
||||||
|
|
||||||
PATTERN = "{{(\s?cookiecutter)[.](.*?)}}"
|
PATTERN = r"{{(\s?cookiecutter)[.](.*?)}}"
|
||||||
RE_OBJ = re.compile(PATTERN)
|
RE_OBJ = re.compile(PATTERN)
|
||||||
|
|
||||||
|
|
||||||
|
@ -24,6 +26,51 @@ def context():
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest_fixture_plus
|
||||||
|
@pytest.mark.parametrize("windows", ["y", "n"], ids=lambda yn: f"win:{yn}")
|
||||||
|
@pytest.mark.parametrize("use_docker", ["y", "n"], ids=lambda yn: f"docker:{yn}")
|
||||||
|
@pytest.mark.parametrize("use_celery", ["y", "n"], ids=lambda yn: f"celery:{yn}")
|
||||||
|
@pytest.mark.parametrize("use_mailhog", ["y", "n"], ids=lambda yn: f"mailhog:{yn}")
|
||||||
|
@pytest.mark.parametrize("use_sentry", ["y", "n"], ids=lambda yn: f"sentry:{yn}")
|
||||||
|
@pytest.mark.parametrize("use_compressor", ["y", "n"], ids=lambda yn: f"cmpr:{yn}")
|
||||||
|
@pytest.mark.parametrize("use_drf", ["y", "n"], ids=lambda yn: f"drf:{yn}")
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"use_whitenoise,cloud_provider",
|
||||||
|
[
|
||||||
|
("y", "AWS"),
|
||||||
|
("y", "GCP"),
|
||||||
|
("y", "None"),
|
||||||
|
("n", "AWS"),
|
||||||
|
("n", "GCP"),
|
||||||
|
# no whitenoise + no cloud provider is not supported
|
||||||
|
],
|
||||||
|
ids=lambda id: f"wnoise:{id[0]}-cloud:{id[1]}",
|
||||||
|
)
|
||||||
|
def context_combination(
|
||||||
|
windows,
|
||||||
|
use_docker,
|
||||||
|
use_celery,
|
||||||
|
use_mailhog,
|
||||||
|
use_sentry,
|
||||||
|
use_compressor,
|
||||||
|
use_whitenoise,
|
||||||
|
use_drf,
|
||||||
|
cloud_provider,
|
||||||
|
):
|
||||||
|
"""Fixture that parametrize the function where it's used."""
|
||||||
|
return {
|
||||||
|
"windows": windows,
|
||||||
|
"use_docker": use_docker,
|
||||||
|
"use_compressor": use_compressor,
|
||||||
|
"use_celery": use_celery,
|
||||||
|
"use_mailhog": use_mailhog,
|
||||||
|
"use_sentry": use_sentry,
|
||||||
|
"use_whitenoise": use_whitenoise,
|
||||||
|
"use_drf": use_drf,
|
||||||
|
"cloud_provider": cloud_provider,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def build_files_list(root_dir):
|
def build_files_list(root_dir):
|
||||||
"""Build a list containing absolute paths to the generated files."""
|
"""Build a list containing absolute paths to the generated files."""
|
||||||
return [
|
return [
|
||||||
|
@ -48,8 +95,13 @@ def check_paths(paths):
|
||||||
assert match is None, msg.format(path)
|
assert match is None, msg.format(path)
|
||||||
|
|
||||||
|
|
||||||
def test_default_configuration(cookies, context):
|
def test_project_generation(cookies, context, context_combination):
|
||||||
result = cookies.bake(extra_context=context)
|
"""
|
||||||
|
Test that project is generated and fully rendered.
|
||||||
|
|
||||||
|
This is parametrized for each combination from ``context_combination`` fixture
|
||||||
|
"""
|
||||||
|
result = cookies.bake(extra_context={**context, **context_combination})
|
||||||
assert result.exit_code == 0
|
assert result.exit_code == 0
|
||||||
assert result.exception is None
|
assert result.exception is None
|
||||||
assert result.project.basename == context["project_slug"]
|
assert result.project.basename == context["project_slug"]
|
||||||
|
@ -60,27 +112,14 @@ def test_default_configuration(cookies, context):
|
||||||
check_paths(paths)
|
check_paths(paths)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(params=["use_mailhog", "use_celery", "windows"])
|
@pytest.mark.flake8
|
||||||
def feature_context(request, context):
|
def test_flake8_passes(cookies, context_combination):
|
||||||
context.update({request.param: "y"})
|
"""
|
||||||
return context
|
Generated project should pass flake8.
|
||||||
|
|
||||||
|
This is parametrized for each combination from ``context_combination`` fixture
|
||||||
def test_enabled_features(cookies, feature_context):
|
"""
|
||||||
result = cookies.bake(extra_context=feature_context)
|
result = cookies.bake(extra_context=context_combination)
|
||||||
assert result.exit_code == 0
|
|
||||||
assert result.exception is None
|
|
||||||
assert result.project.basename == feature_context["project_slug"]
|
|
||||||
assert result.project.isdir()
|
|
||||||
|
|
||||||
paths = build_files_list(str(result.project))
|
|
||||||
assert paths
|
|
||||||
check_paths(paths)
|
|
||||||
|
|
||||||
|
|
||||||
def test_flake8_compliance(cookies):
|
|
||||||
"""generated project should pass flake8"""
|
|
||||||
result = cookies.bake()
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
sh.flake8(str(result.project))
|
sh.flake8(str(result.project))
|
||||||
|
@ -88,8 +127,23 @@ def test_flake8_compliance(cookies):
|
||||||
pytest.fail(e)
|
pytest.fail(e)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.black
|
||||||
|
def test_black_passes(cookies, context_combination):
|
||||||
|
"""
|
||||||
|
Generated project should pass black.
|
||||||
|
|
||||||
|
This is parametrized for each combination from ``context_combination`` fixture
|
||||||
|
"""
|
||||||
|
result = cookies.bake(extra_context=context_combination)
|
||||||
|
|
||||||
|
try:
|
||||||
|
sh.black("--check", "--diff", "--exclude", "migrations", f"{result.project}/")
|
||||||
|
except sh.ErrorReturnCode as e:
|
||||||
|
pytest.fail(e)
|
||||||
|
|
||||||
|
|
||||||
def test_travis_invokes_pytest(cookies, context):
|
def test_travis_invokes_pytest(cookies, context):
|
||||||
context.update({"use_travisci": "y"})
|
context.update({"ci_tool": "Travis"})
|
||||||
result = cookies.bake(extra_context=context)
|
result = cookies.bake(extra_context=context)
|
||||||
|
|
||||||
assert result.exit_code == 0
|
assert result.exit_code == 0
|
||||||
|
@ -97,8 +151,46 @@ def test_travis_invokes_pytest(cookies, context):
|
||||||
assert result.project.basename == context["project_slug"]
|
assert result.project.basename == context["project_slug"]
|
||||||
assert result.project.isdir()
|
assert result.project.isdir()
|
||||||
|
|
||||||
with open(f'{result.project}/.travis.yml', 'r') as travis_yml:
|
with open(f"{result.project}/.travis.yml", "r") as travis_yml:
|
||||||
try:
|
try:
|
||||||
assert yaml.load(travis_yml)['script'] == ['pytest']
|
assert yaml.load(travis_yml)["script"] == ["pytest"]
|
||||||
except yaml.YAMLError as e:
|
except yaml.YAMLError as e:
|
||||||
pytest.fail(e)
|
pytest.fail(e)
|
||||||
|
|
||||||
|
|
||||||
|
def test_gitlab_invokes_flake8_and_pytest(cookies, context):
|
||||||
|
context.update({"ci_tool": "Gitlab"})
|
||||||
|
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}/.gitlab-ci.yml", "r") as gitlab_yml:
|
||||||
|
try:
|
||||||
|
gitlab_config = yaml.load(gitlab_yml)
|
||||||
|
assert gitlab_config["flake8"]["script"] == ["flake8"]
|
||||||
|
assert gitlab_config["pytest"]["script"] == ["pytest"]
|
||||||
|
except yaml.YAMLError as e:
|
||||||
|
pytest.fail(e)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("slug", ["project slug", "Project_Slug"])
|
||||||
|
def test_invalid_slug(cookies, context, slug):
|
||||||
|
"""Invalid slug should failed pre-generation hook."""
|
||||||
|
context.update({"project_slug": slug})
|
||||||
|
|
||||||
|
result = cookies.bake(extra_context=context)
|
||||||
|
|
||||||
|
assert result.exit_code != 0
|
||||||
|
assert isinstance(result.exception, FailedHookException)
|
||||||
|
|
||||||
|
|
||||||
|
def test_no_whitenoise_and_no_cloud_provider(cookies, context):
|
||||||
|
"""It should not generate project if neither whitenoise or cloud provider are set"""
|
||||||
|
context.update({"use_whitenoise": "n", "cloud_provider": "None"})
|
||||||
|
result = cookies.bake(extra_context=context)
|
||||||
|
|
||||||
|
assert result.exit_code != 0
|
||||||
|
assert isinstance(result.exception, FailedHookException)
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
# it is meant to be run from the root directory of the repository, eg:
|
# it is meant to be run from the root directory of the repository, eg:
|
||||||
# sh tests/test_docker.sh
|
# sh tests/test_docker.sh
|
||||||
|
|
||||||
|
set -o errexit
|
||||||
|
|
||||||
# install test requirements
|
# install test requirements
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
@ -11,12 +13,15 @@ mkdir -p .cache/docker
|
||||||
cd .cache/docker
|
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
|
cookiecutter ../../ --no-input --overwrite-if-exists use_docker=y $@
|
||||||
cd my_awesome_project
|
cd my_awesome_project
|
||||||
|
|
||||||
# run the project's type checks
|
# run the project's type checks
|
||||||
docker-compose -f local.yml run django mypy my_awesome_project
|
docker-compose -f local.yml run django mypy my_awesome_project
|
||||||
|
|
||||||
|
# Run black with --check option
|
||||||
|
docker-compose -f local.yml run django black --check --diff --exclude 'migrations' ./
|
||||||
|
|
||||||
# run the project's tests
|
# run the project's tests
|
||||||
docker-compose -f local.yml run django pytest
|
docker-compose -f local.yml run django pytest
|
||||||
|
|
||||||
|
|
16
tox.ini
16
tox.ini
|
@ -1,7 +1,19 @@
|
||||||
[tox]
|
[tox]
|
||||||
skipsdist = true
|
skipsdist = true
|
||||||
envlist = py36
|
envlist = py37,flake8,black,black-template
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
deps = -rrequirements.txt
|
deps = -rrequirements.txt
|
||||||
commands = pytest {posargs:./tests}
|
commands = pytest -m "not flake8" -m "not black" {posargs:./tests}
|
||||||
|
|
||||||
|
[testenv:flake8]
|
||||||
|
deps = -rrequirements.txt
|
||||||
|
commands = pytest -m flake8 {posargs:./tests}
|
||||||
|
|
||||||
|
[testenv:black]
|
||||||
|
deps = -rrequirements.txt
|
||||||
|
commands = pytest -m black {posargs:./tests}
|
||||||
|
|
||||||
|
[testenv:black-template]
|
||||||
|
deps = black
|
||||||
|
commands = black --check hooks tests setup.py docs
|
||||||
|
|
|
@ -13,10 +13,16 @@ indent_style = space
|
||||||
indent_size = 4
|
indent_size = 4
|
||||||
|
|
||||||
[*.py]
|
[*.py]
|
||||||
line_length=120
|
line_length = 120
|
||||||
known_first_party={{ cookiecutter.project_slug }}
|
known_first_party = {{ cookiecutter.project_slug }}
|
||||||
multi_line_output=3
|
multi_line_output = 3
|
||||||
default_section=THIRDPARTY
|
default_section = THIRDPARTY
|
||||||
|
recursive = true
|
||||||
|
skip = venv/
|
||||||
|
skip_glob = **/migrations/*.py
|
||||||
|
include_trailing_comma = true
|
||||||
|
force_grid_wrap = 0
|
||||||
|
use_parentheses = true
|
||||||
|
|
||||||
[*.{html,css,scss,json,yml}]
|
[*.{html,css,scss,json,yml}]
|
||||||
indent_style = space
|
indent_style = space
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
# Caddy
|
|
||||||
# ------------------------------------------------------------------------------
|
|
||||||
DOMAIN_NAME={{ cookiecutter.domain_name }}
|
|
|
@ -16,13 +16,18 @@ DJANGO_SECURE_SSL_REDIRECT=False
|
||||||
MAILGUN_API_KEY=
|
MAILGUN_API_KEY=
|
||||||
DJANGO_SERVER_EMAIL=
|
DJANGO_SERVER_EMAIL=
|
||||||
MAILGUN_DOMAIN=
|
MAILGUN_DOMAIN=
|
||||||
|
{% if cookiecutter.cloud_provider == 'AWS' %}
|
||||||
# AWS
|
# AWS
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
DJANGO_AWS_ACCESS_KEY_ID=
|
DJANGO_AWS_ACCESS_KEY_ID=
|
||||||
DJANGO_AWS_SECRET_ACCESS_KEY=
|
DJANGO_AWS_SECRET_ACCESS_KEY=
|
||||||
DJANGO_AWS_STORAGE_BUCKET_NAME=
|
DJANGO_AWS_STORAGE_BUCKET_NAME=
|
||||||
|
{% elif cookiecutter.cloud_provider == 'GCP' %}
|
||||||
|
# GCP
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
GOOGLE_APPLICATION_CREDENTIALS=
|
||||||
|
DJANGO_GCP_STORAGE_BUCKET_NAME=
|
||||||
|
{% endif %}
|
||||||
# django-allauth
|
# django-allauth
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
DJANGO_ACCOUNT_ALLOW_REGISTRATION=True
|
DJANGO_ACCOUNT_ALLOW_REGISTRATION=True
|
||||||
|
|
1
{{cookiecutter.project_slug}}/.gitignore
vendored
1
{{cookiecutter.project_slug}}/.gitignore
vendored
|
@ -325,7 +325,6 @@ tags
|
||||||
|
|
||||||
### VirtualEnv template
|
### VirtualEnv template
|
||||||
# Virtualenv
|
# Virtualenv
|
||||||
# http://iamzed.com/2009/05/07/a-primer-on-virtualenv/
|
|
||||||
[Bb]in
|
[Bb]in
|
||||||
[Ii]nclude
|
[Ii]nclude
|
||||||
[Ll]ib
|
[Ll]ib
|
||||||
|
|
33
{{cookiecutter.project_slug}}/.gitlab-ci.yml
Normal file
33
{{cookiecutter.project_slug}}/.gitlab-ci.yml
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
stages:
|
||||||
|
- lint
|
||||||
|
- test
|
||||||
|
|
||||||
|
variables:
|
||||||
|
POSTGRES_USER: '{{ cookiecutter.project_slug }}'
|
||||||
|
POSTGRES_PASSWORD: ''
|
||||||
|
POSTGRES_DB: 'test_{{ cookiecutter.project_slug }}'
|
||||||
|
|
||||||
|
flake8:
|
||||||
|
stage: lint
|
||||||
|
image: python:3.7-alpine
|
||||||
|
before_script:
|
||||||
|
- pip install -q flake8
|
||||||
|
script:
|
||||||
|
- flake8
|
||||||
|
|
||||||
|
pytest:
|
||||||
|
stage: test
|
||||||
|
image: python:3.7
|
||||||
|
tags:
|
||||||
|
- docker
|
||||||
|
services:
|
||||||
|
- postgres:11
|
||||||
|
variables:
|
||||||
|
DATABASE_URL: pgsql://$POSTGRES_USER:$POSTGRES_PASSWORD@postgres/$POSTGRES_DB
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
- pip install -r requirements/local.txt
|
||||||
|
|
||||||
|
script:
|
||||||
|
- pytest
|
||||||
|
|
14
{{cookiecutter.project_slug}}/.idea/workspace.xml
Normal file
14
{{cookiecutter.project_slug}}/.idea/workspace.xml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
{%- if cookiecutter.use_celery == 'y' %}
|
||||||
|
<component name="DjangoConsoleOptions"
|
||||||
|
custom-start-script="import sys; print('Python %s on %s' % (sys.version, sys.platform)) import django; print('Django %s' % django.get_version()) import os os.environ.setdefault("DATABASE_URL","postgres://{}:{}@{}:{}/{}".format(os.environ['POSTGRES_USER'], os.environ['POSTGRES_PASSWORD'], os.environ['POSTGRES_HOST'], os.environ['POSTGRES_PORT'], os.environ['POSTGRES_DB'])) os.environ.setdefault("CELERY_BROKER_URL", os.environ['REDIS_URL']) sys.path.extend([WORKING_DIR_AND_PYTHON_PATHS]) if 'setup' in dir(django): django.setup() import django_manage_shell; django_manage_shell.run(PROJECT_ROOT)"
|
||||||
|
module-name="{{ cookiecutter.project_slug }}" is-module-sdk="true">
|
||||||
|
</component>
|
||||||
|
{%- else %}
|
||||||
|
<component name="DjangoConsoleOptions"
|
||||||
|
custom-start-script="import sys; print('Python %s on %s' % (sys.version, sys.platform)) import django; print('Django %s' % django.get_version()) import os os.environ.setdefault("DATABASE_URL","postgres://{}:{}@{}:{}/{}".format(os.environ['POSTGRES_USER'], os.environ['POSTGRES_PASSWORD'], os.environ['POSTGRES_HOST'], os.environ['POSTGRES_PORT'], os.environ['POSTGRES_DB'])) sys.path.extend([WORKING_DIR_AND_PYTHON_PATHS]) if 'setup' in dir(django): django.setup() import django_manage_shell; django_manage_shell.run(PROJECT_ROOT)"
|
||||||
|
module-name="{{ cookiecutter.project_slug }}" is-module-sdk="true">
|
||||||
|
</component>
|
||||||
|
{%- endif %}
|
||||||
|
</project>
|
|
@ -41,7 +41,7 @@
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
<component name="TestRunnerService">
|
<component name="TestRunnerService">
|
||||||
<option name="projectConfiguration" value="py.test" />
|
<option name="projectConfiguration" value="pytest" />
|
||||||
<option name="PROJECT_TEST_RUNNER" value="py.test" />
|
<option name="PROJECT_TEST_RUNNER" value="pytest" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
||||||
|
|
19
{{cookiecutter.project_slug}}/.pre-commit-config.yaml
Normal file
19
{{cookiecutter.project_slug}}/.pre-commit-config.yaml
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
exclude: 'docs|node_modules|migrations|.git|.tox'
|
||||||
|
default_stages: [commit]
|
||||||
|
fail_fast: true
|
||||||
|
|
||||||
|
repos:
|
||||||
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
|
rev: master
|
||||||
|
hooks:
|
||||||
|
- id: trailing-whitespace
|
||||||
|
files: (^|/)a/.+\.(py|html|sh|css|js)$
|
||||||
|
|
||||||
|
- repo: local
|
||||||
|
hooks:
|
||||||
|
- id: flake8
|
||||||
|
name: flake8
|
||||||
|
entry: flake8
|
||||||
|
language: python
|
||||||
|
types: [python]
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
[MASTER]
|
[MASTER]
|
||||||
load-plugins=pylint_common, pylint_django{% if cookiecutter.use_celery == "y" %}, pylint_celery {% endif %}
|
load-plugins=pylint_django{% if cookiecutter.use_celery == "y" %}, pylint_celery {% endif %}
|
||||||
|
|
||||||
[FORMAT]
|
[FORMAT]
|
||||||
max-line-length=120
|
max-line-length=120
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
sudo: true
|
dist: xenial
|
||||||
|
services:
|
||||||
|
- postgresql
|
||||||
before_install:
|
before_install:
|
||||||
- sudo apt-get update -qq
|
- sudo apt-get update -qq
|
||||||
- sudo apt-get install -qq build-essential gettext python-dev zlib1g-dev libpq-dev xvfb
|
- sudo apt-get install -qq build-essential gettext python-dev zlib1g-dev libpq-dev xvfb
|
||||||
- sudo apt-get install -qq libtiff4-dev libjpeg8-dev libfreetype6-dev liblcms1-dev libwebp-dev
|
- sudo apt-get install -qq libjpeg8-dev libfreetype6-dev libwebp-dev
|
||||||
- sudo apt-get install -qq graphviz-dev python-setuptools python3-dev python-virtualenv python-pip
|
- sudo apt-get install -qq graphviz-dev python-setuptools python3-dev python-virtualenv python-pip
|
||||||
- sudo apt-get install -qq firefox automake libtool libreadline6 libreadline6-dev libreadline-dev
|
- sudo apt-get install -qq firefox automake libtool libreadline6 libreadline6-dev libreadline-dev
|
||||||
- sudo apt-get install -qq libsqlite3-dev libxml2 libxml2-dev libssl-dev libbz2-dev wget curl llvm
|
- sudo apt-get install -qq libsqlite3-dev libxml2 libxml2-dev libssl-dev libbz2-dev wget curl llvm
|
||||||
language: python
|
language: python
|
||||||
python:
|
python:
|
||||||
- "3.6"
|
- "3.7"
|
||||||
install:
|
install:
|
||||||
- pip install -r requirements/local.txt
|
- pip install -r requirements/local.txt
|
||||||
script:
|
script:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
release: python manage.py migrate
|
release: python manage.py migrate
|
||||||
web: gunicorn config.wsgi:application
|
web: gunicorn config.wsgi:application
|
||||||
{% if cookiecutter.use_celery == "y" -%}
|
{% if cookiecutter.use_celery == "y" -%}
|
||||||
worker: celery worker --app={{cookiecutter.project_slug}}.taskapp --loglevel=info
|
worker: celery worker --app=config.celery_app --loglevel=info
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
|
@ -6,6 +6,9 @@
|
||||||
.. image:: https://img.shields.io/badge/built%20with-Cookiecutter%20Django-ff69b4.svg
|
.. image:: https://img.shields.io/badge/built%20with-Cookiecutter%20Django-ff69b4.svg
|
||||||
:target: https://github.com/pydanny/cookiecutter-django/
|
:target: https://github.com/pydanny/cookiecutter-django/
|
||||||
:alt: Built with Cookiecutter Django
|
:alt: Built with Cookiecutter Django
|
||||||
|
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
|
||||||
|
:target: https://github.com/ambv/black
|
||||||
|
:alt: Black code style
|
||||||
{% if cookiecutter.open_source_license != "Not open source" %}
|
{% if cookiecutter.open_source_license != "Not open source" %}
|
||||||
|
|
||||||
:License: {{cookiecutter.open_source_license}}
|
:License: {{cookiecutter.open_source_license}}
|
||||||
|
@ -76,7 +79,7 @@ To run a celery worker:
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
cd {{cookiecutter.project_slug}}
|
cd {{cookiecutter.project_slug}}
|
||||||
celery -A {{cookiecutter.project_slug}}.taskapp worker -l info
|
celery -A config.celery_app worker -l info
|
||||||
|
|
||||||
Please note: For Celery's import magic to work, it is important *where* the celery commands are run. If you are in the same folder with *manage.py*, you should be right.
|
Please note: For Celery's import magic to work, it is important *where* the celery commands are run. If you are in the same folder with *manage.py*, you should be right.
|
||||||
|
|
||||||
|
@ -156,7 +159,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.1.1 is installed using npm and customised by tweaking your variables in ``static/sass/custom_bootstrap_vars``.
|
Bootstrap v4 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`_.
|
||||||
|
|
||||||
|
|
|
@ -1,42 +1,40 @@
|
||||||
FROM python:3.6-alpine
|
FROM python:3.7-slim-buster
|
||||||
|
|
||||||
ENV PYTHONUNBUFFERED 1
|
ENV PYTHONUNBUFFERED 1
|
||||||
|
|
||||||
RUN apk update \
|
RUN apt-get update \
|
||||||
|
# dependencies for building Python packages
|
||||||
|
&& apt-get install -y build-essential \
|
||||||
# psycopg2 dependencies
|
# psycopg2 dependencies
|
||||||
&& apk add --virtual build-deps gcc python3-dev musl-dev \
|
&& apt-get install -y libpq-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 py-cffi \
|
|
||||||
# Translations dependencies
|
# Translations dependencies
|
||||||
&& apk add gettext \
|
&& apt-get install -y gettext \
|
||||||
# https://docs.djangoproject.com/en/dev/ref/django-admin/#dbshell
|
# cleaning up unused files
|
||||||
&& apk add postgresql-client
|
&& apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Requirements are installed here to ensure they will be cached.
|
# Requirements are installed here to ensure they will be cached.
|
||||||
COPY ./requirements /requirements
|
COPY ./requirements /requirements
|
||||||
RUN pip install -r /requirements/local.txt
|
RUN pip install -r /requirements/local.txt
|
||||||
|
|
||||||
COPY ./compose/production/django/entrypoint /entrypoint
|
COPY ./compose/production/django/entrypoint /entrypoint
|
||||||
RUN sed -i 's/\r//' /entrypoint
|
RUN sed -i 's/\r$//g' /entrypoint
|
||||||
RUN chmod +x /entrypoint
|
RUN chmod +x /entrypoint
|
||||||
|
|
||||||
COPY ./compose/local/django/start /start
|
COPY ./compose/local/django/start /start
|
||||||
RUN sed -i 's/\r//' /start
|
RUN sed -i 's/\r$//g' /start
|
||||||
RUN chmod +x /start
|
RUN chmod +x /start
|
||||||
{% if cookiecutter.use_celery == "y" %}
|
{% if cookiecutter.use_celery == "y" %}
|
||||||
COPY ./compose/local/django/celery/worker/start /start-celeryworker
|
COPY ./compose/local/django/celery/worker/start /start-celeryworker
|
||||||
RUN sed -i 's/\r//' /start-celeryworker
|
RUN sed -i 's/\r$//g' /start-celeryworker
|
||||||
RUN chmod +x /start-celeryworker
|
RUN chmod +x /start-celeryworker
|
||||||
|
|
||||||
COPY ./compose/local/django/celery/beat/start /start-celerybeat
|
COPY ./compose/local/django/celery/beat/start /start-celerybeat
|
||||||
RUN sed -i 's/\r//' /start-celerybeat
|
RUN sed -i 's/\r$//g' /start-celerybeat
|
||||||
RUN chmod +x /start-celerybeat
|
RUN chmod +x /start-celerybeat
|
||||||
|
|
||||||
COPY ./compose/local/django/celery/flower/start /start-flower
|
COPY ./compose/local/django/celery/flower/start /start-flower
|
||||||
RUN sed -i 's/\r//' /start-flower
|
RUN sed -i 's/\r$//g' /start-flower
|
||||||
RUN chmod +x /start-flower
|
RUN chmod +x /start-flower
|
||||||
{% endif %}
|
{% endif %}
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
#!/bin/sh
|
#!/bin/bash
|
||||||
|
|
||||||
set -o errexit
|
set -o errexit
|
||||||
set -o nounset
|
set -o nounset
|
||||||
|
|
||||||
|
|
||||||
rm -f './celerybeat.pid'
|
rm -f './celerybeat.pid'
|
||||||
celery -A {{cookiecutter.project_slug}}.taskapp beat -l INFO
|
celery -A config.celery_app beat -l INFO
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
#!/bin/sh
|
#!/bin/bash
|
||||||
|
|
||||||
set -o errexit
|
set -o errexit
|
||||||
set -o nounset
|
set -o nounset
|
||||||
|
|
||||||
|
|
||||||
celery flower \
|
celery flower \
|
||||||
--app={{cookiecutter.project_slug}}.taskapp \
|
--app=config.celery_app \
|
||||||
--broker="${CELERY_BROKER_URL}" \
|
--broker="${CELERY_BROKER_URL}" \
|
||||||
--basic_auth="${CELERY_FLOWER_USER}:${CELERY_FLOWER_PASSWORD}"
|
--basic_auth="${CELERY_FLOWER_USER}:${CELERY_FLOWER_PASSWORD}"
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#!/bin/sh
|
#!/bin/bash
|
||||||
|
|
||||||
set -o errexit
|
set -o errexit
|
||||||
set -o nounset
|
set -o nounset
|
||||||
|
|
||||||
|
|
||||||
celery -A {{cookiecutter.project_slug}}.taskapp worker -l INFO
|
celery -A config.celery_app worker -l INFO
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/bin/sh
|
#!/bin/bash
|
||||||
|
|
||||||
set -o errexit
|
set -o errexit
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
FROM node:10-stretch-slim
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY ./package.json /app
|
||||||
|
|
||||||
|
RUN npm install && npm cache clean --force
|
||||||
|
|
||||||
|
ENV PATH ./node_modules/.bin/:$PATH
|
|
@ -0,0 +1,9 @@
|
||||||
|
FROM garland/aws-cli-docker:1.15.47
|
||||||
|
|
||||||
|
COPY ./compose/production/aws/maintenance /usr/local/bin/maintenance
|
||||||
|
COPY ./compose/production/postgres/maintenance/_sourced /usr/local/bin/maintenance/_sourced
|
||||||
|
|
||||||
|
RUN chmod +x /usr/local/bin/maintenance/*
|
||||||
|
|
||||||
|
RUN mv /usr/local/bin/maintenance/* /usr/local/bin \
|
||||||
|
&& rmdir /usr/local/bin/maintenance
|
|
@ -0,0 +1,24 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
### Download a file from your Amazon S3 bucket to the postgres /backups folder
|
||||||
|
###
|
||||||
|
### Usage:
|
||||||
|
### $ docker-compose -f production.yml run --rm awscli <1>
|
||||||
|
|
||||||
|
set -o errexit
|
||||||
|
set -o pipefail
|
||||||
|
set -o nounset
|
||||||
|
|
||||||
|
working_dir="$(dirname ${0})"
|
||||||
|
source "${working_dir}/_sourced/constants.sh"
|
||||||
|
source "${working_dir}/_sourced/messages.sh"
|
||||||
|
|
||||||
|
export AWS_ACCESS_KEY_ID="${DJANGO_AWS_ACCESS_KEY_ID}"
|
||||||
|
export AWS_SECRET_ACCESS_KEY="${DJANGO_AWS_SECRET_ACCESS_KEY}"
|
||||||
|
export AWS_STORAGE_BUCKET_NAME="${DJANGO_AWS_STORAGE_BUCKET_NAME}"
|
||||||
|
|
||||||
|
|
||||||
|
aws s3 cp s3://${AWS_STORAGE_BUCKET_NAME}${BACKUP_DIR_PATH}/${1} ${BACKUP_DIR_PATH}/${1}
|
||||||
|
|
||||||
|
message_success "Finished downloading ${1}."
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
### Upload the /backups folder to Amazon S3
|
||||||
|
###
|
||||||
|
### Usage:
|
||||||
|
### $ docker-compose -f production.yml run --rm awscli upload
|
||||||
|
|
||||||
|
set -o errexit
|
||||||
|
set -o pipefail
|
||||||
|
set -o nounset
|
||||||
|
|
||||||
|
working_dir="$(dirname ${0})"
|
||||||
|
source "${working_dir}/_sourced/constants.sh"
|
||||||
|
source "${working_dir}/_sourced/messages.sh"
|
||||||
|
|
||||||
|
export AWS_ACCESS_KEY_ID="${DJANGO_AWS_ACCESS_KEY_ID}"
|
||||||
|
export AWS_SECRET_ACCESS_KEY="${DJANGO_AWS_SECRET_ACCESS_KEY}"
|
||||||
|
export AWS_STORAGE_BUCKET_NAME="${DJANGO_AWS_STORAGE_BUCKET_NAME}"
|
||||||
|
|
||||||
|
|
||||||
|
message_info "Upload the backups directory to S3 bucket {$AWS_STORAGE_BUCKET_NAME}"
|
||||||
|
|
||||||
|
aws s3 cp ${BACKUP_DIR_PATH} s3://${AWS_STORAGE_BUCKET_NAME}${BACKUP_DIR_PATH} --recursive
|
||||||
|
|
||||||
|
message_info "Cleaning the directory ${BACKUP_DIR_PATH}"
|
||||||
|
|
||||||
|
rm -rf ${BACKUP_DIR_PATH}/*
|
||||||
|
|
||||||
|
message_success "Finished uploading and cleaning."
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
www.{% raw %}{$DOMAIN_NAME}{% endraw %} {
|
|
||||||
redir https://{% raw %}{$DOMAIN_NAME}{% endraw %}
|
|
||||||
}
|
|
||||||
|
|
||||||
{% raw %}{$DOMAIN_NAME}{% endraw %} {
|
|
||||||
proxy / django:5000 {
|
|
||||||
header_upstream Host {host}
|
|
||||||
header_upstream X-Real-IP {remote}
|
|
||||||
header_upstream X-Forwarded-Proto {scheme}
|
|
||||||
header_upstream X-CSRFToken {~csrftoken}
|
|
||||||
}
|
|
||||||
log stdout
|
|
||||||
errors stdout
|
|
||||||
gzip
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
FROM abiosoft/caddy:0.11.0
|
|
||||||
|
|
||||||
COPY ./compose/production/caddy/Caddyfile /etc/Caddyfile
|
|
|
@ -1,18 +1,31 @@
|
||||||
FROM python:3.6-alpine
|
{% if cookiecutter.js_task_runner == 'Gulp' -%}
|
||||||
|
FROM node:10-stretch-slim as client-builder
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
COPY ./package.json /app
|
||||||
|
RUN npm install && npm cache clean --force
|
||||||
|
COPY . /app
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# Python build stage
|
||||||
|
{%- endif %}
|
||||||
|
FROM python:3.7-slim-buster
|
||||||
|
|
||||||
ENV PYTHONUNBUFFERED 1
|
ENV PYTHONUNBUFFERED 1
|
||||||
|
|
||||||
RUN apk update \
|
RUN apt-get update \
|
||||||
|
# dependencies for building Python packages
|
||||||
|
&& apt-get install -y build-essential \
|
||||||
# psycopg2 dependencies
|
# psycopg2 dependencies
|
||||||
&& apk add --virtual build-deps gcc python3-dev musl-dev \
|
&& apt-get install -y libpq-dev \
|
||||||
&& apk add postgresql-dev \
|
# Translations dependencies
|
||||||
# Pillow dependencies
|
&& apt-get install -y gettext \
|
||||||
&& apk add jpeg-dev zlib-dev freetype-dev lcms2-dev openjpeg-dev tiff-dev tk-dev tcl-dev \
|
# cleaning up unused files
|
||||||
# CFFI dependencies
|
&& apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \
|
||||||
&& apk add libffi-dev py-cffi
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
RUN addgroup -S django \
|
RUN addgroup --system django \
|
||||||
&& adduser -S -G django django
|
&& adduser --system --ingroup django django
|
||||||
|
|
||||||
# Requirements are installed here to ensure they will be cached.
|
# Requirements are installed here to ensure they will be cached.
|
||||||
COPY ./requirements /requirements
|
COPY ./requirements /requirements
|
||||||
|
@ -20,32 +33,36 @@ RUN pip install --no-cache-dir -r /requirements/production.txt \
|
||||||
&& rm -rf /requirements
|
&& rm -rf /requirements
|
||||||
|
|
||||||
COPY ./compose/production/django/entrypoint /entrypoint
|
COPY ./compose/production/django/entrypoint /entrypoint
|
||||||
RUN sed -i 's/\r//' /entrypoint
|
RUN sed -i 's/\r$//g' /entrypoint
|
||||||
RUN chmod +x /entrypoint
|
RUN chmod +x /entrypoint
|
||||||
RUN chown django /entrypoint
|
RUN chown django /entrypoint
|
||||||
|
|
||||||
COPY ./compose/production/django/start /start
|
COPY ./compose/production/django/start /start
|
||||||
RUN sed -i 's/\r//' /start
|
RUN sed -i 's/\r$//g' /start
|
||||||
RUN chmod +x /start
|
RUN chmod +x /start
|
||||||
RUN chown django /start
|
RUN chown django /start
|
||||||
{% if cookiecutter.use_celery == "y" %}
|
|
||||||
|
{%- if cookiecutter.use_celery == "y" %}
|
||||||
COPY ./compose/production/django/celery/worker/start /start-celeryworker
|
COPY ./compose/production/django/celery/worker/start /start-celeryworker
|
||||||
RUN sed -i 's/\r//' /start-celeryworker
|
RUN sed -i 's/\r$//g' /start-celeryworker
|
||||||
RUN chmod +x /start-celeryworker
|
RUN chmod +x /start-celeryworker
|
||||||
RUN chown django /start-celeryworker
|
RUN chown django /start-celeryworker
|
||||||
|
|
||||||
COPY ./compose/production/django/celery/beat/start /start-celerybeat
|
COPY ./compose/production/django/celery/beat/start /start-celerybeat
|
||||||
RUN sed -i 's/\r//' /start-celerybeat
|
RUN sed -i 's/\r$//g' /start-celerybeat
|
||||||
RUN chmod +x /start-celerybeat
|
RUN chmod +x /start-celerybeat
|
||||||
RUN chown django /start-celerybeat
|
RUN chown django /start-celerybeat
|
||||||
|
|
||||||
COPY ./compose/production/django/celery/flower/start /start-flower
|
COPY ./compose/production/django/celery/flower/start /start-flower
|
||||||
RUN sed -i 's/\r//' /start-flower
|
RUN sed -i 's/\r$//g' /start-flower
|
||||||
RUN chmod +x /start-flower
|
RUN chmod +x /start-flower
|
||||||
{% endif %}
|
{%- endif %}
|
||||||
COPY . /app
|
|
||||||
|
|
||||||
RUN chown -R django /app
|
{%- if cookiecutter.js_task_runner == 'Gulp' %}
|
||||||
|
COPY --from=client-builder --chown=django:django /app /app
|
||||||
|
{% else %}
|
||||||
|
COPY --chown=django:django . /app
|
||||||
|
{%- endif %}
|
||||||
|
|
||||||
USER django
|
USER django
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
#!/bin/sh
|
#!/bin/bash
|
||||||
|
|
||||||
set -o errexit
|
set -o errexit
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
set -o nounset
|
set -o nounset
|
||||||
|
|
||||||
|
|
||||||
celery -A {{cookiecutter.project_slug}}.taskapp beat -l INFO
|
celery -A config.celery_app beat -l INFO
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
#!/bin/sh
|
#!/bin/bash
|
||||||
|
|
||||||
set -o errexit
|
set -o errexit
|
||||||
set -o nounset
|
set -o nounset
|
||||||
|
|
||||||
|
|
||||||
celery flower \
|
celery flower \
|
||||||
--app={{cookiecutter.project_slug}}.taskapp \
|
--app=config.celery_app \
|
||||||
--broker="${CELERY_BROKER_URL}" \
|
--broker="${CELERY_BROKER_URL}" \
|
||||||
--basic_auth="${CELERY_FLOWER_USER}:${CELERY_FLOWER_PASSWORD}"
|
--basic_auth="${CELERY_FLOWER_USER}:${CELERY_FLOWER_PASSWORD}"
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
#!/bin/sh
|
#!/bin/bash
|
||||||
|
|
||||||
set -o errexit
|
set -o errexit
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
set -o nounset
|
set -o nounset
|
||||||
|
|
||||||
|
|
||||||
celery -A {{cookiecutter.project_slug}}.taskapp worker -l INFO
|
celery -A config.celery_app worker -l INFO
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/bin/sh
|
#!/bin/bash
|
||||||
|
|
||||||
set -o errexit
|
set -o errexit
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/bin/sh
|
#!/bin/bash
|
||||||
|
|
||||||
set -o errexit
|
set -o errexit
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
FROM traefik:v2.0
|
||||||
|
RUN mkdir -p /etc/traefik/acme
|
||||||
|
RUN touch /etc/traefik/acme/acme.json
|
||||||
|
RUN chmod 600 /etc/traefik/acme/acme.json
|
||||||
|
COPY ./compose/production/traefik/traefik.yml /etc/traefik
|
|
@ -0,0 +1,67 @@
|
||||||
|
log:
|
||||||
|
level: INFO
|
||||||
|
|
||||||
|
entryPoints:
|
||||||
|
web:
|
||||||
|
# http
|
||||||
|
address: ":80"
|
||||||
|
|
||||||
|
web-secure:
|
||||||
|
# https
|
||||||
|
address: ":443"
|
||||||
|
|
||||||
|
certificatesResolvers:
|
||||||
|
letsencrypt:
|
||||||
|
# https://docs.traefik.io/master/https/acme/#lets-encrypt
|
||||||
|
acme:
|
||||||
|
email: "{{ cookiecutter.email }}"
|
||||||
|
storage: /etc/traefik/acme/acme.json
|
||||||
|
# https://docs.traefik.io/master/https/acme/#httpchallenge
|
||||||
|
httpChallenge:
|
||||||
|
entryPoint: web
|
||||||
|
|
||||||
|
http:
|
||||||
|
routers:
|
||||||
|
web-router:
|
||||||
|
rule: "Host(`{{ cookiecutter.domain_name }}`)"
|
||||||
|
entryPoints:
|
||||||
|
- web
|
||||||
|
middlewares:
|
||||||
|
- redirect
|
||||||
|
- csrf
|
||||||
|
service: django
|
||||||
|
|
||||||
|
web-secure-router:
|
||||||
|
rule: "Host(`{{ cookiecutter.domain_name }}`)"
|
||||||
|
entryPoints:
|
||||||
|
- web-secure
|
||||||
|
middlewares:
|
||||||
|
- csrf
|
||||||
|
service: django
|
||||||
|
tls:
|
||||||
|
# https://docs.traefik.io/master/routing/routers/#certresolver
|
||||||
|
certResolver: letsencrypt
|
||||||
|
|
||||||
|
middlewares:
|
||||||
|
redirect:
|
||||||
|
# https://docs.traefik.io/master/middlewares/redirectscheme/
|
||||||
|
redirectScheme:
|
||||||
|
scheme: https
|
||||||
|
permanent: true
|
||||||
|
csrf:
|
||||||
|
# https://docs.traefik.io/master/middlewares/headers/#hostsproxyheaders
|
||||||
|
# https://docs.djangoproject.com/en/dev/ref/csrf/#ajax
|
||||||
|
headers:
|
||||||
|
hostsProxyHeaders: ['X-CSRFToken']
|
||||||
|
|
||||||
|
services:
|
||||||
|
django:
|
||||||
|
loadBalancer:
|
||||||
|
servers:
|
||||||
|
- url: http://django:5000
|
||||||
|
|
||||||
|
providers:
|
||||||
|
# https://docs.traefik.io/master/providers/file/
|
||||||
|
file:
|
||||||
|
filename: /etc/traefik/traefik.yml
|
||||||
|
watch: true
|
|
@ -0,0 +1,7 @@
|
||||||
|
{% if cookiecutter.use_celery == 'y' -%}
|
||||||
|
# This will make sure the app is always imported when
|
||||||
|
# Django starts so that shared_task will use this app.
|
||||||
|
from .celery_app import app as celery_app
|
||||||
|
|
||||||
|
__all__ = ("celery_app",)
|
||||||
|
{% endif -%}
|
14
{{cookiecutter.project_slug}}/config/api_router.py
Normal file
14
{{cookiecutter.project_slug}}/config/api_router.py
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
from rest_framework.routers import DefaultRouter, SimpleRouter
|
||||||
|
from django.conf import settings
|
||||||
|
from {{ cookiecutter.project_slug }}.users.api.views import UserViewSet
|
||||||
|
|
||||||
|
if settings.DEBUG:
|
||||||
|
router = DefaultRouter()
|
||||||
|
else:
|
||||||
|
router = SimpleRouter()
|
||||||
|
|
||||||
|
router.register("users", UserViewSet)
|
||||||
|
|
||||||
|
|
||||||
|
app_name = "api"
|
||||||
|
urlpatterns = router.urls
|
16
{{cookiecutter.project_slug}}/config/celery_app.py
Normal file
16
{{cookiecutter.project_slug}}/config/celery_app.py
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import os
|
||||||
|
from celery import Celery
|
||||||
|
|
||||||
|
# set the default Django settings module for the 'celery' program.
|
||||||
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.local")
|
||||||
|
|
||||||
|
app = Celery("{{cookiecutter.project_slug}}")
|
||||||
|
|
||||||
|
# Using a string here means the worker doesn't have to serialize
|
||||||
|
# the configuration object to child processes.
|
||||||
|
# - namespace='CELERY' means all celery-related configuration keys
|
||||||
|
# should have a `CELERY_` prefix.
|
||||||
|
app.config_from_object("django.conf:settings", namespace="CELERY")
|
||||||
|
|
||||||
|
# Load task modules from all registered Django app configs.
|
||||||
|
app.autodiscover_tasks()
|
|
@ -4,27 +4,29 @@ Base settings to build other settings files upon.
|
||||||
|
|
||||||
import environ
|
import environ
|
||||||
|
|
||||||
ROOT_DIR = environ.Path(__file__) - 3 # ({{ cookiecutter.project_slug }}/config/settings/base.py - 3 = {{ cookiecutter.project_slug }}/)
|
ROOT_DIR = (
|
||||||
APPS_DIR = ROOT_DIR.path('{{ cookiecutter.project_slug }}')
|
environ.Path(__file__) - 3
|
||||||
|
) # ({{ cookiecutter.project_slug }}/config/settings/base.py - 3 = {{ cookiecutter.project_slug }}/)
|
||||||
|
APPS_DIR = ROOT_DIR.path("{{ cookiecutter.project_slug }}")
|
||||||
|
|
||||||
env = environ.Env()
|
env = environ.Env()
|
||||||
|
|
||||||
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:
|
||||||
# OS environment variables take precedence over variables from .env
|
# OS environment variables take precedence over variables from .env
|
||||||
env.read_env(str(ROOT_DIR.path('.env')))
|
env.read_env(str(ROOT_DIR.path(".env")))
|
||||||
|
|
||||||
# GENERAL
|
# GENERAL
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#debug
|
# https://docs.djangoproject.com/en/dev/ref/settings/#debug
|
||||||
DEBUG = env.bool('DJANGO_DEBUG', False)
|
DEBUG = env.bool("DJANGO_DEBUG", False)
|
||||||
# Local time zone. Choices are
|
# Local time zone. Choices are
|
||||||
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
|
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
|
||||||
# though not all of them may be available with every OS.
|
# though not all of them may be available with every OS.
|
||||||
# In Windows, this must be set to your system time zone.
|
# In Windows, this must be set to your system time zone.
|
||||||
TIME_ZONE = '{{ cookiecutter.timezone }}'
|
TIME_ZONE = "{{ cookiecutter.timezone }}"
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#language-code
|
# https://docs.djangoproject.com/en/dev/ref/settings/#language-code
|
||||||
LANGUAGE_CODE = 'en-us'
|
LANGUAGE_CODE = "en-us"
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#site-id
|
# https://docs.djangoproject.com/en/dev/ref/settings/#site-id
|
||||||
SITE_ID = 1
|
SITE_ID = 1
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#use-i18n
|
# https://docs.djangoproject.com/en/dev/ref/settings/#use-i18n
|
||||||
|
@ -33,49 +35,54 @@ USE_I18N = True
|
||||||
USE_L10N = True
|
USE_L10N = True
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#use-tz
|
# https://docs.djangoproject.com/en/dev/ref/settings/#use-tz
|
||||||
USE_TZ = True
|
USE_TZ = True
|
||||||
|
# https://docs.djangoproject.com/en/dev/ref/settings/#locale-paths
|
||||||
|
LOCALE_PATHS = [ROOT_DIR.path("locale")]
|
||||||
|
|
||||||
# DATABASES
|
# DATABASES
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#databases
|
# https://docs.djangoproject.com/en/dev/ref/settings/#databases
|
||||||
{% if cookiecutter.use_docker == 'y' -%}
|
{% if cookiecutter.use_docker == "y" -%}
|
||||||
DATABASES = {
|
DATABASES = {"default": env.db("DATABASE_URL")}
|
||||||
'default': env.db('DATABASE_URL'),
|
|
||||||
}
|
|
||||||
{%- else %}
|
{%- else %}
|
||||||
DATABASES = {
|
DATABASES = {
|
||||||
'default': env.db('DATABASE_URL', default='postgres://{% if cookiecutter.windows == 'y' %}localhost{% endif %}/{{cookiecutter.project_slug}}'),
|
"default": env.db("DATABASE_URL", default="postgres://{% if cookiecutter.windows == 'y' %}localhost{% endif %}/{{cookiecutter.project_slug}}")
|
||||||
}
|
}
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
DATABASES['default']['ATOMIC_REQUESTS'] = True
|
DATABASES["default"]["ATOMIC_REQUESTS"] = True
|
||||||
|
|
||||||
# URLS
|
# URLS
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#root-urlconf
|
# https://docs.djangoproject.com/en/dev/ref/settings/#root-urlconf
|
||||||
ROOT_URLCONF = 'config.urls'
|
ROOT_URLCONF = "config.urls"
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#wsgi-application
|
# https://docs.djangoproject.com/en/dev/ref/settings/#wsgi-application
|
||||||
WSGI_APPLICATION = 'config.wsgi.application'
|
WSGI_APPLICATION = "config.wsgi.application"
|
||||||
|
|
||||||
# APPS
|
# APPS
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
DJANGO_APPS = [
|
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
|
# "django.contrib.humanize", # Handy template tags
|
||||||
'django.contrib.admin',
|
"django.contrib.admin",
|
||||||
|
"django.forms",
|
||||||
]
|
]
|
||||||
THIRD_PARTY_APPS = [
|
THIRD_PARTY_APPS = [
|
||||||
'crispy_forms',
|
"crispy_forms",
|
||||||
'allauth',
|
"allauth",
|
||||||
'allauth.account',
|
"allauth.account",
|
||||||
'allauth.socialaccount',
|
"allauth.socialaccount",
|
||||||
'rest_framework',
|
"rest_framework",
|
||||||
|
{%- if cookiecutter.use_celery == 'y' %}
|
||||||
|
"django_celery_beat",
|
||||||
|
{%- endif %}
|
||||||
]
|
]
|
||||||
|
|
||||||
LOCAL_APPS = [
|
LOCAL_APPS = [
|
||||||
'{{ cookiecutter.project_slug }}.users.apps.UsersAppConfig',
|
"{{ 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
|
# https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps
|
||||||
|
@ -84,86 +91,80 @@ INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS
|
||||||
# MIGRATIONS
|
# MIGRATIONS
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#migration-modules
|
# 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'
|
|
||||||
}
|
|
||||||
|
|
||||||
# AUTHENTICATION
|
# AUTHENTICATION
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#authentication-backends
|
# https://docs.djangoproject.com/en/dev/ref/settings/#authentication-backends
|
||||||
AUTHENTICATION_BACKENDS = [
|
AUTHENTICATION_BACKENDS = [
|
||||||
'django.contrib.auth.backends.ModelBackend',
|
"django.contrib.auth.backends.ModelBackend",
|
||||||
'allauth.account.auth_backends.AuthenticationBackend',
|
"allauth.account.auth_backends.AuthenticationBackend",
|
||||||
]
|
]
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#auth-user-model
|
# https://docs.djangoproject.com/en/dev/ref/settings/#auth-user-model
|
||||||
AUTH_USER_MODEL = 'users.User'
|
AUTH_USER_MODEL = "users.User"
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#login-redirect-url
|
# https://docs.djangoproject.com/en/dev/ref/settings/#login-redirect-url
|
||||||
LOGIN_REDIRECT_URL = 'users:redirect'
|
LOGIN_REDIRECT_URL = "users:redirect"
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#login-url
|
# https://docs.djangoproject.com/en/dev/ref/settings/#login-url
|
||||||
LOGIN_URL = 'account_login'
|
LOGIN_URL = "account_login"
|
||||||
|
|
||||||
# PASSWORDS
|
# PASSWORDS
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#password-hashers
|
# https://docs.djangoproject.com/en/dev/ref/settings/#password-hashers
|
||||||
PASSWORD_HASHERS = [
|
PASSWORD_HASHERS = [
|
||||||
# https://docs.djangoproject.com/en/dev/topics/auth/passwords/#using-argon2-with-django
|
# 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',
|
|
||||||
]
|
]
|
||||||
# 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"
|
||||||
},
|
|
||||||
{
|
|
||||||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
|
||||||
},
|
},
|
||||||
|
{"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator"},
|
||||||
|
{"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator"},
|
||||||
|
{"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator"},
|
||||||
]
|
]
|
||||||
|
|
||||||
# MIDDLEWARE
|
# MIDDLEWARE
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#middleware
|
# https://docs.djangoproject.com/en/dev/ref/settings/#middleware
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
'django.middleware.security.SecurityMiddleware',
|
"django.middleware.security.SecurityMiddleware",
|
||||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
{%- if cookiecutter.use_whitenoise == 'y' %}
|
||||||
'django.middleware.common.CommonMiddleware',
|
"whitenoise.middleware.WhiteNoiseMiddleware",
|
||||||
'django.middleware.csrf.CsrfViewMiddleware',
|
{%- endif %}
|
||||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
"django.contrib.sessions.middleware.SessionMiddleware",
|
||||||
'django.contrib.messages.middleware.MessageMiddleware',
|
"django.middleware.locale.LocaleMiddleware",
|
||||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
"django.middleware.common.CommonMiddleware",
|
||||||
|
"django.middleware.csrf.CsrfViewMiddleware",
|
||||||
|
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
||||||
|
"django.contrib.messages.middleware.MessageMiddleware",
|
||||||
|
"django.middleware.common.BrokenLinkEmailsMiddleware",
|
||||||
|
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||||
]
|
]
|
||||||
|
|
||||||
# STATIC
|
# STATIC
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#static-root
|
# https://docs.djangoproject.com/en/dev/ref/settings/#static-root
|
||||||
STATIC_ROOT = str(ROOT_DIR('staticfiles'))
|
STATIC_ROOT = str(ROOT_DIR("staticfiles"))
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#static-url
|
# https://docs.djangoproject.com/en/dev/ref/settings/#static-url
|
||||||
STATIC_URL = '/static/'
|
STATIC_URL = "/static/"
|
||||||
# https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#std:setting-STATICFILES_DIRS
|
# https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#std:setting-STATICFILES_DIRS
|
||||||
STATICFILES_DIRS = [
|
STATICFILES_DIRS = [str(APPS_DIR.path("static"))]
|
||||||
str(APPS_DIR.path('static')),
|
|
||||||
]
|
|
||||||
# https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#staticfiles-finders
|
# https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#staticfiles-finders
|
||||||
STATICFILES_FINDERS = [
|
STATICFILES_FINDERS = [
|
||||||
'django.contrib.staticfiles.finders.FileSystemFinder',
|
"django.contrib.staticfiles.finders.FileSystemFinder",
|
||||||
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
|
"django.contrib.staticfiles.finders.AppDirectoriesFinder",
|
||||||
]
|
]
|
||||||
|
|
||||||
# MEDIA
|
# MEDIA
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#media-root
|
# https://docs.djangoproject.com/en/dev/ref/settings/#media-root
|
||||||
MEDIA_ROOT = str(APPS_DIR('media'))
|
MEDIA_ROOT = str(APPS_DIR("media"))
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#media-url
|
# https://docs.djangoproject.com/en/dev/ref/settings/#media-url
|
||||||
MEDIA_URL = '/media/'
|
MEDIA_URL = "/media/"
|
||||||
|
|
||||||
# TEMPLATES
|
# TEMPLATES
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
@ -171,43 +172,42 @@ MEDIA_URL = '/media/'
|
||||||
TEMPLATES = [
|
TEMPLATES = [
|
||||||
{
|
{
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-TEMPLATES-BACKEND
|
# https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-TEMPLATES-BACKEND
|
||||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#template-dirs
|
# https://docs.djangoproject.com/en/dev/ref/settings/#template-dirs
|
||||||
'DIRS': [
|
"DIRS": [str(APPS_DIR.path("templates"))],
|
||||||
str(APPS_DIR.path('templates')),
|
"OPTIONS": {
|
||||||
],
|
|
||||||
'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/settings/#template-loaders
|
||||||
# https://docs.djangoproject.com/en/dev/ref/templates/api/#loader-types
|
# https://docs.djangoproject.com/en/dev/ref/templates/api/#loader-types
|
||||||
'loaders': [
|
"loaders": [
|
||||||
'django.template.loaders.filesystem.Loader',
|
"django.template.loaders.filesystem.Loader",
|
||||||
'django.template.loaders.app_directories.Loader',
|
"django.template.loaders.app_directories.Loader",
|
||||||
],
|
],
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#template-context-processors
|
# https://docs.djangoproject.com/en/dev/ref/settings/#template-context-processors
|
||||||
'context_processors': [
|
"context_processors": [
|
||||||
'django.template.context_processors.debug',
|
"django.template.context_processors.debug",
|
||||||
'django.template.context_processors.request',
|
"django.template.context_processors.request",
|
||||||
'django.contrib.auth.context_processors.auth',
|
"django.contrib.auth.context_processors.auth",
|
||||||
'django.template.context_processors.i18n',
|
"django.template.context_processors.i18n",
|
||||||
'django.template.context_processors.media',
|
"django.template.context_processors.media",
|
||||||
'django.template.context_processors.static',
|
"django.template.context_processors.static",
|
||||||
'django.template.context_processors.tz',
|
"django.template.context_processors.tz",
|
||||||
'django.contrib.messages.context_processors.messages',
|
"django.contrib.messages.context_processors.messages",
|
||||||
|
"{{ cookiecutter.project_slug }}.utils.context_processors.settings_context",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# https://docs.djangoproject.com/en/dev/ref/settings/#form-renderer
|
||||||
|
FORM_RENDERER = "django.forms.renderers.TemplatesSetting"
|
||||||
|
|
||||||
# http://django-crispy-forms.readthedocs.io/en/latest/install.html#template-packs
|
# http://django-crispy-forms.readthedocs.io/en/latest/install.html#template-packs
|
||||||
CRISPY_TEMPLATE_PACK = 'bootstrap4'
|
CRISPY_TEMPLATE_PACK = "bootstrap4"
|
||||||
|
|
||||||
# FIXTURES
|
# FIXTURES
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#fixture-dirs
|
# https://docs.djangoproject.com/en/dev/ref/settings/#fixture-dirs
|
||||||
FIXTURE_DIRS = (
|
FIXTURE_DIRS = (str(APPS_DIR.path("fixtures")),)
|
||||||
str(APPS_DIR.path('fixtures')),
|
|
||||||
)
|
|
||||||
|
|
||||||
# SECURITY
|
# SECURITY
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
@ -218,70 +218,107 @@ CSRF_COOKIE_HTTPONLY = True
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#secure-browser-xss-filter
|
# https://docs.djangoproject.com/en/dev/ref/settings/#secure-browser-xss-filter
|
||||||
SECURE_BROWSER_XSS_FILTER = True
|
SECURE_BROWSER_XSS_FILTER = True
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#x-frame-options
|
# https://docs.djangoproject.com/en/dev/ref/settings/#x-frame-options
|
||||||
X_FRAME_OPTIONS = 'DENY'
|
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
|
||||||
EMAIL_BACKEND = env('DJANGO_EMAIL_BACKEND', default='django.core.mail.backends.smtp.EmailBackend')
|
EMAIL_BACKEND = env(
|
||||||
|
"DJANGO_EMAIL_BACKEND", default="django.core.mail.backends.smtp.EmailBackend"
|
||||||
|
)
|
||||||
|
# https://docs.djangoproject.com/en/2.2/ref/settings/#email-timeout
|
||||||
|
EMAIL_TIMEOUT = 5
|
||||||
|
|
||||||
# ADMIN
|
# ADMIN
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# Django Admin URL.
|
# Django Admin URL.
|
||||||
ADMIN_URL = 'admin/'
|
ADMIN_URL = "admin/"
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#admins
|
# https://docs.djangoproject.com/en/dev/ref/settings/#admins
|
||||||
ADMINS = [
|
ADMINS = [("""{{cookiecutter.author_name}}""", "{{cookiecutter.email}}")]
|
||||||
("""{{cookiecutter.author_name}}""", '{{cookiecutter.email}}'),
|
|
||||||
]
|
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#managers
|
# https://docs.djangoproject.com/en/dev/ref/settings/#managers
|
||||||
MANAGERS = ADMINS
|
MANAGERS = ADMINS
|
||||||
|
|
||||||
|
# LOGGING
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# https://docs.djangoproject.com/en/dev/ref/settings/#logging
|
||||||
|
# See https://docs.djangoproject.com/en/dev/topics/logging for
|
||||||
|
# more details on how to customize your logging configuration.
|
||||||
|
LOGGING = {
|
||||||
|
"version": 1,
|
||||||
|
"disable_existing_loggers": False,
|
||||||
|
"formatters": {
|
||||||
|
"verbose": {
|
||||||
|
"format": "%(levelname)s %(asctime)s %(module)s "
|
||||||
|
"%(process)d %(thread)d %(message)s"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"handlers": {
|
||||||
|
"console": {
|
||||||
|
"level": "DEBUG",
|
||||||
|
"class": "logging.StreamHandler",
|
||||||
|
"formatter": "verbose",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {"level": "INFO", "handlers": ["console"]},
|
||||||
|
}
|
||||||
|
|
||||||
{% if cookiecutter.use_celery == 'y' -%}
|
{% if cookiecutter.use_celery == 'y' -%}
|
||||||
# Celery
|
# Celery
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
INSTALLED_APPS += ['{{cookiecutter.project_slug}}.taskapp.celery.CeleryAppConfig']
|
|
||||||
if USE_TZ:
|
if USE_TZ:
|
||||||
# http://docs.celeryproject.org/en/latest/userguide/configuration.html#std:setting-timezone
|
# http://docs.celeryproject.org/en/latest/userguide/configuration.html#std:setting-timezone
|
||||||
CELERY_TIMEZONE = TIME_ZONE
|
CELERY_TIMEZONE = TIME_ZONE
|
||||||
# http://docs.celeryproject.org/en/latest/userguide/configuration.html#std:setting-broker_url
|
# http://docs.celeryproject.org/en/latest/userguide/configuration.html#std:setting-broker_url
|
||||||
CELERY_BROKER_URL = env('CELERY_BROKER_URL')
|
CELERY_BROKER_URL = env("CELERY_BROKER_URL")
|
||||||
# http://docs.celeryproject.org/en/latest/userguide/configuration.html#std:setting-result_backend
|
# http://docs.celeryproject.org/en/latest/userguide/configuration.html#std:setting-result_backend
|
||||||
CELERY_RESULT_BACKEND = CELERY_BROKER_URL
|
CELERY_RESULT_BACKEND = CELERY_BROKER_URL
|
||||||
# http://docs.celeryproject.org/en/latest/userguide/configuration.html#std:setting-accept_content
|
# http://docs.celeryproject.org/en/latest/userguide/configuration.html#std:setting-accept_content
|
||||||
CELERY_ACCEPT_CONTENT = ['json']
|
CELERY_ACCEPT_CONTENT = ["json"]
|
||||||
# http://docs.celeryproject.org/en/latest/userguide/configuration.html#std:setting-task_serializer
|
# http://docs.celeryproject.org/en/latest/userguide/configuration.html#std:setting-task_serializer
|
||||||
CELERY_TASK_SERIALIZER = 'json'
|
CELERY_TASK_SERIALIZER = "json"
|
||||||
# http://docs.celeryproject.org/en/latest/userguide/configuration.html#std:setting-result_serializer
|
# http://docs.celeryproject.org/en/latest/userguide/configuration.html#std:setting-result_serializer
|
||||||
CELERY_RESULT_SERIALIZER = 'json'
|
CELERY_RESULT_SERIALIZER = "json"
|
||||||
# http://docs.celeryproject.org/en/latest/userguide/configuration.html#task-time-limit
|
# http://docs.celeryproject.org/en/latest/userguide/configuration.html#task-time-limit
|
||||||
# TODO: set to whatever value is adequate in your circumstances
|
# TODO: set to whatever value is adequate in your circumstances
|
||||||
CELERYD_TASK_TIME_LIMIT = 5 * 60
|
CELERY_TASK_TIME_LIMIT = 5 * 60
|
||||||
# http://docs.celeryproject.org/en/latest/userguide/configuration.html#task-soft-time-limit
|
# http://docs.celeryproject.org/en/latest/userguide/configuration.html#task-soft-time-limit
|
||||||
# TODO: set to whatever value is adequate in your circumstances
|
# TODO: set to whatever value is adequate in your circumstances
|
||||||
CELERYD_TASK_SOFT_TIME_LIMIT = 60
|
CELERY_TASK_SOFT_TIME_LIMIT = 60
|
||||||
|
# http://docs.celeryproject.org/en/latest/userguide/configuration.html#beat-scheduler
|
||||||
|
CELERY_BEAT_SCHEDULER = "django_celery_beat.schedulers:DatabaseScheduler"
|
||||||
|
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
# django-allauth
|
# django-allauth
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
ACCOUNT_ALLOW_REGISTRATION = env.bool('DJANGO_ACCOUNT_ALLOW_REGISTRATION', True)
|
ACCOUNT_ALLOW_REGISTRATION = env.bool("DJANGO_ACCOUNT_ALLOW_REGISTRATION", True)
|
||||||
# https://django-allauth.readthedocs.io/en/latest/configuration.html
|
# https://django-allauth.readthedocs.io/en/latest/configuration.html
|
||||||
ACCOUNT_AUTHENTICATION_METHOD = 'username'
|
ACCOUNT_AUTHENTICATION_METHOD = "username"
|
||||||
# https://django-allauth.readthedocs.io/en/latest/configuration.html
|
# https://django-allauth.readthedocs.io/en/latest/configuration.html
|
||||||
ACCOUNT_EMAIL_REQUIRED = True
|
ACCOUNT_EMAIL_REQUIRED = True
|
||||||
# https://django-allauth.readthedocs.io/en/latest/configuration.html
|
# https://django-allauth.readthedocs.io/en/latest/configuration.html
|
||||||
ACCOUNT_EMAIL_VERIFICATION = 'mandatory'
|
ACCOUNT_EMAIL_VERIFICATION = "mandatory"
|
||||||
# https://django-allauth.readthedocs.io/en/latest/configuration.html
|
# https://django-allauth.readthedocs.io/en/latest/configuration.html
|
||||||
ACCOUNT_ADAPTER = '{{cookiecutter.project_slug}}.users.adapters.AccountAdapter'
|
ACCOUNT_ADAPTER = "{{cookiecutter.project_slug}}.users.adapters.AccountAdapter"
|
||||||
# https://django-allauth.readthedocs.io/en/latest/configuration.html
|
# https://django-allauth.readthedocs.io/en/latest/configuration.html
|
||||||
SOCIALACCOUNT_ADAPTER = '{{cookiecutter.project_slug}}.users.adapters.SocialAccountAdapter'
|
SOCIALACCOUNT_ADAPTER = "{{cookiecutter.project_slug}}.users.adapters.SocialAccountAdapter"
|
||||||
|
|
||||||
{% if cookiecutter.use_compressor == 'y' -%}
|
{% if cookiecutter.use_compressor == 'y' -%}
|
||||||
# django-compressor
|
# django-compressor
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# https://django-compressor.readthedocs.io/en/latest/quickstart/#installation
|
# 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 %}
|
||||||
|
{% if cookiecutter.use_drf == "y" -%}
|
||||||
|
# django-reset-framework
|
||||||
|
# -------------------------------------------------------------------------------
|
||||||
|
# django-rest-framework - https://www.django-rest-framework.org/api-guide/settings/
|
||||||
|
REST_FRAMEWORK = {
|
||||||
|
"DEFAULT_AUTHENTICATION_CLASSES": (
|
||||||
|
"rest_framework.authentication.SessionAuthentication",
|
||||||
|
"rest_framework.authentication.TokenAuthentication",
|
||||||
|
),
|
||||||
|
"DEFAULT_PERMISSION_CLASSES": ("rest_framework.permissions.IsAuthenticated",),
|
||||||
|
}
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
# Your stuff...
|
# Your stuff...
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
|
@ -6,72 +6,75 @@ from .base import env
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#debug
|
# https://docs.djangoproject.com/en/dev/ref/settings/#debug
|
||||||
DEBUG = True
|
DEBUG = True
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#secret-key
|
# https://docs.djangoproject.com/en/dev/ref/settings/#secret-key
|
||||||
SECRET_KEY = env('DJANGO_SECRET_KEY', default='!!!SET DJANGO_SECRET_KEY!!!')
|
SECRET_KEY = env(
|
||||||
|
"DJANGO_SECRET_KEY",
|
||||||
|
default="!!!SET DJANGO_SECRET_KEY!!!",
|
||||||
|
)
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts
|
# https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts
|
||||||
ALLOWED_HOSTS = [
|
ALLOWED_HOSTS = ["localhost", "0.0.0.0", "127.0.0.1"]
|
||||||
"localhost",
|
|
||||||
"0.0.0.0",
|
|
||||||
"127.0.0.1",
|
|
||||||
]
|
|
||||||
|
|
||||||
# CACHES
|
# CACHES
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#caches
|
# 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",
|
||||||
'LOCATION': ''
|
"LOCATION": "",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# TEMPLATES
|
|
||||||
# ------------------------------------------------------------------------------
|
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#templates
|
|
||||||
TEMPLATES[0]['OPTIONS']['debug'] = DEBUG # noqa F405
|
|
||||||
|
|
||||||
# EMAIL
|
# EMAIL
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
{% if cookiecutter.use_mailhog == 'y' and cookiecutter.use_docker == 'y' -%}
|
{% if cookiecutter.use_mailhog == 'y' and cookiecutter.use_docker == 'y' -%}
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#email-host
|
# https://docs.djangoproject.com/en/dev/ref/settings/#email-host
|
||||||
EMAIL_HOST = env('EMAIL_HOST', default='mailhog')
|
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
|
# https://docs.djangoproject.com/en/dev/ref/settings/#email-port
|
||||||
EMAIL_PORT = 1025
|
EMAIL_PORT = 1025
|
||||||
|
{%- elif cookiecutter.use_mailhog == 'y' and cookiecutter.use_docker == 'n' -%}
|
||||||
|
# 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
|
||||||
|
{%- else -%}
|
||||||
|
# https://docs.djangoproject.com/en/dev/ref/settings/#email-backend
|
||||||
|
EMAIL_BACKEND = env(
|
||||||
|
"DJANGO_EMAIL_BACKEND", default="django.core.mail.backends.console.EmailBackend"
|
||||||
|
)
|
||||||
|
{%- endif %}
|
||||||
|
|
||||||
|
{%- if cookiecutter.use_whitenoise == 'y' %}
|
||||||
|
|
||||||
|
# WhiteNoise
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# http://whitenoise.evans.io/en/latest/django.html#using-whitenoise-in-development
|
||||||
|
INSTALLED_APPS = ["whitenoise.runserver_nostatic"] + INSTALLED_APPS # noqa F405
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
# django-debug-toolbar
|
# django-debug-toolbar
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# https://django-debug-toolbar.readthedocs.io/en/latest/installation.html#prerequisites
|
# https://django-debug-toolbar.readthedocs.io/en/latest/installation.html#prerequisites
|
||||||
INSTALLED_APPS += ['debug_toolbar'] # noqa F405
|
INSTALLED_APPS += ["debug_toolbar"] # noqa F405
|
||||||
# https://django-debug-toolbar.readthedocs.io/en/latest/installation.html#middleware
|
# https://django-debug-toolbar.readthedocs.io/en/latest/installation.html#middleware
|
||||||
MIDDLEWARE += ['debug_toolbar.middleware.DebugToolbarMiddleware'] # noqa F405
|
MIDDLEWARE += ["debug_toolbar.middleware.DebugToolbarMiddleware"] # noqa F405
|
||||||
# https://django-debug-toolbar.readthedocs.io/en/latest/configuration.html#debug-toolbar-config
|
# https://django-debug-toolbar.readthedocs.io/en/latest/configuration.html#debug-toolbar-config
|
||||||
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
|
# https://django-debug-toolbar.readthedocs.io/en/latest/installation.html#internal-ips
|
||||||
INTERNAL_IPS = ['127.0.0.1', '10.0.2.2']
|
INTERNAL_IPS = ["127.0.0.1", "10.0.2.2"]
|
||||||
{% if cookiecutter.use_docker == 'y' -%}
|
{% if cookiecutter.use_docker == 'y' -%}
|
||||||
if env('USE_DOCKER') == 'yes':
|
if env("USE_DOCKER") == "yes":
|
||||||
import socket
|
import socket
|
||||||
|
|
||||||
hostname, _, ips = socket.gethostbyname_ex(socket.gethostname())
|
hostname, _, ips = socket.gethostbyname_ex(socket.gethostname())
|
||||||
INTERNAL_IPS += [ip[:-1] + '1' for ip in ips]
|
INTERNAL_IPS += [ip[:-1] + "1" for ip in ips]
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
||||||
# django-extensions
|
# django-extensions
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# https://django-extensions.readthedocs.io/en/latest/installation_instructions.html#configuration
|
# https://django-extensions.readthedocs.io/en/latest/installation_instructions.html#configuration
|
||||||
INSTALLED_APPS += ['django_extensions'] # noqa F405
|
INSTALLED_APPS += ["django_extensions"] # noqa F405
|
||||||
{% if cookiecutter.use_celery == 'y' -%}
|
{% if cookiecutter.use_celery == 'y' -%}
|
||||||
|
|
||||||
# Celery
|
# Celery
|
||||||
|
|
|
@ -1,6 +1,14 @@
|
||||||
{% if cookiecutter.use_sentry == 'y' -%}
|
{% if cookiecutter.use_sentry == 'y' -%}
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
import sentry_sdk
|
||||||
|
|
||||||
|
from sentry_sdk.integrations.django import DjangoIntegration
|
||||||
|
from sentry_sdk.integrations.logging import LoggingIntegration
|
||||||
|
{%- if cookiecutter.use_celery == 'y' %}
|
||||||
|
from sentry_sdk.integrations.celery import CeleryIntegration
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% endif -%}
|
{% endif -%}
|
||||||
from .base import * # noqa
|
from .base import * # noqa
|
||||||
from .base import env
|
from .base import env
|
||||||
|
@ -8,37 +16,37 @@ from .base import env
|
||||||
# GENERAL
|
# GENERAL
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#secret-key
|
# https://docs.djangoproject.com/en/dev/ref/settings/#secret-key
|
||||||
SECRET_KEY = env('DJANGO_SECRET_KEY')
|
SECRET_KEY = env("DJANGO_SECRET_KEY")
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts
|
# https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts
|
||||||
ALLOWED_HOSTS = env.list('DJANGO_ALLOWED_HOSTS', default=['{{ cookiecutter.domain_name }}'])
|
ALLOWED_HOSTS = env.list("DJANGO_ALLOWED_HOSTS", default=["{{ cookiecutter.domain_name }}"])
|
||||||
|
|
||||||
# DATABASES
|
# DATABASES
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
DATABASES['default'] = env.db('DATABASE_URL') # noqa F405
|
DATABASES["default"] = env.db("DATABASE_URL") # noqa F405
|
||||||
DATABASES['default']['ATOMIC_REQUESTS'] = True # noqa F405
|
DATABASES["default"]["ATOMIC_REQUESTS"] = True # noqa F405
|
||||||
DATABASES['default']['CONN_MAX_AGE'] = env.int('CONN_MAX_AGE', default=60) # noqa F405
|
DATABASES["default"]["CONN_MAX_AGE"] = env.int("CONN_MAX_AGE", default=60) # noqa F405
|
||||||
|
|
||||||
# CACHES
|
# CACHES
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
CACHES = {
|
CACHES = {
|
||||||
'default': {
|
"default": {
|
||||||
'BACKEND': 'django_redis.cache.RedisCache',
|
"BACKEND": "django_redis.cache.RedisCache",
|
||||||
'LOCATION': env('REDIS_URL'),
|
"LOCATION": env("REDIS_URL"),
|
||||||
'OPTIONS': {
|
"OPTIONS": {
|
||||||
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
|
"CLIENT_CLASS": "django_redis.client.DefaultClient",
|
||||||
# Mimicing 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,
|
"IGNORE_EXCEPTIONS": True,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# SECURITY
|
# SECURITY
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#secure-proxy-ssl-header
|
# https://docs.djangoproject.com/en/dev/ref/settings/#secure-proxy-ssl-header
|
||||||
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
|
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#secure-ssl-redirect
|
# https://docs.djangoproject.com/en/dev/ref/settings/#secure-ssl-redirect
|
||||||
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/#csrf-cookie-secure
|
# https://docs.djangoproject.com/en/dev/ref/settings/#csrf-cookie-secure
|
||||||
|
@ -48,249 +56,257 @@ CSRF_COOKIE_SECURE = True
|
||||||
# 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
|
||||||
SECURE_HSTS_SECONDS = 60
|
SECURE_HSTS_SECONDS = 60
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#secure-hsts-include-subdomains
|
# 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)
|
SECURE_HSTS_INCLUDE_SUBDOMAINS = env.bool(
|
||||||
|
"DJANGO_SECURE_HSTS_INCLUDE_SUBDOMAINS", default=True
|
||||||
|
)
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#secure-hsts-preload
|
# https://docs.djangoproject.com/en/dev/ref/settings/#secure-hsts-preload
|
||||||
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
|
||||||
|
)
|
||||||
|
|
||||||
|
{% if cookiecutter.cloud_provider != 'None' -%}
|
||||||
# STORAGES
|
# STORAGES
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# https://django-storages.readthedocs.io/en/latest/#installation
|
# https://django-storages.readthedocs.io/en/latest/#installation
|
||||||
INSTALLED_APPS += ['storages'] # noqa F405
|
INSTALLED_APPS += ["storages"] # noqa F405
|
||||||
|
{%- endif -%}
|
||||||
|
{% if cookiecutter.cloud_provider == 'AWS' %}
|
||||||
# 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_ACCESS_KEY_ID = env('DJANGO_AWS_ACCESS_KEY_ID')
|
AWS_ACCESS_KEY_ID = env("DJANGO_AWS_ACCESS_KEY_ID")
|
||||||
# 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_SECRET_ACCESS_KEY = env('DJANGO_AWS_SECRET_ACCESS_KEY')
|
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_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
|
||||||
# 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_S3_OBJECT_PARAMETERS = {
|
AWS_S3_OBJECT_PARAMETERS = {
|
||||||
'CacheControl': f'max-age={_AWS_EXPIRY}, s-maxage={_AWS_EXPIRY}, must-revalidate',
|
"CacheControl": f"max-age={_AWS_EXPIRY}, s-maxage={_AWS_EXPIRY}, must-revalidate"
|
||||||
}
|
}
|
||||||
|
# https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#settings
|
||||||
|
AWS_DEFAULT_ACL = None
|
||||||
|
# https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#settings
|
||||||
|
AWS_S3_REGION_NAME = env("DJANGO_AWS_S3_REGION_NAME", default=None)
|
||||||
|
{% elif cookiecutter.cloud_provider == 'GCP' %}
|
||||||
|
GS_BUCKET_NAME = env("DJANGO_GCP_STORAGE_BUCKET_NAME")
|
||||||
|
GS_DEFAULT_ACL = "publicRead"
|
||||||
|
{% endif -%}
|
||||||
|
|
||||||
|
{% if cookiecutter.cloud_provider != 'None' or cookiecutter.use_whitenoise == 'y' -%}
|
||||||
# STATIC
|
# STATIC
|
||||||
# ------------------------
|
# ------------------------
|
||||||
|
{% endif -%}
|
||||||
{% if cookiecutter.use_whitenoise == 'y' -%}
|
{% if cookiecutter.use_whitenoise == 'y' -%}
|
||||||
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
|
STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage"
|
||||||
{%- else %}
|
{% elif cookiecutter.cloud_provider == 'AWS' -%}
|
||||||
STATICFILES_STORAGE = 'config.settings.production.StaticRootS3Boto3Storage'
|
STATICFILES_STORAGE = "config.settings.production.StaticRootS3Boto3Storage"
|
||||||
STATIC_URL = f'https://{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com/static/'
|
COLLECTFAST_STRATEGY = "collectfast.strategies.boto3.Boto3Strategy"
|
||||||
{%- endif %}
|
STATIC_URL = f"https://{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com/static/"
|
||||||
|
{% elif cookiecutter.cloud_provider == 'GCP' -%}
|
||||||
|
STATICFILES_STORAGE = "config.settings.production.StaticRootGoogleCloudStorage"
|
||||||
|
COLLECTFAST_STRATEGY = "collectfast.strategies.gcloud.GoogleCloudStrategy"
|
||||||
|
STATIC_URL = f"https://storage.googleapis.com/{GS_BUCKET_NAME}/static/"
|
||||||
|
{% endif -%}
|
||||||
|
|
||||||
# MEDIA
|
# MEDIA
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
{% if cookiecutter.use_whitenoise == 'y' -%}
|
{%- if cookiecutter.cloud_provider == 'AWS' %}
|
||||||
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
|
|
||||||
MEDIA_URL = f'https://{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com/'
|
|
||||||
{%- else %}
|
|
||||||
# region http://stackoverflow.com/questions/10390244/
|
# region http://stackoverflow.com/questions/10390244/
|
||||||
# Full-fledge class: https://stackoverflow.com/a/18046120/104731
|
# 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
|
||||||
|
|
||||||
|
|
||||||
class StaticRootS3Boto3Storage(S3Boto3Storage):
|
class StaticRootS3Boto3Storage(S3Boto3Storage):
|
||||||
location = 'static'
|
location = "static"
|
||||||
|
default_acl = "public-read"
|
||||||
|
|
||||||
|
|
||||||
class MediaRootS3Boto3Storage(S3Boto3Storage):
|
class MediaRootS3Boto3Storage(S3Boto3Storage):
|
||||||
location = 'media'
|
location = "media"
|
||||||
file_overwrite = False
|
file_overwrite = False
|
||||||
|
|
||||||
|
|
||||||
# endregion
|
# endregion
|
||||||
DEFAULT_FILE_STORAGE = 'config.settings.production.MediaRootS3Boto3Storage'
|
DEFAULT_FILE_STORAGE = "config.settings.production.MediaRootS3Boto3Storage"
|
||||||
MEDIA_URL = f'https://{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com/media/'
|
MEDIA_URL = f"https://{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com/media/"
|
||||||
|
{%- elif cookiecutter.cloud_provider == 'GCP' %}
|
||||||
|
from storages.backends.gcloud import GoogleCloudStorage # noqa E402
|
||||||
|
|
||||||
|
|
||||||
|
class StaticRootGoogleCloudStorage(GoogleCloudStorage):
|
||||||
|
location = "static"
|
||||||
|
default_acl = "publicRead"
|
||||||
|
|
||||||
|
|
||||||
|
class MediaRootGoogleCloudStorage(GoogleCloudStorage):
|
||||||
|
location = "media"
|
||||||
|
file_overwrite = False
|
||||||
|
|
||||||
|
|
||||||
|
DEFAULT_FILE_STORAGE = "config.settings.production.MediaRootGoogleCloudStorage"
|
||||||
|
MEDIA_URL = f"https://storage.googleapis.com/{GS_BUCKET_NAME}/media/"
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
||||||
# TEMPLATES
|
# TEMPLATES
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#templates
|
# https://docs.djangoproject.com/en/dev/ref/settings/#templates
|
||||||
TEMPLATES[0]['OPTIONS']['loaders'] = [ # noqa F405
|
TEMPLATES[-1]["OPTIONS"]["loaders"] = [ # type: ignore[index] # noqa F405
|
||||||
(
|
(
|
||||||
'django.template.loaders.cached.Loader',
|
"django.template.loaders.cached.Loader",
|
||||||
[
|
[
|
||||||
'django.template.loaders.filesystem.Loader',
|
"django.template.loaders.filesystem.Loader",
|
||||||
'django.template.loaders.app_directories.Loader',
|
"django.template.loaders.app_directories.Loader",
|
||||||
]
|
],
|
||||||
),
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
# EMAIL
|
# EMAIL
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#default-from-email
|
# https://docs.djangoproject.com/en/dev/ref/settings/#default-from-email
|
||||||
DEFAULT_FROM_EMAIL = env(
|
DEFAULT_FROM_EMAIL = env(
|
||||||
'DJANGO_DEFAULT_FROM_EMAIL',
|
"DJANGO_DEFAULT_FROM_EMAIL", default="{{cookiecutter.project_name}} <noreply@{{cookiecutter.domain_name}}>"
|
||||||
default='{{cookiecutter.project_name}} <noreply@{{cookiecutter.domain_name}}>'
|
|
||||||
)
|
)
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#server-email
|
# https://docs.djangoproject.com/en/dev/ref/settings/#server-email
|
||||||
SERVER_EMAIL = env('DJANGO_SERVER_EMAIL', default=DEFAULT_FROM_EMAIL)
|
SERVER_EMAIL = env("DJANGO_SERVER_EMAIL", default=DEFAULT_FROM_EMAIL)
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#email-subject-prefix
|
# https://docs.djangoproject.com/en/dev/ref/settings/#email-subject-prefix
|
||||||
EMAIL_SUBJECT_PREFIX = env('DJANGO_EMAIL_SUBJECT_PREFIX', default='[{{cookiecutter.project_name}}]')
|
EMAIL_SUBJECT_PREFIX = env(
|
||||||
|
"DJANGO_EMAIL_SUBJECT_PREFIX", default="[{{cookiecutter.project_name}}]"
|
||||||
|
)
|
||||||
|
|
||||||
# ADMIN
|
# ADMIN
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# Django Admin URL regex.
|
# Django Admin URL regex.
|
||||||
ADMIN_URL = env('DJANGO_ADMIN_URL')
|
ADMIN_URL = env("DJANGO_ADMIN_URL")
|
||||||
|
|
||||||
# Anymail (Mailgun)
|
# Anymail (Mailgun)
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# https://anymail.readthedocs.io/en/stable/installation/#installing-anymail
|
# https://anymail.readthedocs.io/en/stable/installation/#installing-anymail
|
||||||
INSTALLED_APPS += ['anymail'] # noqa F405
|
INSTALLED_APPS += ["anymail"] # noqa F405
|
||||||
EMAIL_BACKEND = 'anymail.backends.mailgun.EmailBackend'
|
EMAIL_BACKEND = "anymail.backends.mailgun.EmailBackend"
|
||||||
# https://anymail.readthedocs.io/en/stable/installation/#anymail-settings-reference
|
# https://anymail.readthedocs.io/en/stable/installation/#anymail-settings-reference
|
||||||
ANYMAIL = {
|
ANYMAIL = {
|
||||||
'MAILGUN_API_KEY': env('MAILGUN_API_KEY'),
|
"MAILGUN_API_KEY": env("MAILGUN_API_KEY"),
|
||||||
'MAILGUN_SENDER_DOMAIN': env('MAILGUN_DOMAIN')
|
"MAILGUN_SENDER_DOMAIN": env("MAILGUN_DOMAIN"),
|
||||||
|
"MAILGUN_API_URL": env("MAILGUN_API_URL", default="https://api.mailgun.net/v3"),
|
||||||
}
|
}
|
||||||
|
|
||||||
# Gunicorn
|
{% if cookiecutter.use_compressor == 'y' -%}
|
||||||
# ------------------------------------------------------------------------------
|
|
||||||
INSTALLED_APPS += ['gunicorn'] # noqa F405
|
|
||||||
|
|
||||||
{% if cookiecutter.use_whitenoise == 'y' -%}
|
|
||||||
# WhiteNoise
|
|
||||||
# ------------------------------------------------------------------------------
|
|
||||||
# http://whitenoise.evans.io/en/latest/django.html#enable-whitenoise
|
|
||||||
MIDDLEWARE.insert(1, 'whitenoise.middleware.WhiteNoiseMiddleware') # noqa F405
|
|
||||||
|
|
||||||
{% endif %}
|
|
||||||
{%- if cookiecutter.use_compressor == 'y' -%}
|
|
||||||
# django-compressor
|
# django-compressor
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# https://django-compressor.readthedocs.io/en/latest/settings/#django.conf.settings.COMPRESS_ENABLED
|
# https://django-compressor.readthedocs.io/en/latest/settings/#django.conf.settings.COMPRESS_ENABLED
|
||||||
COMPRESS_ENABLED = env.bool('COMPRESS_ENABLED', default=True)
|
COMPRESS_ENABLED = env.bool("COMPRESS_ENABLED", default=True)
|
||||||
# https://django-compressor.readthedocs.io/en/latest/settings/#django.conf.settings.COMPRESS_STORAGE
|
# https://django-compressor.readthedocs.io/en/latest/settings/#django.conf.settings.COMPRESS_STORAGE
|
||||||
COMPRESS_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
|
COMPRESS_STORAGE = "storages.backends.s3boto3.S3Boto3Storage"
|
||||||
# https://django-compressor.readthedocs.io/en/latest/settings/#django.conf.settings.COMPRESS_URL
|
# https://django-compressor.readthedocs.io/en/latest/settings/#django.conf.settings.COMPRESS_URL
|
||||||
COMPRESS_URL = STATIC_URL
|
COMPRESS_URL = STATIC_URL{% if cookiecutter.use_whitenoise == 'y' or cookiecutter.cloud_provider == 'None' %} # noqa F405{% endif %}
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{%- if cookiecutter.use_whitenoise == 'n' -%}
|
{%- if cookiecutter.use_whitenoise == 'n' -%}
|
||||||
# Collectfast
|
# Collectfast
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# https://github.com/antonagestam/collectfast#installation
|
# https://github.com/antonagestam/collectfast#installation
|
||||||
INSTALLED_APPS = ['collectfast'] + INSTALLED_APPS # noqa F405
|
INSTALLED_APPS = ["collectfast"] + INSTALLED_APPS # noqa F405
|
||||||
AWS_PRELOAD_METADATA = True
|
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{%- if cookiecutter.use_sentry == '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('SENTRY_DSN')
|
|
||||||
SENTRY_CLIENT = env('DJANGO_SENTRY_CLIENT', default='raven.contrib.django.raven_compat.DjangoClient')
|
|
||||||
LOGGING = {
|
|
||||||
'version': 1,
|
|
||||||
'disable_existing_loggers': True,
|
|
||||||
'root': {
|
|
||||||
'level': 'WARNING',
|
|
||||||
'handlers': ['sentry'],
|
|
||||||
},
|
|
||||||
'formatters': {
|
|
||||||
'verbose': {
|
|
||||||
'format': '%(levelname)s %(asctime)s %(module)s '
|
|
||||||
'%(process)d %(thread)d %(message)s'
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'handlers': {
|
|
||||||
'sentry': {
|
|
||||||
'level': 'ERROR',
|
|
||||||
'class': 'raven.contrib.django.raven_compat.handlers.SentryHandler',
|
|
||||||
},
|
|
||||||
'console': {
|
|
||||||
'level': 'DEBUG',
|
|
||||||
'class': 'logging.StreamHandler',
|
|
||||||
'formatter': 'verbose'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'loggers': {
|
|
||||||
'django.db.backends': {
|
|
||||||
'level': 'ERROR',
|
|
||||||
'handlers': ['console'],
|
|
||||||
'propagate': False,
|
|
||||||
},
|
|
||||||
'raven': {
|
|
||||||
'level': 'DEBUG',
|
|
||||||
'handlers': ['console'],
|
|
||||||
'propagate': False,
|
|
||||||
},
|
|
||||||
'sentry.errors': {
|
|
||||||
'level': 'DEBUG',
|
|
||||||
'handlers': ['console'],
|
|
||||||
'propagate': False,
|
|
||||||
},
|
|
||||||
'django.security.DisallowedHost': {
|
|
||||||
'level': 'ERROR',
|
|
||||||
'handlers': ['console', 'sentry'],
|
|
||||||
'propagate': False,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
SENTRY_CELERY_LOGLEVEL = env.int('DJANGO_SENTRY_LOG_LEVEL', logging.INFO)
|
|
||||||
RAVEN_CONFIG = {
|
|
||||||
'dsn': SENTRY_DSN
|
|
||||||
}
|
|
||||||
|
|
||||||
{%- else %}
|
|
||||||
# LOGGING
|
# LOGGING
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# See: https://docs.djangoproject.com/en/dev/ref/settings/#logging
|
# https://docs.djangoproject.com/en/dev/ref/settings/#logging
|
||||||
|
# See https://docs.djangoproject.com/en/dev/topics/logging for
|
||||||
|
# more details on how to customize your logging configuration.
|
||||||
|
{% if cookiecutter.use_sentry == 'n' -%}
|
||||||
# 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 on every HTTP 500 error when DEBUG=False.
|
||||||
# See https://docs.djangoproject.com/en/dev/topics/logging for
|
|
||||||
# more details on how to customize your logging configuration.
|
|
||||||
LOGGING = {
|
LOGGING = {
|
||||||
'version': 1,
|
"version": 1,
|
||||||
'disable_existing_loggers': False,
|
"disable_existing_loggers": False,
|
||||||
'filters': {
|
"filters": {"require_debug_false": {"()": "django.utils.log.RequireDebugFalse"}},
|
||||||
'require_debug_false': {
|
"formatters": {
|
||||||
'()': 'django.utils.log.RequireDebugFalse'
|
"verbose": {
|
||||||
|
"format": "%(levelname)s %(asctime)s %(module)s "
|
||||||
|
"%(process)d %(thread)d %(message)s"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'formatters': {
|
"handlers": {
|
||||||
'verbose': {
|
"mail_admins": {
|
||||||
'format': '%(levelname)s %(asctime)s %(module)s '
|
"level": "ERROR",
|
||||||
'%(process)d %(thread)d %(message)s'
|
"filters": ["require_debug_false"],
|
||||||
|
"class": "django.utils.log.AdminEmailHandler",
|
||||||
|
},
|
||||||
|
"console": {
|
||||||
|
"level": "DEBUG",
|
||||||
|
"class": "logging.StreamHandler",
|
||||||
|
"formatter": "verbose",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'handlers': {
|
"root": {"level": "INFO", "handlers": ["console"]},
|
||||||
'mail_admins': {
|
"loggers": {
|
||||||
'level': 'ERROR',
|
"django.request": {
|
||||||
'filters': ['require_debug_false'],
|
"handlers": ["mail_admins"],
|
||||||
'class': 'django.utils.log.AdminEmailHandler'
|
"level": "ERROR",
|
||||||
|
"propagate": True,
|
||||||
},
|
},
|
||||||
'console': {
|
"django.security.DisallowedHost": {
|
||||||
'level': 'DEBUG',
|
"level": "ERROR",
|
||||||
'class': 'logging.StreamHandler',
|
"handlers": ["console", "mail_admins"],
|
||||||
'formatter': 'verbose',
|
"propagate": True,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'loggers': {
|
}
|
||||||
'django.request': {
|
{% else %}
|
||||||
'handlers': ['mail_admins'],
|
LOGGING = {
|
||||||
'level': 'ERROR',
|
"version": 1,
|
||||||
'propagate': True
|
"disable_existing_loggers": True,
|
||||||
},
|
"formatters": {
|
||||||
'django.security.DisallowedHost': {
|
"verbose": {
|
||||||
'level': 'ERROR',
|
"format": "%(levelname)s %(asctime)s %(module)s "
|
||||||
'handlers': ['console', 'mail_admins'],
|
"%(process)d %(thread)d %(message)s"
|
||||||
'propagate': True
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"handlers": {
|
||||||
|
"console": {
|
||||||
|
"level": "DEBUG",
|
||||||
|
"class": "logging.StreamHandler",
|
||||||
|
"formatter": "verbose",
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"root": {"level": "INFO", "handlers": ["console"]},
|
||||||
|
"loggers": {
|
||||||
|
"django.db.backends": {
|
||||||
|
"level": "ERROR",
|
||||||
|
"handlers": ["console"],
|
||||||
|
"propagate": False,
|
||||||
|
},
|
||||||
|
# Errors logged by the SDK itself
|
||||||
|
"sentry_sdk": {"level": "ERROR", "handlers": ["console"], "propagate": False},
|
||||||
|
"django.security.DisallowedHost": {
|
||||||
|
"level": "ERROR",
|
||||||
|
"handlers": ["console"],
|
||||||
|
"propagate": False,
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Sentry
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
SENTRY_DSN = env("SENTRY_DSN")
|
||||||
|
SENTRY_LOG_LEVEL = env.int("DJANGO_SENTRY_LOG_LEVEL", logging.INFO)
|
||||||
|
|
||||||
|
sentry_logging = LoggingIntegration(
|
||||||
|
level=SENTRY_LOG_LEVEL, # Capture info and above as breadcrumbs
|
||||||
|
event_level=logging.ERROR, # Send errors as events
|
||||||
|
)
|
||||||
|
|
||||||
|
{%- if cookiecutter.use_celery == 'y' %}
|
||||||
|
sentry_sdk.init(
|
||||||
|
dsn=SENTRY_DSN,
|
||||||
|
integrations=[sentry_logging, DjangoIntegration(), CeleryIntegration()],
|
||||||
|
)
|
||||||
|
{% else %}
|
||||||
|
sentry_sdk.init(dsn=SENTRY_DSN, integrations=[sentry_logging, DjangoIntegration()])
|
||||||
|
{% endif -%}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
# Your stuff...
|
# Your stuff...
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
|
@ -7,10 +7,11 @@ from .base import env
|
||||||
|
|
||||||
# GENERAL
|
# GENERAL
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#debug
|
|
||||||
DEBUG = False
|
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#secret-key
|
# https://docs.djangoproject.com/en/dev/ref/settings/#secret-key
|
||||||
SECRET_KEY = env("DJANGO_SECRET_KEY", default="!!!SET DJANGO_SECRET_KEY!!!")
|
SECRET_KEY = env(
|
||||||
|
"DJANGO_SECRET_KEY",
|
||||||
|
default="!!!SET DJANGO_SECRET_KEY!!!",
|
||||||
|
)
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#test-runner
|
# https://docs.djangoproject.com/en/dev/ref/settings/#test-runner
|
||||||
TEST_RUNNER = "django.test.runner.DiscoverRunner"
|
TEST_RUNNER = "django.test.runner.DiscoverRunner"
|
||||||
|
|
||||||
|
@ -19,7 +20,8 @@ TEST_RUNNER = "django.test.runner.DiscoverRunner"
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#caches
|
# https://docs.djangoproject.com/en/dev/ref/settings/#caches
|
||||||
CACHES = {
|
CACHES = {
|
||||||
"default": {
|
"default": {
|
||||||
"BACKEND": "django.core.cache.backends.locmem.LocMemCache", "LOCATION": ""
|
"BACKEND": "django.core.cache.backends.locmem.LocMemCache",
|
||||||
|
"LOCATION": "",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,9 +32,7 @@ PASSWORD_HASHERS = ["django.contrib.auth.hashers.MD5PasswordHasher"]
|
||||||
|
|
||||||
# TEMPLATES
|
# TEMPLATES
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#templates
|
TEMPLATES[-1]["OPTIONS"]["loaders"] = [ # type: ignore[index] # noqa F405
|
||||||
TEMPLATES[0]["OPTIONS"]["debug"] = DEBUG # noqa F405
|
|
||||||
TEMPLATES[0]["OPTIONS"]["loaders"] = [ # noqa F405
|
|
||||||
(
|
(
|
||||||
"django.template.loaders.cached.Loader",
|
"django.template.loaders.cached.Loader",
|
||||||
[
|
[
|
||||||
|
@ -46,10 +46,6 @@ TEMPLATES[0]["OPTIONS"]["loaders"] = [ # noqa F405
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#email-backend
|
# https://docs.djangoproject.com/en/dev/ref/settings/#email-backend
|
||||||
EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend"
|
EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend"
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#email-host
|
|
||||||
EMAIL_HOST = "localhost"
|
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#email-port
|
|
||||||
EMAIL_PORT = 1025
|
|
||||||
|
|
||||||
# Your stuff...
|
# Your stuff...
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
|
@ -4,26 +4,31 @@ from django.conf.urls.static import static
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.views.generic import TemplateView
|
from django.views.generic import TemplateView
|
||||||
from django.views import defaults as default_views
|
from django.views import defaults as default_views
|
||||||
|
{% if cookiecutter.use_drf == 'y' -%}
|
||||||
|
from rest_framework.authtoken.views import obtain_auth_token
|
||||||
|
{%- endif %}
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("", TemplateView.as_view(template_name="pages/home.html"), name="home"),
|
path("", TemplateView.as_view(template_name="pages/home.html"), name="home"),
|
||||||
path(
|
path(
|
||||||
"about/",
|
"about/", TemplateView.as_view(template_name="pages/about.html"), name="about"
|
||||||
TemplateView.as_view(template_name="pages/about.html"),
|
|
||||||
name="about",
|
|
||||||
),
|
),
|
||||||
# Django Admin, use {% raw %}{% url 'admin:index' %}{% endraw %}
|
# Django Admin, use {% raw %}{% url 'admin:index' %}{% endraw %}
|
||||||
path(settings.ADMIN_URL, admin.site.urls),
|
path(settings.ADMIN_URL, admin.site.urls),
|
||||||
# User management
|
# User management
|
||||||
path(
|
path("users/", include("{{ cookiecutter.project_slug }}.users.urls", namespace="users")),
|
||||||
"users/",
|
|
||||||
include("{{ cookiecutter.project_slug }}.users.urls", namespace="users"),
|
|
||||||
),
|
|
||||||
path("accounts/", include("allauth.urls")),
|
path("accounts/", include("allauth.urls")),
|
||||||
# Your stuff: custom urls includes go here
|
# Your stuff: custom urls includes go here
|
||||||
] + static(
|
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||||
settings.MEDIA_URL, document_root=settings.MEDIA_ROOT
|
{% if cookiecutter.use_drf == 'y' -%}
|
||||||
)
|
# API URLS
|
||||||
|
urlpatterns += [
|
||||||
|
# API base url
|
||||||
|
path("api/", include("config.api_router")),
|
||||||
|
# DRF auth token
|
||||||
|
path("auth-token/", obtain_auth_token),
|
||||||
|
]
|
||||||
|
{%- endif %}
|
||||||
|
|
||||||
if settings.DEBUG:
|
if settings.DEBUG:
|
||||||
# This allows the error pages to be debugged during development, just visit
|
# This allows the error pages to be debugged during development, just visit
|
||||||
|
|
|
@ -20,13 +20,10 @@ from django.core.wsgi import get_wsgi_application
|
||||||
|
|
||||||
# This allows easy placement of apps within the interior
|
# This allows easy placement of apps within the interior
|
||||||
# {{ cookiecutter.project_slug }} directory.
|
# {{ cookiecutter.project_slug }} directory.
|
||||||
app_path = os.path.abspath(os.path.join(
|
app_path = os.path.abspath(
|
||||||
os.path.dirname(os.path.abspath(__file__)), os.pardir))
|
os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir)
|
||||||
sys.path.append(os.path.join(app_path, '{{ cookiecutter.project_slug }}'))
|
)
|
||||||
{% if cookiecutter.use_sentry == 'y' -%}
|
sys.path.append(os.path.join(app_path, "{{ cookiecutter.project_slug }}"))
|
||||||
if os.environ.get('DJANGO_SETTINGS_MODULE') == 'config.settings.production':
|
|
||||||
from raven.contrib.django.raven_compat.middleware.wsgi import Sentry
|
|
||||||
{%- endif %}
|
|
||||||
# We defer to a DJANGO_SETTINGS_MODULE already in the environment. This breaks
|
# We defer to a DJANGO_SETTINGS_MODULE already in the environment. This breaks
|
||||||
# if running multiple sites in the same mod_wsgi process. To fix this, use
|
# if running multiple sites in the same mod_wsgi process. To fix this, use
|
||||||
# mod_wsgi daemon mode with each site in its own daemon process, or use
|
# mod_wsgi daemon mode with each site in its own daemon process, or use
|
||||||
|
@ -37,10 +34,6 @@ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.production")
|
||||||
# file. This includes Django's development server, if the WSGI_APPLICATION
|
# file. This includes Django's development server, if the WSGI_APPLICATION
|
||||||
# setting points here.
|
# setting points here.
|
||||||
application = get_wsgi_application()
|
application = get_wsgi_application()
|
||||||
{% if cookiecutter.use_sentry == 'y' -%}
|
|
||||||
if os.environ.get('DJANGO_SETTINGS_MODULE') == 'config.settings.production':
|
|
||||||
application = Sentry(application)
|
|
||||||
{%- endif %}
|
|
||||||
# Apply WSGI middleware here.
|
# Apply WSGI middleware here.
|
||||||
# from helloworld.wsgi import HelloWorldApplication
|
# from helloworld.wsgi import HelloWorldApplication
|
||||||
# application = HelloWorldApplication(application)
|
# application = HelloWorldApplication(application)
|
||||||
|
|
|
@ -1,153 +1,20 @@
|
||||||
# Makefile for Sphinx documentation
|
# Minimal makefile for Sphinx documentation
|
||||||
#
|
#
|
||||||
|
|
||||||
# You can set these variables from the command line.
|
# You can set these variables from the command line, and also
|
||||||
SPHINXOPTS =
|
# from the environment for the first two.
|
||||||
SPHINXBUILD = sphinx-build
|
SPHINXOPTS ?=
|
||||||
PAPER =
|
SPHINXBUILD ?= sphinx-build
|
||||||
|
SOURCEDIR = .
|
||||||
BUILDDIR = _build
|
BUILDDIR = _build
|
||||||
|
|
||||||
# Internal variables.
|
# Put it first so that "make" without argument is like "make help".
|
||||||
PAPEROPT_a4 = -D latex_paper_size=a4
|
|
||||||
PAPEROPT_letter = -D latex_paper_size=letter
|
|
||||||
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
|
||||||
# the i18n builder cannot share the environment and doctrees with the others
|
|
||||||
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
|
||||||
|
|
||||||
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
|
|
||||||
|
|
||||||
help:
|
help:
|
||||||
@echo "Please use \`make <target>' where <target> is one of"
|
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||||
@echo " html to make standalone HTML files"
|
|
||||||
@echo " dirhtml to make HTML files named index.html in directories"
|
|
||||||
@echo " singlehtml to make a single large HTML file"
|
|
||||||
@echo " pickle to make pickle files"
|
|
||||||
@echo " json to make JSON files"
|
|
||||||
@echo " htmlhelp to make HTML files and a HTML help project"
|
|
||||||
@echo " qthelp to make HTML files and a qthelp project"
|
|
||||||
@echo " devhelp to make HTML files and a Devhelp project"
|
|
||||||
@echo " epub to make an epub"
|
|
||||||
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
|
||||||
@echo " latexpdf to make LaTeX files and run them through pdflatex"
|
|
||||||
@echo " text to make text files"
|
|
||||||
@echo " man to make manual pages"
|
|
||||||
@echo " texinfo to make Texinfo files"
|
|
||||||
@echo " info to make Texinfo files and run them through makeinfo"
|
|
||||||
@echo " gettext to make PO message catalogs"
|
|
||||||
@echo " changes to make an overview of all changed/added/deprecated items"
|
|
||||||
@echo " linkcheck to check all external links for integrity"
|
|
||||||
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
|
||||||
|
|
||||||
clean:
|
.PHONY: help Makefile
|
||||||
-rm -rf $(BUILDDIR)/*
|
|
||||||
|
|
||||||
html:
|
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||||
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||||
@echo
|
%: Makefile
|
||||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||||
|
|
||||||
dirhtml:
|
|
||||||
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
|
|
||||||
@echo
|
|
||||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
|
|
||||||
|
|
||||||
singlehtml:
|
|
||||||
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
|
|
||||||
@echo
|
|
||||||
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
|
|
||||||
|
|
||||||
pickle:
|
|
||||||
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
|
|
||||||
@echo
|
|
||||||
@echo "Build finished; now you can process the pickle files."
|
|
||||||
|
|
||||||
json:
|
|
||||||
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
|
|
||||||
@echo
|
|
||||||
@echo "Build finished; now you can process the JSON files."
|
|
||||||
|
|
||||||
htmlhelp:
|
|
||||||
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
|
|
||||||
@echo
|
|
||||||
@echo "Build finished; now you can run HTML Help Workshop with the" \
|
|
||||||
".hhp project file in $(BUILDDIR)/htmlhelp."
|
|
||||||
|
|
||||||
qthelp:
|
|
||||||
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
|
|
||||||
@echo
|
|
||||||
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
|
|
||||||
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
|
|
||||||
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/{{ cookiecutter.project_slug }}.qhcp"
|
|
||||||
@echo "To view the help file:"
|
|
||||||
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/{{ cookiecutter.project_slug }}.qhc"
|
|
||||||
|
|
||||||
devhelp:
|
|
||||||
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
|
|
||||||
@echo
|
|
||||||
@echo "Build finished."
|
|
||||||
@echo "To view the help file:"
|
|
||||||
@echo "# mkdir -p $$HOME/.local/share/devhelp/{{ cookiecutter.project_slug }}"
|
|
||||||
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/{{ cookiecutter.project_slug }}"
|
|
||||||
@echo "# devhelp"
|
|
||||||
|
|
||||||
epub:
|
|
||||||
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
|
|
||||||
@echo
|
|
||||||
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
|
|
||||||
|
|
||||||
latex:
|
|
||||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
|
||||||
@echo
|
|
||||||
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
|
|
||||||
@echo "Run \`make' in that directory to run these through (pdf)latex" \
|
|
||||||
"(use \`make latexpdf' here to do that automatically)."
|
|
||||||
|
|
||||||
latexpdf:
|
|
||||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
|
||||||
@echo "Running LaTeX files through pdflatex..."
|
|
||||||
$(MAKE) -C $(BUILDDIR)/latex all-pdf
|
|
||||||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
|
||||||
|
|
||||||
text:
|
|
||||||
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
|
|
||||||
@echo
|
|
||||||
@echo "Build finished. The text files are in $(BUILDDIR)/text."
|
|
||||||
|
|
||||||
man:
|
|
||||||
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
|
|
||||||
@echo
|
|
||||||
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
|
|
||||||
|
|
||||||
texinfo:
|
|
||||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
|
||||||
@echo
|
|
||||||
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
|
|
||||||
@echo "Run \`make' in that directory to run these through makeinfo" \
|
|
||||||
"(use \`make info' here to do that automatically)."
|
|
||||||
|
|
||||||
info:
|
|
||||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
|
||||||
@echo "Running Texinfo files through makeinfo..."
|
|
||||||
make -C $(BUILDDIR)/texinfo info
|
|
||||||
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
|
|
||||||
|
|
||||||
gettext:
|
|
||||||
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
|
|
||||||
@echo
|
|
||||||
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
|
|
||||||
|
|
||||||
changes:
|
|
||||||
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
|
|
||||||
@echo
|
|
||||||
@echo "The overview file is in $(BUILDDIR)/changes."
|
|
||||||
|
|
||||||
linkcheck:
|
|
||||||
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
|
|
||||||
@echo
|
|
||||||
@echo "Link check complete; look for any errors in the above output " \
|
|
||||||
"or in $(BUILDDIR)/linkcheck/output.txt."
|
|
||||||
|
|
||||||
doctest:
|
|
||||||
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
|
|
||||||
@echo "Testing of doctests in the sources finished, look at the " \
|
|
||||||
"results in $(BUILDDIR)/doctest/output.txt."
|
|
||||||
|
|
|
@ -1,255 +1,55 @@
|
||||||
# {{ cookiecutter.project_name }} documentation build configuration file, created by
|
# Configuration file for the Sphinx documentation builder.
|
||||||
# sphinx-quickstart.
|
|
||||||
#
|
#
|
||||||
# This file is execfile()d with the current directory set to its containing dir.
|
# This file only contains a selection of the most common options. For a full
|
||||||
#
|
# list see the documentation:
|
||||||
# Note that not all possible configuration values are present in this
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
||||||
# autogenerated file.
|
|
||||||
#
|
|
||||||
# All configuration values have a default; values that are commented out
|
|
||||||
# serve to show the default.
|
|
||||||
|
|
||||||
import os
|
# -- Path setup --------------------------------------------------------------
|
||||||
import sys
|
|
||||||
|
|
||||||
# If extensions (or modules to document with autodoc) are in another directory,
|
# If extensions (or modules to document with autodoc) are in another directory,
|
||||||
# add these directories to sys.path here. If the directory is relative to the
|
# add these directories to sys.path here. If the directory is relative to the
|
||||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||||
# sys.path.insert(0, os.path.abspath('.'))
|
#
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
# -- General configuration -----------------------------------------------------
|
# import django
|
||||||
|
# sys.path.insert(0, os.path.abspath('..'))
|
||||||
|
# os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.local")
|
||||||
|
# django.setup()
|
||||||
|
|
||||||
# If your documentation needs a minimal Sphinx version, state it here.
|
|
||||||
# needs_sphinx = '1.0'
|
|
||||||
|
|
||||||
# Add any Sphinx extension module names here, as strings. They can be extensions
|
# -- Project information -----------------------------------------------------
|
||||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
|
||||||
|
project = "{{ cookiecutter.project_name }}"
|
||||||
|
copyright = """{% now 'utc', '%Y' %}, {{ cookiecutter.author_name }}"""
|
||||||
|
author = "{{ cookiecutter.author_name }}"
|
||||||
|
|
||||||
|
|
||||||
|
# -- General configuration ---------------------------------------------------
|
||||||
|
|
||||||
|
# Add any Sphinx extension module names here, as strings. They can be
|
||||||
|
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||||
|
# ones.
|
||||||
extensions = []
|
extensions = []
|
||||||
|
|
||||||
# Add any paths that contain templates here, relative to this directory.
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
templates_path = ["_templates"]
|
templates_path = ["_templates"]
|
||||||
|
|
||||||
# The suffix of source filenames.
|
|
||||||
source_suffix = ".rst"
|
|
||||||
|
|
||||||
# The encoding of source files.
|
|
||||||
# source_encoding = 'utf-8-sig'
|
|
||||||
|
|
||||||
# The master toctree document.
|
|
||||||
master_doc = "index"
|
|
||||||
|
|
||||||
# General information about the project.
|
|
||||||
project = "{{ cookiecutter.project_name }}"
|
|
||||||
copyright = """{% now 'utc', '%Y' %}, {{ cookiecutter.author_name }}"""
|
|
||||||
|
|
||||||
# The version info for the project you're documenting, acts as replacement for
|
|
||||||
# |version| and |release|, also used in various other places throughout the
|
|
||||||
# built documents.
|
|
||||||
#
|
|
||||||
# The short X.Y version.
|
|
||||||
version = "0.1"
|
|
||||||
# The full version, including alpha/beta/rc tags.
|
|
||||||
release = "0.1"
|
|
||||||
|
|
||||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
|
||||||
# for a list of supported languages.
|
|
||||||
# language = None
|
|
||||||
|
|
||||||
# There are two options for replacing |today|: either, you set today to some
|
|
||||||
# non-false value, then it is used:
|
|
||||||
# today = ''
|
|
||||||
# Else, today_fmt is used as the format for a strftime call.
|
|
||||||
# today_fmt = '%B %d, %Y'
|
|
||||||
|
|
||||||
# List of patterns, relative to source directory, that match files and
|
# List of patterns, relative to source directory, that match files and
|
||||||
# directories to ignore when looking for source files.
|
# directories to ignore when looking for source files.
|
||||||
exclude_patterns = ["_build"]
|
# This pattern also affects html_static_path and html_extra_path.
|
||||||
|
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
|
||||||
# The reST default role (used for this markup: `text`) to use for all documents.
|
|
||||||
# default_role = None
|
|
||||||
|
|
||||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
|
||||||
# add_function_parentheses = True
|
|
||||||
|
|
||||||
# If true, the current module name will be prepended to all description
|
|
||||||
# unit titles (such as .. function::).
|
|
||||||
# add_module_names = True
|
|
||||||
|
|
||||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
|
||||||
# output. They are ignored by default.
|
|
||||||
# show_authors = False
|
|
||||||
|
|
||||||
# The name of the Pygments (syntax highlighting) style to use.
|
|
||||||
pygments_style = "sphinx"
|
|
||||||
|
|
||||||
# A list of ignored prefixes for module index sorting.
|
|
||||||
# modindex_common_prefix = []
|
|
||||||
|
|
||||||
|
|
||||||
# -- Options for HTML output ---------------------------------------------------
|
# -- Options for HTML output -------------------------------------------------
|
||||||
|
|
||||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||||
# a list of builtin themes.
|
# a list of builtin themes.
|
||||||
html_theme = "default"
|
#
|
||||||
|
html_theme = "alabaster"
|
||||||
# Theme options are theme-specific and customize the look and feel of a theme
|
|
||||||
# further. For a list of options available for each theme, see the
|
|
||||||
# documentation.
|
|
||||||
# html_theme_options = {}
|
|
||||||
|
|
||||||
# Add any paths that contain custom themes here, relative to this directory.
|
|
||||||
# html_theme_path = []
|
|
||||||
|
|
||||||
# The name for this set of Sphinx documents. If None, it defaults to
|
|
||||||
# "<project> v<release> documentation".
|
|
||||||
# html_title = None
|
|
||||||
|
|
||||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
|
||||||
# html_short_title = None
|
|
||||||
|
|
||||||
# The name of an image file (relative to this directory) to place at the top
|
|
||||||
# of the sidebar.
|
|
||||||
# html_logo = None
|
|
||||||
|
|
||||||
# The name of an image file (within the static path) to use as favicon of the
|
|
||||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
|
||||||
# pixels large.
|
|
||||||
# html_favicon = None
|
|
||||||
|
|
||||||
# Add any paths that contain custom static files (such as style sheets) here,
|
# Add any paths that contain custom static files (such as style sheets) here,
|
||||||
# relative to this directory. They are copied after the builtin static files,
|
# relative to this directory. They are copied after the builtin static files,
|
||||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||||
html_static_path = ["_static"]
|
html_static_path = ["_static"]
|
||||||
|
|
||||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
|
||||||
# using the given strftime format.
|
|
||||||
# html_last_updated_fmt = '%b %d, %Y'
|
|
||||||
|
|
||||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
|
||||||
# typographically correct entities.
|
|
||||||
# html_use_smartypants = True
|
|
||||||
|
|
||||||
# Custom sidebar templates, maps document names to template names.
|
|
||||||
# html_sidebars = {}
|
|
||||||
|
|
||||||
# Additional templates that should be rendered to pages, maps page names to
|
|
||||||
# template names.
|
|
||||||
# html_additional_pages = {}
|
|
||||||
|
|
||||||
# If false, no module index is generated.
|
|
||||||
# html_domain_indices = True
|
|
||||||
|
|
||||||
# If false, no index is generated.
|
|
||||||
# html_use_index = True
|
|
||||||
|
|
||||||
# If true, the index is split into individual pages for each letter.
|
|
||||||
# html_split_index = False
|
|
||||||
|
|
||||||
# If true, links to the reST sources are added to the pages.
|
|
||||||
# html_show_sourcelink = True
|
|
||||||
|
|
||||||
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
|
||||||
# html_show_sphinx = True
|
|
||||||
|
|
||||||
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
|
||||||
# html_show_copyright = True
|
|
||||||
|
|
||||||
# If true, an OpenSearch description file will be output, and all pages will
|
|
||||||
# contain a <link> tag referring to it. The value of this option must be the
|
|
||||||
# base URL from which the finished HTML is served.
|
|
||||||
# html_use_opensearch = ''
|
|
||||||
|
|
||||||
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
|
||||||
# html_file_suffix = None
|
|
||||||
|
|
||||||
# Output file base name for HTML help builder.
|
|
||||||
htmlhelp_basename = "{{ cookiecutter.project_slug }}doc"
|
|
||||||
|
|
||||||
|
|
||||||
# -- Options for LaTeX output --------------------------------------------------
|
|
||||||
|
|
||||||
latex_elements = {
|
|
||||||
# The paper size ('letterpaper' or 'a4paper').
|
|
||||||
# 'papersize': 'letterpaper',
|
|
||||||
# The font size ('10pt', '11pt' or '12pt').
|
|
||||||
# 'pointsize': '10pt',
|
|
||||||
# Additional stuff for the LaTeX preamble.
|
|
||||||
# 'preamble': '',
|
|
||||||
}
|
|
||||||
|
|
||||||
# Grouping the document tree into LaTeX files. List of tuples
|
|
||||||
# (source start file, target name, title, author, documentclass [howto/manual]).
|
|
||||||
latex_documents = [
|
|
||||||
(
|
|
||||||
"index",
|
|
||||||
"{{ cookiecutter.project_slug }}.tex",
|
|
||||||
"{{ cookiecutter.project_name }} Documentation",
|
|
||||||
"""{{ cookiecutter.author_name }}""",
|
|
||||||
"manual",
|
|
||||||
)
|
|
||||||
]
|
|
||||||
|
|
||||||
# The name of an image file (relative to this directory) to place at the top of
|
|
||||||
# the title page.
|
|
||||||
# latex_logo = None
|
|
||||||
|
|
||||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
|
||||||
# not chapters.
|
|
||||||
# latex_use_parts = False
|
|
||||||
|
|
||||||
# If true, show page references after internal links.
|
|
||||||
# latex_show_pagerefs = False
|
|
||||||
|
|
||||||
# If true, show URL addresses after external links.
|
|
||||||
# latex_show_urls = False
|
|
||||||
|
|
||||||
# Documents to append as an appendix to all manuals.
|
|
||||||
# latex_appendices = []
|
|
||||||
|
|
||||||
# If false, no module index is generated.
|
|
||||||
# latex_domain_indices = True
|
|
||||||
|
|
||||||
|
|
||||||
# -- Options for manual page output --------------------------------------------
|
|
||||||
|
|
||||||
# One entry per manual page. List of tuples
|
|
||||||
# (source start file, name, description, authors, manual section).
|
|
||||||
man_pages = [
|
|
||||||
(
|
|
||||||
"index",
|
|
||||||
"{{ cookiecutter.project_slug }}",
|
|
||||||
"{{ cookiecutter.project_name }} Documentation",
|
|
||||||
["""{{ cookiecutter.author_name }}"""],
|
|
||||||
1,
|
|
||||||
)
|
|
||||||
]
|
|
||||||
|
|
||||||
# If true, show URL addresses after external links.
|
|
||||||
# man_show_urls = False
|
|
||||||
|
|
||||||
|
|
||||||
# -- Options for Texinfo output ------------------------------------------------
|
|
||||||
|
|
||||||
# Grouping the document tree into Texinfo files. List of tuples
|
|
||||||
# (source start file, target name, title, author,
|
|
||||||
# dir menu entry, description, category)
|
|
||||||
texinfo_documents = [
|
|
||||||
(
|
|
||||||
"index",
|
|
||||||
"{{ cookiecutter.project_slug }}",
|
|
||||||
"{{ cookiecutter.project_name }} Documentation",
|
|
||||||
"""{{ cookiecutter.author_name }}""",
|
|
||||||
"{{ cookiecutter.project_name }}",
|
|
||||||
"""{{ cookiecutter.description }}""",
|
|
||||||
"Miscellaneous",
|
|
||||||
)
|
|
||||||
]
|
|
||||||
|
|
||||||
# Documents to append as an appendix to all manuals.
|
|
||||||
# texinfo_appendices = []
|
|
||||||
|
|
||||||
# If false, no module index is generated.
|
|
||||||
# texinfo_domain_indices = True
|
|
||||||
|
|
||||||
# How to display URL addresses: 'footnote', 'no', or 'inline'.
|
|
||||||
# texinfo_show_urls = 'footnote'
|
|
||||||
|
|
|
@ -3,17 +3,19 @@
|
||||||
You can adapt this file completely to your liking, but it should at least
|
You can adapt this file completely to your liking, but it should at least
|
||||||
contain the root `toctree` directive.
|
contain the root `toctree` directive.
|
||||||
|
|
||||||
{{ cookiecutter.project_name }} Project Documentation
|
Welcome to {{ cookiecutter.project_name }}'s documentation!
|
||||||
====================================================================
|
======================================================================
|
||||||
|
|
||||||
Table of Contents:
|
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
|
:caption: Contents:
|
||||||
|
|
||||||
|
pycharm/configuration
|
||||||
|
|
||||||
|
|
||||||
Indices & Tables
|
|
||||||
================
|
Indices and tables
|
||||||
|
==================
|
||||||
|
|
||||||
* :ref:`genindex`
|
* :ref:`genindex`
|
||||||
* :ref:`modindex`
|
* :ref:`modindex`
|
||||||
|
|
|
@ -1,190 +1,35 @@
|
||||||
@ECHO OFF
|
@ECHO OFF
|
||||||
|
|
||||||
|
pushd %~dp0
|
||||||
|
|
||||||
REM Command file for Sphinx documentation
|
REM Command file for Sphinx documentation
|
||||||
|
|
||||||
if "%SPHINXBUILD%" == "" (
|
if "%SPHINXBUILD%" == "" (
|
||||||
set SPHINXBUILD=sphinx-build
|
set SPHINXBUILD=sphinx-build
|
||||||
)
|
)
|
||||||
|
set SOURCEDIR=.
|
||||||
set BUILDDIR=_build
|
set BUILDDIR=_build
|
||||||
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
|
|
||||||
set I18NSPHINXOPTS=%SPHINXOPTS% .
|
|
||||||
if NOT "%PAPER%" == "" (
|
|
||||||
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
|
|
||||||
set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "" goto help
|
if "%1" == "" goto help
|
||||||
|
|
||||||
if "%1" == "help" (
|
%SPHINXBUILD% >NUL 2>NUL
|
||||||
:help
|
if errorlevel 9009 (
|
||||||
echo.Please use `make ^<target^>` where ^<target^> is one of
|
|
||||||
echo. html to make standalone HTML files
|
|
||||||
echo. dirhtml to make HTML files named index.html in directories
|
|
||||||
echo. singlehtml to make a single large HTML file
|
|
||||||
echo. pickle to make pickle files
|
|
||||||
echo. json to make JSON files
|
|
||||||
echo. htmlhelp to make HTML files and a HTML help project
|
|
||||||
echo. qthelp to make HTML files and a qthelp project
|
|
||||||
echo. devhelp to make HTML files and a Devhelp project
|
|
||||||
echo. epub to make an epub
|
|
||||||
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
|
|
||||||
echo. text to make text files
|
|
||||||
echo. man to make manual pages
|
|
||||||
echo. texinfo to make Texinfo files
|
|
||||||
echo. gettext to make PO message catalogs
|
|
||||||
echo. changes to make an overview over all changed/added/deprecated items
|
|
||||||
echo. linkcheck to check all external links for integrity
|
|
||||||
echo. doctest to run all doctests embedded in the documentation if enabled
|
|
||||||
goto end
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "clean" (
|
|
||||||
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
|
|
||||||
del /q /s %BUILDDIR%\*
|
|
||||||
goto end
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "html" (
|
|
||||||
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
|
|
||||||
if errorlevel 1 exit /b 1
|
|
||||||
echo.
|
echo.
|
||||||
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
|
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||||
goto end
|
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||||
|
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||||
|
echo.may add the Sphinx directory to PATH.
|
||||||
|
echo.
|
||||||
|
echo.If you don't have Sphinx installed, grab it from
|
||||||
|
echo.http://sphinx-doc.org/
|
||||||
|
exit /b 1
|
||||||
)
|
)
|
||||||
|
|
||||||
if "%1" == "dirhtml" (
|
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||||
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
|
goto end
|
||||||
if errorlevel 1 exit /b 1
|
|
||||||
echo.
|
|
||||||
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
|
|
||||||
goto end
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "singlehtml" (
|
:help
|
||||||
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
|
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||||
if errorlevel 1 exit /b 1
|
|
||||||
echo.
|
|
||||||
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
|
|
||||||
goto end
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "pickle" (
|
|
||||||
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
|
|
||||||
if errorlevel 1 exit /b 1
|
|
||||||
echo.
|
|
||||||
echo.Build finished; now you can process the pickle files.
|
|
||||||
goto end
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "json" (
|
|
||||||
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
|
|
||||||
if errorlevel 1 exit /b 1
|
|
||||||
echo.
|
|
||||||
echo.Build finished; now you can process the JSON files.
|
|
||||||
goto end
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "htmlhelp" (
|
|
||||||
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
|
|
||||||
if errorlevel 1 exit /b 1
|
|
||||||
echo.
|
|
||||||
echo.Build finished; now you can run HTML Help Workshop with the ^
|
|
||||||
.hhp project file in %BUILDDIR%/htmlhelp.
|
|
||||||
goto end
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "qthelp" (
|
|
||||||
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
|
|
||||||
if errorlevel 1 exit /b 1
|
|
||||||
echo.
|
|
||||||
echo.Build finished; now you can run "qcollectiongenerator" with the ^
|
|
||||||
.qhcp project file in %BUILDDIR%/qthelp, like this:
|
|
||||||
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\{{ cookiecutter.project_slug }}.qhcp
|
|
||||||
echo.To view the help file:
|
|
||||||
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\{{ cookiecutter.project_slug }}.ghc
|
|
||||||
goto end
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "devhelp" (
|
|
||||||
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
|
|
||||||
if errorlevel 1 exit /b 1
|
|
||||||
echo.
|
|
||||||
echo.Build finished.
|
|
||||||
goto end
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "epub" (
|
|
||||||
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
|
|
||||||
if errorlevel 1 exit /b 1
|
|
||||||
echo.
|
|
||||||
echo.Build finished. The epub file is in %BUILDDIR%/epub.
|
|
||||||
goto end
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "latex" (
|
|
||||||
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
|
|
||||||
if errorlevel 1 exit /b 1
|
|
||||||
echo.
|
|
||||||
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
|
|
||||||
goto end
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "text" (
|
|
||||||
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
|
|
||||||
if errorlevel 1 exit /b 1
|
|
||||||
echo.
|
|
||||||
echo.Build finished. The text files are in %BUILDDIR%/text.
|
|
||||||
goto end
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "man" (
|
|
||||||
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
|
|
||||||
if errorlevel 1 exit /b 1
|
|
||||||
echo.
|
|
||||||
echo.Build finished. The manual pages are in %BUILDDIR%/man.
|
|
||||||
goto end
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "texinfo" (
|
|
||||||
%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
|
|
||||||
if errorlevel 1 exit /b 1
|
|
||||||
echo.
|
|
||||||
echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
|
|
||||||
goto end
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "gettext" (
|
|
||||||
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
|
|
||||||
if errorlevel 1 exit /b 1
|
|
||||||
echo.
|
|
||||||
echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
|
|
||||||
goto end
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "changes" (
|
|
||||||
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
|
|
||||||
if errorlevel 1 exit /b 1
|
|
||||||
echo.
|
|
||||||
echo.The overview file is in %BUILDDIR%/changes.
|
|
||||||
goto end
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "linkcheck" (
|
|
||||||
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
|
|
||||||
if errorlevel 1 exit /b 1
|
|
||||||
echo.
|
|
||||||
echo.Link check complete; look for any errors in the above output ^
|
|
||||||
or in %BUILDDIR%/linkcheck/output.txt.
|
|
||||||
goto end
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "doctest" (
|
|
||||||
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
|
|
||||||
if errorlevel 1 exit /b 1
|
|
||||||
echo.
|
|
||||||
echo.Testing of doctests in the sources finished, look at the ^
|
|
||||||
results in %BUILDDIR%/doctest/output.txt.
|
|
||||||
goto end
|
|
||||||
)
|
|
||||||
|
|
||||||
:end
|
:end
|
||||||
|
popd
|
||||||
|
|
|
@ -14,7 +14,7 @@ This repository comes with already prepared "Run/Debug Configurations" for docke
|
||||||
|
|
||||||
.. image:: images/2.png
|
.. image:: images/2.png
|
||||||
|
|
||||||
But as you can see, at the beggining there is something wrong with them. They have red X on django icon, and they cannot be used, without configuring remote python interpteter. To do that, you have to go to *Settings > Build, Execution, Deployment* first.
|
But as you can see, at the beginning there is something wrong with them. They have red X on django icon, and they cannot be used, without configuring remote python interpteter. To do that, you have to go to *Settings > Build, Execution, Deployment* first.
|
||||||
|
|
||||||
|
|
||||||
Next, you have to add new remote python interpreter, based on already tested deployment settings. Go to *Settings > Project > Project Interpreter*. Click on the cog icon, and click *Add Remote*.
|
Next, you have to add new remote python interpreter, based on already tested deployment settings. Go to *Settings > Project > Project Interpreter*. Click on the cog icon, and click *Add Remote*.
|
||||||
|
@ -36,12 +36,18 @@ After few seconds, all *Run/Debug Configurations* should be ready to use.
|
||||||
**Things you can do with provided configuration**:
|
**Things you can do with provided configuration**:
|
||||||
|
|
||||||
* run and debug python code
|
* run and debug python code
|
||||||
|
|
||||||
.. image:: images/f1.png
|
.. image:: images/f1.png
|
||||||
|
|
||||||
* run and debug tests
|
* run and debug tests
|
||||||
|
|
||||||
.. image:: images/f2.png
|
.. image:: images/f2.png
|
||||||
.. image:: images/f3.png
|
.. image:: images/f3.png
|
||||||
|
|
||||||
* run and debug migrations or different django management commands
|
* run and debug migrations or different django management commands
|
||||||
|
|
||||||
.. image:: images/f4.png
|
.. image:: images/f4.png
|
||||||
|
|
||||||
* and many others..
|
* and many others..
|
||||||
|
|
||||||
Known issues
|
Known issues
|
||||||
|
|
|
@ -127,7 +127,23 @@ function initBrowserSync() {
|
||||||
`${paths.js}/*.js`,
|
`${paths.js}/*.js`,
|
||||||
`${paths.templates}/*.html`
|
`${paths.templates}/*.html`
|
||||||
], {
|
], {
|
||||||
proxy: "localhost:8000"
|
// https://www.browsersync.io/docs/options/#option-proxy
|
||||||
|
{%- if cookiecutter.use_docker == 'n' %}
|
||||||
|
proxy: 'localhost:8000'
|
||||||
|
{% else %}
|
||||||
|
proxy: {
|
||||||
|
target: 'django:8000',
|
||||||
|
proxyReq: [
|
||||||
|
function(proxyReq, req) {
|
||||||
|
// Assign proxy "host" header same as current request at Browsersync server
|
||||||
|
proxyReq.setHeader('Host', req.headers.host)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
// https://www.browsersync.io/docs/options/#option-open
|
||||||
|
// Disable as it doesn't work from inside a container
|
||||||
|
open: false
|
||||||
|
{%- endif %}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -149,7 +165,9 @@ const generateAssets = parallel(
|
||||||
|
|
||||||
// Set up dev environment
|
// Set up dev environment
|
||||||
const dev = parallel(
|
const dev = parallel(
|
||||||
|
{%- if cookiecutter.use_docker == 'n' %}
|
||||||
runServer,
|
runServer,
|
||||||
|
{%- endif %}
|
||||||
initBrowserSync,
|
initBrowserSync,
|
||||||
watchPaths
|
watchPaths
|
||||||
)
|
)
|
||||||
|
|
|
@ -45,7 +45,7 @@ services:
|
||||||
{%- if cookiecutter.use_celery == 'y' %}
|
{%- if cookiecutter.use_celery == 'y' %}
|
||||||
|
|
||||||
redis:
|
redis:
|
||||||
image: redis:3.2
|
image: redis:5.0
|
||||||
|
|
||||||
celeryworker:
|
celeryworker:
|
||||||
<<: *django
|
<<: *django
|
||||||
|
@ -79,3 +79,23 @@ services:
|
||||||
command: /start-flower
|
command: /start-flower
|
||||||
|
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
{%- if cookiecutter.js_task_runner == 'Gulp' %}
|
||||||
|
|
||||||
|
node:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: ./compose/local/node/Dockerfile
|
||||||
|
image: {{ cookiecutter.project_slug }}_local_node
|
||||||
|
depends_on:
|
||||||
|
- django
|
||||||
|
volumes:
|
||||||
|
- .:/app
|
||||||
|
# http://jdlm.info/articles/2016/03/06/lessons-building-node-app-docker.html
|
||||||
|
- /app/node_modules
|
||||||
|
command: npm run dev
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
# Expose browsersync UI: https://www.browsersync.io/docs/options/#option-ui
|
||||||
|
- "3001:3001"
|
||||||
|
|
||||||
|
{%- endif %}
|
||||||
|
|
|
@ -8,7 +8,6 @@ PRODUCTION_DOTENVS_DIR_PATH = os.path.join(ROOT_DIR_PATH, ".envs", ".production"
|
||||||
PRODUCTION_DOTENV_FILE_PATHS = [
|
PRODUCTION_DOTENV_FILE_PATHS = [
|
||||||
os.path.join(PRODUCTION_DOTENVS_DIR_PATH, ".django"),
|
os.path.join(PRODUCTION_DOTENVS_DIR_PATH, ".django"),
|
||||||
os.path.join(PRODUCTION_DOTENVS_DIR_PATH, ".postgres"),
|
os.path.join(PRODUCTION_DOTENVS_DIR_PATH, ".postgres"),
|
||||||
os.path.join(PRODUCTION_DOTENVS_DIR_PATH, ".caddy"),
|
|
||||||
]
|
]
|
||||||
DOTENV_FILE_PATH = os.path.join(ROOT_DIR_PATH, ".env")
|
DOTENV_FILE_PATH = os.path.join(ROOT_DIR_PATH, ".env")
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
"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.1.1",
|
"bootstrap": "4.3.1",
|
||||||
"gulp-concat": "^2.6.1",
|
"gulp-concat": "^2.6.1",
|
||||||
"jquery": "3.3.1",
|
"jquery": "3.3.1",
|
||||||
"popper.js": "1.14.3",
|
"popper.js": "1.14.3",
|
||||||
|
@ -31,7 +31,8 @@
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
{% if cookiecutter.js_task_runner == 'Gulp' -%}
|
{% if cookiecutter.js_task_runner == 'Gulp' -%}
|
||||||
"dev": "gulp"
|
"dev": "gulp",
|
||||||
|
"build": "gulp generate-assets"
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ version: '3'
|
||||||
volumes:
|
volumes:
|
||||||
production_postgres_data: {}
|
production_postgres_data: {}
|
||||||
production_postgres_data_backups: {}
|
production_postgres_data_backups: {}
|
||||||
production_caddy: {}
|
production_traefik: {}
|
||||||
|
|
||||||
services:
|
services:
|
||||||
django:{% if cookiecutter.use_celery == 'y' %} &django{% endif %}
|
django:{% if cookiecutter.use_celery == 'y' %} &django{% endif %}
|
||||||
|
@ -30,23 +30,21 @@ services:
|
||||||
env_file:
|
env_file:
|
||||||
- ./.envs/.production/.postgres
|
- ./.envs/.production/.postgres
|
||||||
|
|
||||||
caddy:
|
traefik:
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: ./compose/production/caddy/Dockerfile
|
dockerfile: ./compose/production/traefik/Dockerfile
|
||||||
image: {{ cookiecutter.project_slug }}_production_caddy
|
image: {{ cookiecutter.project_slug }}_production_traefik
|
||||||
depends_on:
|
depends_on:
|
||||||
- django
|
- django
|
||||||
volumes:
|
volumes:
|
||||||
- production_caddy:/root/.caddy
|
- production_traefik:/etc/traefik/acme
|
||||||
env_file:
|
|
||||||
- ./.envs/.production/.caddy
|
|
||||||
ports:
|
ports:
|
||||||
- "0.0.0.0:80:80"
|
- "0.0.0.0:80:80"
|
||||||
- "0.0.0.0:443:443"
|
- "0.0.0.0:443:443"
|
||||||
|
|
||||||
redis:
|
redis:
|
||||||
image: redis:3.2
|
image: redis:5.0
|
||||||
{%- if cookiecutter.use_celery == 'y' %}
|
{%- if cookiecutter.use_celery == 'y' %}
|
||||||
|
|
||||||
celeryworker:
|
celeryworker:
|
||||||
|
@ -67,3 +65,14 @@ services:
|
||||||
command: /start-flower
|
command: /start-flower
|
||||||
|
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
||||||
|
{% if cookiecutter.cloud_provider == 'AWS' %}
|
||||||
|
awscli:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: ./compose/production/aws/Dockerfile
|
||||||
|
env_file:
|
||||||
|
- ./.envs/.production/.django
|
||||||
|
volumes:
|
||||||
|
- production_postgres_data_backups:/backups
|
||||||
|
{%- endif %}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
[pytest]
|
[pytest]
|
||||||
DJANGO_SETTINGS_MODULE=config.settings.test
|
addopts = --ds=config.settings.test --reuse-db
|
||||||
|
python_files = tests.py test_*.py
|
||||||
{%- if cookiecutter.js_task_runner != 'None' %}
|
{%- if cookiecutter.js_task_runner != 'None' %}
|
||||||
norecursedirs = node_modules
|
norecursedirs = node_modules
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
|
@ -1,33 +1,34 @@
|
||||||
pytz==2018.9 # https://github.com/stub42/pytz
|
pytz==2019.3 # https://github.com/stub42/pytz
|
||||||
python-slugify==2.0.1 # https://github.com/un33k/python-slugify
|
python-slugify==4.0.0 # https://github.com/un33k/python-slugify
|
||||||
Pillow==5.4.1 # https://github.com/python-pillow/Pillow
|
Pillow==7.0.0 # 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' and cookiecutter.use_docker == 'n' %} --install-option="--without-c-extensions"{% endif %} # https://github.com/ndparker/rcssmin
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
argon2-cffi==19.1.0 # https://github.com/hynek/argon2_cffi
|
argon2-cffi==19.2.0 # https://github.com/hynek/argon2_cffi
|
||||||
{%- if cookiecutter.use_whitenoise == 'y' %}
|
{%- if cookiecutter.use_whitenoise == 'y' %}
|
||||||
whitenoise==4.1.2 # https://github.com/evansd/whitenoise
|
whitenoise==5.0.1 # https://github.com/evansd/whitenoise
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
redis>=2.10.6, < 3 # pyup: < 3 # https://github.com/antirez/redis
|
redis==3.3.11 # pyup: != 3.4.0 # https://github.com/andymccurdy/redis-py
|
||||||
{%- if cookiecutter.use_celery == "y" %}
|
{%- if cookiecutter.use_celery == "y" %}
|
||||||
celery==4.2.1 # pyup: < 5.0 # https://github.com/celery/celery
|
celery==4.4.0 # pyup: < 5.0 # https://github.com/celery/celery
|
||||||
|
django-celery-beat==1.6.0 # https://github.com/celery/django-celery-beat
|
||||||
{%- if cookiecutter.use_docker == 'y' %}
|
{%- if cookiecutter.use_docker == 'y' %}
|
||||||
flower==0.9.2 # https://github.com/mher/flower
|
flower==0.9.3 # https://github.com/mher/flower
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
||||||
# Django
|
# Django
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
django==2.0.13 # pyup: < 2.1 # https://www.djangoproject.com/
|
django==2.2.9 # pyup: < 3.0 # 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==4.0.0 # https://github.com/jazzband/django-model-utils
|
||||||
django-allauth==0.38.0 # https://github.com/pennersr/django-allauth
|
django-allauth==0.41.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.8.1 # 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.4 # https://github.com/django-compressor/django-compressor
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
django-redis==4.10.0 # https://github.com/niwinz/django-redis
|
django-redis==4.11.0 # https://github.com/niwinz/django-redis
|
||||||
|
|
||||||
# Django REST Framework
|
# Django REST Framework
|
||||||
djangorestframework==3.9.1 # https://github.com/encode/django-rest-framework
|
djangorestframework==3.11.0 # 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
|
||||||
|
|
|
@ -1,30 +1,37 @@
|
||||||
-r ./base.txt
|
-r ./base.txt
|
||||||
|
|
||||||
Werkzeug==0.14.1 # https://github.com/pallets/werkzeug
|
Werkzeug==0.16.1 # https://github.com/pallets/werkzeug
|
||||||
ipdb==0.11 # https://github.com/gotcha/ipdb
|
ipdb==0.12.3 # https://github.com/gotcha/ipdb
|
||||||
Sphinx==1.8.4 # https://github.com/sphinx-doc/sphinx
|
Sphinx==2.3.1 # 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.8.4 --no-binary psycopg2 # https://github.com/psycopg/psycopg2
|
||||||
{%- else %}
|
{%- else %}
|
||||||
psycopg2-binary==2.7.7 # https://github.com/psycopg/psycopg2
|
psycopg2-binary==2.8.4 # https://github.com/psycopg/psycopg2
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
||||||
# Testing
|
# Testing
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
mypy==0.670 # https://github.com/python/mypy
|
mypy==0.761 # https://github.com/python/mypy
|
||||||
pytest==4.2.0 # https://github.com/pytest-dev/pytest
|
django-stubs==1.4.0 # https://github.com/typeddjango/django-stubs
|
||||||
|
pytest==5.3.5 # https://github.com/pytest-dev/pytest
|
||||||
pytest-sugar==0.9.2 # https://github.com/Frozenball/pytest-sugar
|
pytest-sugar==0.9.2 # https://github.com/Frozenball/pytest-sugar
|
||||||
|
|
||||||
# Code quality
|
# Code quality
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
flake8==3.7.5 # https://github.com/PyCQA/flake8
|
flake8==3.7.9 # https://github.com/PyCQA/flake8
|
||||||
coverage==4.5.2 # https://github.com/nedbat/coveragepy
|
coverage==5.0.3 # https://github.com/nedbat/coveragepy
|
||||||
|
black==19.10b0 # https://github.com/ambv/black
|
||||||
|
pylint-django==2.0.13 # https://github.com/PyCQA/pylint-django
|
||||||
|
{%- if cookiecutter.use_celery == 'y' %}
|
||||||
|
pylint-celery==0.3 # https://github.com/PyCQA/pylint-celery
|
||||||
|
{%- endif %}
|
||||||
|
pre-commit==2.0.1 # https://github.com/pre-commit/pre-commit
|
||||||
|
|
||||||
# Django
|
# Django
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
factory-boy==2.11.1 # https://github.com/FactoryBoy/factory_boy
|
factory-boy==2.12.0 # https://github.com/FactoryBoy/factory_boy
|
||||||
|
|
||||||
django-debug-toolbar==1.11 # https://github.com/jazzband/django-debug-toolbar
|
django-debug-toolbar==2.2 # https://github.com/jazzband/django-debug-toolbar
|
||||||
django-extensions==2.1.5 # https://github.com/django-extensions/django-extensions
|
django-extensions==2.2.6 # https://github.com/django-extensions/django-extensions
|
||||||
django-coverage-plugin==1.6.0 # https://github.com/nedbat/django_coverage_plugin
|
django-coverage-plugin==1.8.0 # https://github.com/nedbat/django_coverage_plugin
|
||||||
pytest-django==3.4.7 # https://github.com/pytest-dev/pytest-django
|
pytest-django==3.8.0 # https://github.com/pytest-dev/pytest-django
|
||||||
|
|
|
@ -2,16 +2,20 @@
|
||||||
|
|
||||||
-r ./base.txt
|
-r ./base.txt
|
||||||
|
|
||||||
gunicorn==19.9.0 # https://github.com/benoitc/gunicorn
|
gunicorn==20.0.4 # https://github.com/benoitc/gunicorn
|
||||||
psycopg2==2.7.4 --no-binary psycopg2 # https://github.com/psycopg/psycopg2
|
psycopg2==2.8.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==1.3.1 # https://github.com/antonagestam/collectfast
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{%- if cookiecutter.use_sentry == "y" %}
|
{%- if cookiecutter.use_sentry == "y" %}
|
||||||
raven==6.10.0 # https://github.com/getsentry/raven-python
|
sentry-sdk==0.14.1 # https://github.com/getsentry/sentry-python
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
||||||
# Django
|
# Django
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
django-storages[boto3]==1.7.1 # https://github.com/jschneier/django-storages
|
{%- if cookiecutter.cloud_provider == 'AWS' %}
|
||||||
django-anymail[mailgun]==5.0 # https://github.com/anymail/django-anymail
|
django-storages[boto3]==1.8 # https://github.com/jschneier/django-storages
|
||||||
|
{%- elif cookiecutter.cloud_provider == 'GCP' %}
|
||||||
|
django-storages[google]==1.8 # https://github.com/jschneier/django-storages
|
||||||
|
{%- endif %}
|
||||||
|
django-anymail[mailgun]==7.0.0 # https://github.com/anymail/django-anymail
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
python-3.6.8
|
python-3.7.6
|
||||||
|
|
|
@ -7,14 +7,16 @@ max-line-length = 120
|
||||||
exclude = .tox,.git,*/migrations/*,*/static/CACHE/*,docs,node_modules
|
exclude = .tox,.git,*/migrations/*,*/static/CACHE/*,docs,node_modules
|
||||||
|
|
||||||
[mypy]
|
[mypy]
|
||||||
python_version = 3.6
|
python_version = 3.7
|
||||||
check_untyped_defs = True
|
check_untyped_defs = True
|
||||||
ignore_errors = False
|
|
||||||
ignore_missing_imports = True
|
ignore_missing_imports = True
|
||||||
strict_optional = True
|
|
||||||
warn_unused_ignores = True
|
warn_unused_ignores = True
|
||||||
warn_redundant_casts = True
|
warn_redundant_casts = True
|
||||||
warn_unused_configs = True
|
warn_unused_configs = True
|
||||||
|
plugins = mypy_django_plugin.main
|
||||||
|
|
||||||
|
[mypy.plugins.django-stubs]
|
||||||
|
django_settings_module = config.settings.test
|
||||||
|
|
||||||
[mypy-*.migrations.*]
|
[mypy-*.migrations.*]
|
||||||
# Django migrations should not produce any errors:
|
# Django migrations should not produce any errors:
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
##basic build dependencies of various Django apps for Ubuntu Bionic 18.04
|
||||||
|
#build-essential metapackage install: make, gcc, g++,
|
||||||
|
build-essential
|
||||||
|
#required to translate
|
||||||
|
gettext
|
||||||
|
python3-dev
|
||||||
|
|
||||||
|
##shared dependencies of:
|
||||||
|
##Pillow, pylibmc
|
||||||
|
zlib1g-dev
|
||||||
|
|
||||||
|
##Postgresql and psycopg2 dependencies
|
||||||
|
libpq-dev
|
||||||
|
|
||||||
|
##Pillow dependencies
|
||||||
|
libtiff5-dev
|
||||||
|
libjpeg8-dev
|
||||||
|
libfreetype6-dev
|
||||||
|
liblcms2-dev
|
||||||
|
libwebp-dev
|
||||||
|
|
||||||
|
##django-extensions
|
||||||
|
libgraphviz-dev
|
|
@ -0,0 +1,23 @@
|
||||||
|
##basic build dependencies of various Django apps for Debian Jessie 10.x
|
||||||
|
#build-essential metapackage install: make, gcc, g++,
|
||||||
|
build-essential
|
||||||
|
#required to translate
|
||||||
|
gettext
|
||||||
|
python3-dev
|
||||||
|
|
||||||
|
##shared dependencies of:
|
||||||
|
##Pillow, pylibmc
|
||||||
|
zlib1g-dev
|
||||||
|
|
||||||
|
##Postgresql and psycopg2 dependencies
|
||||||
|
libpq-dev
|
||||||
|
|
||||||
|
##Pillow dependencies
|
||||||
|
libtiff5-dev
|
||||||
|
libjpeg62-turbo-dev
|
||||||
|
libfreetype6-dev
|
||||||
|
liblcms2-dev
|
||||||
|
libwebp-dev
|
||||||
|
|
||||||
|
##django-extensions
|
||||||
|
libgraphviz-dev
|
|
@ -1,7 +1,7 @@
|
||||||
import pytest
|
import pytest
|
||||||
from django.conf import settings
|
|
||||||
from django.test import RequestFactory
|
from django.test import RequestFactory
|
||||||
|
|
||||||
|
from {{ cookiecutter.project_slug }}.users.models import User
|
||||||
from {{ cookiecutter.project_slug }}.users.tests.factories import UserFactory
|
from {{ cookiecutter.project_slug }}.users.tests.factories import UserFactory
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ def media_storage(settings, tmpdir):
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def user() -> settings.AUTH_USER_MODEL:
|
def user() -> User:
|
||||||
return UserFactory()
|
return UserFactory()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,58 +0,0 @@
|
||||||
{% if cookiecutter.use_celery == 'y' %}
|
|
||||||
import os
|
|
||||||
from celery import Celery
|
|
||||||
from django.apps import apps, AppConfig
|
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
|
|
||||||
if not settings.configured:
|
|
||||||
# set the default Django settings module for the 'celery' program.
|
|
||||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings.local') # pragma: no cover
|
|
||||||
|
|
||||||
|
|
||||||
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):
|
|
||||||
name = '{{cookiecutter.project_slug}}.taskapp'
|
|
||||||
verbose_name = 'Celery Config'
|
|
||||||
|
|
||||||
def ready(self):
|
|
||||||
installed_apps = [app_config.name for app_config in apps.get_app_configs()]
|
|
||||||
app.autodiscover_tasks(lambda: installed_apps, force=True)
|
|
||||||
|
|
||||||
{% if cookiecutter.use_sentry == 'y' -%}
|
|
||||||
if hasattr(settings, 'RAVEN_CONFIG'):
|
|
||||||
# Celery signal registration
|
|
||||||
{% if cookiecutter.use_pycharm == 'y' -%}
|
|
||||||
# Since raven is required in production only,
|
|
||||||
# imports might (most surely will) be wiped out
|
|
||||||
# during PyCharm code clean up started
|
|
||||||
# in other environments.
|
|
||||||
# @formatter:off
|
|
||||||
{%- endif %}
|
|
||||||
from raven import Client as RavenClient
|
|
||||||
from raven.contrib.celery import register_signal as raven_register_signal
|
|
||||||
from raven.contrib.celery import register_logger_signal as raven_register_logger_signal
|
|
||||||
{% if cookiecutter.use_pycharm == 'y' -%}
|
|
||||||
# @formatter:on
|
|
||||||
{%- endif %}
|
|
||||||
|
|
||||||
raven_client = RavenClient(dsn=settings.RAVEN_CONFIG['dsn'])
|
|
||||||
raven_register_logger_signal(raven_client)
|
|
||||||
raven_register_signal(raven_client)
|
|
||||||
{%- endif %}
|
|
||||||
|
|
||||||
|
|
||||||
@app.task(bind=True)
|
|
||||||
def debug_task(self):
|
|
||||||
print(f'Request: {self.request!r}') # pragma: no cover
|
|
||||||
{% else %}
|
|
||||||
# Use this as a starting point for your project with celery.
|
|
||||||
# If you are not using celery, you can remove this app
|
|
||||||
{% endif -%}
|
|
|
@ -15,7 +15,7 @@
|
||||||
<form method="POST" action=".">
|
<form method="POST" action=".">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{{ form|crispy }}
|
{{ form|crispy }}
|
||||||
<input type="submit" name="action" value="{% trans 'change password' %}"/>
|
<input class="btn btn-primary" type="submit" name="action" value="{% trans 'change password' %}"/>
|
||||||
</form>
|
</form>
|
||||||
{% else %}
|
{% else %}
|
||||||
<p>{% trans 'Your password is now changed.' %}</p>
|
<p>{% trans 'Your password is now changed.' %}</p>
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
<form method="POST" action="{% url 'account_set_password' %}" class="password_set">
|
<form method="POST" action="{% url 'account_set_password' %}" class="password_set">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{{ form|crispy }}
|
{{ form|crispy }}
|
||||||
<input type="submit" name="action" value="{% trans 'Set Password' %}"/>
|
<input class="btn btn-primary" type="submit" name="action" value="{% trans 'Set Password' %}"/>
|
||||||
</form>
|
</form>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% endraw %}
|
{% endraw %}
|
||||||
|
|
|
@ -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.1.1 CSS -->
|
<!-- Latest compiled and minified Bootstrap CSS -->
|
||||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" integrity="sha384-WskhaSGFgHYWDcbwN70/dfYBj47jz9qbsMId/iRN3ewGhXQFZCSftd1LZCfmhktB" crossorigin="anonymous">
|
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
|
||||||
{% endraw %}{% endif %}{% raw %}
|
{% endraw %}{% endif %}{% raw %}
|
||||||
|
|
||||||
<!-- Your stuff: Third-party CSS libraries go here -->
|
<!-- Your stuff: Third-party CSS libraries go here -->
|
||||||
|
@ -80,7 +80,7 @@
|
||||||
|
|
||||||
{% if messages %}
|
{% if messages %}
|
||||||
{% for message in messages %}
|
{% for message in messages %}
|
||||||
<div class="alert {% if message.tags %}alert-{{ message.tags }}{% endif %}">{{ message }}</div>
|
<div class="alert {% if message.tags %}alert-{{ message.tags }}{% endif %}">{{ message }}<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button></div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
@ -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.1.1 -->
|
<!-- Bootstrap JS and its dependencies-->
|
||||||
<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://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.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" 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://stackpath.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js" integrity="sha384-smHYKdLADwkXOn1EmN1qk/HfnUcbVRZyYmZ4qpPea6sjB/pTJ0euyQp0Mk8ck+5T" crossorigin="anonymous"></script>
|
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" 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 %}
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
{{ form|crispy }}
|
{{ form|crispy }}
|
||||||
<div class="control-group">
|
<div class="control-group">
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<button type="submit" class="btn">Update</button>
|
<button type="submit" class="btn btn-primary">Update</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
{% raw %}{% extends "base.html" %}
|
|
||||||
{% load static i18n %}
|
|
||||||
{% block title %}Members{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div class="container">
|
|
||||||
<h2>Users</h2>
|
|
||||||
|
|
||||||
<div class="list-group">
|
|
||||||
{% for user in user_list %}
|
|
||||||
<a href="{% url 'users:detail' user.username %}" class="list-group-item">
|
|
||||||
<h4 class="list-group-item-heading">{{ user.username }}</h4>
|
|
||||||
</a>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock content %}{% endraw %}
|
|
|
@ -7,12 +7,10 @@ from django.http import HttpRequest
|
||||||
|
|
||||||
|
|
||||||
class AccountAdapter(DefaultAccountAdapter):
|
class AccountAdapter(DefaultAccountAdapter):
|
||||||
|
|
||||||
def is_open_for_signup(self, request: HttpRequest):
|
def is_open_for_signup(self, request: HttpRequest):
|
||||||
return getattr(settings, "ACCOUNT_ALLOW_REGISTRATION", True)
|
return getattr(settings, "ACCOUNT_ALLOW_REGISTRATION", True)
|
||||||
|
|
||||||
|
|
||||||
class SocialAccountAdapter(DefaultSocialAccountAdapter):
|
class SocialAccountAdapter(DefaultSocialAccountAdapter):
|
||||||
|
|
||||||
def is_open_for_signup(self, request: HttpRequest, sociallogin: Any):
|
def is_open_for_signup(self, request: HttpRequest, sociallogin: Any):
|
||||||
return getattr(settings, "ACCOUNT_ALLOW_REGISTRATION", True)
|
return getattr(settings, "ACCOUNT_ALLOW_REGISTRATION", True)
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
from rest_framework import serializers
|
||||||
|
from {{ cookiecutter.project_slug }}.users.models import User
|
||||||
|
|
||||||
|
|
||||||
|
class UserSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = User
|
||||||
|
fields = ["username", "email", "name", "url"]
|
||||||
|
|
||||||
|
extra_kwargs = {
|
||||||
|
"url": {"view_name": "api:user-detail", "lookup_field": "username"}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user