mirror of
https://github.com/cookiecutter/cookiecutter-django.git
synced 2024-11-22 17:47:08 +03:00
Merge branch 'master' into docs
# Conflicts: # {{cookiecutter.project_slug}}/requirements/local.txt
This commit is contained in:
commit
196167490d
11
.github/labeler.yml
vendored
11
.github/labeler.yml
vendored
|
@ -1,11 +0,0 @@
|
||||||
# Add 'docs' to any changes within 'docs' folder or any subfolders
|
|
||||||
docs:
|
|
||||||
- 'README.rst'
|
|
||||||
- 'docs/**/*'
|
|
||||||
- '{{cookiecutter.project_slug}}/docs/**/*'
|
|
||||||
|
|
||||||
# Flag PR related to docker
|
|
||||||
docker:
|
|
||||||
- '{{cookiecutter.project_slug}}/compose/**/*'
|
|
||||||
- '{{cookiecutter.project_slug}}/local.yml'
|
|
||||||
- '{{cookiecutter.project_slug}}/production.yml'
|
|
20
.github/workflows/label.yml
vendored
20
.github/workflows/label.yml
vendored
|
@ -1,20 +0,0 @@
|
||||||
# This workflow will triage pull requests and apply a label based on the
|
|
||||||
# paths that are modified in the pull request.
|
|
||||||
#
|
|
||||||
# To use this workflow, you will need to set up a .github/labeler.yml
|
|
||||||
# file with configuration. For more information, see:
|
|
||||||
# https://github.com/actions/labeler/blob/master/README.md
|
|
||||||
|
|
||||||
|
|
||||||
name: Labeler
|
|
||||||
on: [pull_request]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
label:
|
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/labeler@v2
|
|
||||||
with:
|
|
||||||
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
|
|
@ -13,8 +13,6 @@ pin: True
|
||||||
# default: empty
|
# default: empty
|
||||||
label_prs: update
|
label_prs: update
|
||||||
|
|
||||||
# Specify requirement files by hand, pyup seems to struggle to
|
|
||||||
# find the ones in the project_slug folder
|
|
||||||
requirements:
|
requirements:
|
||||||
- "requirements.txt"
|
- "requirements.txt"
|
||||||
- "{{cookiecutter.project_slug}}/requirements/base.txt"
|
- "{{cookiecutter.project_slug}}/requirements/base.txt"
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
dist: xenial
|
|
||||||
|
|
||||||
services:
|
services:
|
||||||
- docker
|
- docker
|
||||||
|
|
||||||
|
@ -19,8 +17,8 @@ matrix:
|
||||||
script: tox -e black-template
|
script: tox -e black-template
|
||||||
- name: Basic Docker
|
- name: Basic Docker
|
||||||
script: sh tests/test_docker.sh
|
script: sh tests/test_docker.sh
|
||||||
- name: Docker with Celery
|
- name: Extended Docker
|
||||||
script: sh tests/test_docker.sh use_celery=y
|
script: sh tests/test_docker.sh use_celery=y use_drf=y
|
||||||
- name: Bare metal
|
- name: Bare metal
|
||||||
script: sh tests/test_bare.sh use_celery=y use_compressor=y
|
script: sh tests/test_bare.sh use_celery=y use_compressor=y
|
||||||
services:
|
services:
|
||||||
|
|
|
@ -65,6 +65,7 @@ Listed in alphabetical order.
|
||||||
Anuj Bansal `@ahhda`_
|
Anuj Bansal `@ahhda`_
|
||||||
Arcuri Davide `@dadokkio`_
|
Arcuri Davide `@dadokkio`_
|
||||||
Areski Belaid `@areski`_
|
Areski Belaid `@areski`_
|
||||||
|
AsheKR `@ashekr`_
|
||||||
Ashley Camba
|
Ashley Camba
|
||||||
Barclay Gauld `@yunti`_
|
Barclay Gauld `@yunti`_
|
||||||
Bartek `@btknu`_
|
Bartek `@btknu`_
|
||||||
|
@ -146,6 +147,7 @@ Listed in alphabetical order.
|
||||||
Jerome Leclanche `@jleclanche`_ @Adys
|
Jerome Leclanche `@jleclanche`_ @Adys
|
||||||
Jimmy Gitonga `@afrowave`_ @afrowave
|
Jimmy Gitonga `@afrowave`_ @afrowave
|
||||||
John Cass `@jcass77`_ @cass_john
|
John Cass `@jcass77`_ @cass_john
|
||||||
|
Jonathan Thompson `@nojanath`_
|
||||||
Jules Cheron `@jules-ch`_
|
Jules Cheron `@jules-ch`_
|
||||||
Julien Almarcha `@sladinji`_
|
Julien Almarcha `@sladinji`_
|
||||||
Julio Castillo `@juliocc`_
|
Julio Castillo `@juliocc`_
|
||||||
|
@ -161,6 +163,7 @@ Listed in alphabetical order.
|
||||||
Krzysztof Żuraw `@krzysztofzuraw`_
|
Krzysztof Żuraw `@krzysztofzuraw`_
|
||||||
Leo won `@leollon`_
|
Leo won `@leollon`_
|
||||||
Leo Zhou `@glasslion`_
|
Leo Zhou `@glasslion`_
|
||||||
|
Leon Kim `@PilhwanKim`_
|
||||||
Leonardo Jimenez `@xpostudio4`_
|
Leonardo Jimenez `@xpostudio4`_
|
||||||
Lin Xianyi `@iynaix`_
|
Lin Xianyi `@iynaix`_
|
||||||
Luis Nell `@originell`_
|
Luis Nell `@originell`_
|
||||||
|
@ -249,6 +252,7 @@ Listed in alphabetical order.
|
||||||
.. _@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
|
||||||
|
.. _@ashekr: https://github.com/ashekr
|
||||||
.. _@bertdemiranda: https://github.com/bertdemiranda
|
.. _@bertdemiranda: https://github.com/bertdemiranda
|
||||||
.. _@bittner: https://github.com/bittner
|
.. _@bittner: https://github.com/bittner
|
||||||
.. _@blaxpy: https://github.com/blaxpy
|
.. _@blaxpy: https://github.com/blaxpy
|
||||||
|
@ -312,6 +316,7 @@ Listed in alphabetical order.
|
||||||
.. _@hackebrot: https://github.com/hackebrot
|
.. _@hackebrot: https://github.com/hackebrot
|
||||||
.. _@hairychris: https://github.com/hairychris
|
.. _@hairychris: https://github.com/hairychris
|
||||||
.. _@hanaquadara: https://github.com/hanaquadara
|
.. _@hanaquadara: https://github.com/hanaquadara
|
||||||
|
.. _@hanhanhan: https://github.com/hanhanhan
|
||||||
.. _@hendrikschneider: https://github.com/hendrikschneider
|
.. _@hendrikschneider: https://github.com/hendrikschneider
|
||||||
.. _@highpost: https://github.com/highpost
|
.. _@highpost: https://github.com/highpost
|
||||||
.. _@hjwp: https://github.com/hjwp
|
.. _@hjwp: https://github.com/hjwp
|
||||||
|
@ -358,12 +363,14 @@ Listed in alphabetical order.
|
||||||
.. _@myilmaz: https://github.com/myilmaz
|
.. _@myilmaz: https://github.com/myilmaz
|
||||||
.. _@nicolas471: https://github.com/nicolas471
|
.. _@nicolas471: https://github.com/nicolas471
|
||||||
.. _@noisy: https://github.com/noisy
|
.. _@noisy: https://github.com/noisy
|
||||||
|
.. _@nojanath: https://github.com/nojanath
|
||||||
.. _@originell: https://github.com/originell
|
.. _@originell: https://github.com/originell
|
||||||
.. _@oubiga: https://github.com/oubiga
|
.. _@oubiga: https://github.com/oubiga
|
||||||
.. _@parbhat: https://github.com/parbhat
|
.. _@parbhat: https://github.com/parbhat
|
||||||
.. _@rjsnh1522: https://github.com/rjsnh1522
|
.. _@rjsnh1522: https://github.com/rjsnh1522
|
||||||
.. _@pchiquet: https://github.com/pchiquet
|
.. _@pchiquet: https://github.com/pchiquet
|
||||||
.. _@phiberjenz: https://github.com/phiberjenz
|
.. _@phiberjenz: https://github.com/phiberjenz
|
||||||
|
.. _@PilhwanKim: https://github.com/PilhwanKim
|
||||||
.. _@purplediane: https://github.com/purplediane
|
.. _@purplediane: https://github.com/purplediane
|
||||||
.. _@raonyguimaraes: https://github.com/raonyguimaraes
|
.. _@raonyguimaraes: https://github.com/raonyguimaraes
|
||||||
.. _@reggieriser: https://github.com/reggieriser
|
.. _@reggieriser: https://github.com/reggieriser
|
||||||
|
|
|
@ -5,6 +5,10 @@ Cookiecutter Django
|
||||||
:target: https://travis-ci.org/pydanny/cookiecutter-django?branch=master
|
:target: https://travis-ci.org/pydanny/cookiecutter-django?branch=master
|
||||||
:alt: Build Status
|
:alt: Build Status
|
||||||
|
|
||||||
|
.. image:: https://readthedocs.org/projects/cookiecutter-django/badge/?version=latest
|
||||||
|
:target: https://cookiecutter-django.readthedocs.io/en/latest/?badge=latest
|
||||||
|
:alt: Documentation Status
|
||||||
|
|
||||||
.. image:: https://pyup.io/repos/github/pydanny/cookiecutter-django/shield.svg
|
.. image:: https://pyup.io/repos/github/pydanny/cookiecutter-django/shield.svg
|
||||||
:target: https://pyup.io/repos/github/pydanny/cookiecutter-django/
|
:target: https://pyup.io/repos/github/pydanny/cookiecutter-django/
|
||||||
:alt: Updates
|
:alt: Updates
|
||||||
|
|
|
@ -154,6 +154,15 @@ django-debug-toolbar
|
||||||
In order for ``django-debug-toolbar`` to work designate your Docker Machine IP with ``INTERNAL_IPS`` in ``local.py``.
|
In order for ``django-debug-toolbar`` to work designate your Docker Machine IP with ``INTERNAL_IPS`` in ``local.py``.
|
||||||
|
|
||||||
|
|
||||||
|
docker
|
||||||
|
""""""
|
||||||
|
|
||||||
|
The ``container_name`` from the yml file can be used to check on containers with docker commands, for example: ::
|
||||||
|
|
||||||
|
$ docker logs worker
|
||||||
|
$ docker top worker
|
||||||
|
|
||||||
|
|
||||||
Mailhog
|
Mailhog
|
||||||
~~~~~~~
|
~~~~~~~
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ Make sure to have the following on your host:
|
||||||
* Python 3.8
|
* Python 3.8
|
||||||
* PostgreSQL_.
|
* PostgreSQL_.
|
||||||
* Redis_, if using Celery
|
* Redis_, if using Celery
|
||||||
|
* Cookiecutter_
|
||||||
|
|
||||||
First things first.
|
First things first.
|
||||||
|
|
||||||
|
@ -23,9 +24,14 @@ First things first.
|
||||||
|
|
||||||
$ source <virtual env path>/bin/activate
|
$ source <virtual env path>/bin/activate
|
||||||
|
|
||||||
|
#. Install cookiecutter-django
|
||||||
|
|
||||||
|
$ cookiecutter gh:pydanny/cookiecutter-django ::
|
||||||
|
|
||||||
#. Install development requirements: ::
|
#. Install development requirements: ::
|
||||||
|
|
||||||
$ pip install -r requirements/local.txt
|
$ pip install -r requirements/local.txt
|
||||||
|
$ git init # A git repo is required for pre-commit to install
|
||||||
$ pre-commit install
|
$ pre-commit install
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
@ -74,10 +80,11 @@ First things first.
|
||||||
|
|
||||||
or if you're running asynchronously: ::
|
or if you're running asynchronously: ::
|
||||||
|
|
||||||
$ gunicorn config.asgi --bind 0.0.0.0:8000 -k uvicorn.workers.UvicornWorker --reload
|
$ uvicorn config.asgi:application --host 0.0.0.0 --reload
|
||||||
|
|
||||||
.. _PostgreSQL: https://www.postgresql.org/download/
|
.. _PostgreSQL: https://www.postgresql.org/download/
|
||||||
.. _Redis: https://redis.io/download
|
.. _Redis: https://redis.io/download
|
||||||
|
.. _CookieCutter: https://github.com/cookiecutter/cookiecutter
|
||||||
.. _createdb: https://www.postgresql.org/docs/current/static/app-createdb.html
|
.. _createdb: https://www.postgresql.org/docs/current/static/app-createdb.html
|
||||||
.. _initial PostgreSQL set up: http://suite.opengeo.org/docs/latest/dataadmin/pgGettingStarted/firstconnect.html
|
.. _initial PostgreSQL set up: http://suite.opengeo.org/docs/latest/dataadmin/pgGettingStarted/firstconnect.html
|
||||||
.. _postgres documentation: https://www.postgresql.org/docs/current/static/auth-pg-hba-conf.html
|
.. _postgres documentation: https://www.postgresql.org/docs/current/static/auth-pg-hba-conf.html
|
||||||
|
|
|
@ -23,6 +23,7 @@ Contents:
|
||||||
deployment-on-heroku
|
deployment-on-heroku
|
||||||
deployment-with-docker
|
deployment-with-docker
|
||||||
docker-postgres-backups
|
docker-postgres-backups
|
||||||
|
websocket
|
||||||
faq
|
faq
|
||||||
troubleshooting
|
troubleshooting
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,7 @@ DJANGO_AWS_ACCESS_KEY_ID AWS_ACCESS_KEY_ID n/a
|
||||||
DJANGO_AWS_SECRET_ACCESS_KEY AWS_SECRET_ACCESS_KEY n/a raises error
|
DJANGO_AWS_SECRET_ACCESS_KEY AWS_SECRET_ACCESS_KEY n/a raises error
|
||||||
DJANGO_AWS_STORAGE_BUCKET_NAME AWS_STORAGE_BUCKET_NAME n/a raises error
|
DJANGO_AWS_STORAGE_BUCKET_NAME AWS_STORAGE_BUCKET_NAME n/a raises error
|
||||||
DJANGO_AWS_S3_REGION_NAME AWS_S3_REGION_NAME n/a None
|
DJANGO_AWS_S3_REGION_NAME AWS_S3_REGION_NAME n/a None
|
||||||
|
DJANGO_AWS_S3_CUSTOM_DOMAIN AWS_S3_CUSTOM_DOMAIN n/a None
|
||||||
DJANGO_GCP_STORAGE_BUCKET_NAME GS_BUCKET_NAME n/a raises error
|
DJANGO_GCP_STORAGE_BUCKET_NAME GS_BUCKET_NAME n/a raises error
|
||||||
GOOGLE_APPLICATION_CREDENTIALS n/a n/a raises error
|
GOOGLE_APPLICATION_CREDENTIALS n/a n/a raises error
|
||||||
SENTRY_DSN SENTRY_DSN n/a raises error
|
SENTRY_DSN SENTRY_DSN n/a raises error
|
||||||
|
|
25
docs/websocket.rst
Normal file
25
docs/websocket.rst
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
.. _websocket:
|
||||||
|
|
||||||
|
=========
|
||||||
|
Websocket
|
||||||
|
=========
|
||||||
|
|
||||||
|
You can enable web sockets if you select ``use_async`` option when creating a project. That indicates whether the project can use web sockets with Uvicorn + Gunicorn.
|
||||||
|
|
||||||
|
Usage
|
||||||
|
-----
|
||||||
|
|
||||||
|
JavaScript example: ::
|
||||||
|
|
||||||
|
> ws = new WebSocket('ws://localhost:8000/') // or 'wss://<mydomain.com>/' in prod
|
||||||
|
WebSocket {url: "ws://localhost:8000/", readyState: 0, bufferedAmount: 0, onopen: null, onerror: null, …}
|
||||||
|
> ws.onmessage = event => console.log(event.data)
|
||||||
|
event => console.log(event.data)
|
||||||
|
> ws.send("ping")
|
||||||
|
undefined
|
||||||
|
pong!
|
||||||
|
|
||||||
|
|
||||||
|
If you don't use Traefik, you might have to configure your reverse proxy accordingly (example with Nginx_).
|
||||||
|
|
||||||
|
.. _Nginx: https://www.nginx.com/blog/websocket-nginx/
|
|
@ -299,6 +299,16 @@ def remove_aws_dockerfile():
|
||||||
def remove_drf_starter_files():
|
def remove_drf_starter_files():
|
||||||
os.remove(os.path.join("config", "api_router.py"))
|
os.remove(os.path.join("config", "api_router.py"))
|
||||||
shutil.rmtree(os.path.join("{{cookiecutter.project_slug}}", "users", "api"))
|
shutil.rmtree(os.path.join("{{cookiecutter.project_slug}}", "users", "api"))
|
||||||
|
os.remove(
|
||||||
|
os.path.join(
|
||||||
|
"{{cookiecutter.project_slug}}", "users", "tests", "test_drf_urls.py"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
os.remove(
|
||||||
|
os.path.join(
|
||||||
|
"{{cookiecutter.project_slug}}", "users", "tests", "test_drf_views.py"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def remove_storages_module():
|
def remove_storages_module():
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
cookiecutter==1.7.2
|
cookiecutter==1.7.2
|
||||||
sh==1.12.14
|
sh==1.13.1
|
||||||
binaryornot==0.4.4
|
binaryornot==0.4.4
|
||||||
|
|
||||||
# Code quality
|
# Code quality
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
black==19.10b0
|
black==19.10b0
|
||||||
flake8==3.7.9
|
flake8==3.8.3
|
||||||
flake8-isort==3.0.0
|
flake8-isort==3.0.0
|
||||||
|
|
||||||
# Testing
|
# Testing
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
tox==3.14.6
|
tox==3.16.0
|
||||||
pytest==5.4.1
|
pytest==5.4.3
|
||||||
pytest-cookies==0.5.1
|
pytest-cookies==0.5.1
|
||||||
pytest-instafail==0.4.1.post0
|
pytest-instafail==0.4.2
|
||||||
pyyaml==5.3.1
|
pyyaml==5.3.1
|
||||||
|
|
2
setup.py
2
setup.py
|
@ -10,7 +10,7 @@ except ImportError:
|
||||||
|
|
||||||
# Our version ALWAYS matches the version of Django we support
|
# Our version ALWAYS matches the version of Django we support
|
||||||
# If Django has a new release, we branch, tag, then update this setting after the tag.
|
# If Django has a new release, we branch, tag, then update this setting after the tag.
|
||||||
version = "3.0.5-01"
|
version = "3.0.7"
|
||||||
|
|
||||||
if sys.argv[-1] == "tag":
|
if sys.argv[-1] == "tag":
|
||||||
os.system(f'git tag -a {version} -m "version {version}"')
|
os.system(f'git tag -a {version} -m "version {version}"')
|
||||||
|
|
|
@ -156,7 +156,7 @@ def test_flake8_passes(cookies, context_override):
|
||||||
result = cookies.bake(extra_context=context_override)
|
result = cookies.bake(extra_context=context_override)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
sh.flake8(str(result.project))
|
sh.flake8(_cwd=str(result.project))
|
||||||
except sh.ErrorReturnCode as e:
|
except sh.ErrorReturnCode as e:
|
||||||
pytest.fail(e.stdout.decode())
|
pytest.fail(e.stdout.decode())
|
||||||
|
|
||||||
|
@ -167,7 +167,9 @@ def test_black_passes(cookies, context_override):
|
||||||
result = cookies.bake(extra_context=context_override)
|
result = cookies.bake(extra_context=context_override)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
sh.black("--check", "--diff", "--exclude", "migrations", f"{result.project}/")
|
sh.black(
|
||||||
|
"--check", "--diff", "--exclude", "migrations", _cwd=str(result.project)
|
||||||
|
)
|
||||||
except sh.ErrorReturnCode as e:
|
except sh.ErrorReturnCode as e:
|
||||||
pytest.fail(e.stdout.decode())
|
pytest.fail(e.stdout.decode())
|
||||||
|
|
||||||
|
|
|
@ -23,10 +23,11 @@ pytest:
|
||||||
stage: test
|
stage: test
|
||||||
image: python:3.7
|
image: python:3.7
|
||||||
{% if cookiecutter.use_docker == 'y' -%}
|
{% if cookiecutter.use_docker == 'y' -%}
|
||||||
|
image: docker/compose:latest
|
||||||
tags:
|
tags:
|
||||||
- docker
|
- docker
|
||||||
services:
|
services:
|
||||||
- docker
|
- docker:dind
|
||||||
before_script:
|
before_script:
|
||||||
- docker-compose -f local.yml build
|
- docker-compose -f local.yml build
|
||||||
# Ensure celerybeat does not crash due to non-existent tables
|
# Ensure celerybeat does not crash due to non-existent tables
|
||||||
|
|
|
@ -3,18 +3,22 @@ default_stages: [commit]
|
||||||
fail_fast: true
|
fail_fast: true
|
||||||
|
|
||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
rev: master
|
rev: master
|
||||||
hooks:
|
hooks:
|
||||||
- id: trailing-whitespace
|
- id: trailing-whitespace
|
||||||
files: (^|/).+\.(py|html|sh|css|js)$
|
- id: end-of-file-fixer
|
||||||
|
- id: check-yaml
|
||||||
|
|
||||||
- repo: local
|
- repo: https://github.com/psf/black
|
||||||
|
rev: 19.10b0
|
||||||
|
hooks:
|
||||||
|
- id: black
|
||||||
|
|
||||||
|
- repo: https://gitlab.com/pycqa/flake8
|
||||||
|
rev: 3.8.3
|
||||||
hooks:
|
hooks:
|
||||||
- id: flake8
|
- id: flake8
|
||||||
name: flake8
|
|
||||||
entry: flake8
|
|
||||||
language: python
|
|
||||||
types: [python]
|
|
||||||
args: ['--config=setup.cfg']
|
args: ['--config=setup.cfg']
|
||||||
|
additional_dependencies: [flake8-isort]
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ set -o nounset
|
||||||
|
|
||||||
python manage.py migrate
|
python manage.py migrate
|
||||||
{%- if cookiecutter.use_async == 'y' %}
|
{%- if cookiecutter.use_async == 'y' %}
|
||||||
/usr/local/bin/gunicorn config.asgi --bind 0.0.0.0:8000 --chdir=/app -k uvicorn.workers.UvicornWorker --reload
|
uvicorn config.asgi:application --host 0.0.0.0 --reload
|
||||||
{%- else %}
|
{%- else %}
|
||||||
python manage.py runserver_plus 0.0.0.0:8000
|
python manage.py runserver_plus 0.0.0.0:8000
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -26,10 +26,9 @@ certificatesResolvers:
|
||||||
entryPoint: web
|
entryPoint: web
|
||||||
|
|
||||||
http:
|
http:
|
||||||
{%- set domain_dots = cookiecutter.domain_name.count('.') %}
|
|
||||||
routers:
|
routers:
|
||||||
web-router:
|
web-router:
|
||||||
{%- if domain_dots == 1 or (domain_dots == 2 and '.co.' in cookiecutter.domain_name) %}
|
{%- if cookiecutter.domain_name.count('.') == 1 %}
|
||||||
rule: "Host(`{{ cookiecutter.domain_name }}`) || Host(`www.{{ cookiecutter.domain_name }}`)"
|
rule: "Host(`{{ cookiecutter.domain_name }}`) || Host(`www.{{ cookiecutter.domain_name }}`)"
|
||||||
{% else %}
|
{% else %}
|
||||||
rule: "Host(`{{ cookiecutter.domain_name }}`)"
|
rule: "Host(`{{ cookiecutter.domain_name }}`)"
|
||||||
|
@ -42,7 +41,7 @@ http:
|
||||||
service: django
|
service: django
|
||||||
|
|
||||||
web-secure-router:
|
web-secure-router:
|
||||||
{%- if domain_dots == 1 or (domain_dots == 2 and '.co.' in cookiecutter.domain_name) %}
|
{%- if cookiecutter.domain_name.count('.') == 1 %}
|
||||||
rule: "Host(`{{ cookiecutter.domain_name }}`) || Host(`www.{{ cookiecutter.domain_name }}`)"
|
rule: "Host(`{{ cookiecutter.domain_name }}`) || Host(`www.{{ cookiecutter.domain_name }}`)"
|
||||||
{% else %}
|
{% else %}
|
||||||
rule: "Host(`{{ cookiecutter.domain_name }}`)"
|
rule: "Host(`{{ cookiecutter.domain_name }}`)"
|
||||||
|
|
|
@ -15,8 +15,8 @@ from django.core.asgi import get_asgi_application
|
||||||
|
|
||||||
# This allows easy placement of apps within the interior
|
# This allows easy placement of apps within the interior
|
||||||
# {{ cookiecutter.project_slug }} directory.
|
# {{ cookiecutter.project_slug }} directory.
|
||||||
app_path = Path(__file__).parents[1].resolve()
|
ROOT_DIR = Path(__file__).resolve(strict=True).parent.parent
|
||||||
sys.path.append(str(app_path / "{{ cookiecutter.project_slug }}"))
|
sys.path.append(str(ROOT_DIR / "{{ cookiecutter.project_slug }}"))
|
||||||
|
|
||||||
# If DJANGO_SETTINGS_MODULE is unset, default to the local settings
|
# If DJANGO_SETTINGS_MODULE is unset, default to the local settings
|
||||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.local")
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.local")
|
||||||
|
|
|
@ -5,8 +5,8 @@ from pathlib import Path
|
||||||
|
|
||||||
import environ
|
import environ
|
||||||
|
|
||||||
ROOT_DIR = Path(__file__).parents[2]
|
ROOT_DIR = Path(__file__).resolve(strict=True).parent.parent.parent
|
||||||
# {{ cookiecutter.project_slug }}/)
|
# {{ cookiecutter.project_slug }}/
|
||||||
APPS_DIR = ROOT_DIR / "{{ cookiecutter.project_slug }}"
|
APPS_DIR = ROOT_DIR / "{{ cookiecutter.project_slug }}"
|
||||||
env = environ.Env()
|
env = environ.Env()
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ CACHES = {
|
||||||
"OPTIONS": {
|
"OPTIONS": {
|
||||||
"CLIENT_CLASS": "django_redis.client.DefaultClient",
|
"CLIENT_CLASS": "django_redis.client.DefaultClient",
|
||||||
# Mimicing memcache behavior.
|
# Mimicing memcache behavior.
|
||||||
# http://niwinz.github.io/django-redis/latest/#_memcached_exceptions_behavior
|
# http://jazzband.github.io/django-redis/latest/#_memcached_exceptions_behavior
|
||||||
"IGNORE_EXCEPTIONS": True,
|
"IGNORE_EXCEPTIONS": True,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -90,6 +90,9 @@ AWS_S3_OBJECT_PARAMETERS = {
|
||||||
AWS_DEFAULT_ACL = None
|
AWS_DEFAULT_ACL = None
|
||||||
# https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#settings
|
# https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#settings
|
||||||
AWS_S3_REGION_NAME = env("DJANGO_AWS_S3_REGION_NAME", default=None)
|
AWS_S3_REGION_NAME = env("DJANGO_AWS_S3_REGION_NAME", default=None)
|
||||||
|
# https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#cloudfront
|
||||||
|
AWS_S3_CUSTOM_DOMAIN = env("DJANGO_AWS_S3_CUSTOM_DOMAIN", default=None)
|
||||||
|
aws_s3_domain = AWS_S3_CUSTOM_DOMAIN or f"{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com"
|
||||||
{% elif cookiecutter.cloud_provider == 'GCP' %}
|
{% elif cookiecutter.cloud_provider == 'GCP' %}
|
||||||
GS_BUCKET_NAME = env("DJANGO_GCP_STORAGE_BUCKET_NAME")
|
GS_BUCKET_NAME = env("DJANGO_GCP_STORAGE_BUCKET_NAME")
|
||||||
GS_DEFAULT_ACL = "publicRead"
|
GS_DEFAULT_ACL = "publicRead"
|
||||||
|
@ -104,7 +107,7 @@ STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage"
|
||||||
{% elif cookiecutter.cloud_provider == 'AWS' -%}
|
{% elif cookiecutter.cloud_provider == 'AWS' -%}
|
||||||
STATICFILES_STORAGE = "{{cookiecutter.project_slug}}.utils.storages.StaticRootS3Boto3Storage"
|
STATICFILES_STORAGE = "{{cookiecutter.project_slug}}.utils.storages.StaticRootS3Boto3Storage"
|
||||||
COLLECTFAST_STRATEGY = "collectfast.strategies.boto3.Boto3Strategy"
|
COLLECTFAST_STRATEGY = "collectfast.strategies.boto3.Boto3Strategy"
|
||||||
STATIC_URL = f"https://{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com/static/"
|
STATIC_URL = f"https://{aws_s3_domain}/static/"
|
||||||
{% elif cookiecutter.cloud_provider == 'GCP' -%}
|
{% elif cookiecutter.cloud_provider == 'GCP' -%}
|
||||||
STATICFILES_STORAGE = "{{cookiecutter.project_slug}}.utils.storages.StaticRootGoogleCloudStorage"
|
STATICFILES_STORAGE = "{{cookiecutter.project_slug}}.utils.storages.StaticRootGoogleCloudStorage"
|
||||||
COLLECTFAST_STRATEGY = "collectfast.strategies.gcloud.GoogleCloudStrategy"
|
COLLECTFAST_STRATEGY = "collectfast.strategies.gcloud.GoogleCloudStrategy"
|
||||||
|
@ -115,7 +118,7 @@ STATIC_URL = f"https://storage.googleapis.com/{GS_BUCKET_NAME}/static/"
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
{%- if cookiecutter.cloud_provider == 'AWS' %}
|
{%- if cookiecutter.cloud_provider == 'AWS' %}
|
||||||
DEFAULT_FILE_STORAGE = "{{cookiecutter.project_slug}}.utils.storages.MediaRootS3Boto3Storage"
|
DEFAULT_FILE_STORAGE = "{{cookiecutter.project_slug}}.utils.storages.MediaRootS3Boto3Storage"
|
||||||
MEDIA_URL = f"https://{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com/media/"
|
MEDIA_URL = f"https://{aws_s3_domain}/media/"
|
||||||
{%- elif cookiecutter.cloud_provider == 'GCP' %}
|
{%- elif cookiecutter.cloud_provider == 'GCP' %}
|
||||||
DEFAULT_FILE_STORAGE = "{{cookiecutter.project_slug}}.utils.storages.MediaRootGoogleCloudStorage"
|
DEFAULT_FILE_STORAGE = "{{cookiecutter.project_slug}}.utils.storages.MediaRootGoogleCloudStorage"
|
||||||
MEDIA_URL = f"https://storage.googleapis.com/{GS_BUCKET_NAME}/media/"
|
MEDIA_URL = f"https://storage.googleapis.com/{GS_BUCKET_NAME}/media/"
|
||||||
|
|
|
@ -21,8 +21,8 @@ from django.core.wsgi import get_wsgi_application
|
||||||
|
|
||||||
# This allows easy placement of apps within the interior
|
# This allows easy placement of apps within the interior
|
||||||
# {{ cookiecutter.project_slug }} directory.
|
# {{ cookiecutter.project_slug }} directory.
|
||||||
app_path = Path(__file__).parents[1].resolve()
|
ROOT_DIR = Path(__file__).resolve(strict=True).parent.parent
|
||||||
sys.path.append(str(app_path / "{{ cookiecutter.project_slug }}"))
|
sys.path.append(str(ROOT_DIR / "{{ cookiecutter.project_slug }}"))
|
||||||
# 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
|
||||||
|
|
|
@ -10,6 +10,7 @@ services:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: ./compose/local/django/Dockerfile
|
dockerfile: ./compose/local/django/Dockerfile
|
||||||
image: {{ cookiecutter.project_slug }}_local_django
|
image: {{ cookiecutter.project_slug }}_local_django
|
||||||
|
container_name: django
|
||||||
depends_on:
|
depends_on:
|
||||||
- postgres
|
- postgres
|
||||||
{%- if cookiecutter.use_mailhog == 'y' %}
|
{%- if cookiecutter.use_mailhog == 'y' %}
|
||||||
|
@ -29,6 +30,7 @@ services:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: ./compose/production/postgres/Dockerfile
|
dockerfile: ./compose/production/postgres/Dockerfile
|
||||||
image: {{ cookiecutter.project_slug }}_production_postgres
|
image: {{ cookiecutter.project_slug }}_production_postgres
|
||||||
|
container_name: postgres
|
||||||
volumes:
|
volumes:
|
||||||
- local_postgres_data:/var/lib/postgresql/data
|
- local_postgres_data:/var/lib/postgresql/data
|
||||||
- local_postgres_data_backups:/backups
|
- local_postgres_data_backups:/backups
|
||||||
|
@ -54,6 +56,7 @@ services:
|
||||||
|
|
||||||
mailhog:
|
mailhog:
|
||||||
image: mailhog/mailhog:v1.0.0
|
image: mailhog/mailhog:v1.0.0
|
||||||
|
container_name: mailhog
|
||||||
ports:
|
ports:
|
||||||
- "8025:8025"
|
- "8025:8025"
|
||||||
|
|
||||||
|
@ -62,10 +65,12 @@ services:
|
||||||
|
|
||||||
redis:
|
redis:
|
||||||
image: redis:5.0
|
image: redis:5.0
|
||||||
|
container_name: redis
|
||||||
|
|
||||||
celeryworker:
|
celeryworker:
|
||||||
<<: *django
|
<<: *django
|
||||||
image: {{ cookiecutter.project_slug }}_local_celeryworker
|
image: {{ cookiecutter.project_slug }}_local_celeryworker
|
||||||
|
container_name: celeryworker
|
||||||
depends_on:
|
depends_on:
|
||||||
- redis
|
- redis
|
||||||
- postgres
|
- postgres
|
||||||
|
@ -78,6 +83,7 @@ services:
|
||||||
celerybeat:
|
celerybeat:
|
||||||
<<: *django
|
<<: *django
|
||||||
image: {{ cookiecutter.project_slug }}_local_celerybeat
|
image: {{ cookiecutter.project_slug }}_local_celerybeat
|
||||||
|
container_name: celerybeat
|
||||||
depends_on:
|
depends_on:
|
||||||
- redis
|
- redis
|
||||||
- postgres
|
- postgres
|
||||||
|
@ -90,6 +96,7 @@ services:
|
||||||
flower:
|
flower:
|
||||||
<<: *django
|
<<: *django
|
||||||
image: {{ cookiecutter.project_slug }}_local_flower
|
image: {{ cookiecutter.project_slug }}_local_flower
|
||||||
|
container_name: flower
|
||||||
ports:
|
ports:
|
||||||
- "5555:5555"
|
- "5555:5555"
|
||||||
command: /start-flower
|
command: /start-flower
|
||||||
|
@ -102,6 +109,7 @@ services:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: ./compose/local/node/Dockerfile
|
dockerfile: ./compose/local/node/Dockerfile
|
||||||
image: {{ cookiecutter.project_slug }}_local_node
|
image: {{ cookiecutter.project_slug }}_local_node
|
||||||
|
container_name: node
|
||||||
depends_on:
|
depends_on:
|
||||||
- django
|
- django
|
||||||
volumes:
|
volumes:
|
||||||
|
|
|
@ -1,37 +1,39 @@
|
||||||
pytz==2019.3 # https://github.com/stub42/pytz
|
pytz==2020.1 # https://github.com/stub42/pytz
|
||||||
python-slugify==4.0.0 # https://github.com/un33k/python-slugify
|
python-slugify==4.0.0 # https://github.com/un33k/python-slugify
|
||||||
Pillow==7.1.1 # https://github.com/python-pillow/Pillow
|
Pillow==7.1.2 # https://github.com/python-pillow/Pillow
|
||||||
{%- if cookiecutter.use_compressor == "y" %}
|
{%- if cookiecutter.use_compressor == "y" %}
|
||||||
rcssmin==1.0.6{% if cookiecutter.windows == 'y' and cookiecutter.use_docker == 'n' %} --install-option="--without-c-extensions"{% endif %} # https://github.com/ndparker/rcssmin
|
rcssmin==1.0.6{% if cookiecutter.windows == 'y' and cookiecutter.use_docker == 'n' %} --install-option="--without-c-extensions"{% endif %} # https://github.com/ndparker/rcssmin
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
argon2-cffi==19.2.0 # https://github.com/hynek/argon2_cffi
|
argon2-cffi==20.1.0 # https://github.com/hynek/argon2_cffi
|
||||||
{%- if cookiecutter.use_whitenoise == 'y' %}
|
{%- if cookiecutter.use_whitenoise == 'y' %}
|
||||||
whitenoise==5.0.1 # https://github.com/evansd/whitenoise
|
whitenoise==5.1.0 # https://github.com/evansd/whitenoise
|
||||||
|
{%- endif %}
|
||||||
|
redis==3.5.0 # https://github.com/andymccurdy/redis-py
|
||||||
|
{%- if cookiecutter.use_docker == "y" or cookiecutter.windows == "n" %}
|
||||||
|
hiredis==1.0.1 # https://github.com/redis/hiredis-py
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
redis==3.4.1 # https://github.com/andymccurdy/redis-py
|
|
||||||
{%- if cookiecutter.use_celery == "y" %}
|
{%- if cookiecutter.use_celery == "y" %}
|
||||||
celery==4.4.2 # pyup: < 5.0 # https://github.com/celery/celery
|
celery==4.4.5 # pyup: < 5.0 # https://github.com/celery/celery
|
||||||
django-celery-beat==2.0.0 # https://github.com/celery/django-celery-beat
|
django-celery-beat==2.0.0 # https://github.com/celery/django-celery-beat
|
||||||
{%- if cookiecutter.use_docker == 'y' %}
|
{%- if cookiecutter.use_docker == 'y' %}
|
||||||
flower==0.9.4 # https://github.com/mher/flower
|
flower==0.9.4 # https://github.com/mher/flower
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{%- if cookiecutter.use_async == 'y' %}
|
{%- if cookiecutter.use_async == 'y' %}
|
||||||
uvicorn==0.11.3 # https://github.com/encode/uvicorn
|
uvicorn==0.11.5 # https://github.com/encode/uvicorn
|
||||||
gunicorn==20.0.4 # https://github.com/benoitc/gunicorn
|
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
||||||
# Django
|
# Django
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
django==3.0.5 # pyup: < 3.1 # https://www.djangoproject.com/
|
django==3.0.7 # pyup: < 3.1 # https://www.djangoproject.com/
|
||||||
django-environ==0.4.5 # https://github.com/joke2k/django-environ
|
django-environ==0.4.5 # https://github.com/joke2k/django-environ
|
||||||
django-model-utils==4.0.0 # https://github.com/jazzband/django-model-utils
|
django-model-utils==4.0.0 # https://github.com/jazzband/django-model-utils
|
||||||
django-allauth==0.41.0 # https://github.com/pennersr/django-allauth
|
django-allauth==0.42.0 # https://github.com/pennersr/django-allauth
|
||||||
django-crispy-forms==1.9.0 # https://github.com/django-crispy-forms/django-crispy-forms
|
django-crispy-forms==1.9.1 # https://github.com/django-crispy-forms/django-crispy-forms
|
||||||
{%- if cookiecutter.use_compressor == "y" %}
|
{%- if cookiecutter.use_compressor == "y" %}
|
||||||
django-compressor==2.4 # https://github.com/django-compressor/django-compressor
|
django-compressor==2.4 # https://github.com/django-compressor/django-compressor
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
django-redis==4.11.0 # https://github.com/niwinz/django-redis
|
django-redis==4.12.1 # https://github.com/jazzband/django-redis
|
||||||
{%- if cookiecutter.use_drf == "y" %}
|
{%- if cookiecutter.use_drf == "y" %}
|
||||||
# Django REST Framework
|
# Django REST Framework
|
||||||
djangorestframework==3.11.0 # https://github.com/encode/django-rest-framework
|
djangorestframework==3.11.0 # https://github.com/encode/django-rest-framework
|
||||||
|
|
|
@ -1,28 +1,31 @@
|
||||||
-r ./base.txt
|
-r ./base.txt
|
||||||
|
|
||||||
Werkzeug==1.0.1 # https://github.com/pallets/werkzeug
|
Werkzeug==1.0.1 # https://github.com/pallets/werkzeug
|
||||||
ipdb==0.13.2 # https://github.com/gotcha/ipdb
|
ipdb==0.13.3 # https://github.com/gotcha/ipdb
|
||||||
{%- if cookiecutter.use_docker == 'y' %}
|
{%- if cookiecutter.use_docker == 'y' %}
|
||||||
psycopg2==2.8.5 --no-binary psycopg2 # https://github.com/psycopg/psycopg2
|
psycopg2==2.8.5 --no-binary psycopg2 # https://github.com/psycopg/psycopg2
|
||||||
{%- else %}
|
{%- else %}
|
||||||
psycopg2-binary==2.8.5 # https://github.com/psycopg/psycopg2
|
psycopg2-binary==2.8.5 # https://github.com/psycopg/psycopg2
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
{%- if cookiecutter.use_async == 'y' %}
|
||||||
|
watchgod==0.6 # https://github.com/samuelcolvin/watchgod
|
||||||
|
{%- endif %}
|
||||||
|
|
||||||
# Testing
|
# Testing
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
mypy==0.770 # https://github.com/python/mypy
|
mypy==0.782 # https://github.com/python/mypy
|
||||||
django-stubs==1.5.0 # https://github.com/typeddjango/django-stubs
|
django-stubs==1.5.0 # https://github.com/typeddjango/django-stubs
|
||||||
pytest==5.3.5 # https://github.com/pytest-dev/pytest
|
pytest==5.4.3 # https://github.com/pytest-dev/pytest
|
||||||
pytest-sugar==0.9.2 # https://github.com/Frozenball/pytest-sugar
|
pytest-sugar==0.9.3 # https://github.com/Frozenball/pytest-sugar
|
||||||
|
|
||||||
# Documentation
|
# Documentation
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
sphinx==3.0.2 # https://github.com/sphinx-doc/sphinx
|
sphinx==3.1.1 # https://github.com/sphinx-doc/sphinx
|
||||||
sphinx-autobuild # https://github.com/GaretJax/sphinx-autobuild
|
sphinx-autobuild # https://github.com/GaretJax/sphinx-autobuild
|
||||||
|
|
||||||
# Code quality
|
# Code quality
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
flake8==3.7.9 # https://github.com/PyCQA/flake8
|
flake8==3.8.3 # https://github.com/PyCQA/flake8
|
||||||
flake8-isort==3.0.0 # https://github.com/gforcada/flake8-isort
|
flake8-isort==3.0.0 # https://github.com/gforcada/flake8-isort
|
||||||
coverage==5.1 # https://github.com/nedbat/coveragepy
|
coverage==5.1 # https://github.com/nedbat/coveragepy
|
||||||
black==19.10b0 # https://github.com/ambv/black
|
black==19.10b0 # https://github.com/ambv/black
|
||||||
|
@ -30,13 +33,13 @@ pylint-django==2.0.15 # https://github.com/PyCQA/pylint-django
|
||||||
{%- if cookiecutter.use_celery == 'y' %}
|
{%- if cookiecutter.use_celery == 'y' %}
|
||||||
pylint-celery==0.3 # https://github.com/PyCQA/pylint-celery
|
pylint-celery==0.3 # https://github.com/PyCQA/pylint-celery
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
pre-commit==2.3.0 # https://github.com/pre-commit/pre-commit
|
pre-commit==2.5.1 # https://github.com/pre-commit/pre-commit
|
||||||
|
|
||||||
# Django
|
# Django
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
factory-boy==2.12.0 # https://github.com/FactoryBoy/factory_boy
|
factory-boy==2.12.0 # https://github.com/FactoryBoy/factory_boy
|
||||||
|
|
||||||
django-debug-toolbar==2.2 # https://github.com/jazzband/django-debug-toolbar
|
django-debug-toolbar==2.2 # https://github.com/jazzband/django-debug-toolbar
|
||||||
django-extensions==2.2.9 # https://github.com/django-extensions/django-extensions
|
django-extensions==3.0.0 # https://github.com/django-extensions/django-extensions
|
||||||
django-coverage-plugin==1.8.0 # https://github.com/nedbat/django_coverage_plugin
|
django-coverage-plugin==1.8.0 # https://github.com/nedbat/django_coverage_plugin
|
||||||
pytest-django==3.9.0 # https://github.com/pytest-dev/pytest-django
|
pytest-django==3.9.0 # https://github.com/pytest-dev/pytest-django
|
||||||
|
|
|
@ -2,15 +2,16 @@
|
||||||
|
|
||||||
-r ./base.txt
|
-r ./base.txt
|
||||||
|
|
||||||
{%- if cookiecutter.use_async == 'n' %}
|
|
||||||
gunicorn==20.0.4 # https://github.com/benoitc/gunicorn
|
gunicorn==20.0.4 # https://github.com/benoitc/gunicorn
|
||||||
{%- endif %}
|
|
||||||
psycopg2==2.8.5 --no-binary psycopg2 # https://github.com/psycopg/psycopg2
|
psycopg2==2.8.5 --no-binary psycopg2 # https://github.com/psycopg/psycopg2
|
||||||
{%- if cookiecutter.use_whitenoise == 'n' %}
|
{%- if cookiecutter.use_whitenoise == 'n' %}
|
||||||
Collectfast==2.1.0 # https://github.com/antonagestam/collectfast
|
Collectfast==2.2.0 # https://github.com/antonagestam/collectfast
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{%- if cookiecutter.use_sentry == "y" %}
|
{%- if cookiecutter.use_sentry == "y" %}
|
||||||
sentry-sdk==0.14.3 # https://github.com/getsentry/sentry-python
|
sentry-sdk==0.15.1 # https://github.com/getsentry/sentry-python
|
||||||
|
{%- endif %}
|
||||||
|
{%- if cookiecutter.use_docker == "n" and cookiecutter.windows == "y" %}
|
||||||
|
hiredis==1.0.1 # https://github.com/redis/hiredis-py
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
||||||
# Django
|
# Django
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
|
from django.contrib.auth import get_user_model
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from {{ cookiecutter.project_slug }}.users.models import User
|
User = get_user_model()
|
||||||
|
|
||||||
|
|
||||||
class UserSerializer(serializers.ModelSerializer):
|
class UserSerializer(serializers.ModelSerializer):
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from django.contrib.auth import forms, get_user_model
|
from django.contrib.auth import forms, get_user_model
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
User = get_user_model()
|
User = get_user_model()
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
import pytest
|
||||||
|
from django.urls import resolve, reverse
|
||||||
|
|
||||||
|
from {{ cookiecutter.project_slug }}.users.models import User
|
||||||
|
|
||||||
|
pytestmark = pytest.mark.django_db
|
||||||
|
|
||||||
|
|
||||||
|
def test_user_detail(user: User):
|
||||||
|
assert (
|
||||||
|
reverse("api:user-detail", kwargs={"username": user.username})
|
||||||
|
== f"/api/users/{user.username}/"
|
||||||
|
)
|
||||||
|
assert resolve(f"/api/users/{user.username}/").view_name == "api:user-detail"
|
||||||
|
|
||||||
|
|
||||||
|
def test_user_list():
|
||||||
|
assert reverse("api:user-list") == "/api/users/"
|
||||||
|
assert resolve("/api/users/").view_name == "api:user-list"
|
||||||
|
|
||||||
|
|
||||||
|
def test_user_me():
|
||||||
|
assert reverse("api:user-me") == "/api/users/me/"
|
||||||
|
assert resolve("/api/users/me/").view_name == "api:user-me"
|
|
@ -0,0 +1,34 @@
|
||||||
|
import pytest
|
||||||
|
from django.test import RequestFactory
|
||||||
|
|
||||||
|
from {{ cookiecutter.project_slug }}.users.api.views import UserViewSet
|
||||||
|
from {{ cookiecutter.project_slug }}.users.models import User
|
||||||
|
|
||||||
|
pytestmark = pytest.mark.django_db
|
||||||
|
|
||||||
|
|
||||||
|
class TestUserViewSet:
|
||||||
|
def test_get_queryset(self, user: User, rf: RequestFactory):
|
||||||
|
view = UserViewSet()
|
||||||
|
request = rf.get("/fake-url/")
|
||||||
|
request.user = user
|
||||||
|
|
||||||
|
view.request = request
|
||||||
|
|
||||||
|
assert user in view.get_queryset()
|
||||||
|
|
||||||
|
def test_me(self, user: User, rf: RequestFactory):
|
||||||
|
view = UserViewSet()
|
||||||
|
request = rf.get("/fake-url/")
|
||||||
|
request.user = user
|
||||||
|
|
||||||
|
view.request = request
|
||||||
|
|
||||||
|
response = view.me(request)
|
||||||
|
|
||||||
|
assert response.data == {
|
||||||
|
"username": user.username,
|
||||||
|
"email": user.email,
|
||||||
|
"name": user.name,
|
||||||
|
"url": f"http://testserver/api/users/{user.username}/",
|
||||||
|
}
|
|
@ -1,8 +1,15 @@
|
||||||
import pytest
|
import pytest
|
||||||
|
from django.contrib.auth.models import AnonymousUser
|
||||||
|
from django.http.response import Http404
|
||||||
from django.test import RequestFactory
|
from django.test import RequestFactory
|
||||||
|
|
||||||
from {{ cookiecutter.project_slug }}.users.models import User
|
from {{ cookiecutter.project_slug }}.users.models import User
|
||||||
from {{ cookiecutter.project_slug }}.users.views import UserRedirectView, UserUpdateView
|
from {{ cookiecutter.project_slug }}.users.tests.factories import UserFactory
|
||||||
|
from {{ cookiecutter.project_slug }}.users.views import (
|
||||||
|
UserRedirectView,
|
||||||
|
UserUpdateView,
|
||||||
|
user_detail_view,
|
||||||
|
)
|
||||||
|
|
||||||
pytestmark = pytest.mark.django_db
|
pytestmark = pytest.mark.django_db
|
||||||
|
|
||||||
|
@ -44,3 +51,29 @@ class TestUserRedirectView:
|
||||||
view.request = request
|
view.request = request
|
||||||
|
|
||||||
assert view.get_redirect_url() == f"/users/{user.username}/"
|
assert view.get_redirect_url() == f"/users/{user.username}/"
|
||||||
|
|
||||||
|
|
||||||
|
class TestUserDetailView:
|
||||||
|
def test_authenticated(self, user: User, rf: RequestFactory):
|
||||||
|
request = rf.get("/fake-url/")
|
||||||
|
request.user = UserFactory()
|
||||||
|
|
||||||
|
response = user_detail_view(request, username=user.username)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
def test_not_authenticated(self, user: User, rf: RequestFactory):
|
||||||
|
request = rf.get("/fake-url/")
|
||||||
|
request.user = AnonymousUser() # type: ignore
|
||||||
|
|
||||||
|
response = user_detail_view(request, username=user.username)
|
||||||
|
|
||||||
|
assert response.status_code == 302
|
||||||
|
assert response.url == "/accounts/login/?next=/fake-url/"
|
||||||
|
|
||||||
|
def test_case_sensitivity(self, rf: RequestFactory):
|
||||||
|
request = rf.get("/fake-url/")
|
||||||
|
request.user = UserFactory(username="UserName")
|
||||||
|
|
||||||
|
with pytest.raises(Http404):
|
||||||
|
user_detail_view(request, username="username")
|
||||||
|
|
Loading…
Reference in New Issue
Block a user