mirror of
https://github.com/cookiecutter/cookiecutter-django.git
synced 2025-08-09 14:34:53 +03:00
Merged with latest master
This commit is contained in:
commit
0ba293a566
33
.github/ISSUE_TEMPLATE.md
vendored
33
.github/ISSUE_TEMPLATE.md
vendored
|
@ -1,32 +1 @@
|
||||||
**Note: for support questions, please use the `cookiecutter-django` tag on stackoverflow**. This repository's issues are reserved for feature requests and bug reports.
|
## [Make sure to follow one of the issue templates we've got](https://github.com/pydanny/cookiecutter-django/issues/new/choose), otherwise the issue might be closed immeditely
|
||||||
|
|
||||||
* **I'm submitting a ... **
|
|
||||||
- [ ] bug report
|
|
||||||
- [ ] feature request
|
|
||||||
- [ ] support request => Please do not submit support request here, see note at the top of this template.
|
|
||||||
|
|
||||||
|
|
||||||
* **Do you want to request a *feature* or report a *bug*?**
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
* **What is the current behavior?**
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
* **If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem**
|
|
||||||
|
|
||||||
|
|
||||||
* **What is the expected behavior?**
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
* **What is the motivation / use case for changing the behavior?**
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
* **Please tell us about your environment:**
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
* **Other information** (e.g. detailed explanation, stacktraces, related issues, suggestions how to fix, links for us to have context, eg. stackoverflow, gitter, etc)
|
|
||||||
|
|
23
.github/ISSUE_TEMPLATE/bug.md
vendored
Normal file
23
.github/ISSUE_TEMPLATE/bug.md
vendored
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
---
|
||||||
|
name: Bug Report
|
||||||
|
about: Report a bug
|
||||||
|
---
|
||||||
|
|
||||||
|
## What happened?
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## What should've happened instead?
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Steps to reproduce
|
||||||
|
|
||||||
|
[//]: # (Any or all of the following:)
|
||||||
|
[//]: # (* Host system configuration: OS, Docker & friends' versions etc.)
|
||||||
|
[//]: # (* Project generation options)
|
||||||
|
[//]: # (* Logs)
|
||||||
|
|
||||||
|
|
24
.github/ISSUE_TEMPLATE/feature.md
vendored
Normal file
24
.github/ISSUE_TEMPLATE/feature.md
vendored
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
---
|
||||||
|
name: New Feature Proposal
|
||||||
|
about: Propose a new feature
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
[//]: # (What's it you're proposing? How should it be implemented?)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Rationale
|
||||||
|
|
||||||
|
[//]: # (Why should this feature be implemented?)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Use case(s) / visualization(s)
|
||||||
|
|
||||||
|
[//]: # ("Better to see something once than to hear about it a thousand times.")
|
||||||
|
|
||||||
|
|
24
.github/ISSUE_TEMPLATE/improvement.md
vendored
Normal file
24
.github/ISSUE_TEMPLATE/improvement.md
vendored
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
---
|
||||||
|
name: Improvement Suggestion
|
||||||
|
about: Let us know how we could improve
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
[//]: # (What's it you're proposing? How should it be implemented?)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Rationale
|
||||||
|
|
||||||
|
[//]: # (Why should this feature be implemented?)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Use case(s) / visualization(s)
|
||||||
|
|
||||||
|
[//]: # ("Better to see something once than to hear about it a thousand times.")
|
||||||
|
|
||||||
|
|
10
.github/ISSUE_TEMPLATE/paid-support.md
vendored
Normal file
10
.github/ISSUE_TEMPLATE/paid-support.md
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
---
|
||||||
|
name: Paid Support Request
|
||||||
|
about: Ask Core Team members to help you out
|
||||||
|
---
|
||||||
|
|
||||||
|
Provided your question goes beyound [regular support](https://github.com/pydanny/cookiecutter-django/issues/new?template=question.md), and/or the task at hand is of timely/high priority nature use the below information to reach out for contributors directly.
|
||||||
|
|
||||||
|
* Daniel Roy Greenfeld, Project Lead ([GitHub](https://github.com/pydanny), [Patreon](https://www.patreon.com/danielroygreenfeld)): expertise in Django and AWS ELB.
|
||||||
|
|
||||||
|
* Nikita Shupeyko, Core Developer ([GitHub](https://github.com/webyneter)): expertise in Python/Django, hands-on DevOps and frontend experience.
|
6
.github/ISSUE_TEMPLATE/question.md
vendored
Normal file
6
.github/ISSUE_TEMPLATE/question.md
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
name: Question
|
||||||
|
about: Please, ask your question on StackOverflow or Gitter
|
||||||
|
---
|
||||||
|
|
||||||
|
First, make sure to examine [the docs](https://cookiecutter-django.readthedocs.io/en/latest/). If that doesn't help post a question on [StackOverflow](https://stackoverflow.com/questions/tagged/cookiecutter-django) tagged with `cookiecutter-django`. Finally, feel free to join [Gitter](https://gitter.im/pydanny/cookiecutter-django) and ask around.
|
28
.github/ISSUE_TEMPLATE/regression.md
vendored
Normal file
28
.github/ISSUE_TEMPLATE/regression.md
vendored
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
---
|
||||||
|
name: Regression Report
|
||||||
|
about: Let us know if something that'd been working has broke
|
||||||
|
---
|
||||||
|
|
||||||
|
## What happened before?
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## What happens now?
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Last stable commit / Since when?
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Steps to reproduce
|
||||||
|
|
||||||
|
[//]: # (Any or all of the following:)
|
||||||
|
[//]: # (* Host system configuration: OS, Docker & friends' versions etc.)
|
||||||
|
[//]: # (* Project generation options)
|
||||||
|
[//]: # (* Logs)
|
||||||
|
|
||||||
|
|
27
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
27
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
[//]: # (Thank you for helping us out: your efforts mean great deal to the project and the community as a whole!)
|
||||||
|
|
||||||
|
[//]: # (Before you proceed:)
|
||||||
|
|
||||||
|
[//]: # (1. Make sure to add yourself to `CONTRIBUTORS.rst` through this PR provided you're contributing here for the first time)
|
||||||
|
[//]: # (2. Don't forget to update the `docs/` presuming others would benefit from a concise description of whatever that you're proposing)
|
||||||
|
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
[//]: # (What's it you're proposing?)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Rationale
|
||||||
|
|
||||||
|
[//]: # (Why does the project need that?)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Use case(s) / visualization(s)
|
||||||
|
|
||||||
|
[//]: # ("Better to see something once than to hear about it a thousand times.")
|
||||||
|
|
||||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -215,7 +215,6 @@ tags
|
||||||
[Ii]nclude
|
[Ii]nclude
|
||||||
[Ll]ib
|
[Ll]ib
|
||||||
[Ll]ib64
|
[Ll]ib64
|
||||||
[Ll]ocal
|
|
||||||
[Ss]cripts
|
[Ss]cripts
|
||||||
pyvenv.cfg
|
pyvenv.cfg
|
||||||
pip-selfcheck.json
|
pip-selfcheck.json
|
||||||
|
|
10
.travis.yml
10
.travis.yml
|
@ -1,5 +1,3 @@
|
||||||
# Config file for automatic testing at travis-ci.org
|
|
||||||
|
|
||||||
sudo: required
|
sudo: required
|
||||||
|
|
||||||
services:
|
services:
|
||||||
|
@ -10,18 +8,18 @@ language: python
|
||||||
python: 3.6
|
python: 3.6
|
||||||
|
|
||||||
env:
|
env:
|
||||||
- TOX_ENV=py36
|
- TOX_ENV=py36
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- docker-compose -v
|
- docker-compose -v
|
||||||
- docker -v
|
- docker -v
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- tox -e $TOX_ENV
|
- tox -e $TOX_ENV
|
||||||
- sh tests/test_docker.sh
|
- sh tests/test_docker.sh
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- pip install tox
|
- pip install tox
|
||||||
|
|
||||||
notifications:
|
notifications:
|
||||||
email:
|
email:
|
||||||
|
|
|
@ -87,6 +87,7 @@ Listed in alphabetical order.
|
||||||
David Díaz `@ddiazpinto`_ @DavidDiazPinto
|
David Díaz `@ddiazpinto`_ @DavidDiazPinto
|
||||||
Davur Clementsen `@dsclementsen`_ @davur
|
Davur Clementsen `@dsclementsen`_ @davur
|
||||||
Delio Castillo `@jangeador`_ @jangeador
|
Delio Castillo `@jangeador`_ @jangeador
|
||||||
|
Denis Orehovsky `@apirobot`_
|
||||||
Dónal Adams `@epileptic-fish`_
|
Dónal Adams `@epileptic-fish`_
|
||||||
Dong Huynh `@trungdong`_
|
Dong Huynh `@trungdong`_
|
||||||
Emanuel Calso `@bloodpet`_ @bloodpet
|
Emanuel Calso `@bloodpet`_ @bloodpet
|
||||||
|
@ -120,6 +121,7 @@ Listed in alphabetical order.
|
||||||
Lyla Fischer
|
Lyla Fischer
|
||||||
Malik Sulaimanov `@flyudvik`_ @flyudvik
|
Malik Sulaimanov `@flyudvik`_ @flyudvik
|
||||||
Martin Blech
|
Martin Blech
|
||||||
|
Martin Saizar `@msaizar`_
|
||||||
Mathijs Hoogland `@MathijsHoogland`_
|
Mathijs Hoogland `@MathijsHoogland`_
|
||||||
Matt Braymer-Hayes `@mattayes`_ @mattayes
|
Matt Braymer-Hayes `@mattayes`_ @mattayes
|
||||||
Matt Linares
|
Matt Linares
|
||||||
|
@ -160,6 +162,7 @@ Listed in alphabetical order.
|
||||||
Will Farley `@goldhand`_ @g01dhand
|
Will Farley `@goldhand`_ @g01dhand
|
||||||
William Archinal `@archinal`_
|
William Archinal `@archinal`_
|
||||||
Yaroslav Halchenko
|
Yaroslav Halchenko
|
||||||
|
Denis Bobrov `@delneg`_
|
||||||
========================== ============================ ==============
|
========================== ============================ ==============
|
||||||
|
|
||||||
.. _@a7p: https://github.com/a7p
|
.. _@a7p: https://github.com/a7p
|
||||||
|
@ -171,6 +174,7 @@ Listed in alphabetical order.
|
||||||
.. _@amjith: https://github.com/amjith
|
.. _@amjith: https://github.com/amjith
|
||||||
.. _@andor-pierdelacabeza: https://github.com/andor-pierdelacabeza
|
.. _@andor-pierdelacabeza: https://github.com/andor-pierdelacabeza
|
||||||
.. _@antoniablair: https://github.com/antoniablair
|
.. _@antoniablair: https://github.com/antoniablair
|
||||||
|
.. _@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
|
||||||
|
@ -218,6 +222,7 @@ Listed in alphabetical order.
|
||||||
.. _@kevgathuku: https://github.com/kevgathuku
|
.. _@kevgathuku: https://github.com/kevgathuku
|
||||||
.. _@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
|
||||||
.. _@MathijsHoogland: https://github.com/MathijsHoogland
|
.. _@MathijsHoogland: https://github.com/MathijsHoogland
|
||||||
.. _@mattayes: https://github.com/mattayes
|
.. _@mattayes: https://github.com/mattayes
|
||||||
.. _@menzenski: https://github.com/menzenski
|
.. _@menzenski: https://github.com/menzenski
|
||||||
|
@ -261,7 +266,7 @@ Listed in alphabetical order.
|
||||||
.. _@brentpayne: https://github.com/brentpayne
|
.. _@brentpayne: https://github.com/brentpayne
|
||||||
.. _@afrowave: https://github.com/afrowave
|
.. _@afrowave: https://github.com/afrowave
|
||||||
.. _@pchiquet: https://github.com/pchiquet
|
.. _@pchiquet: https://github.com/pchiquet
|
||||||
|
.. _@delneg: https://github.com/delneg
|
||||||
Special Thanks
|
Special Thanks
|
||||||
~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
17
README.rst
17
README.rst
|
@ -65,7 +65,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 or Whitenoise_
|
||||||
* Configuration for Celery_
|
* 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
|
||||||
|
|
||||||
|
@ -78,6 +78,7 @@ Optional Integrations
|
||||||
.. _Mailgun: http://www.mailgun.com/
|
.. _Mailgun: http://www.mailgun.com/
|
||||||
.. _Whitenoise: https://whitenoise.readthedocs.io/
|
.. _Whitenoise: https://whitenoise.readthedocs.io/
|
||||||
.. _Celery: http://www.celeryproject.org/
|
.. _Celery: http://www.celeryproject.org/
|
||||||
|
.. _Flower: https://github.com/mher/flower
|
||||||
.. _Anymail: https://github.com/anymail/django-anymail
|
.. _Anymail: https://github.com/anymail/django-anymail
|
||||||
.. _MailHog: https://github.com/mailhog/MailHog
|
.. _MailHog: https://github.com/mailhog/MailHog
|
||||||
.. _Sentry: https://sentry.io/welcome/
|
.. _Sentry: https://sentry.io/welcome/
|
||||||
|
@ -98,7 +99,9 @@ Support this Project!
|
||||||
|
|
||||||
This project is run by volunteers. Please support them in their efforts to maintain and improve Cookiecutter Django:
|
This project is run by volunteers. Please support them in their efforts to maintain and improve Cookiecutter Django:
|
||||||
|
|
||||||
* https://www.patreon.com/danielroygreenfeld: Project lead. Expertise in AWS ELB and Django.
|
* Daniel Roy Greenfeld, Project Lead (`GitHub <https://github.com/pydanny>`_, `Patreon <https://www.patreon.com/danielroygreenfeld>`_): expertise in Django and AWS ELB.
|
||||||
|
|
||||||
|
* Nikita Shupeyko, Core Developer (`GitHub <https://github.com/webyneter>`_): expertise in Python/Django, hands-on DevOps and frontend experience.
|
||||||
|
|
||||||
Projects that provide financial support to the maintainers:
|
Projects that provide financial support to the maintainers:
|
||||||
|
|
||||||
|
@ -158,13 +161,13 @@ Answer the prompts with your own desired options_. For example::
|
||||||
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
|
||||||
use_whitenoise [y]: n
|
use_whitenoise [n]: n
|
||||||
use_celery [n]: y
|
use_celery [n]: y
|
||||||
use_mailhog [n]: n
|
use_mailhog [n]: n
|
||||||
use_sentry [y]: y
|
use_sentry [n]: y
|
||||||
use_pycharm [n]: y
|
use_pycharm [n]: y
|
||||||
windows [n]: n
|
windows [n]: n
|
||||||
use_docker [y]: n
|
use_docker [n]: n
|
||||||
use_heroku [n]: y
|
use_heroku [n]: y
|
||||||
use_compressor [n]: y
|
use_compressor [n]: y
|
||||||
Select postgresql_version:
|
Select postgresql_version:
|
||||||
|
@ -279,6 +282,8 @@ experience better.
|
||||||
Articles
|
Articles
|
||||||
---------
|
---------
|
||||||
|
|
||||||
|
* `cookiecutter-django with Nginx, Route 53 and ELB`_ - Feb. 12, 2018
|
||||||
|
* `cookiecutter-django and Amazon RDS`_ - Feb. 7, 2018
|
||||||
* `Deploying Cookiecutter-Django with Docker-Compose`_ - Oct. 19, 2017
|
* `Deploying Cookiecutter-Django with Docker-Compose`_ - Oct. 19, 2017
|
||||||
* `Using Cookiecutter to Jumpstart a Django Project on Windows with PyCharm`_ - May 19, 2017
|
* `Using Cookiecutter to Jumpstart a Django Project on Windows with PyCharm`_ - May 19, 2017
|
||||||
* `Exploring with Cookiecutter`_ - Dec. 3, 2016
|
* `Exploring with Cookiecutter`_ - Dec. 3, 2016
|
||||||
|
@ -290,6 +295,8 @@ Articles
|
||||||
|
|
||||||
Have a blog or online publication? Write about your cookiecutter-django tips and tricks, then send us a pull request with the link.
|
Have a blog or online publication? Write about your cookiecutter-django tips and tricks, then send us a pull request with the link.
|
||||||
|
|
||||||
|
.. _`cookiecutter-django with Nginx, Route 53 and ELB`: https://msaizar.com/blog/cookiecutter-django-nginx-route-53-and-elb/
|
||||||
|
.. _`cookiecutter-django and Amazon RDS`: https://msaizar.com/blog/cookiecutter-django-and-amazon-rds/
|
||||||
.. _`Deploying Cookiecutter-Django with Docker-Compose`: http://adamantine.me/2017/10/19/deploying-cookiecutter-django-with-docker-compose/
|
.. _`Deploying Cookiecutter-Django with Docker-Compose`: http://adamantine.me/2017/10/19/deploying-cookiecutter-django-with-docker-compose/
|
||||||
.. _`Exploring with Cookiecutter`: http://www.snowboardingcoder.com/django/2016/12/03/exploring-with-cookiecutter/
|
.. _`Exploring with Cookiecutter`: http://www.snowboardingcoder.com/django/2016/12/03/exploring-with-cookiecutter/
|
||||||
.. _`Using Cookiecutter to Jumpstart a Django Project on Windows with PyCharm`: https://joshuahunter.com/posts/using-cookiecutter-to-jumpstart-a-django-project-on-windows-with-pycharm/
|
.. _`Using Cookiecutter to Jumpstart a Django Project on Windows with PyCharm`: https://joshuahunter.com/posts/using-cookiecutter-to-jumpstart-a-django-project-on-windows-with-pycharm/
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
"use_pycharm": "n",
|
"use_pycharm": "n",
|
||||||
"use_docker": "n",
|
"use_docker": "n",
|
||||||
"postgresql_version": [
|
"postgresql_version": [
|
||||||
|
"10.4",
|
||||||
"10.3",
|
"10.3",
|
||||||
"10.2",
|
"10.2",
|
||||||
"10.1",
|
"10.1",
|
||||||
|
@ -34,8 +35,8 @@
|
||||||
"use_compressor": "n",
|
"use_compressor": "n",
|
||||||
"use_celery": "n",
|
"use_celery": "n",
|
||||||
"use_mailhog": "n",
|
"use_mailhog": "n",
|
||||||
"use_sentry": "y",
|
"use_sentry": "n",
|
||||||
"use_whitenoise": "y",
|
"use_whitenoise": "n",
|
||||||
"use_heroku": "n",
|
"use_heroku": "n",
|
||||||
"use_travisci": "n",
|
"use_travisci": "n",
|
||||||
"keep_local_envs_in_vcs": "y",
|
"keep_local_envs_in_vcs": "y",
|
||||||
|
|
|
@ -14,26 +14,41 @@ Run these commands to deploy the project to Heroku:
|
||||||
heroku pg:promote DATABASE_URL
|
heroku pg:promote DATABASE_URL
|
||||||
|
|
||||||
heroku addons:create heroku-redis:hobby-dev
|
heroku addons:create heroku-redis:hobby-dev
|
||||||
heroku addons:create mailgun
|
|
||||||
|
|
||||||
heroku config:set WEB_CONCURRENCY=4
|
# If using mailgun:
|
||||||
# Generating a 32 character-long random string without any of the visually similiar characters "IOl01":
|
heroku addons:create mailgun:starter
|
||||||
heroku config:set DJANGO_ADMIN_URL="$(openssl rand -base64 4096 | tr -dc 'A-HJ-NP-Za-km-z2-9' | head -c 32)/"
|
|
||||||
heroku config:set DJANGO_SECRET_KEY="$(openssl rand -base64 64)"
|
|
||||||
heroku config:set DJANGO_SETTINGS_MODULE=config.settings.production
|
|
||||||
heroku config:set DJANGO_ALLOWED_HOSTS='.herokuapp.com'
|
|
||||||
|
|
||||||
heroku config:set DJANGO_AWS_ACCESS_KEY_ID=YOUR_AWS_ID_HERE
|
heroku addons:create sentry:f1
|
||||||
heroku config:set DJANGO_AWS_SECRET_ACCESS_KEY=YOUR_AWS_SECRET_ACCESS_KEY_HERE
|
|
||||||
heroku config:set DJANGO_AWS_STORAGE_BUCKET_NAME=YOUR_AWS_S3_BUCKET_NAME_HERE
|
|
||||||
|
|
||||||
# This is to be set only if you're using Sentry:
|
|
||||||
heroku config:set DJANGO_SENTRY_DSN=YOUR_SENTRY_DSN
|
|
||||||
|
|
||||||
heroku config:set PYTHONHASHSEED=random
|
heroku config:set PYTHONHASHSEED=random
|
||||||
|
|
||||||
|
heroku config:set WEB_CONCURRENCY=4
|
||||||
|
|
||||||
|
heroku config:set DJANGO_DEBUG=False
|
||||||
|
heroku config:set DJANGO_SETTINGS_MODULE=config.settings.production
|
||||||
|
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":
|
||||||
|
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'
|
||||||
|
heroku config:set DJANGO_ALLOWED_HOSTS=
|
||||||
|
|
||||||
|
# Assign with AWS_ACCESS_KEY_ID
|
||||||
|
heroku config:set DJANGO_AWS_ACCESS_KEY_ID=
|
||||||
|
|
||||||
|
# Assign with AWS_SECRET_ACCESS_KEY
|
||||||
|
heroku config:set DJANGO_AWS_SECRET_ACCESS_KEY=
|
||||||
|
|
||||||
|
# Assign with AWS_STORAGE_BUCKET_NAME
|
||||||
|
heroku config:set DJANGO_AWS_STORAGE_BUCKET_NAME=
|
||||||
|
|
||||||
git push heroku master
|
git push heroku master
|
||||||
|
|
||||||
heroku run python manage.py migrate
|
heroku run python manage.py migrate
|
||||||
heroku run python manage.py check --deploy
|
|
||||||
heroku run python manage.py createsuperuser
|
heroku run python manage.py createsuperuser
|
||||||
|
heroku run python manage.py collectstatic --no-input
|
||||||
|
|
||||||
|
heroku run python manage.py check --deploy
|
||||||
|
|
||||||
heroku open
|
heroku open
|
||||||
|
|
|
@ -21,10 +21,13 @@ Before you begin, check out the ``production.yml`` file in the root of this proj
|
||||||
* ``redis``: Redis instance for caching;
|
* ``redis``: Redis instance for caching;
|
||||||
* ``caddy``: Caddy web server with HTTPS on by default.
|
* ``caddy``: Caddy web server with HTTPS on by default.
|
||||||
|
|
||||||
Provided you have opted for Celery (via setting ``use_celery`` to ``y``) there are two more services:
|
Provided you have opted for Celery (via setting ``use_celery`` to ``y``) there are three more services:
|
||||||
|
|
||||||
* ``celeryworker`` running a Celery worker process;
|
* ``celeryworker`` running a Celery worker process;
|
||||||
* ``celerybeat`` running a Celery beat process.
|
* ``celerybeat`` running a Celery beat process;
|
||||||
|
* ``flower`` running Flower_ (for more info, check out :ref:`CeleryFlower` instructions for local environment).
|
||||||
|
|
||||||
|
.. _`Flower`: https://github.com/mher/flower
|
||||||
|
|
||||||
|
|
||||||
Configuring the Stack
|
Configuring the Stack
|
||||||
|
@ -32,7 +35,7 @@ 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 ``DJANGO_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.
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
|
@ -70,7 +73,7 @@ You can read more about this here at `Automatic HTTPS`_ in the Caddy docs.
|
||||||
(Optional) Postgres Data Volume Modifications
|
(Optional) Postgres Data Volume Modifications
|
||||||
---------------------------------------------
|
---------------------------------------------
|
||||||
|
|
||||||
Postgres is saving its database files to the ``postgres_data`` volume by default. Change that if you want something else and make sure to make backups since this is not done automatically.
|
Postgres is saving its database files to the ``production_postgres_data`` volume by default. Change that if you want something else and make sure to make backups since this is not done automatically.
|
||||||
|
|
||||||
|
|
||||||
Building & Running Production Stack
|
Building & Running Production Stack
|
||||||
|
@ -84,6 +87,10 @@ Once this is ready, you can run it with::
|
||||||
|
|
||||||
docker-compose -f production.yml up
|
docker-compose -f production.yml up
|
||||||
|
|
||||||
|
To run the stack and detach the containers, run::
|
||||||
|
|
||||||
|
docker-compose -f production.yml up -d
|
||||||
|
|
||||||
To run a migration, open up a second terminal and run::
|
To run a migration, open up a second terminal and run::
|
||||||
|
|
||||||
docker-compose -f production.yml run --rm django python manage.py migrate
|
docker-compose -f production.yml run --rm django python manage.py migrate
|
||||||
|
|
|
@ -91,8 +91,8 @@ This is the excerpt from your project's ``local.yml``: ::
|
||||||
context: .
|
context: .
|
||||||
dockerfile: ./compose/production/postgres/Dockerfile
|
dockerfile: ./compose/production/postgres/Dockerfile
|
||||||
volumes:
|
volumes:
|
||||||
- postgres_data_local:/var/lib/postgresql/data
|
- local_postgres_data:/var/lib/postgresql/data
|
||||||
- postgres_backup_local:/backups
|
- local_postgres_data_backups:/backups
|
||||||
env_file:
|
env_file:
|
||||||
- ./.envs/.local/.postgres
|
- ./.envs/.local/.postgres
|
||||||
|
|
||||||
|
@ -170,3 +170,20 @@ When developing locally you can go with MailHog_ for email testing provided ``us
|
||||||
#. open up ``http://127.0.0.1:8025``.
|
#. open up ``http://127.0.0.1:8025``.
|
||||||
|
|
||||||
.. _Mailhog: https://github.com/mailhog/MailHog/
|
.. _Mailhog: https://github.com/mailhog/MailHog/
|
||||||
|
|
||||||
|
|
||||||
|
.. _`CeleryFlower`:
|
||||||
|
|
||||||
|
Celery Flower
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
`Flower`_ is a "real-time monitor and web admin for Celery distributed task queue".
|
||||||
|
|
||||||
|
Prerequisites:
|
||||||
|
|
||||||
|
* ``use_docker`` was set to ``y`` on project initialization;
|
||||||
|
* ``use_celery`` was set to ``y`` on project initialization.
|
||||||
|
|
||||||
|
By default, it's enabled both in local and production environments (``local.yml`` and ``production.yml`` Docker Compose configs, respectively) through a ``flower`` service. For added security, ``flower`` requires its clients to provide authentication credentials specified as the corresponding environments' ``.envs/.local/.django`` and ``.envs/.production/.django`` ``CELERY_FLOWER_USER`` and ``CELERY_FLOWER_PASSWORD`` environment variables. Check out ``localhost:5555`` and see for yourself.
|
||||||
|
|
||||||
|
.. _`Flower`: https://github.com/mher/flower
|
||||||
|
|
|
@ -1,31 +1,31 @@
|
||||||
Project Generation Options
|
Project Generation Options
|
||||||
==========================
|
==========================
|
||||||
|
|
||||||
project_name [My Awesome Project]:
|
project_name:
|
||||||
Your project's human-readable name, capitals and spaces allowed.
|
Your project's human-readable name, capitals and spaces allowed.
|
||||||
|
|
||||||
project_slug [my_awesome_project]:
|
project_slug:
|
||||||
Your project's slug without dashes or spaces. Used to name your repo
|
Your project's slug without dashes or spaces. Used to name your repo
|
||||||
and in other places where a Python-importable version of your project name
|
and in other places where a Python-importable version of your project name
|
||||||
is needed.
|
is needed.
|
||||||
|
|
||||||
description [Behold My Awesome Project!]
|
description:
|
||||||
Describes your project and gets used in places like ``README.rst`` and such.
|
Describes your project and gets used in places like ``README.rst`` and such.
|
||||||
|
|
||||||
author_name [Daniel Roy Greenfeld]:
|
author_name:
|
||||||
This is you! The value goes into places like ``LICENSE`` and such.
|
This is you! The value goes into places like ``LICENSE`` and such.
|
||||||
|
|
||||||
email [daniel-roy-greenfeld@example.com]:
|
email:
|
||||||
The email address you want to identify yourself in the project.
|
The email address you want to identify yourself in the project.
|
||||||
|
|
||||||
domain_name [example.com]
|
domain_name:
|
||||||
The domain name you plan to use for your project once it goes live.
|
The domain name you plan to use for your project once it goes live.
|
||||||
Note that it can be safely changed later on whenever you need to.
|
Note that it can be safely changed later on whenever you need to.
|
||||||
|
|
||||||
version [0.1.0]
|
version:
|
||||||
The version of the project at its inception.
|
The version of the project at its inception.
|
||||||
|
|
||||||
open_source_license [1]
|
open_source_license:
|
||||||
A software license for the project. The choices are:
|
A software license for the project. The choices are:
|
||||||
|
|
||||||
1. MIT_
|
1. MIT_
|
||||||
|
@ -34,19 +34,19 @@ open_source_license [1]
|
||||||
4. `Apache Software License 2.0`_
|
4. `Apache Software License 2.0`_
|
||||||
5. Not open source
|
5. Not open source
|
||||||
|
|
||||||
timezone [UTC]
|
timezone:
|
||||||
The value to be used for the ``TIME_ZONE`` setting of the project.
|
The value to be used for the ``TIME_ZONE`` setting of the project.
|
||||||
|
|
||||||
windows [n]
|
windows:
|
||||||
Indicates whether the project should be configured for development on Windows.
|
Indicates whether the project should be configured for development on Windows.
|
||||||
|
|
||||||
use_pycharm [n]
|
use_pycharm:
|
||||||
Indicates whether the project should be configured for development with PyCharm_.
|
Indicates whether the project should be configured for development with PyCharm_.
|
||||||
|
|
||||||
use_docker [y]
|
use_docker:
|
||||||
Indicates whether the project should be configured to use Docker_ and `Docker Compose`_.
|
Indicates whether the project should be configured to use Docker_ and `Docker Compose`_.
|
||||||
|
|
||||||
postgresql_version [1]
|
postgresql_version:
|
||||||
Select a PostgreSQL_ version to use. The choices are:
|
Select a PostgreSQL_ version to use. The choices are:
|
||||||
|
|
||||||
1. 10.3
|
1. 10.3
|
||||||
|
@ -57,45 +57,45 @@ postgresql_version [1]
|
||||||
6. 9.4
|
6. 9.4
|
||||||
7. 9.3
|
7. 9.3
|
||||||
|
|
||||||
js_task_runner [1]
|
js_task_runner:
|
||||||
Select a JavaScript task runner. The choices are:
|
Select a JavaScript task runner. The choices are:
|
||||||
|
|
||||||
1. None
|
1. None
|
||||||
2. Gulp_
|
2. Gulp_
|
||||||
|
|
||||||
custom_bootstrap_compilation [n]
|
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
|
||||||
for real-time Bootstrap variable alteration.
|
for real-time Bootstrap variable alteration.
|
||||||
|
|
||||||
use_compressor [n]
|
use_compressor:
|
||||||
Indicates whether the project should be configured to use `Django Compressor`_.
|
Indicates whether the project should be configured to use `Django Compressor`_.
|
||||||
|
|
||||||
use_celery [n]
|
use_celery:
|
||||||
Indicates whether the project should be configured to use Celery_.
|
Indicates whether the project should be configured to use Celery_.
|
||||||
|
|
||||||
use_mailhog [n]
|
use_mailhog:
|
||||||
Indicates whether the project should be configured to use MailHog_.
|
Indicates whether the project should be configured to use MailHog_.
|
||||||
|
|
||||||
use_sentry [n]
|
use_sentry:
|
||||||
Indicates whether the project should be configured to use Sentry_.
|
Indicates whether the project should be configured to use Sentry_.
|
||||||
|
|
||||||
use_whitenoise [y]
|
use_whitenoise:
|
||||||
Indicates whether the project should be configured to use WhiteNoise_.
|
Indicates whether the project should be configured to use WhiteNoise_.
|
||||||
|
|
||||||
use_heroku [n]
|
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 [n]
|
use_travisci:
|
||||||
Indicates whether the project should be configured to use `Travis CI`_.
|
Indicates whether the project should be configured to use `Travis CI`_.
|
||||||
|
|
||||||
keep_local_envs_in_vcs [y]
|
keep_local_envs_in_vcs:
|
||||||
Indicates whether the project's ``.envs/.local/`` should be kept in VCS
|
Indicates whether the project's ``.envs/.local/`` should be kept in VCS
|
||||||
(comes in handy when working in teams where local environment reproducibility
|
(comes in handy when working in teams where local environment reproducibility
|
||||||
is strongly encouraged).
|
is strongly encouraged).
|
||||||
|
|
||||||
debug [n]
|
debug:
|
||||||
Indicates whether the project should be configured for debugging.
|
Indicates whether the project should be configured for debugging.
|
||||||
This option is relevant for Cookiecutter Django developers only.
|
This option is relevant for Cookiecutter Django developers only.
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ Environment Variable Django Setting Development
|
||||||
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_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_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_ACCESS_KEY n/a raises error
|
||||||
|
|
|
@ -32,7 +32,10 @@ DEBUG_VALUE = "debug"
|
||||||
|
|
||||||
|
|
||||||
def remove_open_source_files():
|
def remove_open_source_files():
|
||||||
file_names = ["CONTRIBUTORS.txt"]
|
file_names = [
|
||||||
|
"CONTRIBUTORS.txt",
|
||||||
|
"LICENSE",
|
||||||
|
]
|
||||||
for file_name in file_names:
|
for file_name in file_names:
|
||||||
os.remove(file_name)
|
os.remove(file_name)
|
||||||
|
|
||||||
|
@ -61,6 +64,10 @@ def remove_docker_files():
|
||||||
os.remove(file_name)
|
os.remove(file_name)
|
||||||
|
|
||||||
|
|
||||||
|
def remove_utility_files():
|
||||||
|
shutil.rmtree("utility")
|
||||||
|
|
||||||
|
|
||||||
def remove_heroku_files():
|
def remove_heroku_files():
|
||||||
file_names = ["Procfile", "runtime.txt", "requirements.txt"]
|
file_names = ["Procfile", "runtime.txt", "requirements.txt"]
|
||||||
for file_name in file_names:
|
for file_name in file_names:
|
||||||
|
@ -162,8 +169,12 @@ def set_django_admin_url(file_path):
|
||||||
return django_admin_url
|
return django_admin_url
|
||||||
|
|
||||||
|
|
||||||
|
def generate_random_user():
|
||||||
|
return generate_random_string(length=32, using_ascii_letters=True)
|
||||||
|
|
||||||
|
|
||||||
def generate_postgres_user(debug=False):
|
def generate_postgres_user(debug=False):
|
||||||
return DEBUG_VALUE if debug else generate_random_string(length=32, using_ascii_letters=True)
|
return DEBUG_VALUE if debug else generate_random_user()
|
||||||
|
|
||||||
|
|
||||||
def set_postgres_user(file_path, value):
|
def set_postgres_user(file_path, value):
|
||||||
|
@ -187,25 +198,56 @@ def set_postgres_password(file_path, value=None):
|
||||||
return postgres_password
|
return postgres_password
|
||||||
|
|
||||||
|
|
||||||
|
def set_celery_flower_user(file_path, value):
|
||||||
|
celery_flower_user = set_flag(
|
||||||
|
file_path,
|
||||||
|
"!!!SET CELERY_FLOWER_USER!!!",
|
||||||
|
value=value,
|
||||||
|
)
|
||||||
|
return celery_flower_user
|
||||||
|
|
||||||
|
|
||||||
|
def set_celery_flower_password(file_path, value=None):
|
||||||
|
celery_flower_password = set_flag(
|
||||||
|
file_path,
|
||||||
|
"!!!SET CELERY_FLOWER_PASSWORD!!!",
|
||||||
|
value=value,
|
||||||
|
length=64,
|
||||||
|
using_digits=True,
|
||||||
|
using_ascii_letters=True,
|
||||||
|
)
|
||||||
|
return celery_flower_password
|
||||||
|
|
||||||
|
|
||||||
def append_to_gitignore_file(s):
|
def append_to_gitignore_file(s):
|
||||||
with open(".gitignore", "a") as gitignore_file:
|
with open(".gitignore", "a") as gitignore_file:
|
||||||
gitignore_file.write(s)
|
gitignore_file.write(s)
|
||||||
gitignore_file.write(os.linesep)
|
gitignore_file.write(os.linesep)
|
||||||
|
|
||||||
|
|
||||||
def set_flags_in_envs(postgres_user, debug=False):
|
def set_flags_in_envs(
|
||||||
local_postgres_envs_path = os.path.join(".envs", ".local", ".postgres")
|
postgres_user,
|
||||||
set_postgres_user(local_postgres_envs_path, value=postgres_user)
|
celery_flower_user,
|
||||||
set_postgres_password(local_postgres_envs_path, value=DEBUG_VALUE if debug else None)
|
debug=False,
|
||||||
|
):
|
||||||
|
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")
|
||||||
|
production_postgres_envs_path = os.path.join(".envs", ".production", ".postgres")
|
||||||
|
|
||||||
set_django_secret_key(production_django_envs_path)
|
set_django_secret_key(production_django_envs_path)
|
||||||
set_django_admin_url(production_django_envs_path)
|
set_django_admin_url(production_django_envs_path)
|
||||||
|
|
||||||
production_postgres_envs_path = os.path.join(".envs", ".production", ".postgres")
|
set_postgres_user(local_postgres_envs_path, value=postgres_user)
|
||||||
|
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_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_password(production_django_envs_path, value=DEBUG_VALUE if debug else None)
|
||||||
|
|
||||||
|
|
||||||
def set_flags_in_settings_files():
|
def set_flags_in_settings_files():
|
||||||
set_django_secret_key(os.path.join("config", "settings", "local.py"))
|
set_django_secret_key(os.path.join("config", "settings", "local.py"))
|
||||||
|
@ -223,8 +265,13 @@ def remove_celery_compose_dirs():
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
postgres_user = generate_postgres_user(debug="{{ cookiecutter.debug }}".lower() == "y")
|
debug = "{{ cookiecutter.debug }}".lower() == "y"
|
||||||
set_flags_in_envs(postgres_user, debug="{{ cookiecutter.debug }}".lower() == "y")
|
|
||||||
|
set_flags_in_envs(
|
||||||
|
DEBUG_VALUE if debug else generate_random_user(),
|
||||||
|
DEBUG_VALUE if debug else generate_random_user(),
|
||||||
|
debug=debug,
|
||||||
|
)
|
||||||
set_flags_in_settings_files()
|
set_flags_in_settings_files()
|
||||||
|
|
||||||
if "{{ cookiecutter.open_source_license }}" == "Not open source":
|
if "{{ cookiecutter.open_source_license }}" == "Not open source":
|
||||||
|
@ -235,7 +282,9 @@ def main():
|
||||||
if "{{ cookiecutter.use_pycharm }}".lower() == "n":
|
if "{{ cookiecutter.use_pycharm }}".lower() == "n":
|
||||||
remove_pycharm_files()
|
remove_pycharm_files()
|
||||||
|
|
||||||
if "{{ cookiecutter.use_docker }}".lower() == "n":
|
if "{{ cookiecutter.use_docker }}".lower() == "y":
|
||||||
|
remove_utility_files()
|
||||||
|
else:
|
||||||
remove_docker_files()
|
remove_docker_files()
|
||||||
|
|
||||||
if "{{ cookiecutter.use_heroku }}".lower() == "n":
|
if "{{ cookiecutter.use_heroku }}".lower() == "n":
|
||||||
|
|
|
@ -8,6 +8,6 @@ flake8==3.5.0
|
||||||
|
|
||||||
# Testing
|
# Testing
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
tox==3.0.0
|
tox==3.1.1
|
||||||
pytest==3.5.1
|
pytest==3.6.3
|
||||||
pytest-cookies==0.3.0
|
pytest-cookies==0.3.0
|
||||||
|
|
|
@ -11,7 +11,7 @@ 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 js_task_runner=None
|
cookiecutter ../../ --no-input --overwrite-if-exists use_docker=y
|
||||||
cd my_awesome_project
|
cd my_awesome_project
|
||||||
|
|
||||||
# run the project's tests
|
# run the project's tests
|
||||||
|
|
|
@ -5,3 +5,11 @@ USE_DOCKER=yes
|
||||||
# Redis
|
# Redis
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
REDIS_URL=redis://redis:6379/0
|
REDIS_URL=redis://redis:6379/0
|
||||||
|
{% if cookiecutter.use_celery == 'y' %}
|
||||||
|
# Celery
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# Flower
|
||||||
|
CELERY_FLOWER_USER=!!!SET CELERY_FLOWER_USER!!!
|
||||||
|
CELERY_FLOWER_PASSWORD=!!!SET CELERY_FLOWER_PASSWORD!!!
|
||||||
|
{% endif %}
|
||||||
|
|
|
@ -37,9 +37,17 @@ WEB_CONCURRENCY=4
|
||||||
{% if cookiecutter.use_sentry == 'y' %}
|
{% if cookiecutter.use_sentry == 'y' %}
|
||||||
# Sentry
|
# Sentry
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
DJANGO_SENTRY_DSN=
|
SENTRY_DSN=
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
# Redis
|
# Redis
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
REDIS_URL=redis://redis:6379/0
|
REDIS_URL=redis://redis:6379/0
|
||||||
|
{% if cookiecutter.use_celery == 'y' %}
|
||||||
|
# Celery
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# Flower
|
||||||
|
CELERY_FLOWER_USER=!!!SET CELERY_FLOWER_USER!!!
|
||||||
|
CELERY_FLOWER_PASSWORD=!!!SET CELERY_FLOWER_PASSWORD!!!
|
||||||
|
{% endif %}
|
||||||
|
|
3
{{cookiecutter.project_slug}}/.gitignore
vendored
3
{{cookiecutter.project_slug}}/.gitignore
vendored
|
@ -330,7 +330,6 @@ tags
|
||||||
[Ii]nclude
|
[Ii]nclude
|
||||||
[Ll]ib
|
[Ll]ib
|
||||||
[Ll]ib64
|
[Ll]ib64
|
||||||
[Ll]ocal
|
|
||||||
[Ss]cripts
|
[Ss]cripts
|
||||||
pyvenv.cfg
|
pyvenv.cfg
|
||||||
pip-selfcheck.json
|
pip-selfcheck.json
|
||||||
|
@ -341,3 +340,5 @@ pip-selfcheck.json
|
||||||
MailHog
|
MailHog
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{{ cookiecutter.project_slug }}/media/
|
{{ cookiecutter.project_slug }}/media/
|
||||||
|
|
||||||
|
.pytest_cache/
|
||||||
|
|
6
{{cookiecutter.project_slug}}/.idea/misc.xml
Normal file
6
{{cookiecutter.project_slug}}/.idea/misc.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="JavaScriptSettings">
|
||||||
|
<option name="languageLevel" value="ES6" />
|
||||||
|
</component>
|
||||||
|
</project>
|
8
{{cookiecutter.project_slug}}/.idea/modules.xml
Normal file
8
{{cookiecutter.project_slug}}/.idea/modules.xml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/{{ cookiecutter.project_slug }}.iml" filepath="$PROJECT_DIR$/.idea/{{ cookiecutter.project_slug }}.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -1,33 +0,0 @@
|
||||||
<component name="ProjectRunConfigurationManager">
|
|
||||||
<configuration default="false" name="Docker: runserver" type="Python.DjangoServer" factoryName="Django server" singleton="true">
|
|
||||||
<option name="INTERPRETER_OPTIONS" value="" />
|
|
||||||
<option name="PARENT_ENVS" value="true" />
|
|
||||||
<envs>
|
|
||||||
<env name="PYTHONUNBUFFERED" value="1" />
|
|
||||||
<env name="DJANGO_SETTINGS_MODULE" value="config.settings.local" />
|
|
||||||
</envs>
|
|
||||||
<option name="SDK_HOME" value="docker-compose://[$PROJECT_DIR$/local.yml]:django/python" />
|
|
||||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
|
||||||
<option name="IS_MODULE_SDK" value="false" />
|
|
||||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
|
||||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
|
||||||
<module name="{{ cookiecutter.project_slug }}" />
|
|
||||||
<PathMappingSettings>
|
|
||||||
<option name="pathMappings">
|
|
||||||
<list>
|
|
||||||
<mapping local-root="$PROJECT_DIR$" remote-root="/app" />
|
|
||||||
</list>
|
|
||||||
</option>
|
|
||||||
</PathMappingSettings>
|
|
||||||
<option name="launchJavascriptDebuger" value="false" />
|
|
||||||
<option name="port" value="8000" />
|
|
||||||
<option name="host" value="0.0.0.0" />
|
|
||||||
<option name="additionalOptions" value="" />
|
|
||||||
<option name="browserUrl" value="" />
|
|
||||||
<option name="runTestServer" value="false" />
|
|
||||||
<option name="runNoReload" value="false" />
|
|
||||||
<option name="useCustomRunCommand" value="false" />
|
|
||||||
<option name="customRunCommand" value="" />
|
|
||||||
<method />
|
|
||||||
</configuration>
|
|
||||||
</component>
|
|
|
@ -1,30 +0,0 @@
|
||||||
<component name="ProjectRunConfigurationManager">
|
|
||||||
<configuration default="false" name="Docker: tests - all" type="DjangoTestsConfigurationType" factoryName="Django tests" singleton="true">
|
|
||||||
<option name="INTERPRETER_OPTIONS" value="" />
|
|
||||||
<option name="PARENT_ENVS" value="true" />
|
|
||||||
<envs>
|
|
||||||
<env name="PYTHONUNBUFFERED" value="1" />
|
|
||||||
<env name="DJANGO_SETTINGS_MODULE" value="config.settings.test" />
|
|
||||||
</envs>
|
|
||||||
<option name="SDK_HOME" value="docker-compose://[$PROJECT_DIR$/local.yml]:django/python" />
|
|
||||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
|
||||||
<option name="IS_MODULE_SDK" value="true" />
|
|
||||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
|
||||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
|
||||||
<module name="{{ cookiecutter.project_slug }}" />
|
|
||||||
<EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
|
|
||||||
<PathMappingSettings>
|
|
||||||
<option name="pathMappings">
|
|
||||||
<list>
|
|
||||||
<mapping local-root="$PROJECT_DIR$" remote-root="/app" />
|
|
||||||
</list>
|
|
||||||
</option>
|
|
||||||
</PathMappingSettings>
|
|
||||||
<option name="TARGET" value="." />
|
|
||||||
<option name="SETTINGS_FILE" value="" />
|
|
||||||
<option name="CUSTOM_SETTINGS" value="false" />
|
|
||||||
<option name="USE_OPTIONS" value="false" />
|
|
||||||
<option name="OPTIONS" value="" />
|
|
||||||
<method />
|
|
||||||
</configuration>
|
|
||||||
</component>
|
|
|
@ -1,30 +0,0 @@
|
||||||
<component name="ProjectRunConfigurationManager">
|
|
||||||
<configuration default="false" name="Docker: tests - class: TestUser" type="DjangoTestsConfigurationType" factoryName="Django tests" singleton="true">
|
|
||||||
<option name="INTERPRETER_OPTIONS" value="" />
|
|
||||||
<option name="PARENT_ENVS" value="true" />
|
|
||||||
<envs>
|
|
||||||
<env name="PYTHONUNBUFFERED" value="1" />
|
|
||||||
<env name="DJANGO_SETTINGS_MODULE" value="config.settings.test" />
|
|
||||||
</envs>
|
|
||||||
<option name="SDK_HOME" value="docker-compose://[$PROJECT_DIR$/local.yml]:django/python" />
|
|
||||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
|
||||||
<option name="IS_MODULE_SDK" value="true" />
|
|
||||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
|
||||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
|
||||||
<module name="{{ cookiecutter.project_slug }}" />
|
|
||||||
<EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
|
|
||||||
<PathMappingSettings>
|
|
||||||
<option name="pathMappings">
|
|
||||||
<list>
|
|
||||||
<mapping local-root="$PROJECT_DIR$" remote-root="/app" />
|
|
||||||
</list>
|
|
||||||
</option>
|
|
||||||
</PathMappingSettings>
|
|
||||||
<option name="TARGET" value="{{ cookiecutter.project_slug }}.users.tests.test_models.TestUser" />
|
|
||||||
<option name="SETTINGS_FILE" value="" />
|
|
||||||
<option name="CUSTOM_SETTINGS" value="false" />
|
|
||||||
<option name="USE_OPTIONS" value="false" />
|
|
||||||
<option name="OPTIONS" value="" />
|
|
||||||
<method />
|
|
||||||
</configuration>
|
|
||||||
</component>
|
|
|
@ -1,30 +0,0 @@
|
||||||
<component name="ProjectRunConfigurationManager">
|
|
||||||
<configuration default="false" name="Docker: tests - file: test_models" type="DjangoTestsConfigurationType" factoryName="Django tests" singleton="true">
|
|
||||||
<option name="INTERPRETER_OPTIONS" value="" />
|
|
||||||
<option name="PARENT_ENVS" value="true" />
|
|
||||||
<envs>
|
|
||||||
<env name="PYTHONUNBUFFERED" value="1" />
|
|
||||||
<env name="DJANGO_SETTINGS_MODULE" value="config.settings.test" />
|
|
||||||
</envs>
|
|
||||||
<option name="SDK_HOME" value="docker-compose://[$PROJECT_DIR$/local.yml]:django/python" />
|
|
||||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
|
||||||
<option name="IS_MODULE_SDK" value="true" />
|
|
||||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
|
||||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
|
||||||
<module name="{{ cookiecutter.project_slug }}" />
|
|
||||||
<EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
|
|
||||||
<PathMappingSettings>
|
|
||||||
<option name="pathMappings">
|
|
||||||
<list>
|
|
||||||
<mapping local-root="$PROJECT_DIR$" remote-root="/app" />
|
|
||||||
</list>
|
|
||||||
</option>
|
|
||||||
</PathMappingSettings>
|
|
||||||
<option name="TARGET" value="{{ cookiecutter.project_slug }}.users.tests.test_models" />
|
|
||||||
<option name="SETTINGS_FILE" value="" />
|
|
||||||
<option name="CUSTOM_SETTINGS" value="false" />
|
|
||||||
<option name="USE_OPTIONS" value="false" />
|
|
||||||
<option name="OPTIONS" value="" />
|
|
||||||
<method />
|
|
||||||
</configuration>
|
|
||||||
</component>
|
|
|
@ -1,30 +0,0 @@
|
||||||
<component name="ProjectRunConfigurationManager">
|
|
||||||
<configuration default="false" name="Docker: tests - module: users" type="DjangoTestsConfigurationType" factoryName="Django tests" singleton="true">
|
|
||||||
<option name="INTERPRETER_OPTIONS" value="" />
|
|
||||||
<option name="PARENT_ENVS" value="true" />
|
|
||||||
<envs>
|
|
||||||
<env name="PYTHONUNBUFFERED" value="1" />
|
|
||||||
<env name="DJANGO_SETTINGS_MODULE" value="config.settings.test" />
|
|
||||||
</envs>
|
|
||||||
<option name="SDK_HOME" value="docker-compose://[$PROJECT_DIR$/local.yml]:django/python" />
|
|
||||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
|
||||||
<option name="IS_MODULE_SDK" value="true" />
|
|
||||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
|
||||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
|
||||||
<module name="{{ cookiecutter.project_slug }}" />
|
|
||||||
<EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
|
|
||||||
<PathMappingSettings>
|
|
||||||
<option name="pathMappings">
|
|
||||||
<list>
|
|
||||||
<mapping local-root="$PROJECT_DIR$" remote-root="/app" />
|
|
||||||
</list>
|
|
||||||
</option>
|
|
||||||
</PathMappingSettings>
|
|
||||||
<option name="TARGET" value="{{ cookiecutter.project_slug }}.users" />
|
|
||||||
<option name="SETTINGS_FILE" value="" />
|
|
||||||
<option name="CUSTOM_SETTINGS" value="false" />
|
|
||||||
<option name="USE_OPTIONS" value="false" />
|
|
||||||
<option name="OPTIONS" value="" />
|
|
||||||
<method />
|
|
||||||
</configuration>
|
|
||||||
</component>
|
|
|
@ -1,30 +0,0 @@
|
||||||
<component name="ProjectRunConfigurationManager">
|
|
||||||
<configuration default="false" name="Docker: tests - specific: test_get_absolute_url" type="DjangoTestsConfigurationType" factoryName="Django tests" singleton="true">
|
|
||||||
<option name="INTERPRETER_OPTIONS" value="" />
|
|
||||||
<option name="PARENT_ENVS" value="true" />
|
|
||||||
<envs>
|
|
||||||
<env name="PYTHONUNBUFFERED" value="1" />
|
|
||||||
<env name="DJANGO_SETTINGS_MODULE" value="config.settings.test" />
|
|
||||||
</envs>
|
|
||||||
<option name="SDK_HOME" value="docker-compose://[$PROJECT_DIR$/local.yml]:django/python" />
|
|
||||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
|
||||||
<option name="IS_MODULE_SDK" value="true" />
|
|
||||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
|
||||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
|
||||||
<module name="{{ cookiecutter.project_slug }}" />
|
|
||||||
<EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
|
|
||||||
<PathMappingSettings>
|
|
||||||
<option name="pathMappings">
|
|
||||||
<list>
|
|
||||||
<mapping local-root="$PROJECT_DIR$" remote-root="/app" />
|
|
||||||
</list>
|
|
||||||
</option>
|
|
||||||
</PathMappingSettings>
|
|
||||||
<option name="TARGET" value="{{ cookiecutter.project_slug }}.users.tests.test_models.TestUser.test_get_absolute_url" />
|
|
||||||
<option name="SETTINGS_FILE" value="" />
|
|
||||||
<option name="CUSTOM_SETTINGS" value="false" />
|
|
||||||
<option name="USE_OPTIONS" value="false" />
|
|
||||||
<option name="OPTIONS" value="" />
|
|
||||||
<method />
|
|
||||||
</configuration>
|
|
||||||
</component>
|
|
|
@ -1,5 +1,6 @@
|
||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="merge_production_dotenvs_in_dotenv" type="PythonConfigurationType" factoryName="Python" singleton="true">
|
<configuration default="false" name="merge_production_dotenvs_in_dotenv" type="PythonConfigurationType" factoryName="Python" singleton="true">
|
||||||
|
<module name="{{ cookiecutter.project_slug }}" />
|
||||||
<option name="INTERPRETER_OPTIONS" value="" />
|
<option name="INTERPRETER_OPTIONS" value="" />
|
||||||
<option name="PARENT_ENVS" value="true" />
|
<option name="PARENT_ENVS" value="true" />
|
||||||
<envs>
|
<envs>
|
||||||
|
@ -10,7 +11,6 @@
|
||||||
<option name="IS_MODULE_SDK" value="true" />
|
<option name="IS_MODULE_SDK" value="true" />
|
||||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||||
<module name="{{ cookiecutter.project_slug }}" />
|
|
||||||
<EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
|
<EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
|
||||||
<option name="SCRIPT_NAME" value="merge_production_dotenvs_in_dotenv.py" />
|
<option name="SCRIPT_NAME" value="merge_production_dotenvs_in_dotenv.py" />
|
||||||
<option name="PARAMETERS" value="" />
|
<option name="PARAMETERS" value="" />
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="Docker: migrate" type="Python.DjangoServer" factoryName="Django server" singleton="true">
|
<configuration default="false" name="migrate" type="Python.DjangoServer" factoryName="Django server" singleton="true">
|
||||||
|
<module name="{{ cookiecutter.project_slug }}" />
|
||||||
<option name="INTERPRETER_OPTIONS" value="" />
|
<option name="INTERPRETER_OPTIONS" value="" />
|
||||||
<option name="PARENT_ENVS" value="true" />
|
<option name="PARENT_ENVS" value="true" />
|
||||||
<envs>
|
<envs>
|
||||||
<env name="PYTHONUNBUFFERED" value="1" />
|
<env name="PYTHONUNBUFFERED" value="1" />
|
||||||
<env name="DJANGO_SETTINGS_MODULE" value="config.settings.local" />
|
<env name="DJANGO_SETTINGS_MODULE" value="config.settings.local" />
|
||||||
</envs>
|
</envs>
|
||||||
<option name="SDK_HOME" value="docker-compose://[$PROJECT_DIR$/local.yml]:django/python" />
|
<option name="SDK_HOME" value="" />
|
||||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||||
<option name="IS_MODULE_SDK" value="false" />
|
<option name="IS_MODULE_SDK" value="true" />
|
||||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||||
<module name="{{ cookiecutter.project_slug }}" />
|
|
||||||
<PathMappingSettings>
|
<PathMappingSettings>
|
||||||
<option name="pathMappings">
|
<option name="pathMappings">
|
||||||
<list>
|
<list>
|
|
@ -0,0 +1,25 @@
|
||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="pytest: ." type="tests" factoryName="py.test" singleton="true">
|
||||||
|
<module name="{{ cookiecutter.project_slug }}" />
|
||||||
|
<option name="INTERPRETER_OPTIONS" value="" />
|
||||||
|
<option name="PARENT_ENVS" value="true" />
|
||||||
|
<option name="SDK_HOME" value="" />
|
||||||
|
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||||
|
<option name="IS_MODULE_SDK" value="true" />
|
||||||
|
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||||
|
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||||
|
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
|
||||||
|
<PathMappingSettings>
|
||||||
|
<option name="pathMappings">
|
||||||
|
<list>
|
||||||
|
<mapping local-root="$PROJECT_DIR$" remote-root="/app" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</PathMappingSettings>
|
||||||
|
<option name="_new_keywords" value="""" />
|
||||||
|
<option name="_new_additionalArguments" value="""" />
|
||||||
|
<option name="_new_target" value=""."" />
|
||||||
|
<option name="_new_targetType" value=""PATH"" />
|
||||||
|
<method />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
|
@ -0,0 +1,25 @@
|
||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="pytest: users" type="tests" factoryName="py.test" singleton="true">
|
||||||
|
<module name="{{ cookiecutter.project_slug }}" />
|
||||||
|
<option name="INTERPRETER_OPTIONS" value="" />
|
||||||
|
<option name="PARENT_ENVS" value="true" />
|
||||||
|
<option name="SDK_HOME" value="" />
|
||||||
|
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||||
|
<option name="IS_MODULE_SDK" value="true" />
|
||||||
|
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||||
|
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||||
|
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
|
||||||
|
<PathMappingSettings>
|
||||||
|
<option name="pathMappings">
|
||||||
|
<list>
|
||||||
|
<mapping local-root="$PROJECT_DIR$" remote-root="/app" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</PathMappingSettings>
|
||||||
|
<option name="_new_keywords" value="""" />
|
||||||
|
<option name="_new_additionalArguments" value="""" />
|
||||||
|
<option name="_new_target" value=""./{{ cookiecutter.project_slug }}/users/"" />
|
||||||
|
<option name="_new_targetType" value=""PATH"" />
|
||||||
|
<method />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
|
@ -0,0 +1,33 @@
|
||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="runserver" type="Python.DjangoServer" factoryName="Django server" singleton="true">
|
||||||
|
<module name="{{ cookiecutter.project_slug }}" />
|
||||||
|
<option name="INTERPRETER_OPTIONS" value="" />
|
||||||
|
<option name="PARENT_ENVS" value="true" />
|
||||||
|
<envs>
|
||||||
|
<env name="PYTHONUNBUFFERED" value="1" />
|
||||||
|
<env name="DJANGO_SETTINGS_MODULE" value="config.settings.local" />
|
||||||
|
</envs>
|
||||||
|
<option name="SDK_HOME" value="" />
|
||||||
|
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||||
|
<option name="IS_MODULE_SDK" value="true" />
|
||||||
|
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||||
|
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||||
|
<PathMappingSettings>
|
||||||
|
<option name="pathMappings">
|
||||||
|
<list>
|
||||||
|
<mapping local-root="$PROJECT_DIR$" remote-root="/app" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</PathMappingSettings>
|
||||||
|
<option name="launchJavascriptDebuger" value="false" />
|
||||||
|
<option name="port" value="8000" />
|
||||||
|
<option name="host" value="0.0.0.0" />
|
||||||
|
<option name="additionalOptions" value="" />
|
||||||
|
<option name="browserUrl" value="" />
|
||||||
|
<option name="runTestServer" value="false" />
|
||||||
|
<option name="runNoReload" value="false" />
|
||||||
|
<option name="useCustomRunCommand" value="false" />
|
||||||
|
<option name="customRunCommand" value="" />
|
||||||
|
<method />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
|
@ -1,17 +1,17 @@
|
||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="Docker: runserver_plus" type="Python.DjangoServer" factoryName="Django server" singleton="true">
|
<configuration default="false" name="runserver_plus" type="Python.DjangoServer" factoryName="Django server" singleton="true">
|
||||||
|
<module name="{{ cookiecutter.project_slug }}" />
|
||||||
<option name="INTERPRETER_OPTIONS" value="" />
|
<option name="INTERPRETER_OPTIONS" value="" />
|
||||||
<option name="PARENT_ENVS" value="true" />
|
<option name="PARENT_ENVS" value="true" />
|
||||||
<envs>
|
<envs>
|
||||||
<env name="PYTHONUNBUFFERED" value="1" />
|
<env name="PYTHONUNBUFFERED" value="1" />
|
||||||
<env name="DJANGO_SETTINGS_MODULE" value="config.settings.local" />
|
<env name="DJANGO_SETTINGS_MODULE" value="config.settings.local" />
|
||||||
</envs>
|
</envs>
|
||||||
<option name="SDK_HOME" value="docker-compose://[$PROJECT_DIR$/local.yml]:django/python" />
|
<option name="SDK_HOME" value="" />
|
||||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||||
<option name="IS_MODULE_SDK" value="false" />
|
<option name="IS_MODULE_SDK" value="true" />
|
||||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||||
<module name="{{ cookiecutter.project_slug }}" />
|
|
||||||
<PathMappingSettings>
|
<PathMappingSettings>
|
||||||
<option name="pathMappings">
|
<option name="pathMappings">
|
||||||
<list>
|
<list>
|
|
@ -3,4 +3,4 @@
|
||||||
<component name="VcsDirectoryMappings">
|
<component name="VcsDirectoryMappings">
|
||||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
|
|
|
@ -5,19 +5,32 @@
|
||||||
<configuration>
|
<configuration>
|
||||||
<option name="rootFolder" value="$MODULE_DIR$" />
|
<option name="rootFolder" value="$MODULE_DIR$" />
|
||||||
<option name="settingsModule" value="config/settings/local.py" />
|
<option name="settingsModule" value="config/settings/local.py" />
|
||||||
<option name="manageScript" value="manage.py" />
|
<option name="manageScript" value="$MODULE_DIR$/manage.py" />
|
||||||
<option name="environment" value="<map/>" />
|
<option name="environment" value="<map/>" />
|
||||||
|
<option name="doNotUseTestRunner" value="false" />
|
||||||
|
<option name="trackFilePattern" value="migrations" />
|
||||||
</configuration>
|
</configuration>
|
||||||
</facet>
|
</facet>
|
||||||
</component>
|
</component>
|
||||||
<component name="NewModuleRootManager">
|
<component name="NewModuleRootManager">
|
||||||
<content url="file://$MODULE_DIR$">
|
{% if cookiecutter.js_task_runner != 'None' %}
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
<excludeFolder url="file://$MODULE_DIR$/node_modules" />
|
<excludeFolder url="file://$MODULE_DIR$/node_modules" />
|
||||||
</content>
|
</content>
|
||||||
|
{% else %}
|
||||||
|
<content url="file://$MODULE_DIR$" />
|
||||||
|
{% endif %}
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
</component>
|
</component>
|
||||||
<component name="PackageRequirementsSettings">
|
<component name="PackageRequirementsSettings">
|
||||||
<option name="requirementsPath" value="$MODULE_DIR$/requirements/local.txt" />
|
<option name="requirementsPath" value="$MODULE_DIR$/requirements/local.txt" />
|
||||||
|
</component>
|
||||||
|
<component name="PyDocumentationSettings">
|
||||||
|
<option name="renderExternalDocumentation" value="true" />
|
||||||
|
</component>
|
||||||
|
<component name="ReSTService">
|
||||||
|
<option name="workdir" value="$MODULE_DIR$/docs" />
|
||||||
|
<option name="DOC_DIR" value="$MODULE_DIR$/docs" />
|
||||||
</component>
|
</component>
|
||||||
<component name="TemplatesService">
|
<component name="TemplatesService">
|
||||||
<option name="TEMPLATE_CONFIGURATION" value="Django" />
|
<option name="TEMPLATE_CONFIGURATION" value="Django" />
|
||||||
|
@ -31,4 +44,4 @@
|
||||||
<option name="projectConfiguration" value="py.test" />
|
<option name="projectConfiguration" value="py.test" />
|
||||||
<option name="PROJECT_TEST_RUNNER" value="py.test" />
|
<option name="PROJECT_TEST_RUNNER" value="py.test" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
||||||
|
|
|
@ -9,7 +9,7 @@ RUN apk update \
|
||||||
# Pillow dependencies
|
# Pillow dependencies
|
||||||
&& apk add jpeg-dev zlib-dev freetype-dev lcms2-dev openjpeg-dev tiff-dev tk-dev tcl-dev \
|
&& apk add jpeg-dev zlib-dev freetype-dev lcms2-dev openjpeg-dev tiff-dev tk-dev tcl-dev \
|
||||||
# CFFI dependencies
|
# CFFI dependencies
|
||||||
&& apk add libffi-dev openssl-dev py-cffi \
|
&& apk add libffi-dev py-cffi \
|
||||||
# Translations dependencies
|
# Translations dependencies
|
||||||
&& apk add gettext \
|
&& apk add gettext \
|
||||||
# https://docs.djangoproject.com/en/dev/ref/django-admin/#dbshell
|
# https://docs.djangoproject.com/en/dev/ref/django-admin/#dbshell
|
||||||
|
@ -19,22 +19,26 @@ RUN apk update \
|
||||||
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.sh /entrypoint.sh
|
COPY ./compose/production/django/entrypoint /entrypoint
|
||||||
RUN sed -i 's/\r//' /entrypoint.sh
|
RUN sed -i 's/\r//' /entrypoint
|
||||||
RUN chmod +x /entrypoint.sh
|
RUN chmod +x /entrypoint
|
||||||
|
|
||||||
COPY ./compose/local/django/start.sh /start.sh
|
COPY ./compose/local/django/start /start
|
||||||
RUN sed -i 's/\r//' /start.sh
|
RUN sed -i 's/\r//' /start
|
||||||
RUN chmod +x /start.sh
|
RUN chmod +x /start
|
||||||
{% if cookiecutter.use_celery == "y" %}
|
{% if cookiecutter.use_celery == "y" %}
|
||||||
COPY ./compose/local/django/celery/worker/start.sh /start-celeryworker.sh
|
COPY ./compose/local/django/celery/worker/start /start-celeryworker
|
||||||
RUN sed -i 's/\r//' /start-celeryworker.sh
|
RUN sed -i 's/\r//' /start-celeryworker
|
||||||
RUN chmod +x /start-celeryworker.sh
|
RUN chmod +x /start-celeryworker
|
||||||
|
|
||||||
COPY ./compose/local/django/celery/beat/start.sh /start-celerybeat.sh
|
COPY ./compose/local/django/celery/beat/start /start-celerybeat
|
||||||
RUN sed -i 's/\r//' /start-celerybeat.sh
|
RUN sed -i 's/\r//' /start-celerybeat
|
||||||
RUN chmod +x /start-celerybeat.sh
|
RUN chmod +x /start-celerybeat
|
||||||
|
|
||||||
|
COPY ./compose/local/django/celery/flower/start /start-flower
|
||||||
|
RUN sed -i 's/\r//' /start-flower
|
||||||
|
RUN chmod +x /start-flower
|
||||||
{% endif %}
|
{% endif %}
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
ENTRYPOINT ["/entrypoint.sh"]
|
ENTRYPOINT ["/entrypoint"]
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
set -o errexit
|
set -o errexit
|
||||||
set -o pipefail
|
|
||||||
set -o nounset
|
set -o nounset
|
||||||
set -o xtrace
|
|
||||||
|
|
||||||
|
|
||||||
rm -f './celerybeat.pid'
|
rm -f './celerybeat.pid'
|
|
@ -0,0 +1,10 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -o errexit
|
||||||
|
set -o nounset
|
||||||
|
|
||||||
|
|
||||||
|
celery flower \
|
||||||
|
--app={{cookiecutter.project_slug}}.taskapp \
|
||||||
|
--broker="${CELERY_BROKER_URL}" \
|
||||||
|
--basic_auth="${CELERY_FLOWER_USER}:${CELERY_FLOWER_PASSWORD}"
|
|
@ -1,9 +1,7 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
set -o errexit
|
set -o errexit
|
||||||
set -o pipefail
|
|
||||||
set -o nounset
|
set -o nounset
|
||||||
set -o xtrace
|
|
||||||
|
|
||||||
|
|
||||||
celery -A {{cookiecutter.project_slug}}.taskapp worker -l INFO
|
celery -A {{cookiecutter.project_slug}}.taskapp worker -l INFO
|
|
@ -3,7 +3,6 @@
|
||||||
set -o errexit
|
set -o errexit
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
set -o nounset
|
set -o nounset
|
||||||
set -o xtrace
|
|
||||||
|
|
||||||
|
|
||||||
python manage.py migrate
|
python manage.py migrate
|
|
@ -9,7 +9,7 @@ RUN apk update \
|
||||||
# Pillow dependencies
|
# Pillow dependencies
|
||||||
&& apk add jpeg-dev zlib-dev freetype-dev lcms2-dev openjpeg-dev tiff-dev tk-dev tcl-dev \
|
&& apk add jpeg-dev zlib-dev freetype-dev lcms2-dev openjpeg-dev tiff-dev tk-dev tcl-dev \
|
||||||
# CFFI dependencies
|
# CFFI dependencies
|
||||||
&& apk add libffi-dev openssl-dev py-cffi
|
&& apk add libffi-dev py-cffi
|
||||||
|
|
||||||
RUN addgroup -S django \
|
RUN addgroup -S django \
|
||||||
&& adduser -S -G django django
|
&& adduser -S -G django django
|
||||||
|
@ -19,23 +19,29 @@ COPY ./requirements /requirements
|
||||||
RUN pip install --no-cache-dir -r /requirements/production.txt \
|
RUN pip install --no-cache-dir -r /requirements/production.txt \
|
||||||
&& rm -rf /requirements
|
&& rm -rf /requirements
|
||||||
|
|
||||||
COPY ./compose/production/django/gunicorn.sh /gunicorn.sh
|
COPY ./compose/production/django/entrypoint /entrypoint
|
||||||
RUN sed -i 's/\r//' /gunicorn.sh
|
RUN sed -i 's/\r//' /entrypoint
|
||||||
RUN chmod +x /gunicorn.sh
|
RUN chmod +x /entrypoint
|
||||||
RUN chown django /gunicorn.sh
|
RUN chown django /entrypoint
|
||||||
|
|
||||||
COPY ./compose/production/django/entrypoint.sh /entrypoint.sh
|
COPY ./compose/production/django/start /start
|
||||||
RUN sed -i 's/\r//' /entrypoint.sh
|
RUN sed -i 's/\r//' /start
|
||||||
RUN chmod +x /entrypoint.sh
|
RUN chmod +x /start
|
||||||
RUN chown django /entrypoint.sh
|
RUN chown django /start
|
||||||
{% if cookiecutter.use_celery == "y" %}
|
{% if cookiecutter.use_celery == "y" %}
|
||||||
COPY ./compose/production/django/celery/worker/start.sh /start-celeryworker.sh
|
COPY ./compose/production/django/celery/worker/start /start-celeryworker
|
||||||
RUN sed -i 's/\r//' /start-celeryworker.sh
|
RUN sed -i 's/\r//' /start-celeryworker
|
||||||
RUN chmod +x /start-celeryworker.sh
|
RUN chmod +x /start-celeryworker
|
||||||
|
RUN chown django /start-celeryworker
|
||||||
|
|
||||||
COPY ./compose/production/django/celery/beat/start.sh /start-celerybeat.sh
|
COPY ./compose/production/django/celery/beat/start /start-celerybeat
|
||||||
RUN sed -i 's/\r//' /start-celerybeat.sh
|
RUN sed -i 's/\r//' /start-celerybeat
|
||||||
RUN chmod +x /start-celerybeat.sh
|
RUN chmod +x /start-celerybeat
|
||||||
|
RUN chown django /start-celerybeat
|
||||||
|
|
||||||
|
COPY ./compose/production/django/celery/flower/start /start-flower
|
||||||
|
RUN sed -i 's/\r//' /start-flower
|
||||||
|
RUN chmod +x /start-flower
|
||||||
{% endif %}
|
{% endif %}
|
||||||
COPY . /app
|
COPY . /app
|
||||||
|
|
||||||
|
@ -45,4 +51,4 @@ USER django
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
ENTRYPOINT ["/entrypoint.sh"]
|
ENTRYPOINT ["/entrypoint"]
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -o errexit
|
||||||
|
set -o nounset
|
||||||
|
|
||||||
|
|
||||||
|
celery flower \
|
||||||
|
--app={{cookiecutter.project_slug}}.taskapp \
|
||||||
|
--broker="${CELERY_BROKER_URL}" \
|
||||||
|
--basic_auth="${CELERY_FLOWER_USER}:${CELERY_FLOWER_PASSWORD}"
|
|
@ -5,8 +5,6 @@ set -o pipefail
|
||||||
set -o nounset
|
set -o nounset
|
||||||
|
|
||||||
|
|
||||||
cmd="$@"
|
|
||||||
|
|
||||||
# N.B. If only .env files supported variable expansion...
|
# N.B. If only .env files supported variable expansion...
|
||||||
export CELERY_BROKER_URL="${REDIS_URL}"
|
export CELERY_BROKER_URL="${REDIS_URL}"
|
||||||
|
|
||||||
|
@ -36,12 +34,10 @@ sys.exit(0)
|
||||||
|
|
||||||
END
|
END
|
||||||
}
|
}
|
||||||
|
|
||||||
until postgres_ready; do
|
until postgres_ready; do
|
||||||
>&2 echo 'PostgreSQL is unavailable (sleeping)...'
|
>&2 echo 'Waiting for PostgreSQL to become available...'
|
||||||
sleep 1
|
sleep 1
|
||||||
done
|
done
|
||||||
|
>&2 echo 'PostgreSQL is available'
|
||||||
|
|
||||||
>&2 echo 'PostgreSQL is up - continuing...'
|
exec "$@"
|
||||||
|
|
||||||
exec $cmd
|
|
|
@ -75,7 +75,7 @@ THIRD_PARTY_APPS = [
|
||||||
'rest_framework',
|
'rest_framework',
|
||||||
]
|
]
|
||||||
LOCAL_APPS = [
|
LOCAL_APPS = [
|
||||||
'{{ cookiecutter.project_slug }}.users.apps.UsersConfig',
|
'{{ cookiecutter.project_slug }}.users.apps.UsersAppConfig',
|
||||||
# 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
|
||||||
|
@ -228,20 +228,26 @@ MANAGERS = ADMINS
|
||||||
{% if cookiecutter.use_celery == 'y' -%}
|
{% if cookiecutter.use_celery == 'y' -%}
|
||||||
# Celery
|
# Celery
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
INSTALLED_APPS += ['{{cookiecutter.project_slug}}.taskapp.celery.CeleryConfig']
|
INSTALLED_APPS += ['{{cookiecutter.project_slug}}.taskapp.celery.CeleryAppConfig']
|
||||||
|
if USE_TZ:
|
||||||
|
# http://docs.celeryproject.org/en/latest/userguide/configuration.html#std:setting-timezone
|
||||||
|
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', default='django://')
|
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
|
||||||
if CELERY_BROKER_URL == 'django://':
|
CELERY_RESULT_BACKEND = CELERY_BROKER_URL
|
||||||
CELERY_RESULT_BACKEND = 'redis://'
|
|
||||||
else:
|
|
||||||
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
|
||||||
|
# TODO: set to whatever value is adequate in your circumstances
|
||||||
|
CELERYD_TASK_TIME_LIMIT = 5 * 60
|
||||||
|
# http://docs.celeryproject.org/en/latest/userguide/configuration.html#task-soft-time-limit
|
||||||
|
# TODO: set to whatever value is adequate in your circumstances
|
||||||
|
CELERYD_TASK_SOFT_TIME_LIMIT = 60
|
||||||
|
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
# django-allauth
|
# django-allauth
|
||||||
|
|
|
@ -76,8 +76,10 @@ INSTALLED_APPS += ['django_extensions'] # noqa F405
|
||||||
|
|
||||||
# Celery
|
# Celery
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# http://docs.celeryproject.org/en/latest/userguide/configuration.html#std:setting-task_always_eager
|
# http://docs.celeryproject.org/en/latest/userguide/configuration.html#task-always-eager
|
||||||
CELERY_ALWAYS_EAGER = True
|
CELERY_TASK_ALWAYS_EAGER = True
|
||||||
|
# http://docs.celeryproject.org/en/latest/userguide/configuration.html#task-eager-propagates
|
||||||
|
CELERY_TASK_EAGER_PROPAGATES = True
|
||||||
|
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
# Your stuff...
|
# Your stuff...
|
||||||
|
|
|
@ -73,8 +73,6 @@ AWS_SECRET_ACCESS_KEY = env('DJANGO_AWS_SECRET_ACCESS_KEY')
|
||||||
# https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#settings
|
# https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#settings
|
||||||
AWS_STORAGE_BUCKET_NAME = env('DJANGO_AWS_STORAGE_BUCKET_NAME')
|
AWS_STORAGE_BUCKET_NAME = env('DJANGO_AWS_STORAGE_BUCKET_NAME')
|
||||||
# https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#settings
|
# https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#settings
|
||||||
AWS_AUTO_CREATE_BUCKET = True
|
|
||||||
# https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#settings
|
|
||||||
AWS_QUERYSTRING_AUTH = False
|
AWS_QUERYSTRING_AUTH = False
|
||||||
# DO NOT change these unless you know what you're doing.
|
# DO NOT change these unless you know what you're doing.
|
||||||
_AWS_EXPIRY = 60 * 60 * 24 * 7
|
_AWS_EXPIRY = 60 * 60 * 24 * 7
|
||||||
|
@ -99,7 +97,7 @@ DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
|
||||||
MEDIA_URL = f'https://s3.amazonaws.com/{AWS_STORAGE_BUCKET_NAME}/'
|
MEDIA_URL = f'https://s3.amazonaws.com/{AWS_STORAGE_BUCKET_NAME}/'
|
||||||
{%- else %}
|
{%- else %}
|
||||||
# region http://stackoverflow.com/questions/10390244/
|
# region http://stackoverflow.com/questions/10390244/
|
||||||
from storages.backends.s3boto3 import S3Boto3Storage
|
from storages.backends.s3boto3 import S3Boto3Storage # noqa E402
|
||||||
StaticRootS3BotoStorage = lambda: S3Boto3Storage(location='static') # noqa
|
StaticRootS3BotoStorage = lambda: S3Boto3Storage(location='static') # noqa
|
||||||
MediaRootS3BotoStorage = lambda: S3Boto3Storage(location='media', file_overwrite=False) # noqa
|
MediaRootS3BotoStorage = lambda: S3Boto3Storage(location='media', file_overwrite=False) # noqa
|
||||||
# endregion
|
# endregion
|
||||||
|
@ -158,8 +156,8 @@ INSTALLED_APPS += ['gunicorn'] # noqa F405
|
||||||
# http://whitenoise.evans.io/en/latest/django.html#enable-whitenoise
|
# http://whitenoise.evans.io/en/latest/django.html#enable-whitenoise
|
||||||
MIDDLEWARE = ['whitenoise.middleware.WhiteNoiseMiddleware'] + MIDDLEWARE # noqa F405
|
MIDDLEWARE = ['whitenoise.middleware.WhiteNoiseMiddleware'] + MIDDLEWARE # noqa F405
|
||||||
|
|
||||||
{%- endif %}
|
{% endif %}
|
||||||
{% if cookiecutter.use_compressor == 'y' -%}
|
{%- 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
|
||||||
|
@ -169,16 +167,16 @@ 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
|
||||||
|
|
||||||
{%- 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
|
AWS_PRELOAD_METADATA = True
|
||||||
|
|
||||||
{%- endif %}
|
{% endif %}
|
||||||
{% if cookiecutter.use_sentry == 'y' -%}
|
{%- if cookiecutter.use_sentry == 'y' -%}
|
||||||
# raven
|
# raven
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# https://docs.sentry.io/clients/python/integrations/django/
|
# https://docs.sentry.io/clients/python/integrations/django/
|
||||||
|
@ -187,7 +185,7 @@ MIDDLEWARE = ['raven.contrib.django.raven_compat.middleware.SentryResponseErrorI
|
||||||
|
|
||||||
# Sentry
|
# Sentry
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
SENTRY_DSN = env('DJANGO_SENTRY_DSN')
|
SENTRY_DSN = env('SENTRY_DSN')
|
||||||
SENTRY_CLIENT = env('DJANGO_SENTRY_CLIENT', default='raven.contrib.django.raven_compat.DjangoClient')
|
SENTRY_CLIENT = env('DJANGO_SENTRY_CLIENT', default='raven.contrib.django.raven_compat.DjangoClient')
|
||||||
LOGGING = {
|
LOGGING = {
|
||||||
'version': 1,
|
'version': 1,
|
||||||
|
@ -241,6 +239,7 @@ SENTRY_CELERY_LOGLEVEL = env.int('DJANGO_SENTRY_LOG_LEVEL', logging.INFO)
|
||||||
RAVEN_CONFIG = {
|
RAVEN_CONFIG = {
|
||||||
'dsn': SENTRY_DSN
|
'dsn': SENTRY_DSN
|
||||||
}
|
}
|
||||||
|
|
||||||
{%- else %}
|
{%- else %}
|
||||||
# LOGGING
|
# LOGGING
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
@ -290,6 +289,6 @@ LOGGING = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{%- endif %}
|
{% endif %}
|
||||||
# Your stuff...
|
# Your stuff...
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
|
@ -23,12 +23,10 @@ from django.core.wsgi import get_wsgi_application
|
||||||
app_path = os.path.abspath(os.path.join(
|
app_path = os.path.abspath(os.path.join(
|
||||||
os.path.dirname(os.path.abspath(__file__)), os.pardir))
|
os.path.dirname(os.path.abspath(__file__)), os.pardir))
|
||||||
sys.path.append(os.path.join(app_path, '{{ cookiecutter.project_slug }}'))
|
sys.path.append(os.path.join(app_path, '{{ cookiecutter.project_slug }}'))
|
||||||
|
|
||||||
{% if cookiecutter.use_sentry == 'y' -%}
|
{% if cookiecutter.use_sentry == 'y' -%}
|
||||||
if os.environ.get('DJANGO_SETTINGS_MODULE') == 'config.settings.production':
|
if os.environ.get('DJANGO_SETTINGS_MODULE') == 'config.settings.production':
|
||||||
from raven.contrib.django.raven_compat.middleware.wsgi import Sentry
|
from raven.contrib.django.raven_compat.middleware.wsgi import Sentry
|
||||||
{%- endif %}
|
{%- 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
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
version: '2'
|
version: '3'
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
postgres_data_local: {}
|
local_postgres_data: {}
|
||||||
postgres_backup_local: {}
|
local_postgres_data_backups: {}
|
||||||
|
|
||||||
services:
|
services:
|
||||||
django:{% if cookiecutter.use_celery == 'y' %} &django{% endif %}
|
django:{% if cookiecutter.use_celery == 'y' %} &django{% endif %}
|
||||||
|
@ -22,7 +22,7 @@ services:
|
||||||
- ./.envs/.local/.postgres
|
- ./.envs/.local/.postgres
|
||||||
ports:
|
ports:
|
||||||
- "8000:8000"
|
- "8000:8000"
|
||||||
command: /start.sh
|
command: /start
|
||||||
|
|
||||||
postgres:
|
postgres:
|
||||||
build:
|
build:
|
||||||
|
@ -30,8 +30,8 @@ services:
|
||||||
dockerfile: ./compose/production/postgres/Dockerfile
|
dockerfile: ./compose/production/postgres/Dockerfile
|
||||||
image: {{ cookiecutter.project_slug }}_production_postgres
|
image: {{ cookiecutter.project_slug }}_production_postgres
|
||||||
volumes:
|
volumes:
|
||||||
- postgres_data_local:/var/lib/postgresql/data
|
- local_postgres_data:/var/lib/postgresql/data
|
||||||
- postgres_backup_local:/backups
|
- local_postgres_data_backups:/backups
|
||||||
env_file:
|
env_file:
|
||||||
- ./.envs/.local/.postgres
|
- ./.envs/.local/.postgres
|
||||||
{%- if cookiecutter.use_mailhog == 'y' %}
|
{%- if cookiecutter.use_mailhog == 'y' %}
|
||||||
|
@ -56,11 +56,8 @@ services:
|
||||||
{% if cookiecutter.use_mailhog == 'y' -%}
|
{% if cookiecutter.use_mailhog == 'y' -%}
|
||||||
- mailhog
|
- mailhog
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
env_file:
|
|
||||||
- ./.envs/.local/.django
|
|
||||||
- ./.envs/.local/.postgres
|
|
||||||
ports: []
|
ports: []
|
||||||
command: /start-celeryworker.sh
|
command: /start-celeryworker
|
||||||
|
|
||||||
celerybeat:
|
celerybeat:
|
||||||
<<: *django
|
<<: *django
|
||||||
|
@ -71,10 +68,14 @@ services:
|
||||||
{% if cookiecutter.use_mailhog == 'y' -%}
|
{% if cookiecutter.use_mailhog == 'y' -%}
|
||||||
- mailhog
|
- mailhog
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
env_file:
|
|
||||||
- ./.envs/.local/.django
|
|
||||||
- ./.envs/.local/.postgres
|
|
||||||
ports: []
|
ports: []
|
||||||
command: /start-celerybeat.sh
|
command: /start-celerybeat
|
||||||
|
|
||||||
|
flower:
|
||||||
|
<<: *django
|
||||||
|
image: {{ cookiecutter.project_slug }}_local_flower
|
||||||
|
ports:
|
||||||
|
- "5555:5555"
|
||||||
|
command: /start-flower
|
||||||
|
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
version: '2'
|
version: '3'
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
postgres_data: {}
|
production_postgres_data: {}
|
||||||
postgres_backup: {}
|
production_postgres_data_backups: {}
|
||||||
traefik_acme: {}
|
production_traefik: {}
|
||||||
|
|
||||||
services:
|
services:
|
||||||
django:{% if cookiecutter.use_celery == 'y' %} &django{% endif %}
|
django:{% if cookiecutter.use_celery == 'y' %} &django{% endif %}
|
||||||
|
@ -17,7 +17,7 @@ services:
|
||||||
env_file:
|
env_file:
|
||||||
- ./.envs/.production/.django
|
- ./.envs/.production/.django
|
||||||
- ./.envs/.production/.postgres
|
- ./.envs/.production/.postgres
|
||||||
command: /gunicorn.sh
|
command: /start
|
||||||
labels:
|
labels:
|
||||||
- "traefik.enable=true"
|
- "traefik.enable=true"
|
||||||
- "traefik.backend=django"
|
- "traefik.backend=django"
|
||||||
|
@ -30,8 +30,8 @@ services:
|
||||||
dockerfile: ./compose/production/postgres/Dockerfile
|
dockerfile: ./compose/production/postgres/Dockerfile
|
||||||
image: {{ cookiecutter.project_slug }}_production_postgres
|
image: {{ cookiecutter.project_slug }}_production_postgres
|
||||||
volumes:
|
volumes:
|
||||||
- postgres_data:/var/lib/postgresql/data
|
- production_postgres_data:/var/lib/postgresql/data
|
||||||
- postgres_backup:/backups
|
- production_postgres_data_backups:/backups
|
||||||
env_file:
|
env_file:
|
||||||
- ./.envs/.production/.postgres
|
- ./.envs/.production/.postgres
|
||||||
|
|
||||||
|
@ -44,11 +44,11 @@ services:
|
||||||
- django
|
- django
|
||||||
volumes:
|
volumes:
|
||||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
- traefik_acme:/etc/traefik/acme
|
- production_traefik:/etc/traefik/acme
|
||||||
ports:
|
ports:
|
||||||
- "80:80"
|
- "0.0.0.0:80:80"
|
||||||
- "443:443"
|
- "0.0.0.0:443:443"
|
||||||
- "8080:8080"
|
- "0.0.0.0:8080:8080"
|
||||||
|
|
||||||
redis:
|
redis:
|
||||||
image: redis:3.2
|
image: redis:3.2
|
||||||
|
@ -57,26 +57,23 @@ services:
|
||||||
celeryworker:
|
celeryworker:
|
||||||
<<: *django
|
<<: *django
|
||||||
image: {{ cookiecutter.project_slug }}_production_celeryworker
|
image: {{ cookiecutter.project_slug }}_production_celeryworker
|
||||||
depends_on:
|
command: /start-celeryworker
|
||||||
- postgres
|
|
||||||
- redis
|
|
||||||
env_file:
|
|
||||||
- ./.envs/.production/.django
|
|
||||||
- ./.envs/.production/.postgres
|
|
||||||
command: /start-celeryworker.sh
|
|
||||||
labels:
|
labels:
|
||||||
- "traefik.enable=false"
|
- "traefik.enable=false"
|
||||||
|
|
||||||
celerybeat:
|
celerybeat:
|
||||||
<<: *django
|
<<: *django
|
||||||
image: {{ cookiecutter.project_slug }}_production_celerybeat
|
image: {{ cookiecutter.project_slug }}_production_celerybeat
|
||||||
depends_on:
|
command: /start-celerybeat
|
||||||
- postgres
|
labels:
|
||||||
- redis
|
- "traefik.enable=false"
|
||||||
env_file:
|
|
||||||
- ./.envs/.production/.django
|
flower:
|
||||||
- ./.envs/.production/.postgres
|
<<: *django
|
||||||
command: /start-celerybeat.sh
|
image: {{ cookiecutter.project_slug }}_production_flower
|
||||||
|
ports:
|
||||||
|
- "5555:5555"
|
||||||
|
command: /start-flower
|
||||||
labels:
|
labels:
|
||||||
- "traefik.enable=false"
|
- "traefik.enable=false"
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
pytz==2018.4 # https://github.com/stub42/pytz
|
pytz==2018.5 # https://github.com/stub42/pytz
|
||||||
python-slugify==1.2.5 # https://github.com/un33k/python-slugify
|
python-slugify==1.2.5 # https://github.com/un33k/python-slugify
|
||||||
Pillow==5.1.0 # https://github.com/python-pillow/Pillow
|
Pillow==5.2.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' %} --install-option="--without-c-extensions"{% endif %} # https://github.com/ndparker/rcssmin
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
@ -10,13 +10,16 @@ whitenoise==3.3.1 # https://github.com/evansd/whitenoise
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
redis>=2.10.5 # https://github.com/antirez/redis
|
redis>=2.10.5 # https://github.com/antirez/redis
|
||||||
{%- if cookiecutter.use_celery == "y" %}
|
{%- if cookiecutter.use_celery == "y" %}
|
||||||
celery==3.1.25 # pyup: <4.0 # https://github.com/celery/celery
|
celery==4.2.0 # pyup: <5.0 # https://github.com/celery/celery
|
||||||
|
{%- if cookiecutter.use_docker == 'y' %}
|
||||||
|
flower==0.9.2 # https://github.com/mher/flower
|
||||||
|
{%- endif %}
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
||||||
# Django
|
# Django
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
django==2.0.5 # pyup: < 2.1 # https://www.djangoproject.com/
|
django==2.0.7 # pyup: < 2.1 # https://www.djangoproject.com/
|
||||||
django-environ==0.4.4 # https://github.com/joke2k/django-environ
|
django-environ==0.4.5 # https://github.com/joke2k/django-environ
|
||||||
django-model-utils==3.1.2 # https://github.com/jazzband/django-model-utils
|
django-model-utils==3.1.2 # https://github.com/jazzband/django-model-utils
|
||||||
django-allauth==0.36.0 # https://github.com/pennersr/django-allauth
|
django-allauth==0.36.0 # https://github.com/pennersr/django-allauth
|
||||||
django-crispy-forms==1.7.2 # https://github.com/django-crispy-forms/django-crispy-forms
|
django-crispy-forms==1.7.2 # https://github.com/django-crispy-forms/django-crispy-forms
|
||||||
|
|
|
@ -2,16 +2,16 @@
|
||||||
|
|
||||||
Werkzeug==0.14.1 # https://github.com/pallets/werkzeug
|
Werkzeug==0.14.1 # https://github.com/pallets/werkzeug
|
||||||
ipdb==0.11 # https://github.com/gotcha/ipdb
|
ipdb==0.11 # https://github.com/gotcha/ipdb
|
||||||
Sphinx==1.7.4 # https://github.com/sphinx-doc/sphinx
|
Sphinx==1.7.5 # https://github.com/sphinx-doc/sphinx
|
||||||
{%- if cookiecutter.use_docker == 'y' %}
|
{%- if cookiecutter.use_docker == 'y' %}
|
||||||
psycopg2==2.7.4 --no-binary psycopg2 # https://github.com/psycopg/psycopg2
|
psycopg2==2.7.4 --no-binary psycopg2 # https://github.com/psycopg/psycopg2
|
||||||
{%- else %}
|
{%- else %}
|
||||||
psycopg2-binary==2.7.4 # https://github.com/psycopg/psycopg2
|
psycopg2-binary==2.7.5 # https://github.com/psycopg/psycopg2
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
||||||
# Testing
|
# Testing
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
pytest==3.5.1 # https://github.com/pytest-dev/pytest
|
pytest==3.6.3 # https://github.com/pytest-dev/pytest
|
||||||
pytest-sugar==0.9.1 # https://github.com/Frozenball/pytest-sugar
|
pytest-sugar==0.9.1 # https://github.com/Frozenball/pytest-sugar
|
||||||
|
|
||||||
# Code quality
|
# Code quality
|
||||||
|
@ -22,9 +22,8 @@ coverage==4.5.1 # https://github.com/nedbat/coveragepy
|
||||||
# Django
|
# Django
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
factory-boy==2.11.1 # https://github.com/FactoryBoy/factory_boy
|
factory-boy==2.11.1 # https://github.com/FactoryBoy/factory_boy
|
||||||
django-test-plus==1.0.22 # https://github.com/revsys/django-test-plus
|
|
||||||
|
|
||||||
django-debug-toolbar==1.9.1 # https://github.com/jazzband/django-debug-toolbar
|
django-debug-toolbar==1.9.1 # https://github.com/jazzband/django-debug-toolbar
|
||||||
django-extensions==2.0.7 # https://github.com/django-extensions/django-extensions
|
django-extensions==2.0.7 # https://github.com/django-extensions/django-extensions
|
||||||
django-coverage-plugin==1.5.0 # https://github.com/nedbat/django_coverage_plugin
|
django-coverage-plugin==1.5.0 # https://github.com/nedbat/django_coverage_plugin
|
||||||
pytest-django==3.2.1 # https://github.com/pytest-dev/pytest-django
|
pytest-django==3.3.2 # https://github.com/pytest-dev/pytest-django
|
||||||
|
|
|
@ -8,10 +8,10 @@ psycopg2==2.7.4 --no-binary psycopg2 # https://github.com/psycopg/psycopg2
|
||||||
Collectfast==0.6.2 # https://github.com/antonagestam/collectfast
|
Collectfast==0.6.2 # https://github.com/antonagestam/collectfast
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{%- if cookiecutter.use_sentry == "y" %}
|
{%- if cookiecutter.use_sentry == "y" %}
|
||||||
raven==6.8.0 # https://github.com/getsentry/raven-python
|
raven==6.9.0 # https://github.com/getsentry/raven-python
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
||||||
# Django
|
# Django
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
django-storages[boto3]==1.6.6 # https://github.com/jschneier/django-storages
|
django-storages[boto3]==1.6.6 # https://github.com/jschneier/django-storages
|
||||||
django-anymail==2.2 # https://github.com/anymail/django-anymail
|
django-anymail[mailgun]==3.0 # https://github.com/anymail/django-anymail
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
import pytest
|
||||||
|
from django.conf import settings
|
||||||
|
from django.test import RequestFactory
|
||||||
|
|
||||||
|
from {{ cookiecutter.project_slug }}.users.tests.factories import UserFactory
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def media_storage(settings, tmpdir):
|
||||||
|
settings.MEDIA_ROOT = tmpdir.strpath
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def user() -> settings.AUTH_USER_MODEL:
|
||||||
|
return UserFactory()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def request_factory() -> RequestFactory:
|
||||||
|
return RequestFactory()
|
|
@ -13,14 +13,16 @@ if not settings.configured:
|
||||||
app = Celery('{{cookiecutter.project_slug}}')
|
app = Celery('{{cookiecutter.project_slug}}')
|
||||||
|
|
||||||
|
|
||||||
class CeleryConfig(AppConfig):
|
class CeleryAppConfig(AppConfig):
|
||||||
name = '{{cookiecutter.project_slug}}.taskapp'
|
name = '{{cookiecutter.project_slug}}.taskapp'
|
||||||
verbose_name = 'Celery Config'
|
verbose_name = 'Celery Config'
|
||||||
|
|
||||||
def ready(self):
|
def ready(self):
|
||||||
# Using a string here means the worker will not have to
|
# Using a string here means the worker will not have to
|
||||||
# pickle the object when using Windows.
|
# pickle the object when using Windows.
|
||||||
app.config_from_object('django.conf:settings')
|
# - namespace='CELERY' means all celery-related configuration keys
|
||||||
|
# should have a `CELERY_` prefix.
|
||||||
|
app.config_from_object('django.conf:settings', namespace='CELERY')
|
||||||
installed_apps = [app_config.name for app_config in apps.get_app_configs()]
|
installed_apps = [app_config.name for app_config in apps.get_app_configs()]
|
||||||
app.autodiscover_tasks(lambda: installed_apps, force=True)
|
app.autodiscover_tasks(lambda: installed_apps, force=True)
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,18 @@
|
||||||
from django.conf import settings
|
from typing import Any
|
||||||
|
|
||||||
from allauth.account.adapter import DefaultAccountAdapter
|
from allauth.account.adapter import DefaultAccountAdapter
|
||||||
from allauth.socialaccount.adapter import DefaultSocialAccountAdapter
|
from allauth.socialaccount.adapter import DefaultSocialAccountAdapter
|
||||||
|
from django.conf import settings
|
||||||
|
from django.http import HttpRequest
|
||||||
|
|
||||||
|
|
||||||
class AccountAdapter(DefaultAccountAdapter):
|
class AccountAdapter(DefaultAccountAdapter):
|
||||||
|
|
||||||
def is_open_for_signup(self, request):
|
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, sociallogin):
|
def is_open_for_signup(self, request: HttpRequest, sociallogin: Any):
|
||||||
return getattr(settings, "ACCOUNT_ALLOW_REGISTRATION", True)
|
return getattr(settings, "ACCOUNT_ALLOW_REGISTRATION", True)
|
||||||
|
|
|
@ -1,39 +1,17 @@
|
||||||
from django import forms
|
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.contrib.auth.admin import UserAdmin as AuthUserAdmin
|
from django.contrib.auth import admin as auth_admin
|
||||||
from django.contrib.auth.forms import UserChangeForm, UserCreationForm
|
from django.contrib.auth import get_user_model
|
||||||
from .models import User
|
|
||||||
|
|
||||||
|
from {{ cookiecutter.project_slug }}.users.forms import UserChangeForm, UserCreationForm
|
||||||
|
|
||||||
class MyUserChangeForm(UserChangeForm):
|
User = get_user_model()
|
||||||
|
|
||||||
class Meta(UserChangeForm.Meta):
|
|
||||||
model = User
|
|
||||||
|
|
||||||
|
|
||||||
class MyUserCreationForm(UserCreationForm):
|
|
||||||
|
|
||||||
error_message = UserCreationForm.error_messages.update(
|
|
||||||
{"duplicate_username": "This username has already been taken."}
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta(UserCreationForm.Meta):
|
|
||||||
model = User
|
|
||||||
|
|
||||||
def clean_username(self):
|
|
||||||
username = self.cleaned_data["username"]
|
|
||||||
try:
|
|
||||||
User.objects.get(username=username)
|
|
||||||
except User.DoesNotExist:
|
|
||||||
return username
|
|
||||||
|
|
||||||
raise forms.ValidationError(self.error_messages["duplicate_username"])
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(User)
|
@admin.register(User)
|
||||||
class MyUserAdmin(AuthUserAdmin):
|
class UserAdmin(auth_admin.UserAdmin):
|
||||||
form = MyUserChangeForm
|
|
||||||
add_form = MyUserCreationForm
|
form = UserChangeForm
|
||||||
fieldsets = (("User Profile", {"fields": ("name",)}),) + AuthUserAdmin.fieldsets
|
add_form = UserCreationForm
|
||||||
list_display = ("username", "name", "is_superuser")
|
fieldsets = (("User", {"fields": ("name",)}),) + auth_admin.UserAdmin.fieldsets
|
||||||
|
list_display = ["username", "name", "is_superuser"]
|
||||||
search_fields = ["name"]
|
search_fields = ["name"]
|
||||||
|
|
|
@ -1,15 +1,12 @@
|
||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
class UsersConfig(AppConfig):
|
class UsersAppConfig(AppConfig):
|
||||||
name = "{{cookiecutter.project_slug}}.users"
|
|
||||||
|
name = "{{ cookiecutter.project_slug }}.users"
|
||||||
verbose_name = "Users"
|
verbose_name = "Users"
|
||||||
|
|
||||||
def ready(self):
|
def ready(self):
|
||||||
"""Override this to put in:
|
|
||||||
Users system checks
|
|
||||||
Users signal registration
|
|
||||||
"""
|
|
||||||
try:
|
try:
|
||||||
import users.signals # noqa F401
|
import users.signals # noqa F401
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
from django.contrib.auth import get_user_model, forms
|
||||||
|
from django.core.exceptions import ValidationError
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
User = get_user_model()
|
||||||
|
|
||||||
|
|
||||||
|
class UserChangeForm(forms.UserChangeForm):
|
||||||
|
|
||||||
|
class Meta(forms.UserChangeForm.Meta):
|
||||||
|
model = User
|
||||||
|
|
||||||
|
|
||||||
|
class UserCreationForm(forms.UserCreationForm):
|
||||||
|
|
||||||
|
error_message = forms.UserCreationForm.error_messages.update(
|
||||||
|
{"duplicate_username": _("This username has already been taken.")}
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta(forms.UserCreationForm.Meta):
|
||||||
|
model = User
|
||||||
|
|
||||||
|
def clean_username(self):
|
||||||
|
username = self.cleaned_data["username"]
|
||||||
|
|
||||||
|
try:
|
||||||
|
User.objects.get(username=username)
|
||||||
|
except User.DoesNotExist:
|
||||||
|
return username
|
||||||
|
|
||||||
|
raise ValidationError(self.error_messages["duplicate_username"])
|
|
@ -1,5 +1,5 @@
|
||||||
from django.contrib.auth.models import AbstractUser
|
from django.contrib.auth.models import AbstractUser
|
||||||
from django.db import models
|
from django.db.models import CharField
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
@ -8,10 +8,7 @@ class User(AbstractUser):
|
||||||
|
|
||||||
# First Name and Last Name do not cover name patterns
|
# First Name and Last Name do not cover name patterns
|
||||||
# around the globe.
|
# around the globe.
|
||||||
name = models.CharField(_("Name of User"), blank=True, max_length=255)
|
name = CharField(_("Name of User"), blank=True, max_length=255)
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.username
|
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse("users:detail", kwargs={"username": self.username})
|
return reverse("users:detail", kwargs={"username": self.username})
|
||||||
|
|
|
@ -1,11 +1,29 @@
|
||||||
import factory
|
from typing import Any, Sequence
|
||||||
|
|
||||||
|
from django.contrib.auth import get_user_model
|
||||||
|
from factory import DjangoModelFactory, Faker, post_generation
|
||||||
|
|
||||||
|
|
||||||
class UserFactory(factory.django.DjangoModelFactory):
|
class UserFactory(DjangoModelFactory):
|
||||||
username = factory.Sequence(lambda n: f"user-{n}")
|
|
||||||
email = factory.Sequence(lambda n: f"user-{n}@example.com")
|
username = Faker("user_name")
|
||||||
password = factory.PostGenerationMethodCall("set_password", "password")
|
email = Faker("email")
|
||||||
|
name = Faker("name")
|
||||||
|
|
||||||
|
@post_generation
|
||||||
|
def password(self, create: bool, extracted: Sequence[Any], **kwargs):
|
||||||
|
password = Faker(
|
||||||
|
"password",
|
||||||
|
length=42,
|
||||||
|
special_chars=True,
|
||||||
|
digits=True,
|
||||||
|
upper_case=True,
|
||||||
|
lower_case=True,
|
||||||
|
).generate(
|
||||||
|
extra_kwargs={}
|
||||||
|
)
|
||||||
|
self.set_password(password)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = "users.User"
|
model = get_user_model()
|
||||||
django_get_or_create = ("username",)
|
django_get_or_create = ["username"]
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
from test_plus.test import TestCase
|
|
||||||
|
|
||||||
from ..admin import MyUserCreationForm
|
|
||||||
|
|
||||||
|
|
||||||
class TestMyUserCreationForm(TestCase):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
self.user = self.make_user("notalamode", "notalamodespassword")
|
|
||||||
|
|
||||||
def test_clean_username_success(self):
|
|
||||||
# Instantiate the form with a new username
|
|
||||||
form = MyUserCreationForm(
|
|
||||||
{
|
|
||||||
"username": "alamode",
|
|
||||||
"password1": "7jefB#f@Cc7YJB]2v",
|
|
||||||
"password2": "7jefB#f@Cc7YJB]2v",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
# Run is_valid() to trigger the validation
|
|
||||||
valid = form.is_valid()
|
|
||||||
self.assertTrue(valid)
|
|
||||||
|
|
||||||
# Run the actual clean_username method
|
|
||||||
username = form.clean_username()
|
|
||||||
self.assertEqual("alamode", username)
|
|
||||||
|
|
||||||
def test_clean_username_false(self):
|
|
||||||
# Instantiate the form with the same username as self.user
|
|
||||||
form = MyUserCreationForm(
|
|
||||||
{
|
|
||||||
"username": self.user.username,
|
|
||||||
"password1": "notalamodespassword",
|
|
||||||
"password2": "notalamodespassword",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
# Run is_valid() to trigger the validation, which is going to fail
|
|
||||||
# because the username is already taken
|
|
||||||
valid = form.is_valid()
|
|
||||||
self.assertFalse(valid)
|
|
||||||
|
|
||||||
# The form.errors dict should contain a single error called 'username'
|
|
||||||
self.assertTrue(len(form.errors) == 1)
|
|
||||||
self.assertTrue("username" in form.errors)
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from {{ cookiecutter.project_slug }}.users.forms import UserCreationForm
|
||||||
|
from {{ cookiecutter.project_slug }}.users.tests.factories import UserFactory
|
||||||
|
|
||||||
|
pytestmark = pytest.mark.django_db
|
||||||
|
|
||||||
|
|
||||||
|
class TestUserCreationForm:
|
||||||
|
|
||||||
|
def test_clean_username(self):
|
||||||
|
# A user with proto_user params does not exist yet.
|
||||||
|
proto_user = UserFactory.build()
|
||||||
|
|
||||||
|
form = UserCreationForm(
|
||||||
|
{
|
||||||
|
"username": proto_user.username,
|
||||||
|
"password1": proto_user._password,
|
||||||
|
"password2": proto_user._password,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert form.is_valid()
|
||||||
|
assert form.clean_username() == proto_user.username
|
||||||
|
|
||||||
|
# Creating a user.
|
||||||
|
form.save()
|
||||||
|
|
||||||
|
# The user with proto_user params already exists,
|
||||||
|
# hence cannot be created.
|
||||||
|
form = UserCreationForm(
|
||||||
|
{
|
||||||
|
"username": proto_user.username,
|
||||||
|
"password1": proto_user._password,
|
||||||
|
"password2": proto_user._password,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert not form.is_valid()
|
||||||
|
assert len(form.errors) == 1
|
||||||
|
assert "username" in form.errors
|
|
@ -1,16 +1,8 @@
|
||||||
from test_plus.test import TestCase
|
import pytest
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
pytestmark = pytest.mark.django_db
|
||||||
|
|
||||||
|
|
||||||
class TestUser(TestCase):
|
def test_user_get_absolute_url(user: settings.AUTH_USER_MODEL):
|
||||||
|
assert user.get_absolute_url() == f"/users/{user.username}/"
|
||||||
def setUp(self):
|
|
||||||
self.user = self.make_user()
|
|
||||||
|
|
||||||
def test__str__(self):
|
|
||||||
self.assertEqual(
|
|
||||||
self.user.__str__(),
|
|
||||||
"testuser", # This is the default username for self.make_user()
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_get_absolute_url(self):
|
|
||||||
self.assertEqual(self.user.get_absolute_url(), "/users/testuser/")
|
|
||||||
|
|
|
@ -1,44 +1,28 @@
|
||||||
|
import pytest
|
||||||
|
from django.conf import settings
|
||||||
from django.urls import reverse, resolve
|
from django.urls import reverse, resolve
|
||||||
|
|
||||||
from test_plus.test import TestCase
|
pytestmark = pytest.mark.django_db
|
||||||
|
|
||||||
|
|
||||||
class TestUserURLs(TestCase):
|
def test_detail(user: settings.AUTH_USER_MODEL):
|
||||||
"""Test URL patterns for users app."""
|
assert (
|
||||||
|
reverse("users:detail", kwargs={"username": user.username})
|
||||||
|
== f"/users/{user.username}/"
|
||||||
|
)
|
||||||
|
assert resolve(f"/users/{user.username}/").view_name == "users:detail"
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
self.user = self.make_user()
|
|
||||||
|
|
||||||
def test_list_reverse(self):
|
def test_list():
|
||||||
"""users:list should reverse to /users/."""
|
assert reverse("users:list") == "/users/"
|
||||||
self.assertEqual(reverse("users:list"), "/users/")
|
assert resolve("/users/").view_name == "users:list"
|
||||||
|
|
||||||
def test_list_resolve(self):
|
|
||||||
"""/users/ should resolve to users:list."""
|
|
||||||
self.assertEqual(resolve("/users/").view_name, "users:list")
|
|
||||||
|
|
||||||
def test_redirect_reverse(self):
|
def test_update():
|
||||||
"""users:redirect should reverse to /users/~redirect/."""
|
assert reverse("users:update") == "/users/~update/"
|
||||||
self.assertEqual(reverse("users:redirect"), "/users/~redirect/")
|
assert resolve("/users/~update/").view_name == "users:update"
|
||||||
|
|
||||||
def test_redirect_resolve(self):
|
|
||||||
"""/users/~redirect/ should resolve to users:redirect."""
|
|
||||||
self.assertEqual(resolve("/users/~redirect/").view_name, "users:redirect")
|
|
||||||
|
|
||||||
def test_detail_reverse(self):
|
def test_redirect():
|
||||||
"""users:detail should reverse to /users/testuser/."""
|
assert reverse("users:redirect") == "/users/~redirect/"
|
||||||
self.assertEqual(
|
assert resolve("/users/~redirect/").view_name == "users:redirect"
|
||||||
reverse("users:detail", kwargs={"username": "testuser"}), "/users/testuser/"
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_detail_resolve(self):
|
|
||||||
"""/users/testuser/ should resolve to users:detail."""
|
|
||||||
self.assertEqual(resolve("/users/testuser/").view_name, "users:detail")
|
|
||||||
|
|
||||||
def test_update_reverse(self):
|
|
||||||
"""users:update should reverse to /users/~update/."""
|
|
||||||
self.assertEqual(reverse("users:update"), "/users/~update/")
|
|
||||||
|
|
||||||
def test_update_resolve(self):
|
|
||||||
"""/users/~update/ should resolve to users:update."""
|
|
||||||
self.assertEqual(resolve("/users/~update/").view_name, "users:update")
|
|
||||||
|
|
|
@ -1,52 +1,53 @@
|
||||||
|
import pytest
|
||||||
|
from django.conf import settings
|
||||||
from django.test import RequestFactory
|
from django.test import RequestFactory
|
||||||
|
|
||||||
from test_plus.test import TestCase
|
from {{ cookiecutter.project_slug }}.users.views import UserRedirectView, UserUpdateView
|
||||||
|
|
||||||
from ..views import UserRedirectView, UserUpdateView
|
pytestmark = pytest.mark.django_db
|
||||||
|
|
||||||
|
|
||||||
class BaseUserTestCase(TestCase):
|
class TestUserUpdateView:
|
||||||
|
"""
|
||||||
|
TODO:
|
||||||
|
extracting view initialization code as class-scoped fixture
|
||||||
|
would be great if only pytest-django supported non-function-scoped
|
||||||
|
fixture db access -- this is a work-in-progress for now:
|
||||||
|
https://github.com/pytest-dev/pytest-django/pull/258
|
||||||
|
"""
|
||||||
|
|
||||||
def setUp(self):
|
def test_get_success_url(
|
||||||
self.user = self.make_user()
|
self, user: settings.AUTH_USER_MODEL, request_factory: RequestFactory
|
||||||
self.factory = RequestFactory()
|
):
|
||||||
|
view = UserUpdateView()
|
||||||
|
request = request_factory.get("/fake-url/")
|
||||||
|
request.user = user
|
||||||
|
|
||||||
|
|
||||||
class TestUserRedirectView(BaseUserTestCase):
|
|
||||||
|
|
||||||
def test_get_redirect_url(self):
|
|
||||||
# Instantiate the view directly. Never do this outside a test!
|
|
||||||
view = UserRedirectView()
|
|
||||||
# Generate a fake request
|
|
||||||
request = self.factory.get("/fake-url")
|
|
||||||
# Attach the user to the request
|
|
||||||
request.user = self.user
|
|
||||||
# Attach the request to the view
|
|
||||||
view.request = request
|
view.request = request
|
||||||
# Expect: '/users/testuser/', as that is the default username for
|
|
||||||
# self.make_user()
|
assert view.get_success_url() == f"/users/{user.username}/"
|
||||||
self.assertEqual(view.get_redirect_url(), "/users/testuser/")
|
|
||||||
|
def test_get_object(
|
||||||
|
self, user: settings.AUTH_USER_MODEL, request_factory: RequestFactory
|
||||||
|
):
|
||||||
|
view = UserUpdateView()
|
||||||
|
request = request_factory.get("/fake-url/")
|
||||||
|
request.user = user
|
||||||
|
|
||||||
|
view.request = request
|
||||||
|
|
||||||
|
assert view.get_object() == user
|
||||||
|
|
||||||
|
|
||||||
class TestUserUpdateView(BaseUserTestCase):
|
class TestUserRedirectView:
|
||||||
|
|
||||||
def setUp(self):
|
def test_get_redirect_url(
|
||||||
# call BaseUserTestCase.setUp()
|
self, user: settings.AUTH_USER_MODEL, request_factory: RequestFactory
|
||||||
super(TestUserUpdateView, self).setUp()
|
):
|
||||||
# Instantiate the view directly. Never do this outside a test!
|
view = UserRedirectView()
|
||||||
self.view = UserUpdateView()
|
request = request_factory.get("/fake-url")
|
||||||
# Generate a fake request
|
request.user = user
|
||||||
request = self.factory.get("/fake-url")
|
|
||||||
# Attach the user to the request
|
|
||||||
request.user = self.user
|
|
||||||
# Attach the request to the view
|
|
||||||
self.view.request = request
|
|
||||||
|
|
||||||
def test_get_success_url(self):
|
view.request = request
|
||||||
# Expect: '/users/testuser/', as that is the default username for
|
|
||||||
# self.make_user()
|
|
||||||
self.assertEqual(self.view.get_success_url(), "/users/testuser/")
|
|
||||||
|
|
||||||
def test_get_object(self):
|
assert view.get_redirect_url() == f"/users/{user.username}/"
|
||||||
# Expect: self.user, as that is the request's user object
|
|
||||||
self.assertEqual(self.view.get_object(), self.user)
|
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
|
|
||||||
from . import views
|
from {{ cookiecutter.project_slug }}.users.views import (
|
||||||
|
user_list_view,
|
||||||
|
user_redirect_view,
|
||||||
|
user_update_view,
|
||||||
|
user_detail_view,
|
||||||
|
)
|
||||||
|
|
||||||
app_name = "users"
|
app_name = "users"
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("", view=views.UserListView.as_view(), name="list"),
|
path("", view=user_list_view, name="list"),
|
||||||
path("~redirect/", view=views.UserRedirectView.as_view(), name="redirect"),
|
path("~redirect/", view=user_redirect_view, name="redirect"),
|
||||||
path("~update/", view=views.UserUpdateView.as_view(), name="update"),
|
path("~update/", view=user_update_view, name="update"),
|
||||||
path(
|
path("<str:username>/", view=user_detail_view, name="detail"),
|
||||||
"<str:username>",
|
|
||||||
view=views.UserDetailView.as_view(),
|
|
||||||
name="detail",
|
|
||||||
),
|
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,43 +1,52 @@
|
||||||
|
from django.contrib.auth import get_user_model
|
||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.views.generic import DetailView, ListView, RedirectView, UpdateView
|
from django.views.generic import DetailView, ListView, RedirectView, UpdateView
|
||||||
|
|
||||||
from .models import User
|
User = get_user_model()
|
||||||
|
|
||||||
|
|
||||||
class UserDetailView(LoginRequiredMixin, DetailView):
|
class UserDetailView(LoginRequiredMixin, DetailView):
|
||||||
|
|
||||||
model = User
|
model = User
|
||||||
# These next two lines tell the view to index lookups by username
|
|
||||||
slug_field = "username"
|
slug_field = "username"
|
||||||
slug_url_kwarg = "username"
|
slug_url_kwarg = "username"
|
||||||
|
|
||||||
|
|
||||||
|
user_detail_view = UserDetailView.as_view()
|
||||||
|
|
||||||
|
|
||||||
|
class UserListView(LoginRequiredMixin, ListView):
|
||||||
|
|
||||||
|
model = User
|
||||||
|
slug_field = "username"
|
||||||
|
slug_url_kwarg = "username"
|
||||||
|
|
||||||
|
|
||||||
|
user_list_view = UserListView.as_view()
|
||||||
|
|
||||||
|
|
||||||
|
class UserUpdateView(LoginRequiredMixin, UpdateView):
|
||||||
|
|
||||||
|
model = User
|
||||||
|
fields = ["name"]
|
||||||
|
|
||||||
|
def get_success_url(self):
|
||||||
|
return reverse("users:detail", kwargs={"username": self.request.user.username})
|
||||||
|
|
||||||
|
def get_object(self):
|
||||||
|
return User.objects.get(username=self.request.user.username)
|
||||||
|
|
||||||
|
|
||||||
|
user_update_view = UserUpdateView.as_view()
|
||||||
|
|
||||||
|
|
||||||
class UserRedirectView(LoginRequiredMixin, RedirectView):
|
class UserRedirectView(LoginRequiredMixin, RedirectView):
|
||||||
|
|
||||||
permanent = False
|
permanent = False
|
||||||
|
|
||||||
def get_redirect_url(self):
|
def get_redirect_url(self):
|
||||||
return reverse("users:detail", kwargs={"username": self.request.user.username})
|
return reverse("users:detail", kwargs={"username": self.request.user.username})
|
||||||
|
|
||||||
|
|
||||||
class UserUpdateView(LoginRequiredMixin, UpdateView):
|
user_redirect_view = UserRedirectView.as_view()
|
||||||
|
|
||||||
fields = ["name"]
|
|
||||||
|
|
||||||
# we already imported User in the view code above, remember?
|
|
||||||
model = User
|
|
||||||
|
|
||||||
# send the user back to their own page after a successful update
|
|
||||||
|
|
||||||
def get_success_url(self):
|
|
||||||
return reverse("users:detail", kwargs={"username": self.request.user.username})
|
|
||||||
|
|
||||||
def get_object(self):
|
|
||||||
# Only get the User record for the user making the request
|
|
||||||
return User.objects.get(username=self.request.user.username)
|
|
||||||
|
|
||||||
|
|
||||||
class UserListView(LoginRequiredMixin, ListView):
|
|
||||||
model = User
|
|
||||||
# These next two lines tell the view to index lookups by username
|
|
||||||
slug_field = "username"
|
|
||||||
slug_url_kwarg = "username"
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user