mirror of
https://github.com/cookiecutter/cookiecutter-django.git
synced 2025-08-15 09:24:52 +03:00
Merge branch 'master' into email-only
This commit is contained in:
commit
deb1c1e8b6
80
.github/contributors.json
vendored
80
.github/contributors.json
vendored
|
@ -1302,5 +1302,85 @@
|
||||||
"name": "Abe Hanoka",
|
"name": "Abe Hanoka",
|
||||||
"github_login": "abe-101",
|
"github_login": "abe-101",
|
||||||
"twitter_username": "abe__101"
|
"twitter_username": "abe__101"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Adin Hodovic",
|
||||||
|
"github_login": "adinhodovic",
|
||||||
|
"twitter_username": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Leifur Halldor Asgeirsson",
|
||||||
|
"github_login": "leifurhauks",
|
||||||
|
"twitter_username": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "David",
|
||||||
|
"github_login": "buckldav",
|
||||||
|
"twitter_username": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "rguptar",
|
||||||
|
"github_login": "rguptar",
|
||||||
|
"twitter_username": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Omer-5",
|
||||||
|
"github_login": "Omer-5",
|
||||||
|
"twitter_username": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "TAKAHASHI Shuuji",
|
||||||
|
"github_login": "shuuji3",
|
||||||
|
"twitter_username": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Thomas Booij",
|
||||||
|
"github_login": "ThomasBooij95",
|
||||||
|
"twitter_username": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pamela Fox",
|
||||||
|
"github_login": "pamelafox",
|
||||||
|
"twitter_username": "pamelafox"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Robin",
|
||||||
|
"github_login": "Kaffeetasse",
|
||||||
|
"twitter_username": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Patrick Tran",
|
||||||
|
"github_login": "theptrk",
|
||||||
|
"twitter_username": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "tildebox",
|
||||||
|
"github_login": "tildebox",
|
||||||
|
"twitter_username": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "duffn",
|
||||||
|
"github_login": "duffn",
|
||||||
|
"twitter_username": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Delphine LEMIRE",
|
||||||
|
"github_login": "DelphineLemire",
|
||||||
|
"twitter_username": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Hoai-Thu Vuong",
|
||||||
|
"github_login": "thuvh",
|
||||||
|
"twitter_username": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Arkadiusz Michał Ryś",
|
||||||
|
"github_login": "arrys",
|
||||||
|
"twitter_username": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mpsantos",
|
||||||
|
"github_login": "mpsantos",
|
||||||
|
"twitter_username": ""
|
||||||
}
|
}
|
||||||
]
|
]
|
53
.github/dependabot.yml
vendored
53
.github/dependabot.yml
vendored
|
@ -18,3 +18,56 @@ updates:
|
||||||
interval: "daily"
|
interval: "daily"
|
||||||
labels:
|
labels:
|
||||||
- "update"
|
- "update"
|
||||||
|
|
||||||
|
# Enable version updates for Docker
|
||||||
|
# We need to specify each Dockerfile in a separate entry because Dependabot doesn't
|
||||||
|
# support wildcards or recursively checking subdirectories. Check this issue for updates:
|
||||||
|
# https://github.com/dependabot/dependabot-core/issues/2178
|
||||||
|
- package-ecosystem: "docker"
|
||||||
|
directory: "{{cookiecutter.project_slug}}/compose/local/django/"
|
||||||
|
schedule:
|
||||||
|
interval: "daily"
|
||||||
|
labels:
|
||||||
|
- "update"
|
||||||
|
|
||||||
|
- package-ecosystem: "docker"
|
||||||
|
directory: "{{cookiecutter.project_slug}}/compose/local/docs/"
|
||||||
|
schedule:
|
||||||
|
interval: "daily"
|
||||||
|
labels:
|
||||||
|
- "update"
|
||||||
|
|
||||||
|
- package-ecosystem: "docker"
|
||||||
|
directory: "{{cookiecutter.project_slug}}/compose/local/node/"
|
||||||
|
schedule:
|
||||||
|
interval: "daily"
|
||||||
|
labels:
|
||||||
|
- "update"
|
||||||
|
|
||||||
|
- package-ecosystem: "docker"
|
||||||
|
directory: "{{cookiecutter.project_slug}}/compose/production/aws/"
|
||||||
|
schedule:
|
||||||
|
interval: "daily"
|
||||||
|
labels:
|
||||||
|
- "update"
|
||||||
|
|
||||||
|
- package-ecosystem: "docker"
|
||||||
|
directory: "{{cookiecutter.project_slug}}/compose/production/django/"
|
||||||
|
schedule:
|
||||||
|
interval: "daily"
|
||||||
|
labels:
|
||||||
|
- "update"
|
||||||
|
|
||||||
|
- package-ecosystem: "docker"
|
||||||
|
directory: "{{cookiecutter.project_slug}}/compose/production/postgres/"
|
||||||
|
schedule:
|
||||||
|
interval: "daily"
|
||||||
|
labels:
|
||||||
|
- "update"
|
||||||
|
|
||||||
|
- package-ecosystem: "docker"
|
||||||
|
directory: "{{cookiecutter.project_slug}}/compose/production/traefik/"
|
||||||
|
schedule:
|
||||||
|
interval: "daily"
|
||||||
|
labels:
|
||||||
|
- "update"
|
||||||
|
|
34
.github/workflows/ci.yml
vendored
34
.github/workflows/ci.yml
vendored
|
@ -2,6 +2,7 @@ name: CI
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
|
branches: [ "master", "main" ]
|
||||||
pull_request:
|
pull_request:
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
|
@ -9,17 +10,6 @@ concurrency:
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
lint:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-python@v4
|
|
||||||
with:
|
|
||||||
python-version: "3.10"
|
|
||||||
cache: pip
|
|
||||||
- name: Run pre-commit
|
|
||||||
uses: pre-commit/action@v3.0.0
|
|
||||||
|
|
||||||
tests:
|
tests:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
|
@ -29,7 +19,7 @@ jobs:
|
||||||
- windows-latest
|
- windows-latest
|
||||||
- macOS-latest
|
- macOS-latest
|
||||||
|
|
||||||
name: "Run tests"
|
name: "pytest ${{ matrix.os }}"
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
@ -49,10 +39,14 @@ jobs:
|
||||||
script:
|
script:
|
||||||
- name: Basic
|
- name: Basic
|
||||||
args: ""
|
args: ""
|
||||||
- name: Extended
|
- name: Celery & DRF
|
||||||
args: "use_celery=y use_drf=y frontend_pipeline=Gulp"
|
args: "use_celery=y use_drf=y"
|
||||||
|
- name: Gulp
|
||||||
|
args: "frontend_pipeline=Gulp"
|
||||||
|
- name: Webpack
|
||||||
|
args: "frontend_pipeline=Webpack"
|
||||||
|
|
||||||
name: "${{ matrix.script.name }} Docker"
|
name: "Docker ${{ matrix.script.name }}"
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
env:
|
env:
|
||||||
DOCKER_BUILDKIT: 1
|
DOCKER_BUILDKIT: 1
|
||||||
|
@ -74,12 +68,14 @@ jobs:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
script:
|
script:
|
||||||
- name: With Celery
|
- name: Celery
|
||||||
args: "use_celery=y frontend_pipeline='Django Compressor'"
|
args: "use_celery=y frontend_pipeline='Django Compressor'"
|
||||||
- name: With Gulp
|
- name: Gulp
|
||||||
args: "frontend_pipeline='Gulp'"
|
args: "frontend_pipeline=Gulp"
|
||||||
|
- name: Webpack
|
||||||
|
args: "frontend_pipeline=Webpack"
|
||||||
|
|
||||||
name: "${{ matrix.script.name }} Bare metal"
|
name: "Bare metal ${{ matrix.script.name }}"
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
services:
|
services:
|
||||||
redis:
|
redis:
|
||||||
|
|
4
.github/workflows/update-contributors.yml
vendored
4
.github/workflows/update-contributors.yml
vendored
|
@ -29,9 +29,11 @@ jobs:
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
- name: Update list
|
- name: Update list
|
||||||
run: python scripts/update_contributors.py
|
run: python scripts/update_contributors.py
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Commit changes
|
- name: Commit changes
|
||||||
uses: stefanzweifel/git-auto-commit-action@v4.15.3
|
uses: stefanzweifel/git-auto-commit-action@v4.16.0
|
||||||
with:
|
with:
|
||||||
commit_message: Update Contributors
|
commit_message: Update Contributors
|
||||||
file_pattern: CONTRIBUTORS.md .github/contributors.json
|
file_pattern: CONTRIBUTORS.md .github/contributors.json
|
||||||
|
|
|
@ -3,30 +3,30 @@ default_stages: [commit]
|
||||||
|
|
||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
rev: v4.3.0
|
rev: v4.4.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: trailing-whitespace
|
- id: trailing-whitespace
|
||||||
- id: check-yaml
|
- id: check-yaml
|
||||||
|
|
||||||
- repo: https://github.com/asottile/pyupgrade
|
- repo: https://github.com/asottile/pyupgrade
|
||||||
rev: v3.2.2
|
rev: v3.3.1
|
||||||
hooks:
|
hooks:
|
||||||
- id: pyupgrade
|
- id: pyupgrade
|
||||||
args: [--py310-plus]
|
args: [--py310-plus]
|
||||||
exclude: hooks/
|
exclude: hooks/
|
||||||
|
|
||||||
- repo: https://github.com/psf/black
|
- repo: https://github.com/psf/black
|
||||||
rev: 22.10.0
|
rev: 23.1.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: black
|
- id: black
|
||||||
|
|
||||||
- repo: https://github.com/PyCQA/isort
|
- repo: https://github.com/PyCQA/isort
|
||||||
rev: 5.10.1
|
rev: 5.12.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: isort
|
- id: isort
|
||||||
|
|
||||||
- repo: https://github.com/PyCQA/flake8
|
- repo: https://github.com/PyCQA/flake8
|
||||||
rev: 5.0.4
|
rev: 6.0.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: flake8
|
- id: flake8
|
||||||
|
|
||||||
|
|
406
CHANGELOG.md
406
CHANGELOG.md
|
@ -3,6 +3,412 @@ All enhancements and patches to Cookiecutter Django will be documented in this f
|
||||||
|
|
||||||
<!-- GENERATOR_PLACEHOLDER -->
|
<!-- GENERATOR_PLACEHOLDER -->
|
||||||
|
|
||||||
|
## 2023.03.09
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Fix the omit configuration for coverage ([#4201](https://github.com/cookiecutter/cookiecutter-django/pull/4201))
|
||||||
|
### Updated
|
||||||
|
- Update ipdb to 0.13.13 ([#4202](https://github.com/cookiecutter/cookiecutter-django/pull/4202))
|
||||||
|
|
||||||
|
## 2023.03.07
|
||||||
|
|
||||||
|
### Updated
|
||||||
|
- Update mypy to 1.1.1 ([#4196](https://github.com/cookiecutter/cookiecutter-django/pull/4196))
|
||||||
|
- Update django-environ to 0.10.0 ([#4195](https://github.com/cookiecutter/cookiecutter-django/pull/4195))
|
||||||
|
|
||||||
|
## 2023.03.04
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Add option to serve media files locally using nginx ([#2457](https://github.com/cookiecutter/cookiecutter-django/pull/2457))
|
||||||
|
### Documentation
|
||||||
|
- Include contributing page to the docs ([#4144](https://github.com/cookiecutter/cookiecutter-django/pull/4144))
|
||||||
|
### Updated
|
||||||
|
- Update myst-parser to 0.19.1 ([#4193](https://github.com/cookiecutter/cookiecutter-django/pull/4193))
|
||||||
|
- Update pytest to 7.2.2 ([#4191](https://github.com/cookiecutter/cookiecutter-django/pull/4191))
|
||||||
|
- Update drf-spectacular to 0.26.0 ([#4192](https://github.com/cookiecutter/cookiecutter-django/pull/4192))
|
||||||
|
|
||||||
|
## 2023.02.28
|
||||||
|
|
||||||
|
### Updated
|
||||||
|
- Update pre-commit to 3.1.1 ([#4188](https://github.com/cookiecutter/cookiecutter-django/pull/4188))
|
||||||
|
|
||||||
|
## 2023.02.27
|
||||||
|
|
||||||
|
### Updated
|
||||||
|
- Update sentry-sdk to 1.16.0 ([#4187](https://github.com/cookiecutter/cookiecutter-django/pull/4187))
|
||||||
|
|
||||||
|
## 2023.02.26
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Fix readthedocs config file for generated project ([#4172](https://github.com/cookiecutter/cookiecutter-django/pull/4172))
|
||||||
|
### Updated
|
||||||
|
- Bump traefik from v2.2.11 to 2.9.8 ([#4164](https://github.com/cookiecutter/cookiecutter-django/pull/4164))
|
||||||
|
- Update coverage to 7.2.1 ([#4186](https://github.com/cookiecutter/cookiecutter-django/pull/4186))
|
||||||
|
|
||||||
|
## 2023.02.25
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Run linting with pre-commit on GitLab ([#4150](https://github.com/cookiecutter/cookiecutter-django/pull/4150))
|
||||||
|
### Fixed
|
||||||
|
- Disable caching for linter job on GitHub actions ([#4166](https://github.com/cookiecutter/cookiecutter-django/pull/4166))
|
||||||
|
### Documentation
|
||||||
|
- Add instuction to run celery beat ([#4162](https://github.com/cookiecutter/cookiecutter-django/pull/4162))
|
||||||
|
### Updated
|
||||||
|
- Bump garland/aws-cli-docker from 1.15.47 to 1.16.140 ([#4136](https://github.com/cookiecutter/cookiecutter-django/pull/4136))
|
||||||
|
- Update djangorestframework-stubs to 1.9.1 ([#4184](https://github.com/cookiecutter/cookiecutter-django/pull/4184))
|
||||||
|
- Update whitenoise to 6.4.0 ([#4180](https://github.com/cookiecutter/cookiecutter-django/pull/4180))
|
||||||
|
- Update django-stubs to 1.15.0 ([#4183](https://github.com/cookiecutter/cookiecutter-django/pull/4183))
|
||||||
|
- Update django-crispy-forms to 2.0 ([#4158](https://github.com/cookiecutter/cookiecutter-django/pull/4158))
|
||||||
|
- Update django-cors-headers to 3.14.0 ([#4181](https://github.com/cookiecutter/cookiecutter-django/pull/4181))
|
||||||
|
- Update python-slugify to 8.0.1 ([#4178](https://github.com/cookiecutter/cookiecutter-django/pull/4178))
|
||||||
|
- Update pre-commit to 3.1.0 ([#4176](https://github.com/cookiecutter/cookiecutter-django/pull/4176))
|
||||||
|
- Update mypy to 1.0.1 ([#4168](https://github.com/cookiecutter/cookiecutter-django/pull/4168))
|
||||||
|
- Update werkzeug to 2.2.3 ([#4160](https://github.com/cookiecutter/cookiecutter-django/pull/4160))
|
||||||
|
- Update coverage to 7.2.0 ([#4177](https://github.com/cookiecutter/cookiecutter-django/pull/4177))
|
||||||
|
- Update django to 4.0.10 ([#4159](https://github.com/cookiecutter/cookiecutter-django/pull/4159))
|
||||||
|
- Update hiredis to 2.2.2 ([#4156](https://github.com/cookiecutter/cookiecutter-django/pull/4156))
|
||||||
|
|
||||||
|
## 2023.02.17
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Update version of github actions on the template project ([#4167](https://github.com/cookiecutter/cookiecutter-django/pull/4167))
|
||||||
|
|
||||||
|
## 2023.02.09
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Remove unused pip cache paths in GHA & add a note for pre-commit.ci ([#4151](https://github.com/cookiecutter/cookiecutter-django/pull/4151))
|
||||||
|
### Updated
|
||||||
|
- Update mypy to 0.991 ([#4106](https://github.com/cookiecutter/cookiecutter-django/pull/4106))
|
||||||
|
|
||||||
|
## 2023.02.08
|
||||||
|
|
||||||
|
### Updated
|
||||||
|
- Update sphinx to 6.1.3 ([#4148](https://github.com/cookiecutter/cookiecutter-django/pull/4148))
|
||||||
|
- Update redis to 4.5.1 ([#4147](https://github.com/cookiecutter/cookiecutter-django/pull/4147))
|
||||||
|
|
||||||
|
## 2023.02.07
|
||||||
|
|
||||||
|
### Updated
|
||||||
|
- Bump postcss-preset-env from 7.8.3 to 8.0.1 ([#4115](https://github.com/cookiecutter/cookiecutter-django/pull/4115))
|
||||||
|
- Bump sass-loader from 12.6.0 to 13.2.0 ([#4116](https://github.com/cookiecutter/cookiecutter-django/pull/4116))
|
||||||
|
- Bump babel-loader from 8.3.0 to 9.1.2 ([#4117](https://github.com/cookiecutter/cookiecutter-django/pull/4117))
|
||||||
|
- Bump postcss-loader from 6.2.1 to 7.0.2 ([#4114](https://github.com/cookiecutter/cookiecutter-django/pull/4114))
|
||||||
|
- Bump webpack-cli from 4.10.0 to 5.0.1 ([#4118](https://github.com/cookiecutter/cookiecutter-django/pull/4118))
|
||||||
|
- Update redis to 4.5.0 ([#4142](https://github.com/cookiecutter/cookiecutter-django/pull/4142))
|
||||||
|
- Update sentry-sdk to 1.15.0 ([#4141](https://github.com/cookiecutter/cookiecutter-django/pull/4141))
|
||||||
|
|
||||||
|
## 2023.02.06
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Change `RequestFactory` to `APIRequestFactory` in tests for API views ([#4110](https://github.com/cookiecutter/cookiecutter-django/pull/4110))
|
||||||
|
### Fixed
|
||||||
|
- Fix django-webpack-loader setup when running tests ([#4128](https://github.com/cookiecutter/cookiecutter-django/pull/4128))
|
||||||
|
### Documentation
|
||||||
|
- Added AWS ECS Full Deployment Article to README ([#2630](https://github.com/cookiecutter/cookiecutter-django/pull/2630))
|
||||||
|
### Updated
|
||||||
|
- Update hiredis to 2.2.1 ([#4123](https://github.com/cookiecutter/cookiecutter-django/pull/4123))
|
||||||
|
- Update tox to 4.4.4 ([#4133](https://github.com/cookiecutter/cookiecutter-django/pull/4133))
|
||||||
|
- Update django to 4.0.9 ([#4134](https://github.com/cookiecutter/cookiecutter-django/pull/4134))
|
||||||
|
- Update django-webpack-loader to 1.8.1 ([#4132](https://github.com/cookiecutter/cookiecutter-django/pull/4132))
|
||||||
|
|
||||||
|
## 2023.02.05
|
||||||
|
|
||||||
|
### Documentation
|
||||||
|
- Add note about which service to request when running locally with Docker & Webpack or Gulp ([#4130](https://github.com/cookiecutter/cookiecutter-django/pull/4130))
|
||||||
|
|
||||||
|
## 2023.02.03
|
||||||
|
|
||||||
|
### Updated
|
||||||
|
- Update pre-commit to 3.0.4 ([#4127](https://github.com/cookiecutter/cookiecutter-django/pull/4127))
|
||||||
|
|
||||||
|
## 2023.02.02
|
||||||
|
|
||||||
|
### Updated
|
||||||
|
- Update python-slugify to 8.0.0 ([#4111](https://github.com/cookiecutter/cookiecutter-django/pull/4111))
|
||||||
|
- Update pre-commit to 3.0.3 ([#4121](https://github.com/cookiecutter/cookiecutter-django/pull/4121))
|
||||||
|
- Update black to 23.1.0 ([#4120](https://github.com/cookiecutter/cookiecutter-django/pull/4120))
|
||||||
|
- Update black pre-commit hook ([#4122](https://github.com/cookiecutter/cookiecutter-django/pull/4122))
|
||||||
|
|
||||||
|
## 2023.01.29
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Add Webpack support ([#3623](https://github.com/cookiecutter/cookiecutter-django/pull/3623))
|
||||||
|
- Remove `BrokenLinkEmailsMiddleware` ([#4112](https://github.com/cookiecutter/cookiecutter-django/pull/4112))
|
||||||
|
|
||||||
|
## 2023.01.28
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Refactor `merge_production_dotenvs_in_dotenv.py` ([#4105](https://github.com/cookiecutter/cookiecutter-django/pull/4105))
|
||||||
|
### Updated
|
||||||
|
- Update isort to 5.12.0 ([#4109](https://github.com/cookiecutter/cookiecutter-django/pull/4109))
|
||||||
|
- Auto-update pre-commit hooks ([#4108](https://github.com/cookiecutter/cookiecutter-django/pull/4108))
|
||||||
|
|
||||||
|
## 2023.01.27
|
||||||
|
|
||||||
|
### Updated
|
||||||
|
- Update django-stubs to 1.14.0 ([#4103](https://github.com/cookiecutter/cookiecutter-django/pull/4103))
|
||||||
|
|
||||||
|
## 2023.01.26
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Rename BASE_DIR_PATH to BASE_DIR ([#4102](https://github.com/cookiecutter/cookiecutter-django/pull/4102))
|
||||||
|
### Updated
|
||||||
|
- Update pre-commit to 3.0.1 ([#4104](https://github.com/cookiecutter/cookiecutter-django/pull/4104))
|
||||||
|
- Update tox to 4.4.2 ([#4101](https://github.com/cookiecutter/cookiecutter-django/pull/4101))
|
||||||
|
|
||||||
|
## 2023.01.25
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Rename ROOT_DIR to BASE_DIR ([#4086](https://github.com/cookiecutter/cookiecutter-django/pull/4086))
|
||||||
|
- Update postgres and redis to point to mini tiers ([#4099](https://github.com/cookiecutter/cookiecutter-django/pull/4099))
|
||||||
|
### Updated
|
||||||
|
- Update coverage to 7.1.0 ([#4100](https://github.com/cookiecutter/cookiecutter-django/pull/4100))
|
||||||
|
|
||||||
|
## 2023.01.24
|
||||||
|
|
||||||
|
### Updated
|
||||||
|
- Update pre-commit to 3.0.0 ([#4098](https://github.com/cookiecutter/cookiecutter-django/pull/4098))
|
||||||
|
|
||||||
|
## 2023.01.23
|
||||||
|
|
||||||
|
### Updated
|
||||||
|
- Update sentry-sdk to 1.14.0 ([#4096](https://github.com/cookiecutter/cookiecutter-django/pull/4096))
|
||||||
|
|
||||||
|
## 2023.01.22
|
||||||
|
|
||||||
|
### Updated
|
||||||
|
- Update django-compressor to 4.3.1 ([#4094](https://github.com/cookiecutter/cookiecutter-django/pull/4094))
|
||||||
|
|
||||||
|
## 2023.01.21
|
||||||
|
|
||||||
|
### Updated
|
||||||
|
- Update django-stubs to 1.13.2 ([#4093](https://github.com/cookiecutter/cookiecutter-django/pull/4093))
|
||||||
|
|
||||||
|
## 2023.01.19
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Add sourcemaps support to Gulp ([#4089](https://github.com/cookiecutter/cookiecutter-django/pull/4089))
|
||||||
|
### Updated
|
||||||
|
- Update coverage to 7.0.5 ([#4092](https://github.com/cookiecutter/cookiecutter-django/pull/4092))
|
||||||
|
- Update redis to 4.4.2 ([#4091](https://github.com/cookiecutter/cookiecutter-django/pull/4091))
|
||||||
|
- Update requests to 2.28.2 ([#4090](https://github.com/cookiecutter/cookiecutter-django/pull/4090))
|
||||||
|
- Update tox to 4.3.5 ([#4087](https://github.com/cookiecutter/cookiecutter-django/pull/4087))
|
||||||
|
|
||||||
|
## 2023.01.17
|
||||||
|
|
||||||
|
### Updated
|
||||||
|
- Update tox to 4.3.3 ([#4081](https://github.com/cookiecutter/cookiecutter-django/pull/4081))
|
||||||
|
|
||||||
|
## 2023.01.15
|
||||||
|
|
||||||
|
### Updated
|
||||||
|
- Update pytest to 7.2.1 ([#4077](https://github.com/cookiecutter/cookiecutter-django/pull/4077))
|
||||||
|
- Update pytz to 2022.7.1 ([#4078](https://github.com/cookiecutter/cookiecutter-django/pull/4078))
|
||||||
|
|
||||||
|
## 2023.01.12
|
||||||
|
|
||||||
|
### Updated
|
||||||
|
- Update sentry-sdk to 1.13.0 ([#4074](https://github.com/cookiecutter/cookiecutter-django/pull/4074))
|
||||||
|
|
||||||
|
## 2023.01.11
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Update Celery instructions in the documentation ([#4061](https://github.com/cookiecutter/cookiecutter-django/pull/4061))
|
||||||
|
### Updated
|
||||||
|
- Update tox to 4.2.7 ([#4073](https://github.com/cookiecutter/cookiecutter-django/pull/4073))
|
||||||
|
|
||||||
|
## 2023.01.10
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Add dump.rdb to gitignore ([#4062](https://github.com/cookiecutter/cookiecutter-django/pull/4062))
|
||||||
|
### Fixed
|
||||||
|
- Exclude `.venv` from code style checks ([#4069](https://github.com/cookiecutter/cookiecutter-django/pull/4069))
|
||||||
|
### Updated
|
||||||
|
- Update hiredis to 2.1.1 ([#4070](https://github.com/cookiecutter/cookiecutter-django/pull/4070))
|
||||||
|
|
||||||
|
## 2023.01.08
|
||||||
|
|
||||||
|
### Updated
|
||||||
|
- Update redis to 4.4.1 ([#4068](https://github.com/cookiecutter/cookiecutter-django/pull/4068))
|
||||||
|
- Update coverage to 7.0.4 ([#4067](https://github.com/cookiecutter/cookiecutter-django/pull/4067))
|
||||||
|
|
||||||
|
## 2023.01.07
|
||||||
|
|
||||||
|
### Updated
|
||||||
|
- Update tox to 4.2.6 ([#4064](https://github.com/cookiecutter/cookiecutter-django/pull/4064))
|
||||||
|
- Update django-storages to 1.13.2 ([#4057](https://github.com/cookiecutter/cookiecutter-django/pull/4057))
|
||||||
|
- Update isort to 5.11.4 ([#4058](https://github.com/cookiecutter/cookiecutter-django/pull/4058))
|
||||||
|
- Update rcssmin to 1.1.1 ([#4060](https://github.com/cookiecutter/cookiecutter-django/pull/4060))
|
||||||
|
- Update django-compressor to 4.3 ([#4063](https://github.com/cookiecutter/cookiecutter-django/pull/4063))
|
||||||
|
|
||||||
|
## 2023.01.06
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Add `.git` to `.dockerignore` ([#4054](https://github.com/cookiecutter/cookiecutter-django/pull/4054))
|
||||||
|
- Fix link and add non-Docker commands to testing page in the docs ([#4036](https://github.com/cookiecutter/cookiecutter-django/pull/4036))
|
||||||
|
### Updated
|
||||||
|
- Update tox to 4.2.3 ([#4051](https://github.com/cookiecutter/cookiecutter-django/pull/4051))
|
||||||
|
|
||||||
|
## 2023.01.04
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Fix typo on test settings ([#4049](https://github.com/cookiecutter/cookiecutter-django/pull/4049))
|
||||||
|
### Updated
|
||||||
|
- Update tox to 4.2.2 ([#4050](https://github.com/cookiecutter/cookiecutter-django/pull/4050))
|
||||||
|
- Update tox to 4.2.1 ([#4046](https://github.com/cookiecutter/cookiecutter-django/pull/4046))
|
||||||
|
- Update coverage to 7.0.3 ([#4047](https://github.com/cookiecutter/cookiecutter-django/pull/4047))
|
||||||
|
|
||||||
|
## 2023.01.03
|
||||||
|
|
||||||
|
### Updated
|
||||||
|
- Update flake8-isort to 6.0.0 ([#4022](https://github.com/cookiecutter/cookiecutter-django/pull/4022))
|
||||||
|
- Update tox to 4.1.3 ([#4041](https://github.com/cookiecutter/cookiecutter-django/pull/4041))
|
||||||
|
- Update pillow to 9.4.0 ([#4040](https://github.com/cookiecutter/cookiecutter-django/pull/4040))
|
||||||
|
- Update gitpython to 3.1.30 ([#4032](https://github.com/cookiecutter/cookiecutter-django/pull/4032))
|
||||||
|
- Update coverage to 7.0.2 ([#4042](https://github.com/cookiecutter/cookiecutter-django/pull/4042))
|
||||||
|
- Update whitenoise to 6.3.0 ([#4044](https://github.com/cookiecutter/cookiecutter-django/pull/4044))
|
||||||
|
|
||||||
|
## 2022.12.29
|
||||||
|
|
||||||
|
### Updated
|
||||||
|
- Update tox to 4.1.0 ([#4035](https://github.com/cookiecutter/cookiecutter-django/pull/4035))
|
||||||
|
- Update tox to 4.0.19 ([#4030](https://github.com/cookiecutter/cookiecutter-django/pull/4030))
|
||||||
|
- Update django-allauth to 0.52.0 ([#4033](https://github.com/cookiecutter/cookiecutter-django/pull/4033))
|
||||||
|
|
||||||
|
## 2022.12.26
|
||||||
|
|
||||||
|
### Updated
|
||||||
|
- Update tox to 4.0.17 ([#4027](https://github.com/cookiecutter/cookiecutter-django/pull/4027))
|
||||||
|
- Update pre-commit to 2.21.0 ([#4026](https://github.com/cookiecutter/cookiecutter-django/pull/4026))
|
||||||
|
|
||||||
|
## 2022.12.25
|
||||||
|
|
||||||
|
### Updated
|
||||||
|
- Auto-update pre-commit hooks ([#4021](https://github.com/cookiecutter/cookiecutter-django/pull/4021))
|
||||||
|
|
||||||
|
## 2022.12.24
|
||||||
|
|
||||||
|
### Updated
|
||||||
|
- Update coverage to 7.0.1 ([#4024](https://github.com/cookiecutter/cookiecutter-django/pull/4024))
|
||||||
|
|
||||||
|
## 2022.12.21
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Retry when trying to store a Celery result in backend ([#3996](https://github.com/cookiecutter/cookiecutter-django/pull/3996))
|
||||||
|
- Update image URL for build status shield badge ([#4018](https://github.com/cookiecutter/cookiecutter-django/pull/4018))
|
||||||
|
### Updated
|
||||||
|
- Update pytz to 2022.7 ([#4020](https://github.com/cookiecutter/cookiecutter-django/pull/4020))
|
||||||
|
- Update ipdb to 0.13.11 ([#4019](https://github.com/cookiecutter/cookiecutter-django/pull/4019))
|
||||||
|
- Update tox to 4.0.16 ([#4017](https://github.com/cookiecutter/cookiecutter-django/pull/4017))
|
||||||
|
- Update sentry-sdk to 1.12.1 ([#4014](https://github.com/cookiecutter/cookiecutter-django/pull/4014))
|
||||||
|
- Update coverage to 7.0.0 ([#4013](https://github.com/cookiecutter/cookiecutter-django/pull/4013))
|
||||||
|
- Update django-anymail to 9.0 ([#4012](https://github.com/cookiecutter/cookiecutter-django/pull/4012))
|
||||||
|
- Auto-update pre-commit hooks ([#4005](https://github.com/cookiecutter/cookiecutter-django/pull/4005))
|
||||||
|
- Update isort to 5.11.3 ([#4010](https://github.com/cookiecutter/cookiecutter-django/pull/4010))
|
||||||
|
- Update drf-spectacular to 0.25.1 ([#4009](https://github.com/cookiecutter/cookiecutter-django/pull/4009))
|
||||||
|
- Update hiredis to 2.1.0 ([#4006](https://github.com/cookiecutter/cookiecutter-django/pull/4006))
|
||||||
|
|
||||||
|
## 2022.12.13
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Improve documentation for Getting started with Docker ([#4003](https://github.com/cookiecutter/cookiecutter-django/pull/4003))
|
||||||
|
### Updated
|
||||||
|
- Update isort to 5.11.1 ([#3999](https://github.com/cookiecutter/cookiecutter-django/pull/3999))
|
||||||
|
- Auto-update pre-commit hooks ([#3998](https://github.com/cookiecutter/cookiecutter-django/pull/3998))
|
||||||
|
- Update isort to 5.11.0 ([#3997](https://github.com/cookiecutter/cookiecutter-django/pull/3997))
|
||||||
|
|
||||||
|
## 2022.12.10
|
||||||
|
|
||||||
|
### Updated
|
||||||
|
- Update tox to 4.0.5 ([#3993](https://github.com/cookiecutter/cookiecutter-django/pull/3993))
|
||||||
|
- Auto-update pre-commit hooks ([#3991](https://github.com/cookiecutter/cookiecutter-django/pull/3991))
|
||||||
|
|
||||||
|
## 2022.12.09
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Remove bind option mounts for docker compose volumes ([#3981](https://github.com/cookiecutter/cookiecutter-django/pull/3981))
|
||||||
|
### Updated
|
||||||
|
- Update djangorestframework-stubs to 1.8.0 ([#3990](https://github.com/cookiecutter/cookiecutter-django/pull/3990))
|
||||||
|
- Update black to 22.12.0 ([#3988](https://github.com/cookiecutter/cookiecutter-django/pull/3988))
|
||||||
|
|
||||||
|
## 2022.12.08
|
||||||
|
|
||||||
|
### Updated
|
||||||
|
- Update tox to 4.0.3 ([#3987](https://github.com/cookiecutter/cookiecutter-django/pull/3987))
|
||||||
|
- Update tox to 4.0.2 ([#3985](https://github.com/cookiecutter/cookiecutter-django/pull/3985))
|
||||||
|
- Update django-stubs to 1.13.1 ([#3986](https://github.com/cookiecutter/cookiecutter-django/pull/3986))
|
||||||
|
|
||||||
|
## 2022.12.07
|
||||||
|
|
||||||
|
### Updated
|
||||||
|
- Auto-update pre-commit hooks ([#3983](https://github.com/cookiecutter/cookiecutter-django/pull/3983))
|
||||||
|
|
||||||
|
## 2022.12.06
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Simplify production `DATABASES` setting to extend base definition ([#3969](https://github.com/cookiecutter/cookiecutter-django/pull/3969))
|
||||||
|
### Fixed
|
||||||
|
- Only set `SERVERS` for `drf-spectacular` in production ([#3609](https://github.com/cookiecutter/cookiecutter-django/pull/3609))
|
||||||
|
### Updated
|
||||||
|
- Update django-coverage-plugin to 3.0.0 ([#3979](https://github.com/cookiecutter/cookiecutter-django/pull/3979))
|
||||||
|
- Bump stefanzweifel/git-auto-commit-action from 4.15.4 to 4.16.0 ([#3978](https://github.com/cookiecutter/cookiecutter-django/pull/3978))
|
||||||
|
|
||||||
|
## 2022.12.04
|
||||||
|
|
||||||
|
### Updated
|
||||||
|
- Update redis to 4.4.0 ([#3977](https://github.com/cookiecutter/cookiecutter-django/pull/3977))
|
||||||
|
- Update django-debug-toolbar to 3.8.1 ([#3976](https://github.com/cookiecutter/cookiecutter-django/pull/3976))
|
||||||
|
|
||||||
|
## 2022.12.03
|
||||||
|
|
||||||
|
### Updated
|
||||||
|
- Auto-update pre-commit hooks ([#3975](https://github.com/cookiecutter/cookiecutter-django/pull/3975))
|
||||||
|
|
||||||
|
## 2022.12.02
|
||||||
|
|
||||||
|
### Updated
|
||||||
|
- Update flake8 to 6.0.0 ([#3974](https://github.com/cookiecutter/cookiecutter-django/pull/3974))
|
||||||
|
|
||||||
|
## 2022.11.30
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Add Azure Storage as an option to serve static and media files ([#3967](https://github.com/cookiecutter/cookiecutter-django/pull/3967))
|
||||||
|
### Updated
|
||||||
|
- Auto-update pre-commit hooks ([#3970](https://github.com/cookiecutter/cookiecutter-django/pull/3970))
|
||||||
|
|
||||||
|
## 2022.11.26
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Fix typo in flower start for watching celery ([#3966](https://github.com/cookiecutter/cookiecutter-django/pull/3966))
|
||||||
|
|
||||||
|
## 2022.11.24
|
||||||
|
|
||||||
|
### Updated
|
||||||
|
- Auto-update pre-commit hooks ([#3963](https://github.com/cookiecutter/cookiecutter-django/pull/3963))
|
||||||
|
|
||||||
|
## 2022.11.23
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Fix graceful shutdown of local dev containers and use watchfiles for beat + flower ([#3925](https://github.com/cookiecutter/cookiecutter-django/pull/3925))
|
||||||
|
- feat(celery): Enable sending the sent task event by default ([#3961](https://github.com/cookiecutter/cookiecutter-django/pull/3961))
|
||||||
|
### Updated
|
||||||
|
- Bump stefanzweifel/git-auto-commit-action from 4.15.3 to 4.15.4 ([#3940](https://github.com/cookiecutter/cookiecutter-django/pull/3940))
|
||||||
|
- Update django-model-utils to 4.3.1 ([#3948](https://github.com/cookiecutter/cookiecutter-django/pull/3948))
|
||||||
|
- Update flake8-isort to 5.0.3 ([#3952](https://github.com/cookiecutter/cookiecutter-django/pull/3952))
|
||||||
|
|
||||||
|
## 2022.11.22
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Remove USE_L10N due to deprecation ([#3960](https://github.com/cookiecutter/cookiecutter-django/pull/3960))
|
||||||
|
- Remove platform from compose file ([#3957](https://github.com/cookiecutter/cookiecutter-django/pull/3957))
|
||||||
|
- feat(celery): Send task events for Celery by default ([#3959](https://github.com/cookiecutter/cookiecutter-django/pull/3959))
|
||||||
|
### Updated
|
||||||
|
- Update python-slugify to 7.0.0 ([#3950](https://github.com/cookiecutter/cookiecutter-django/pull/3950))
|
||||||
|
- Update redis to 4.3.5 ([#3954](https://github.com/cookiecutter/cookiecutter-django/pull/3954))
|
||||||
|
- Update sentry-sdk to 1.11.1 ([#3955](https://github.com/cookiecutter/cookiecutter-django/pull/3955))
|
||||||
|
- Update uvicorn to 0.20.0 ([#3953](https://github.com/cookiecutter/cookiecutter-django/pull/3953))
|
||||||
|
- Update tox to 3.27.1 ([#3945](https://github.com/cookiecutter/cookiecutter-django/pull/3945))
|
||||||
|
|
||||||
## 2022.11.11
|
## 2022.11.11
|
||||||
|
|
||||||
### Updated
|
### Updated
|
||||||
|
|
112
CONTRIBUTORS.md
112
CONTRIBUTORS.md
|
@ -166,6 +166,13 @@ Listed in alphabetical order.
|
||||||
</td>
|
</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Adin Hodovic</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://github.com/adinhodovic">adinhodovic</a>
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Agam Dua</td>
|
<td>Agam Dua</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -285,6 +292,13 @@ Listed in alphabetical order.
|
||||||
</td>
|
</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Arkadiusz Michał Ryś</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://github.com/arrys">arrys</a>
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Arnav Choudhury</td>
|
<td>Arnav Choudhury</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -600,6 +614,13 @@ Listed in alphabetical order.
|
||||||
</td>
|
</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>David</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://github.com/buckldav">buckldav</a>
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>David Díaz</td>
|
<td>David Díaz</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -628,6 +649,13 @@ Listed in alphabetical order.
|
||||||
</td>
|
</td>
|
||||||
<td>jangeador</td>
|
<td>jangeador</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Delphine LEMIRE</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://github.com/DelphineLemire">DelphineLemire</a>
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Demetris Stavrou</td>
|
<td>Demetris Stavrou</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -691,6 +719,13 @@ Listed in alphabetical order.
|
||||||
</td>
|
</td>
|
||||||
<td>dudanogueira</td>
|
<td>dudanogueira</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>duffn</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://github.com/duffn">duffn</a>
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Dónal Adams</td>
|
<td>Dónal Adams</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -887,6 +922,13 @@ Listed in alphabetical order.
|
||||||
</td>
|
</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Hoai-Thu Vuong</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://github.com/thuvh">thuvh</a>
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Howie Zhao</td>
|
<td>Howie Zhao</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -1153,6 +1195,13 @@ Listed in alphabetical order.
|
||||||
</td>
|
</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Leifur Halldor Asgeirsson</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://github.com/leifurhauks">leifurhauks</a>
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Leo won</td>
|
<td>Leo won</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -1391,6 +1440,13 @@ Listed in alphabetical order.
|
||||||
</td>
|
</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>mpsantos</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://github.com/mpsantos">mpsantos</a>
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Naveen</td>
|
<td>Naveen</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -1426,6 +1482,13 @@ Listed in alphabetical order.
|
||||||
</td>
|
</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Omer-5</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://github.com/Omer-5">Omer-5</a>
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Pablo</td>
|
<td>Pablo</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -1433,6 +1496,13 @@ Listed in alphabetical order.
|
||||||
</td>
|
</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Pamela Fox</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://github.com/pamelafox">pamelafox</a>
|
||||||
|
</td>
|
||||||
|
<td>pamelafox</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Parbhat Puri</td>
|
<td>Parbhat Puri</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -1440,6 +1510,13 @@ Listed in alphabetical order.
|
||||||
</td>
|
</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Patrick Tran</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://github.com/theptrk">theptrk</a>
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Pawan Chaurasia</td>
|
<td>Pawan Chaurasia</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -1524,6 +1601,13 @@ Listed in alphabetical order.
|
||||||
</td>
|
</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>rguptar</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://github.com/rguptar">rguptar</a>
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Richard Hajdu</td>
|
<td>Richard Hajdu</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -1531,6 +1615,13 @@ Listed in alphabetical order.
|
||||||
</td>
|
</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Robin</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://github.com/Kaffeetasse">Kaffeetasse</a>
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Roman Afanaskin</td>
|
<td>Roman Afanaskin</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -1636,6 +1727,13 @@ Listed in alphabetical order.
|
||||||
</td>
|
</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>TAKAHASHI Shuuji</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://github.com/shuuji3">shuuji3</a>
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Tames McTigue</td>
|
<td>Tames McTigue</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -1664,6 +1762,13 @@ Listed in alphabetical order.
|
||||||
</td>
|
</td>
|
||||||
<td>thibault</td>
|
<td>thibault</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Thomas Booij</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://github.com/ThomasBooij95">ThomasBooij95</a>
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Théo Segonds</td>
|
<td>Théo Segonds</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -1671,6 +1776,13 @@ Listed in alphabetical order.
|
||||||
</td>
|
</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>tildebox</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://github.com/tildebox">tildebox</a>
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Tim Claessens</td>
|
<td>Tim Claessens</td>
|
||||||
<td>
|
<td>
|
||||||
|
|
14
README.md
14
README.md
|
@ -1,11 +1,13 @@
|
||||||
# Cookiecutter Django
|
# Cookiecutter Django
|
||||||
|
|
||||||
[](https://github.com/cookiecutter/cookiecutter-django/actions?query=workflow%3ACI)
|
[](https://github.com/cookiecutter/cookiecutter-django/actions/workflows/ci.yml?query=branch%3Amaster)
|
||||||
[](https://cookiecutter-django.readthedocs.io/en/latest/?badge=latest)
|
[](https://cookiecutter-django.readthedocs.io/en/latest/?badge=latest)
|
||||||
|
[](https://results.pre-commit.ci/latest/github/cookiecutter/cookiecutter-django/master)
|
||||||
|
[](https://github.com/ambv/black)
|
||||||
|
|
||||||
[](https://pyup.io/repos/github/cookiecutter/cookiecutter-django/)
|
[](https://pyup.io/repos/github/cookiecutter/cookiecutter-django/)
|
||||||
[](https://discord.gg/uFXweDQc5a)
|
[](https://discord.gg/uFXweDQc5a)
|
||||||
[](https://www.codetriage.com/cookiecutter/cookiecutter-django)
|
[](https://www.codetriage.com/cookiecutter/cookiecutter-django)
|
||||||
[](https://github.com/ambv/black)
|
|
||||||
|
|
||||||
Powered by [Cookiecutter](https://github.com/cookiecutter/cookiecutter), Cookiecutter Django is a framework for jumpstarting
|
Powered by [Cookiecutter](https://github.com/cookiecutter/cookiecutter), Cookiecutter Django is a framework for jumpstarting
|
||||||
production-ready Django projects quickly.
|
production-ready Django projects quickly.
|
||||||
|
@ -27,9 +29,9 @@ production-ready Django projects quickly.
|
||||||
- Registration via [django-allauth](https://github.com/pennersr/django-allauth)
|
- Registration via [django-allauth](https://github.com/pennersr/django-allauth)
|
||||||
- Comes with custom user model ready to go
|
- Comes with custom user model ready to go
|
||||||
- Optional basic ASGI setup for Websockets
|
- Optional basic ASGI setup for Websockets
|
||||||
- Optional custom static build using Gulp and livereload
|
- Optional custom static build using Gulp or Webpack
|
||||||
- Send emails via [Anymail](https://github.com/anymail/django-anymail) (using [Mailgun](http://www.mailgun.com/) by default or Amazon SES if AWS is selected cloud provider, but switchable)
|
- Send emails via [Anymail](https://github.com/anymail/django-anymail) (using [Mailgun](http://www.mailgun.com/) by default or Amazon SES if AWS is selected cloud provider, but switchable)
|
||||||
- Media storage using Amazon S3 or Google Cloud Storage
|
- Media storage using Amazon S3, Google Cloud Storage, Azure Storage or nginx
|
||||||
- Docker support using [docker-compose](https://github.com/docker/compose) for development and production (using [Traefik](https://traefik.io/) with [LetsEncrypt](https://letsencrypt.org/) support)
|
- Docker support using [docker-compose](https://github.com/docker/compose) for development and production (using [Traefik](https://traefik.io/) with [LetsEncrypt](https://letsencrypt.org/) support)
|
||||||
- [Procfile](https://devcenter.heroku.com/articles/procfile) for deploying to Heroku
|
- [Procfile](https://devcenter.heroku.com/articles/procfile) for deploying to Heroku
|
||||||
- Instructions for deploying to [PythonAnywhere](https://www.pythonanywhere.com/)
|
- Instructions for deploying to [PythonAnywhere](https://www.pythonanywhere.com/)
|
||||||
|
@ -41,7 +43,7 @@ production-ready Django projects quickly.
|
||||||
|
|
||||||
*These features can be enabled during initial project setup.*
|
*These features can be enabled during initial project setup.*
|
||||||
|
|
||||||
- Serve static files from Amazon S3, Google Cloud Storage or [Whitenoise](https://whitenoise.readthedocs.io/)
|
- Serve static files from Amazon S3, Google Cloud Storage, Azure Storage or [Whitenoise](https://whitenoise.readthedocs.io/)
|
||||||
- Configuration for [Celery](https://docs.celeryq.dev) and [Flower](https://github.com/mher/flower) (the latter in Docker setup only)
|
- Configuration for [Celery](https://docs.celeryq.dev) and [Flower](https://github.com/mher/flower) (the latter in Docker setup only)
|
||||||
- Integration with [MailHog](https://github.com/mailhog/MailHog) for local email testing
|
- Integration with [MailHog](https://github.com/mailhog/MailHog) for local email testing
|
||||||
- Integration with [Sentry](https://sentry.io/welcome/) for error logging
|
- Integration with [Sentry](https://sentry.io/welcome/) for error logging
|
||||||
|
@ -153,6 +155,7 @@ Answer the prompts with your own desired [options](http://cookiecutter-django.re
|
||||||
1 - None
|
1 - None
|
||||||
2 - Django Compressor
|
2 - Django Compressor
|
||||||
3 - Gulp
|
3 - Gulp
|
||||||
|
4 - Webpack
|
||||||
Choose from 1, 2, 3, 4 [1]: 1
|
Choose from 1, 2, 3, 4 [1]: 1
|
||||||
use_celery [n]: y
|
use_celery [n]: y
|
||||||
use_mailhog [n]: n
|
use_mailhog [n]: n
|
||||||
|
@ -237,6 +240,7 @@ experience better.
|
||||||
## Articles
|
## Articles
|
||||||
|
|
||||||
- [Cookiecutter Django With Amazon RDS](https://haseeburrehman.com/posts/cookiecutter-django-with-amazon-rds/) - Apr, 2, 2021
|
- [Cookiecutter Django With Amazon RDS](https://haseeburrehman.com/posts/cookiecutter-django-with-amazon-rds/) - Apr, 2, 2021
|
||||||
|
- [Complete Walkthrough: Blue/Green Deployment to AWS ECS using GitHub actions](https://github.com/Andrew-Chen-Wang/cookiecutter-django-ecs-github) - June 10, 2020
|
||||||
- [Using cookiecutter-django with Google Cloud Storage](https://ahhda.github.io/cloud/gce/django/2019/03/12/using-django-cookiecutter-cloud-storage.html) - Mar. 12, 2019
|
- [Using cookiecutter-django with Google Cloud Storage](https://ahhda.github.io/cloud/gce/django/2019/03/12/using-django-cookiecutter-cloud-storage.html) - Mar. 12, 2019
|
||||||
- [cookiecutter-django with Nginx, Route 53 and ELB](https://msaizar.com/blog/cookiecutter-django-nginx-route-53-and-elb/) - Feb. 12, 2018
|
- [cookiecutter-django with Nginx, Route 53 and ELB](https://msaizar.com/blog/cookiecutter-django-nginx-route-53-and-elb/) - Feb. 12, 2018
|
||||||
- [cookiecutter-django and Amazon RDS](https://msaizar.com/blog/cookiecutter-django-and-amazon-rds/) - Feb. 7, 2018
|
- [cookiecutter-django and Amazon RDS](https://msaizar.com/blog/cookiecutter-django-and-amazon-rds/) - Feb. 7, 2018
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
"cloud_provider": [
|
"cloud_provider": [
|
||||||
"AWS",
|
"AWS",
|
||||||
"GCP",
|
"GCP",
|
||||||
|
"Azure",
|
||||||
"None"
|
"None"
|
||||||
],
|
],
|
||||||
"mail_service": [
|
"mail_service": [
|
||||||
|
@ -46,7 +47,8 @@
|
||||||
"frontend_pipeline": [
|
"frontend_pipeline": [
|
||||||
"None",
|
"None",
|
||||||
"Django Compressor",
|
"Django Compressor",
|
||||||
"Gulp"
|
"Gulp",
|
||||||
|
"Webpack"
|
||||||
],
|
],
|
||||||
"use_celery": "n",
|
"use_celery": "n",
|
||||||
"use_mailhog": "n",
|
"use_mailhog": "n",
|
||||||
|
|
|
@ -23,13 +23,13 @@ now = datetime.now()
|
||||||
|
|
||||||
# Add any Sphinx extension module names here, as strings. They can be extensions
|
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||||
extensions = []
|
extensions = ["myst_parser"]
|
||||||
|
|
||||||
# Add any paths that contain templates here, relative to this directory.
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
templates_path = ["_templates"]
|
templates_path = ["_templates"]
|
||||||
|
|
||||||
# The suffix of source filenames.
|
# The suffix of source filenames.
|
||||||
source_suffix = ".rst"
|
source_suffix = [".rst", ".md"]
|
||||||
|
|
||||||
# The encoding of source files.
|
# The encoding of source files.
|
||||||
# source_encoding = 'utf-8-sig'
|
# source_encoding = 'utf-8-sig'
|
||||||
|
|
3
docs/contributing.md
Normal file
3
docs/contributing.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
```{include} ../CONTRIBUTING.md
|
||||||
|
|
||||||
|
```
|
|
@ -12,13 +12,13 @@ Run these commands to deploy the project to Heroku:
|
||||||
|
|
||||||
heroku create --buildpack heroku/python
|
heroku create --buildpack heroku/python
|
||||||
|
|
||||||
heroku addons:create heroku-postgresql:hobby-dev
|
heroku addons:create heroku-postgresql:mini
|
||||||
# On Windows use double quotes for the time zone, e.g.
|
# On Windows use double quotes for the time zone, e.g.
|
||||||
# heroku pg:backups schedule --at "02:00 America/Los_Angeles" DATABASE_URL
|
# heroku pg:backups schedule --at "02:00 America/Los_Angeles" DATABASE_URL
|
||||||
heroku pg:backups schedule --at '02:00 America/Los_Angeles' DATABASE_URL
|
heroku pg:backups schedule --at '02:00 America/Los_Angeles' DATABASE_URL
|
||||||
heroku pg:promote DATABASE_URL
|
heroku pg:promote DATABASE_URL
|
||||||
|
|
||||||
heroku addons:create heroku-redis:hobby-dev
|
heroku addons:create heroku-redis:mini
|
||||||
|
|
||||||
# Assuming you chose Mailgun as mail service (see below for others)
|
# Assuming you chose Mailgun as mail service (see below for others)
|
||||||
heroku addons:create mailgun:starter
|
heroku addons:create mailgun:starter
|
||||||
|
@ -109,10 +109,10 @@ Or add the DSN for your account, if you already have one:
|
||||||
.. _Sentry add-on: https://elements.heroku.com/addons/sentry
|
.. _Sentry add-on: https://elements.heroku.com/addons/sentry
|
||||||
|
|
||||||
|
|
||||||
Gulp & Bootstrap compilation
|
Gulp or Webpack
|
||||||
++++++++++++++++++++++++++++
|
+++++++++++++++
|
||||||
|
|
||||||
If you've opted for Gulp, you'll most likely need to setup
|
If you've opted for Gulp or Webpack as frontend pipeline, you'll most likely need to setup
|
||||||
your app to use `multiple buildpacks`_: one for Python & one for Node.js:
|
your app to use `multiple buildpacks`_: one for Python & one for Node.js:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
@ -121,7 +121,7 @@ your app to use `multiple buildpacks`_: one for Python & one for Node.js:
|
||||||
|
|
||||||
At time of writing, this should do the trick: during deployment,
|
At time of writing, this should do the trick: during deployment,
|
||||||
the Heroku should run ``npm install`` and then ``npm build``,
|
the Heroku should run ``npm install`` and then ``npm build``,
|
||||||
which runs Gulp in cookiecutter-django.
|
which run the SASS compilation & JS bundling.
|
||||||
|
|
||||||
If things don't work, please refer to the Heroku docs.
|
If things don't work, please refer to the Heroku docs.
|
||||||
|
|
||||||
|
|
|
@ -84,6 +84,32 @@ You can read more about this feature and how to configure it, at `Automatic HTTP
|
||||||
|
|
||||||
.. _Automatic HTTPS: https://docs.traefik.io/https/acme/
|
.. _Automatic HTTPS: https://docs.traefik.io/https/acme/
|
||||||
|
|
||||||
|
.. _webpack-whitenoise-limitation:
|
||||||
|
|
||||||
|
Webpack without Whitenoise limitation
|
||||||
|
-------------------------------------
|
||||||
|
|
||||||
|
If you opt for Webpack without Whitenoise, Webpack needs to know the static URL at build time, when running ``docker-compose build`` (See ``webpack/prod.config.js``). Depending on your setup, this URL may come from the following environment variables:
|
||||||
|
|
||||||
|
- ``AWS_STORAGE_BUCKET_NAME``
|
||||||
|
- ``DJANGO_AWS_S3_CUSTOM_DOMAIN``
|
||||||
|
- ``DJANGO_GCP_STORAGE_BUCKET_NAME``
|
||||||
|
- ``DJANGO_AZURE_CONTAINER_NAME``
|
||||||
|
|
||||||
|
The Django settings are getting these values at runtime via the ``.envs/.production/.django`` file , but Docker does not read this file at build time, it only look for a ``.env`` in the root of the project. Failing to pass the values correctly will result in a page without CSS styles nor javascript.
|
||||||
|
|
||||||
|
To solve this, you can either:
|
||||||
|
|
||||||
|
1. merge all the env files into ``.env`` by running::
|
||||||
|
|
||||||
|
merge_production_dotenvs_in_dotenv.py
|
||||||
|
|
||||||
|
2. create a ``.env`` file in the root of the project with just variables you need. You'll need to also define them in ``.envs/.production/.django`` (hence duplicating them).
|
||||||
|
3. set these variables when running the build command::
|
||||||
|
|
||||||
|
DJANGO_AWS_S3_CUSTOM_DOMAIN=example.com docker-compose -f production.yml build``.
|
||||||
|
|
||||||
|
None of these options are ideal, we're open to suggestions on how to improve this. If you think you have one, please open an issue or a pull request.
|
||||||
|
|
||||||
(Optional) Postgres Data Volume Modifications
|
(Optional) Postgres Data Volume Modifications
|
||||||
---------------------------------------------
|
---------------------------------------------
|
||||||
|
@ -161,3 +187,7 @@ For status check, run::
|
||||||
|
|
||||||
supervisorctl status
|
supervisorctl status
|
||||||
|
|
||||||
|
Media files without cloud provider
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
If you chose no cloud provider and Docker, the media files will be served by an nginx service, from a ``production_django_media`` volume. Make sure to keep this around to avoid losing any media files.
|
||||||
|
|
|
@ -3,9 +3,6 @@ Getting Up and Running Locally With Docker
|
||||||
|
|
||||||
.. index:: Docker
|
.. index:: Docker
|
||||||
|
|
||||||
The steps below will get you up and running with a local development environment.
|
|
||||||
All of these commands assume you are in the root of your generated project.
|
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
If you're new to Docker, please be aware that some resources are cached system-wide
|
If you're new to Docker, please be aware that some resources are cached system-wide
|
||||||
|
@ -19,10 +16,16 @@ Prerequisites
|
||||||
* Docker; if you don't have it yet, follow the `installation instructions`_;
|
* Docker; if you don't have it yet, follow the `installation instructions`_;
|
||||||
* Docker Compose; refer to the official documentation for the `installation guide`_.
|
* Docker Compose; refer to the official documentation for the `installation guide`_.
|
||||||
* Pre-commit; refer to the official documentation for the `pre-commit`_.
|
* Pre-commit; refer to the official documentation for the `pre-commit`_.
|
||||||
|
* Cookiecutter; refer to the official GitHub repository of `Cookiecutter`_
|
||||||
|
|
||||||
.. _`installation instructions`: https://docs.docker.com/install/#supported-platforms
|
.. _`installation instructions`: https://docs.docker.com/install/#supported-platforms
|
||||||
.. _`installation guide`: https://docs.docker.com/compose/install/
|
.. _`installation guide`: https://docs.docker.com/compose/install/
|
||||||
.. _`pre-commit`: https://pre-commit.com/#install
|
.. _`pre-commit`: https://pre-commit.com/#install
|
||||||
|
.. _`Cookiecutter`: https://github.com/cookiecutter/cookiecutter
|
||||||
|
|
||||||
|
Before Getting Started
|
||||||
|
----------------------
|
||||||
|
.. include:: generate-project-block.rst
|
||||||
|
|
||||||
Build the Stack
|
Build the Stack
|
||||||
---------------
|
---------------
|
||||||
|
@ -210,6 +213,11 @@ By default, it's enabled both in local and production environments (``local.yml`
|
||||||
|
|
||||||
.. _`Flower`: https://github.com/mher/flower
|
.. _`Flower`: https://github.com/mher/flower
|
||||||
|
|
||||||
|
Using Webpack or Gulp
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
When using Webpack or Gulp as the ``frontend_pipeline`` option, you should access your application at the address of the ``node`` service in order to see your correct styles. This is http://localhost:3000 by default. When using any of the other ``frontend_pipeline`` options, you should use the address of the ``django`` service, http://localhost:8000.
|
||||||
|
|
||||||
Developing locally with HTTPS
|
Developing locally with HTTPS
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
|
||||||
|
|
|
@ -24,9 +24,8 @@ First things first.
|
||||||
|
|
||||||
$ source <virtual env path>/bin/activate
|
$ source <virtual env path>/bin/activate
|
||||||
|
|
||||||
#. Install cookiecutter-django: ::
|
#.
|
||||||
|
.. include:: generate-project-block.rst
|
||||||
$ cookiecutter gh:cookiecutter/cookiecutter-django
|
|
||||||
|
|
||||||
#. Install development requirements: ::
|
#. Install development requirements: ::
|
||||||
|
|
||||||
|
@ -43,6 +42,7 @@ First things first.
|
||||||
#. Create a new PostgreSQL database using createdb_: ::
|
#. Create a new PostgreSQL database using createdb_: ::
|
||||||
|
|
||||||
$ createdb --username=postgres <project_slug>
|
$ createdb --username=postgres <project_slug>
|
||||||
|
|
||||||
``project_slug`` is what you have entered as the project_slug at the setup stage.
|
``project_slug`` is what you have entered as the project_slug at the setup stage.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
@ -141,21 +141,38 @@ In production, we have Mailgun_ configured to have your back!
|
||||||
Celery
|
Celery
|
||||||
------
|
------
|
||||||
|
|
||||||
If the project is configured to use Celery as a task scheduler then by default tasks are set to run on the main thread
|
If the project is configured to use Celery as a task scheduler then, by default, tasks are set to run on the main thread when developing locally instead of getting sent to a broker. However, if you have Redis setup on your local machine, you can set the following in ``config/settings/local.py``::
|
||||||
when developing locally. If you have the appropriate setup on your local machine then set the following
|
|
||||||
in ``config/settings/local.py``::
|
|
||||||
|
|
||||||
CELERY_TASK_ALWAYS_EAGER = False
|
CELERY_TASK_ALWAYS_EAGER = False
|
||||||
|
|
||||||
To run Celery locally, make sure redis-server is installed (instructions are available at https://redis.io/topics/quickstart), run the server in one terminal with `redis-server`, and then start celery in another terminal with the following command::
|
Next, make sure `redis-server` is installed (per the `Getting started with Redis`_ guide) and run the server in one terminal::
|
||||||
|
|
||||||
celery -A config.celery_app worker --loglevel=info
|
$ redis-server
|
||||||
|
|
||||||
|
Start the Celery worker by running the following command in another terminal::
|
||||||
|
|
||||||
|
$ celery -A config.celery_app worker --loglevel=info
|
||||||
|
|
||||||
|
That Celery worker should be running whenever your app is running, typically as a background process,
|
||||||
|
so that it can pick up any tasks that get queued. Learn more from the `Celery Workers Guide`_.
|
||||||
|
|
||||||
|
The project comes with a simple task for manual testing purposes, inside `<project_slug>/users/tasks.py`. To queue that task locally, start the Django shell, import the task, and call `delay()` on it::
|
||||||
|
|
||||||
|
$ python manage.py shell
|
||||||
|
>> from <project_slug>.users.tasks import get_users_count
|
||||||
|
>> get_users_count.delay()
|
||||||
|
|
||||||
|
You can also use Django admin to queue up tasks, thanks to the `django-celerybeat`_ package.
|
||||||
|
|
||||||
|
.. _Getting started with Redis guide: https://redis.io/docs/getting-started/
|
||||||
|
.. _Celery Workers Guide: https://docs.celeryq.dev/en/stable/userguide/workers.html
|
||||||
|
.. _django-celerybeat: https://django-celery-beat.readthedocs.io/en/latest/
|
||||||
|
|
||||||
|
|
||||||
Sass Compilation & Live Reloading
|
Sass Compilation & Live Reloading
|
||||||
---------------------------------
|
---------------------------------
|
||||||
|
|
||||||
If you've opted for Gulp as front-end pipeline, the project comes configured with `Sass`_ compilation and `live reloading`_. As you change you Sass/JS source files, the task runner will automatically rebuild the corresponding CSS and JS assets and reload them in your browser without refreshing the page.
|
If you've opted for Gulp or Webpack as front-end pipeline, the project comes configured with `Sass`_ compilation and `live reloading`_. As you change you Sass/JS source files, the task runner will automatically rebuild the corresponding CSS and JS assets and reload them in your browser without refreshing the page.
|
||||||
|
|
||||||
#. Make sure that `Node.js`_ v16 is installed on your machine.
|
#. Make sure that `Node.js`_ v16 is installed on your machine.
|
||||||
#. In the project root, install the JS dependencies with::
|
#. In the project root, install the JS dependencies with::
|
||||||
|
|
7
docs/generate-project-block.rst
Normal file
7
docs/generate-project-block.rst
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
Generate a new cookiecutter-django project: ::
|
||||||
|
|
||||||
|
$ cookiecutter gh:cookiecutter/cookiecutter-django
|
||||||
|
|
||||||
|
For more information refer to
|
||||||
|
:ref:`Project Generation Options <template-options>`.
|
||||||
|
|
|
@ -27,6 +27,7 @@ Contents
|
||||||
websocket
|
websocket
|
||||||
faq
|
faq
|
||||||
troubleshooting
|
troubleshooting
|
||||||
|
contributing
|
||||||
|
|
||||||
Indices and tables
|
Indices and tables
|
||||||
------------------
|
------------------
|
||||||
|
|
|
@ -73,9 +73,10 @@ cloud_provider:
|
||||||
|
|
||||||
1. AWS_
|
1. AWS_
|
||||||
2. GCP_
|
2. GCP_
|
||||||
3. None
|
3. Azure_
|
||||||
|
4. None
|
||||||
|
|
||||||
Note that if you choose no cloud provider, media files won't work.
|
If you choose no cloud provider and docker, the production stack will serve the media files via an nginx Docker service. Without Docker, the media files won't work.
|
||||||
|
|
||||||
mail_service:
|
mail_service:
|
||||||
Select an email service that Django-Anymail provides
|
Select an email service that Django-Anymail provides
|
||||||
|
@ -101,7 +102,10 @@ frontend_pipeline:
|
||||||
|
|
||||||
1. None
|
1. None
|
||||||
2. `Django Compressor`_
|
2. `Django Compressor`_
|
||||||
3. `Gulp`_: support Bootstrap recompilation with real-time variables alteration.
|
3. `Gulp`_
|
||||||
|
4. `Webpack`_
|
||||||
|
|
||||||
|
Both Gulp and Webpack support Bootstrap recompilation with real-time variables alteration.
|
||||||
|
|
||||||
use_celery:
|
use_celery:
|
||||||
Indicates whether the project should be configured to use Celery_.
|
Indicates whether the project should be configured to use Celery_.
|
||||||
|
@ -151,9 +155,11 @@ debug:
|
||||||
.. _PostgreSQL: https://www.postgresql.org/docs/
|
.. _PostgreSQL: https://www.postgresql.org/docs/
|
||||||
|
|
||||||
.. _Gulp: https://github.com/gulpjs/gulp
|
.. _Gulp: https://github.com/gulpjs/gulp
|
||||||
|
.. _Webpack: https://webpack.js.org
|
||||||
|
|
||||||
.. _AWS: https://aws.amazon.com/s3/
|
.. _AWS: https://aws.amazon.com/s3/
|
||||||
.. _GCP: https://cloud.google.com/storage/
|
.. _GCP: https://cloud.google.com/storage/
|
||||||
|
.. _Azure: https://azure.microsoft.com/en-us/products/storage/blobs/
|
||||||
|
|
||||||
.. _Amazon SES: https://aws.amazon.com/ses/
|
.. _Amazon SES: https://aws.amazon.com/ses/
|
||||||
.. _Mailgun: https://www.mailgun.com
|
.. _Mailgun: https://www.mailgun.com
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
sphinx==5.3.0
|
sphinx==6.1.3
|
||||||
sphinx-rtd-theme==1.1.1
|
sphinx-rtd-theme==1.2.0
|
||||||
|
myst-parser==1.0.0
|
||||||
|
|
|
@ -49,6 +49,9 @@ DJANGO_AWS_S3_CUSTOM_DOMAIN AWS_S3_CUSTOM_DOMAIN n/a
|
||||||
DJANGO_AWS_S3_MAX_MEMORY_SIZE AWS_S3_MAX_MEMORY_SIZE n/a 100_000_000
|
DJANGO_AWS_S3_MAX_MEMORY_SIZE AWS_S3_MAX_MEMORY_SIZE n/a 100_000_000
|
||||||
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
|
||||||
|
DJANGO_AZURE_ACCOUNT_KEY AZURE_ACCOUNT_KEY n/a raises error
|
||||||
|
DJANGO_AZURE_ACCOUNT_NAME AZURE_ACCOUNT_NAME n/a raises error
|
||||||
|
DJANGO_AZURE_CONTAINER_NAME AZURE_CONTAINER n/a raises error
|
||||||
SENTRY_DSN SENTRY_DSN n/a raises error
|
SENTRY_DSN SENTRY_DSN n/a raises error
|
||||||
SENTRY_ENVIRONMENT n/a n/a production
|
SENTRY_ENVIRONMENT n/a n/a production
|
||||||
SENTRY_TRACES_SAMPLE_RATE n/a n/a 0.0
|
SENTRY_TRACES_SAMPLE_RATE n/a n/a 0.0
|
||||||
|
|
|
@ -28,10 +28,15 @@ Coverage
|
||||||
|
|
||||||
You should build your tests to provide the highest level of **code coverage**. You can run the ``pytest`` with code ``coverage`` by typing in the following command: ::
|
You should build your tests to provide the highest level of **code coverage**. You can run the ``pytest`` with code ``coverage`` by typing in the following command: ::
|
||||||
|
|
||||||
$ docker-compose -f local.yml run --rm django coverage run -m pytest
|
$ coverage run -m pytest
|
||||||
|
|
||||||
Once the tests are complete, in order to see the code coverage, run the following command: ::
|
Once the tests are complete, in order to see the code coverage, run the following command: ::
|
||||||
|
|
||||||
|
$ coverage report
|
||||||
|
|
||||||
|
If you're running the project locally with Docker, use these commands instead: ::
|
||||||
|
|
||||||
|
$ docker-compose -f local.yml run --rm django coverage run -m pytest
|
||||||
$ docker-compose -f local.yml run --rm django coverage report
|
$ docker-compose -f local.yml run --rm django coverage report
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
@ -53,4 +58,4 @@ Once the tests are complete, in order to see the code coverage, run the followin
|
||||||
.. _develop locally with docker: ./developing-locally-docker.html
|
.. _develop locally with docker: ./developing-locally-docker.html
|
||||||
.. _customize: https://docs.pytest.org/en/latest/customize.html
|
.. _customize: https://docs.pytest.org/en/latest/customize.html
|
||||||
.. _unittest: https://docs.python.org/3/library/unittest.html#module-unittest
|
.. _unittest: https://docs.python.org/3/library/unittest.html#module-unittest
|
||||||
.. _configuring: https://coverage.readthedocs.io/en/v4.5.x/config.html
|
.. _configuring: https://coverage.readthedocs.io/en/latest/config.html
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
Troubleshooting
|
Troubleshooting
|
||||||
=====================================
|
===============
|
||||||
|
|
||||||
This page contains some advice about errors and problems commonly encountered during the development of Cookiecutter Django applications.
|
This page contains some advice about errors and problems commonly encountered during the development of Cookiecutter Django applications.
|
||||||
|
|
||||||
|
@ -38,6 +38,16 @@ To fix this, you can either:
|
||||||
.. _rm: https://docs.docker.com/engine/reference/commandline/volume_rm/
|
.. _rm: https://docs.docker.com/engine/reference/commandline/volume_rm/
|
||||||
.. _prune: https://docs.docker.com/v17.09/engine/reference/commandline/system_prune/
|
.. _prune: https://docs.docker.com/v17.09/engine/reference/commandline/system_prune/
|
||||||
|
|
||||||
|
Variable is not set. Defaulting to a blank string
|
||||||
|
-------------------------------------------------
|
||||||
|
|
||||||
|
Example::
|
||||||
|
|
||||||
|
WARN[0000] The "DJANGO_AWS_STORAGE_BUCKET_NAME" variable is not set. Defaulting to a blank string.
|
||||||
|
WARN[0000] The "DJANGO_AWS_S3_CUSTOM_DOMAIN" variable is not set. Defaulting to a blank string.
|
||||||
|
|
||||||
|
You have probably opted for Docker + Webpack without Whitenoise. This is a know limitation of the combination, which needs a little bit of manual intervention. See the :ref:`dedicated section about it <webpack-whitenoise-limitation>`.
|
||||||
|
|
||||||
Others
|
Others
|
||||||
------
|
------
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ TODO: restrict Cookiecutter Django project initialization to
|
||||||
"""
|
"""
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
|
import json
|
||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
import shutil
|
import shutil
|
||||||
|
@ -87,15 +88,30 @@ def remove_heroku_build_hooks():
|
||||||
shutil.rmtree("bin")
|
shutil.rmtree("bin")
|
||||||
|
|
||||||
|
|
||||||
|
def remove_sass_files():
|
||||||
|
shutil.rmtree(os.path.join("{{cookiecutter.project_slug}}", "static", "sass"))
|
||||||
|
|
||||||
|
|
||||||
def remove_gulp_files():
|
def remove_gulp_files():
|
||||||
file_names = ["gulpfile.js"]
|
file_names = ["gulpfile.js"]
|
||||||
for file_name in file_names:
|
for file_name in file_names:
|
||||||
os.remove(file_name)
|
os.remove(file_name)
|
||||||
remove_sass_files()
|
|
||||||
|
|
||||||
|
|
||||||
def remove_sass_files():
|
def remove_webpack_files():
|
||||||
shutil.rmtree(os.path.join("{{cookiecutter.project_slug}}", "static", "sass"))
|
shutil.rmtree("webpack")
|
||||||
|
remove_vendors_js()
|
||||||
|
|
||||||
|
|
||||||
|
def remove_vendors_js():
|
||||||
|
vendors_js_path = os.path.join(
|
||||||
|
"{{ cookiecutter.project_slug }}",
|
||||||
|
"static",
|
||||||
|
"js",
|
||||||
|
"vendors.js",
|
||||||
|
)
|
||||||
|
if os.path.exists(vendors_js_path):
|
||||||
|
os.remove(vendors_js_path)
|
||||||
|
|
||||||
|
|
||||||
def remove_packagejson_file():
|
def remove_packagejson_file():
|
||||||
|
@ -104,6 +120,83 @@ def remove_packagejson_file():
|
||||||
os.remove(file_name)
|
os.remove(file_name)
|
||||||
|
|
||||||
|
|
||||||
|
def update_package_json(remove_dev_deps=None, remove_keys=None, scripts=None):
|
||||||
|
remove_dev_deps = remove_dev_deps or []
|
||||||
|
remove_keys = remove_keys or []
|
||||||
|
scripts = scripts or {}
|
||||||
|
with open("package.json", mode="r") as fd:
|
||||||
|
content = json.load(fd)
|
||||||
|
for package_name in remove_dev_deps:
|
||||||
|
content["devDependencies"].pop(package_name)
|
||||||
|
for key in remove_keys:
|
||||||
|
content.pop(key)
|
||||||
|
content["scripts"].update(scripts)
|
||||||
|
with open("package.json", mode="w") as fd:
|
||||||
|
json.dump(content, fd, ensure_ascii=False, indent=2)
|
||||||
|
fd.write("\n")
|
||||||
|
|
||||||
|
|
||||||
|
def handle_js_runner(choice, use_docker, use_async):
|
||||||
|
if choice == "Gulp":
|
||||||
|
update_package_json(
|
||||||
|
remove_dev_deps=[
|
||||||
|
"@babel/core",
|
||||||
|
"@babel/preset-env",
|
||||||
|
"babel-loader",
|
||||||
|
"concurrently",
|
||||||
|
"css-loader",
|
||||||
|
"mini-css-extract-plugin",
|
||||||
|
"postcss-loader",
|
||||||
|
"postcss-preset-env",
|
||||||
|
"sass-loader",
|
||||||
|
"webpack",
|
||||||
|
"webpack-bundle-tracker",
|
||||||
|
"webpack-cli",
|
||||||
|
"webpack-dev-server",
|
||||||
|
"webpack-merge",
|
||||||
|
],
|
||||||
|
remove_keys=["babel"],
|
||||||
|
scripts={
|
||||||
|
"dev": "gulp",
|
||||||
|
"build": "gulp generate-assets",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
remove_webpack_files()
|
||||||
|
elif choice == "Webpack":
|
||||||
|
scripts = {
|
||||||
|
"dev": "webpack serve --config webpack/dev.config.js",
|
||||||
|
"build": "webpack --config webpack/prod.config.js",
|
||||||
|
}
|
||||||
|
remove_dev_deps = [
|
||||||
|
"browser-sync",
|
||||||
|
"cssnano",
|
||||||
|
"gulp",
|
||||||
|
"gulp-imagemin",
|
||||||
|
"gulp-plumber",
|
||||||
|
"gulp-postcss",
|
||||||
|
"gulp-rename",
|
||||||
|
"gulp-sass",
|
||||||
|
"gulp-uglify-es",
|
||||||
|
]
|
||||||
|
if not use_docker:
|
||||||
|
dev_django_cmd = (
|
||||||
|
"uvicorn config.asgi:application --reload"
|
||||||
|
if use_async
|
||||||
|
else "python manage.py runserver_plus"
|
||||||
|
)
|
||||||
|
scripts.update(
|
||||||
|
{
|
||||||
|
"dev": "concurrently npm:dev:*",
|
||||||
|
"dev:webpack": "webpack serve --config webpack/dev.config.js",
|
||||||
|
"dev:django": dev_django_cmd,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
remove_dev_deps.append("concurrently")
|
||||||
|
update_package_json(remove_dev_deps=remove_dev_deps, scripts=scripts)
|
||||||
|
remove_gulp_files()
|
||||||
|
|
||||||
|
|
||||||
def remove_celery_files():
|
def remove_celery_files():
|
||||||
file_names = [
|
file_names = [
|
||||||
os.path.join("config", "celery_app.py"),
|
os.path.join("config", "celery_app.py"),
|
||||||
|
@ -293,6 +386,7 @@ def set_flags_in_settings_files():
|
||||||
def remove_envs_and_associated_files():
|
def remove_envs_and_associated_files():
|
||||||
shutil.rmtree(".envs")
|
shutil.rmtree(".envs")
|
||||||
os.remove("merge_production_dotenvs_in_dotenv.py")
|
os.remove("merge_production_dotenvs_in_dotenv.py")
|
||||||
|
shutil.rmtree("tests")
|
||||||
|
|
||||||
|
|
||||||
def remove_celery_compose_dirs():
|
def remove_celery_compose_dirs():
|
||||||
|
@ -383,15 +477,26 @@ def main():
|
||||||
if "{{ cookiecutter.keep_local_envs_in_vcs }}".lower() == "y":
|
if "{{ cookiecutter.keep_local_envs_in_vcs }}".lower() == "y":
|
||||||
append_to_gitignore_file("!.envs/.local/")
|
append_to_gitignore_file("!.envs/.local/")
|
||||||
|
|
||||||
if "{{ cookiecutter.frontend_pipeline }}" != "Gulp":
|
if "{{ cookiecutter.frontend_pipeline }}" in ["None", "Django Compressor"]:
|
||||||
remove_gulp_files()
|
remove_gulp_files()
|
||||||
|
remove_webpack_files()
|
||||||
|
remove_sass_files()
|
||||||
remove_packagejson_file()
|
remove_packagejson_file()
|
||||||
if "{{ cookiecutter.use_docker }}".lower() == "y":
|
if "{{ cookiecutter.use_docker }}".lower() == "y":
|
||||||
remove_node_dockerfile()
|
remove_node_dockerfile()
|
||||||
|
else:
|
||||||
|
handle_js_runner(
|
||||||
|
"{{ cookiecutter.frontend_pipeline }}",
|
||||||
|
use_docker=("{{ cookiecutter.use_docker }}".lower() == "y"),
|
||||||
|
use_async=("{{ cookiecutter.use_async }}".lower() == "y"),
|
||||||
|
)
|
||||||
|
|
||||||
if "{{ cookiecutter.cloud_provider}}" == "None":
|
if (
|
||||||
|
"{{ cookiecutter.cloud_provider }}" == "None"
|
||||||
|
and "{{ cookiecutter.use_docker }}".lower() == "n"
|
||||||
|
):
|
||||||
print(
|
print(
|
||||||
WARNING + "You chose not to use a cloud provider, "
|
WARNING + "You chose to not use any cloud providers nor Docker, "
|
||||||
"media files won't be served in production." + TERMINATOR
|
"media files won't be served in production." + TERMINATOR
|
||||||
)
|
)
|
||||||
remove_storages_module()
|
remove_storages_module()
|
||||||
|
|
|
@ -72,11 +72,8 @@ if (
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
if (
|
if (
|
||||||
"{{ cookiecutter.cloud_provider }}" == "GCP"
|
"{{ cookiecutter.mail_service }}" == "Amazon SES"
|
||||||
and "{{ cookiecutter.mail_service }}" == "Amazon SES"
|
and "{{ cookiecutter.cloud_provider }}" != "AWS"
|
||||||
) or (
|
|
||||||
"{{ cookiecutter.cloud_provider }}" == "None"
|
|
||||||
and "{{ cookiecutter.mail_service }}" == "Amazon SES"
|
|
||||||
):
|
):
|
||||||
print(
|
print(
|
||||||
"You should either use AWS or select a different "
|
"You should either use AWS or select a different "
|
||||||
|
|
|
@ -1,26 +1,26 @@
|
||||||
cookiecutter==2.1.1
|
cookiecutter==2.1.1
|
||||||
sh==1.14.3; sys_platform != "win32"
|
sh==2.0.2; sys_platform != "win32"
|
||||||
binaryornot==0.4.4
|
binaryornot==0.4.4
|
||||||
|
|
||||||
# Code quality
|
# Code quality
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
black==22.10.0
|
black==23.1.0
|
||||||
isort==5.10.1
|
isort==5.12.0
|
||||||
flake8==5.0.4
|
flake8==6.0.0
|
||||||
flake8-isort==5.0.0
|
flake8-isort==6.0.0
|
||||||
pre-commit==2.20.0
|
pre-commit==3.1.1
|
||||||
|
|
||||||
# Testing
|
# Testing
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
tox==3.27.1
|
tox==4.4.6
|
||||||
pytest==7.2.0
|
pytest==7.2.2
|
||||||
pytest-cookies==0.6.1
|
pytest-cookies==0.6.1
|
||||||
pytest-instafail==0.4.2
|
pytest-instafail==0.4.2
|
||||||
pyyaml==6.0
|
pyyaml==6.0
|
||||||
|
|
||||||
# Scripting
|
# Scripting
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
PyGithub==1.57
|
PyGithub==1.58.0
|
||||||
gitpython==3.1.29
|
gitpython==3.1.31
|
||||||
jinja2==3.1.2
|
jinja2==3.1.2
|
||||||
requests==2.28.1
|
requests==2.28.2
|
||||||
|
|
|
@ -82,14 +82,20 @@ def group_pulls_by_change_type(
|
||||||
grouped_pulls = {
|
grouped_pulls = {
|
||||||
"Changed": [],
|
"Changed": [],
|
||||||
"Fixed": [],
|
"Fixed": [],
|
||||||
|
"Documentation": [],
|
||||||
"Updated": [],
|
"Updated": [],
|
||||||
}
|
}
|
||||||
for pull in pull_requests_list:
|
for pull in pull_requests_list:
|
||||||
label_names = {label.name for label in pull.labels}
|
label_names = {label.name for label in pull.labels}
|
||||||
|
if "project infrastructure" in label_names:
|
||||||
|
# Don't mention it in the changelog
|
||||||
|
continue
|
||||||
if "update" in label_names:
|
if "update" in label_names:
|
||||||
group_name = "Updated"
|
group_name = "Updated"
|
||||||
elif "bug" in label_names:
|
elif "bug" in label_names:
|
||||||
group_name = "Fixed"
|
group_name = "Fixed"
|
||||||
|
elif "docs" in label_names:
|
||||||
|
group_name = "Documentation"
|
||||||
else:
|
else:
|
||||||
group_name = "Changed"
|
group_name = "Changed"
|
||||||
grouped_pulls[group_name].append(pull)
|
grouped_pulls[group_name].append(pull)
|
||||||
|
|
2
setup.py
2
setup.py
|
@ -5,7 +5,7 @@ except ImportError:
|
||||||
from distutils.core import setup
|
from distutils.core import setup
|
||||||
|
|
||||||
# We use calendar versioning
|
# We use calendar versioning
|
||||||
version = "2022.11.11"
|
version = "2023.03.09"
|
||||||
|
|
||||||
with open("README.rst") as readme_file:
|
with open("README.rst") as readme_file:
|
||||||
long_description = readme_file.read()
|
long_description = readme_file.read()
|
||||||
|
|
|
@ -32,13 +32,11 @@ pytest
|
||||||
# Make sure the check doesn't raise any warnings
|
# Make sure the check doesn't raise any warnings
|
||||||
python manage.py check --fail-level WARNING
|
python manage.py check --fail-level WARNING
|
||||||
|
|
||||||
|
# Run npm build script if package.json is present
|
||||||
if [ -f "package.json" ]
|
if [ -f "package.json" ]
|
||||||
then
|
then
|
||||||
npm install
|
npm install
|
||||||
if [ -f "gulpfile.js" ]
|
npm run build
|
||||||
then
|
|
||||||
npm run build
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Generate the HTML for the documentation
|
# Generate the HTML for the documentation
|
||||||
|
|
|
@ -56,6 +56,8 @@ SUPPORTED_COMBINATIONS = [
|
||||||
{"cloud_provider": "AWS", "use_whitenoise": "n"},
|
{"cloud_provider": "AWS", "use_whitenoise": "n"},
|
||||||
{"cloud_provider": "GCP", "use_whitenoise": "y"},
|
{"cloud_provider": "GCP", "use_whitenoise": "y"},
|
||||||
{"cloud_provider": "GCP", "use_whitenoise": "n"},
|
{"cloud_provider": "GCP", "use_whitenoise": "n"},
|
||||||
|
{"cloud_provider": "Azure", "use_whitenoise": "y"},
|
||||||
|
{"cloud_provider": "Azure", "use_whitenoise": "n"},
|
||||||
{"cloud_provider": "None", "use_whitenoise": "y", "mail_service": "Mailgun"},
|
{"cloud_provider": "None", "use_whitenoise": "y", "mail_service": "Mailgun"},
|
||||||
{"cloud_provider": "None", "use_whitenoise": "y", "mail_service": "Mailjet"},
|
{"cloud_provider": "None", "use_whitenoise": "y", "mail_service": "Mailjet"},
|
||||||
{"cloud_provider": "None", "use_whitenoise": "y", "mail_service": "Mandrill"},
|
{"cloud_provider": "None", "use_whitenoise": "y", "mail_service": "Mandrill"},
|
||||||
|
@ -82,7 +84,16 @@ SUPPORTED_COMBINATIONS = [
|
||||||
{"cloud_provider": "GCP", "mail_service": "SendinBlue"},
|
{"cloud_provider": "GCP", "mail_service": "SendinBlue"},
|
||||||
{"cloud_provider": "GCP", "mail_service": "SparkPost"},
|
{"cloud_provider": "GCP", "mail_service": "SparkPost"},
|
||||||
{"cloud_provider": "GCP", "mail_service": "Other SMTP"},
|
{"cloud_provider": "GCP", "mail_service": "Other SMTP"},
|
||||||
# Note: cloud_providers GCP and None with mail_service Amazon SES is not supported
|
{"cloud_provider": "Azure", "mail_service": "Mailgun"},
|
||||||
|
{"cloud_provider": "Azure", "mail_service": "Mailjet"},
|
||||||
|
{"cloud_provider": "Azure", "mail_service": "Mandrill"},
|
||||||
|
{"cloud_provider": "Azure", "mail_service": "Postmark"},
|
||||||
|
{"cloud_provider": "Azure", "mail_service": "Sendgrid"},
|
||||||
|
{"cloud_provider": "Azure", "mail_service": "SendinBlue"},
|
||||||
|
{"cloud_provider": "Azure", "mail_service": "SparkPost"},
|
||||||
|
{"cloud_provider": "Azure", "mail_service": "Other SMTP"},
|
||||||
|
# Note: cloud_providers GCP, Azure, and None
|
||||||
|
# with mail_service Amazon SES is not supported
|
||||||
{"use_async": "y"},
|
{"use_async": "y"},
|
||||||
{"use_async": "n"},
|
{"use_async": "n"},
|
||||||
{"use_drf": "y"},
|
{"use_drf": "y"},
|
||||||
|
@ -90,6 +101,7 @@ SUPPORTED_COMBINATIONS = [
|
||||||
{"frontend_pipeline": "None"},
|
{"frontend_pipeline": "None"},
|
||||||
{"frontend_pipeline": "Django Compressor"},
|
{"frontend_pipeline": "Django Compressor"},
|
||||||
{"frontend_pipeline": "Gulp"},
|
{"frontend_pipeline": "Gulp"},
|
||||||
|
{"frontend_pipeline": "Webpack"},
|
||||||
{"use_celery": "y"},
|
{"use_celery": "y"},
|
||||||
{"use_celery": "n"},
|
{"use_celery": "n"},
|
||||||
{"use_mailhog": "y"},
|
{"use_mailhog": "y"},
|
||||||
|
@ -113,6 +125,7 @@ SUPPORTED_COMBINATIONS = [
|
||||||
UNSUPPORTED_COMBINATIONS = [
|
UNSUPPORTED_COMBINATIONS = [
|
||||||
{"cloud_provider": "None", "use_whitenoise": "n"},
|
{"cloud_provider": "None", "use_whitenoise": "n"},
|
||||||
{"cloud_provider": "GCP", "mail_service": "Amazon SES"},
|
{"cloud_provider": "GCP", "mail_service": "Amazon SES"},
|
||||||
|
{"cloud_provider": "Azure", "mail_service": "Amazon SES"},
|
||||||
{"cloud_provider": "None", "mail_service": "Amazon SES"},
|
{"cloud_provider": "None", "mail_service": "Amazon SES"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -122,11 +135,11 @@ def _fixture_id(ctx):
|
||||||
return "-".join(f"{key}:{value}" for key, value in ctx.items())
|
return "-".join(f"{key}:{value}" for key, value in ctx.items())
|
||||||
|
|
||||||
|
|
||||||
def build_files_list(root_dir):
|
def build_files_list(base_dir):
|
||||||
"""Build a list containing absolute paths to the generated files."""
|
"""Build a list containing absolute paths to the generated files."""
|
||||||
return [
|
return [
|
||||||
os.path.join(dirpath, file_path)
|
os.path.join(dirpath, file_path)
|
||||||
for dirpath, subdirs, files in os.walk(root_dir)
|
for dirpath, subdirs, files in os.walk(base_dir)
|
||||||
for file_path in files
|
for file_path in files
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -219,7 +232,7 @@ def test_travis_invokes_pytest(cookies, context, use_docker, expected_test_scrip
|
||||||
("y", "docker-compose -f local.yml run django pytest"),
|
("y", "docker-compose -f local.yml run django pytest"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_gitlab_invokes_flake8_and_pytest(
|
def test_gitlab_invokes_precommit_and_pytest(
|
||||||
cookies, context, use_docker, expected_test_script
|
cookies, context, use_docker, expected_test_script
|
||||||
):
|
):
|
||||||
context.update({"ci_tool": "Gitlab", "use_docker": use_docker})
|
context.update({"ci_tool": "Gitlab", "use_docker": use_docker})
|
||||||
|
@ -233,7 +246,9 @@ def test_gitlab_invokes_flake8_and_pytest(
|
||||||
with open(f"{result.project_path}/.gitlab-ci.yml") as gitlab_yml:
|
with open(f"{result.project_path}/.gitlab-ci.yml") as gitlab_yml:
|
||||||
try:
|
try:
|
||||||
gitlab_config = yaml.safe_load(gitlab_yml)
|
gitlab_config = yaml.safe_load(gitlab_yml)
|
||||||
assert gitlab_config["flake8"]["script"] == ["flake8"]
|
assert gitlab_config["precommit"]["script"] == [
|
||||||
|
"pre-commit run --show-diff-on-failure --color=always --all-files"
|
||||||
|
]
|
||||||
assert gitlab_config["pytest"]["script"] == [expected_test_script]
|
assert gitlab_config["pytest"]["script"] == [expected_test_script]
|
||||||
except yaml.YAMLError as e:
|
except yaml.YAMLError as e:
|
||||||
pytest.fail(e)
|
pytest.fail(e)
|
||||||
|
|
|
@ -41,3 +41,9 @@ docker-compose -f local.yml run django python manage.py check --fail-level WARNI
|
||||||
|
|
||||||
# Generate the HTML for the documentation
|
# Generate the HTML for the documentation
|
||||||
docker-compose -f local.yml run docs make html
|
docker-compose -f local.yml run docs make html
|
||||||
|
|
||||||
|
# Run npm build script if package.json is present
|
||||||
|
if [ -f "package.json" ]
|
||||||
|
then
|
||||||
|
docker-compose -f local.yml run node npm run build
|
||||||
|
fi
|
||||||
|
|
|
@ -8,3 +8,4 @@
|
||||||
.readthedocs.yml
|
.readthedocs.yml
|
||||||
.travis.yml
|
.travis.yml
|
||||||
venv
|
venv
|
||||||
|
.git
|
||||||
|
|
|
@ -44,6 +44,12 @@ DJANGO_AWS_STORAGE_BUCKET_NAME=
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
GOOGLE_APPLICATION_CREDENTIALS=
|
GOOGLE_APPLICATION_CREDENTIALS=
|
||||||
DJANGO_GCP_STORAGE_BUCKET_NAME=
|
DJANGO_GCP_STORAGE_BUCKET_NAME=
|
||||||
|
{% elif cookiecutter.cloud_provider == 'Azure' %}
|
||||||
|
# Azure
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
DJANGO_AZURE_ACCOUNT_KEY=
|
||||||
|
DJANGO_AZURE_ACCOUNT_NAME=
|
||||||
|
DJANGO_AZURE_CONTAINER_NAME=
|
||||||
{% endif %}
|
{% endif %}
|
||||||
# django-allauth
|
# django-allauth
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
|
@ -27,16 +27,15 @@ jobs:
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v3
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: "3.10"
|
python-version: "3.10"
|
||||||
cache: pip
|
|
||||||
cache-dependency-path: |
|
|
||||||
requirements/base.txt
|
|
||||||
requirements/local.txt
|
|
||||||
|
|
||||||
|
{%- if cookiecutter.open_source_license != 'Not open source' %}
|
||||||
|
# Consider using pre-commit.ci for open source project
|
||||||
|
{%- endif %}
|
||||||
- name: Run pre-commit
|
- name: Run pre-commit
|
||||||
uses: pre-commit/action@v2.0.3
|
uses: pre-commit/action@v3.0.0
|
||||||
|
|
||||||
# With no caching at all the entire ci process takes 4m 30s to complete!
|
# With no caching at all the entire ci process takes 4m 30s to complete!
|
||||||
pytest:
|
pytest:
|
||||||
|
@ -85,7 +84,7 @@ jobs:
|
||||||
{%- else %}
|
{%- else %}
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v3
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: "3.10"
|
python-version: "3.10"
|
||||||
cache: pip
|
cache: pip
|
||||||
|
|
8
{{cookiecutter.project_slug}}/.gitignore
vendored
8
{{cookiecutter.project_slug}}/.gitignore
vendored
|
@ -326,6 +326,9 @@ Session.vim
|
||||||
# Auto-generated tag files
|
# Auto-generated tag files
|
||||||
tags
|
tags
|
||||||
|
|
||||||
|
# Redis dump file
|
||||||
|
dump.rdb
|
||||||
|
|
||||||
### Project template
|
### Project template
|
||||||
{%- if cookiecutter.use_mailhog == 'y' and cookiecutter.use_docker == 'n' %}
|
{%- if cookiecutter.use_mailhog == 'y' and cookiecutter.use_docker == 'n' %}
|
||||||
MailHog
|
MailHog
|
||||||
|
@ -343,4 +346,9 @@ project.css
|
||||||
project.min.css
|
project.min.css
|
||||||
vendors.js
|
vendors.js
|
||||||
*.min.js
|
*.min.js
|
||||||
|
*.min.js.map
|
||||||
|
{%- endif %}
|
||||||
|
{%- if cookiecutter.frontend_pipeline == 'Webpack' %}
|
||||||
|
{{ cookiecutter.project_slug }}/static/webpack_bundles/
|
||||||
|
webpack-stats.json
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
|
@ -7,21 +7,26 @@ variables:
|
||||||
POSTGRES_PASSWORD: ''
|
POSTGRES_PASSWORD: ''
|
||||||
POSTGRES_DB: 'test_{{ cookiecutter.project_slug }}'
|
POSTGRES_DB: 'test_{{ cookiecutter.project_slug }}'
|
||||||
POSTGRES_HOST_AUTH_METHOD: trust
|
POSTGRES_HOST_AUTH_METHOD: trust
|
||||||
{% if cookiecutter.use_celery == 'y' -%}
|
{%- if cookiecutter.use_celery == 'y' %}
|
||||||
CELERY_BROKER_URL: 'redis://redis:6379/0'
|
CELERY_BROKER_URL: 'redis://redis:6379/0'
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
||||||
flake8:
|
precommit:
|
||||||
stage: lint
|
stage: lint
|
||||||
image: python:3.10-alpine
|
image: python:3.10
|
||||||
|
variables:
|
||||||
|
PRE_COMMIT_HOME: ${CI_PROJECT_DIR}/.cache/pre-commit
|
||||||
|
cache:
|
||||||
|
paths:
|
||||||
|
- ${PRE_COMMIT_HOME}
|
||||||
before_script:
|
before_script:
|
||||||
- pip install -q flake8
|
- pip install -q pre-commit
|
||||||
script:
|
script:
|
||||||
- flake8
|
- pre-commit run --show-diff-on-failure --color=always --all-files
|
||||||
|
|
||||||
pytest:
|
pytest:
|
||||||
stage: test
|
stage: test
|
||||||
{% if cookiecutter.use_docker == 'y' -%}
|
{%- if cookiecutter.use_docker == 'y' %}
|
||||||
image: docker/compose:1.29.2
|
image: docker/compose:1.29.2
|
||||||
tags:
|
tags:
|
||||||
- docker
|
- docker
|
||||||
|
@ -34,7 +39,7 @@ pytest:
|
||||||
- docker-compose -f local.yml up -d
|
- docker-compose -f local.yml up -d
|
||||||
script:
|
script:
|
||||||
- docker-compose -f local.yml run django pytest
|
- docker-compose -f local.yml run django pytest
|
||||||
{%- else -%}
|
{%- else %}
|
||||||
image: python:3.10
|
image: python:3.10
|
||||||
tags:
|
tags:
|
||||||
- python
|
- python
|
||||||
|
@ -42,11 +47,8 @@ pytest:
|
||||||
- postgres:{{ cookiecutter.postgresql_version }}
|
- postgres:{{ cookiecutter.postgresql_version }}
|
||||||
variables:
|
variables:
|
||||||
DATABASE_URL: pgsql://$POSTGRES_USER:$POSTGRES_PASSWORD@postgres/$POSTGRES_DB
|
DATABASE_URL: pgsql://$POSTGRES_USER:$POSTGRES_PASSWORD@postgres/$POSTGRES_DB
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- pip install -r requirements/local.txt
|
- pip install -r requirements/local.txt
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- pytest
|
- pytest
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
<option value="celeryworker"/>
|
<option value="celeryworker"/>
|
||||||
<option value="celerybeat"/>
|
<option value="celerybeat"/>
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{%- if cookiecutter.frontend_pipeline == 'Gulp' %}
|
{%- if cookiecutter.frontend_pipeline in ['Gulp', 'Webpack'] %}
|
||||||
<option value="node"/>
|
<option value="node"/>
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
</list>
|
</list>
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
</facet>
|
</facet>
|
||||||
</component>
|
</component>
|
||||||
<component name="NewModuleRootManager">
|
<component name="NewModuleRootManager">
|
||||||
{% if cookiecutter.frontend_pipeline == 'Gulp' %}
|
{% if cookiecutter.frontend_pipeline in ['Gulp', 'Webpack'] %}
|
||||||
<content url="file://$MODULE_DIR$">
|
<content url="file://$MODULE_DIR$">
|
||||||
<excludeFolder url="file://$MODULE_DIR$/node_modules" />
|
<excludeFolder url="file://$MODULE_DIR$/node_modules" />
|
||||||
</content>
|
</content>
|
||||||
|
|
|
@ -3,30 +3,30 @@ default_stages: [commit]
|
||||||
|
|
||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
rev: v4.3.0
|
rev: v4.4.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: trailing-whitespace
|
- id: trailing-whitespace
|
||||||
- id: end-of-file-fixer
|
- id: end-of-file-fixer
|
||||||
- id: check-yaml
|
- id: check-yaml
|
||||||
|
|
||||||
- repo: https://github.com/asottile/pyupgrade
|
- repo: https://github.com/asottile/pyupgrade
|
||||||
rev: v3.2.2
|
rev: v3.3.1
|
||||||
hooks:
|
hooks:
|
||||||
- id: pyupgrade
|
- id: pyupgrade
|
||||||
args: [--py310-plus]
|
args: [--py310-plus]
|
||||||
|
|
||||||
- repo: https://github.com/psf/black
|
- repo: https://github.com/psf/black
|
||||||
rev: 22.10.0
|
rev: 23.1.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: black
|
- id: black
|
||||||
|
|
||||||
- repo: https://github.com/PyCQA/isort
|
- repo: https://github.com/PyCQA/isort
|
||||||
rev: 5.10.1
|
rev: 5.12.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: isort
|
- id: isort
|
||||||
|
|
||||||
- repo: https://github.com/PyCQA/flake8
|
- repo: https://github.com/PyCQA/flake8
|
||||||
rev: 5.0.4
|
rev: 6.0.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: flake8
|
- id: flake8
|
||||||
args: ["--config=setup.cfg"]
|
args: ["--config=setup.cfg"]
|
||||||
|
|
|
@ -1,12 +1,20 @@
|
||||||
|
# Read the Docs configuration file
|
||||||
|
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
|
||||||
|
|
||||||
|
# Required
|
||||||
version: 2
|
version: 2
|
||||||
|
|
||||||
|
# Set the version of Python and other tools you might need
|
||||||
|
build:
|
||||||
|
os: ubuntu-22.04
|
||||||
|
tools:
|
||||||
|
python: "3.10"
|
||||||
|
|
||||||
|
# Build documentation in the docs/ directory with Sphinx
|
||||||
sphinx:
|
sphinx:
|
||||||
configuration: docs/conf.py
|
configuration: docs/conf.py
|
||||||
|
|
||||||
build:
|
# Python requirements required to build your docs
|
||||||
image: testing
|
|
||||||
|
|
||||||
python:
|
python:
|
||||||
version: 3.10
|
|
||||||
install:
|
install:
|
||||||
- requirements: requirements/local.txt
|
- requirements: requirements/local.txt
|
||||||
|
|
|
@ -63,6 +63,20 @@ celery -A config.celery_app worker -l info
|
||||||
|
|
||||||
Please note: For Celery's import magic to work, it is important *where* the celery commands are run. If you are in the same folder with *manage.py*, you should be right.
|
Please note: For Celery's import magic to work, it is important *where* the celery commands are run. If you are in the same folder with *manage.py*, you should be right.
|
||||||
|
|
||||||
|
To run [periodic tasks](https://docs.celeryq.dev/en/stable/userguide/periodic-tasks.html), you'll need to start the celery beat scheduler service. You can start it as a standalone process:
|
||||||
|
|
||||||
|
``` bash
|
||||||
|
cd {{cookiecutter.project_slug}}
|
||||||
|
celery -A config.celery_app beat
|
||||||
|
```
|
||||||
|
|
||||||
|
or you can embed the beat service inside a worker with the `-B` option (not recommended for production use):
|
||||||
|
|
||||||
|
``` bash
|
||||||
|
cd {{cookiecutter.project_slug}}
|
||||||
|
celery -A config.celery_app worker -B -l info
|
||||||
|
```
|
||||||
|
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{%- if cookiecutter.use_mailhog == "y" %}
|
{%- if cookiecutter.use_mailhog == "y" %}
|
||||||
|
|
||||||
|
@ -128,13 +142,14 @@ See detailed [cookiecutter-django Heroku documentation](http://cookiecutter-djan
|
||||||
See detailed [cookiecutter-django Docker documentation](http://cookiecutter-django.readthedocs.io/en/latest/deployment-with-docker.html).
|
See detailed [cookiecutter-django Docker documentation](http://cookiecutter-django.readthedocs.io/en/latest/deployment-with-docker.html).
|
||||||
|
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{%- if cookiecutter.frontend_pipeline == 'Gulp' %}
|
{%- if cookiecutter.frontend_pipeline in ['Gulp', 'Webpack'] %}
|
||||||
|
|
||||||
### Custom Bootstrap Compilation
|
### Custom Bootstrap Compilation
|
||||||
|
|
||||||
The generated CSS is set up with automatic Bootstrap recompilation with variables of your choice.
|
The generated CSS is set up with automatic Bootstrap recompilation with variables of your choice.
|
||||||
Bootstrap v5 is installed using npm and customised by tweaking your variables in `static/sass/custom_bootstrap_vars`.
|
Bootstrap v5 is installed using npm and customised by tweaking your variables in `static/sass/custom_bootstrap_vars`.
|
||||||
|
|
||||||
You can find a list of available variables [in the bootstrap source](https://github.com/twbs/bootstrap/blob/main/scss/_variables.scss), or get explanations on them in the [Bootstrap docs](https://getbootstrap.com/docs/5.1/customize/sass/).
|
You can find a list of available variables [in the bootstrap source](https://github.com/twbs/bootstrap/blob/v5.1.3/scss/_variables.scss), or get explanations on them in the [Bootstrap docs](https://getbootstrap.com/docs/5.1/customize/sass/).
|
||||||
|
|
||||||
Bootstrap's javascript as well as its dependencies is concatenated into a single file: `static/js/vendors.js`.
|
Bootstrap's javascript as well as its dependencies are concatenated into a single file: `static/js/vendors.js`.
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
|
@ -5,4 +5,4 @@ set -o nounset
|
||||||
|
|
||||||
|
|
||||||
rm -f './celerybeat.pid'
|
rm -f './celerybeat.pid'
|
||||||
celery -A config.celery_app beat -l INFO
|
exec watchfiles celery.__main__.main --args '-A config.celery_app beat -l INFO'
|
||||||
|
|
|
@ -3,9 +3,6 @@
|
||||||
set -o errexit
|
set -o errexit
|
||||||
set -o nounset
|
set -o nounset
|
||||||
|
|
||||||
|
exec watchfiles celery.__main__.main \
|
||||||
celery \
|
--args \
|
||||||
-A config.celery_app \
|
"-A config.celery_app -b \"${CELERY_BROKER_URL}\" flower --basic_auth=\"${CELERY_FLOWER_USER}:${CELERY_FLOWER_PASSWORD}\""
|
||||||
-b "${CELERY_BROKER_URL}" \
|
|
||||||
flower \
|
|
||||||
--basic_auth="${CELERY_FLOWER_USER}:${CELERY_FLOWER_PASSWORD}"
|
|
||||||
|
|
|
@ -4,4 +4,4 @@ set -o errexit
|
||||||
set -o nounset
|
set -o nounset
|
||||||
|
|
||||||
|
|
||||||
watchfiles celery.__main__.main --args '-A config.celery_app worker -l INFO'
|
exec watchfiles celery.__main__.main --args '-A config.celery_app worker -l INFO'
|
||||||
|
|
|
@ -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' %}
|
||||||
uvicorn config.asgi:application --host 0.0.0.0 --reload --reload-include '*.html'
|
exec uvicorn config.asgi:application --host 0.0.0.0 --reload --reload-include '*.html'
|
||||||
{%- else %}
|
{%- else %}
|
||||||
python manage.py runserver_plus 0.0.0.0:8000
|
exec python manage.py runserver_plus 0.0.0.0:8000
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
|
@ -4,4 +4,4 @@ set -o errexit
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
set -o nounset
|
set -o nounset
|
||||||
|
|
||||||
make livehtml
|
exec make livehtml
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
FROM garland/aws-cli-docker:1.15.47
|
FROM garland/aws-cli-docker:1.16.140
|
||||||
|
|
||||||
COPY ./compose/production/aws/maintenance /usr/local/bin/maintenance
|
COPY ./compose/production/aws/maintenance /usr/local/bin/maintenance
|
||||||
COPY ./compose/production/postgres/maintenance/_sourced /usr/local/bin/maintenance/_sourced
|
COPY ./compose/production/postgres/maintenance/_sourced /usr/local/bin/maintenance/_sourced
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
ARG PYTHON_VERSION=3.10-slim-bullseye
|
ARG PYTHON_VERSION=3.10-slim-bullseye
|
||||||
|
|
||||||
{% if cookiecutter.frontend_pipeline == 'Gulp' -%}
|
{% if cookiecutter.frontend_pipeline in ['Gulp', 'Webpack'] -%}
|
||||||
FROM node:16-bullseye-slim as client-builder
|
FROM node:16-bullseye-slim as client-builder
|
||||||
|
|
||||||
ARG APP_HOME=/app
|
ARG APP_HOME=/app
|
||||||
|
@ -9,6 +9,20 @@ WORKDIR ${APP_HOME}
|
||||||
COPY ./package.json ${APP_HOME}
|
COPY ./package.json ${APP_HOME}
|
||||||
RUN npm install && npm cache clean --force
|
RUN npm install && npm cache clean --force
|
||||||
COPY . ${APP_HOME}
|
COPY . ${APP_HOME}
|
||||||
|
{%- if cookiecutter.frontend_pipeline == 'Webpack' and cookiecutter.use_whitenoise == 'n' %}
|
||||||
|
{%- if cookiecutter.cloud_provider == 'AWS' %}
|
||||||
|
ARG DJANGO_AWS_STORAGE_BUCKET_NAME
|
||||||
|
ENV DJANGO_AWS_STORAGE_BUCKET_NAME=${DJANGO_AWS_STORAGE_BUCKET_NAME}
|
||||||
|
ARG DJANGO_AWS_S3_CUSTOM_DOMAIN
|
||||||
|
ENV DJANGO_AWS_S3_CUSTOM_DOMAIN=${DJANGO_AWS_S3_CUSTOM_DOMAIN}
|
||||||
|
{%- elif cookiecutter.cloud_provider == 'GCP' %}
|
||||||
|
ARG DJANGO_GCP_STORAGE_BUCKET_NAME
|
||||||
|
ENV DJANGO_GCP_STORAGE_BUCKET_NAME=${DJANGO_GCP_STORAGE_BUCKET_NAME}
|
||||||
|
{%- elif cookiecutter.cloud_provider == 'Azure' %}
|
||||||
|
ARG DJANGO_AZURE_ACCOUNT_NAME
|
||||||
|
ENV DJANGO_AZURE_ACCOUNT_NAME=${DJANGO_AZURE_ACCOUNT_NAME}
|
||||||
|
{%- endif %}
|
||||||
|
{%- endif %}
|
||||||
RUN npm run build
|
RUN npm run build
|
||||||
|
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
@ -99,7 +113,7 @@ RUN chmod +x /start-flower
|
||||||
|
|
||||||
|
|
||||||
# copy application code to WORKDIR
|
# copy application code to WORKDIR
|
||||||
{%- if cookiecutter.frontend_pipeline == 'Gulp' %}
|
{%- if cookiecutter.frontend_pipeline in ['Gulp', 'Webpack'] %}
|
||||||
COPY --from=client-builder --chown=django:django ${APP_HOME} ${APP_HOME}
|
COPY --from=client-builder --chown=django:django ${APP_HOME} ${APP_HOME}
|
||||||
{% else %}
|
{% else %}
|
||||||
COPY --chown=django:django . ${APP_HOME}
|
COPY --chown=django:django . ${APP_HOME}
|
||||||
|
|
|
@ -28,7 +28,7 @@ if compress_enabled; then
|
||||||
fi
|
fi
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{%- if cookiecutter.use_async == 'y' %}
|
{%- if cookiecutter.use_async == 'y' %}
|
||||||
/usr/local/bin/gunicorn config.asgi --bind 0.0.0.0:5000 --chdir=/app -k uvicorn.workers.UvicornWorker
|
exec /usr/local/bin/gunicorn config.asgi --bind 0.0.0.0:5000 --chdir=/app -k uvicorn.workers.UvicornWorker
|
||||||
{%- else %}
|
{%- else %}
|
||||||
/usr/local/bin/gunicorn config.wsgi --bind 0.0.0.0:5000 --chdir=/app
|
exec /usr/local/bin/gunicorn config.wsgi --bind 0.0.0.0:5000 --chdir=/app
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
FROM nginx:1.17.8-alpine
|
||||||
|
COPY ./compose/production/nginx/default.conf /etc/nginx/conf.d/default.conf
|
|
@ -0,0 +1,7 @@
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name localhost;
|
||||||
|
location /media/ {
|
||||||
|
alias /usr/share/nginx/media/;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
FROM traefik:v2.2.11
|
FROM traefik:2.9.8
|
||||||
RUN mkdir -p /etc/traefik/acme \
|
RUN mkdir -p /etc/traefik/acme \
|
||||||
&& touch /etc/traefik/acme/acme.json \
|
&& touch /etc/traefik/acme/acme.json \
|
||||||
&& chmod 600 /etc/traefik/acme/acme.json
|
&& chmod 600 /etc/traefik/acme/acme.json
|
||||||
|
|
|
@ -57,6 +57,18 @@ http:
|
||||||
# https://docs.traefik.io/master/routing/routers/#certresolver
|
# https://docs.traefik.io/master/routing/routers/#certresolver
|
||||||
certResolver: letsencrypt
|
certResolver: letsencrypt
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
{%- if cookiecutter.cloud_provider == 'None' %}
|
||||||
|
|
||||||
|
web-media-router:
|
||||||
|
rule: "Host(`{{ cookiecutter.domain_name }}`) && PathPrefix(`/media/`)"
|
||||||
|
entryPoints:
|
||||||
|
- web-secure
|
||||||
|
middlewares:
|
||||||
|
- csrf
|
||||||
|
service: django-media
|
||||||
|
tls:
|
||||||
|
certResolver: letsencrypt
|
||||||
|
{%- endif %}
|
||||||
|
|
||||||
middlewares:
|
middlewares:
|
||||||
csrf:
|
csrf:
|
||||||
|
@ -77,6 +89,13 @@ http:
|
||||||
servers:
|
servers:
|
||||||
- url: http://flower:5555
|
- url: http://flower:5555
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
{%- if cookiecutter.cloud_provider == 'None' %}
|
||||||
|
|
||||||
|
django-media:
|
||||||
|
loadBalancer:
|
||||||
|
servers:
|
||||||
|
- url: http://nginx:80
|
||||||
|
{%- endif %}
|
||||||
|
|
||||||
providers:
|
providers:
|
||||||
# https://docs.traefik.io/master/providers/file/
|
# https://docs.traefik.io/master/providers/file/
|
||||||
|
|
|
@ -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.
|
||||||
ROOT_DIR = Path(__file__).resolve(strict=True).parent.parent
|
BASE_DIR = Path(__file__).resolve(strict=True).parent.parent
|
||||||
sys.path.append(str(ROOT_DIR / "{{ cookiecutter.project_slug }}"))
|
sys.path.append(str(BASE_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,15 +5,15 @@ from pathlib import Path
|
||||||
|
|
||||||
import environ
|
import environ
|
||||||
|
|
||||||
ROOT_DIR = Path(__file__).resolve(strict=True).parent.parent.parent
|
BASE_DIR = Path(__file__).resolve(strict=True).parent.parent.parent
|
||||||
# {{ cookiecutter.project_slug }}/
|
# {{ cookiecutter.project_slug }}/
|
||||||
APPS_DIR = ROOT_DIR / "{{ cookiecutter.project_slug }}"
|
APPS_DIR = BASE_DIR / "{{ cookiecutter.project_slug }}"
|
||||||
env = environ.Env()
|
env = environ.Env()
|
||||||
|
|
||||||
READ_DOT_ENV_FILE = env.bool("DJANGO_READ_DOT_ENV_FILE", default=False)
|
READ_DOT_ENV_FILE = env.bool("DJANGO_READ_DOT_ENV_FILE", default=False)
|
||||||
if READ_DOT_ENV_FILE:
|
if READ_DOT_ENV_FILE:
|
||||||
# OS environment variables take precedence over variables from .env
|
# OS environment variables take precedence over variables from .env
|
||||||
env.read_env(str(ROOT_DIR / ".env"))
|
env.read_env(str(BASE_DIR / ".env"))
|
||||||
|
|
||||||
# GENERAL
|
# GENERAL
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
@ -30,12 +30,10 @@ LANGUAGE_CODE = "en-us"
|
||||||
SITE_ID = 1
|
SITE_ID = 1
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#use-i18n
|
# https://docs.djangoproject.com/en/dev/ref/settings/#use-i18n
|
||||||
USE_I18N = True
|
USE_I18N = True
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#use-l10n
|
|
||||||
USE_L10N = True
|
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#use-tz
|
# https://docs.djangoproject.com/en/dev/ref/settings/#use-tz
|
||||||
USE_TZ = True
|
USE_TZ = True
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#locale-paths
|
# https://docs.djangoproject.com/en/dev/ref/settings/#locale-paths
|
||||||
LOCALE_PATHS = [str(ROOT_DIR / "locale")]
|
LOCALE_PATHS = [str(BASE_DIR / "locale")]
|
||||||
|
|
||||||
# DATABASES
|
# DATABASES
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
@ -89,6 +87,9 @@ THIRD_PARTY_APPS = [
|
||||||
"corsheaders",
|
"corsheaders",
|
||||||
"drf_spectacular",
|
"drf_spectacular",
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
{%- if cookiecutter.frontend_pipeline == 'Webpack' %}
|
||||||
|
"webpack_loader",
|
||||||
|
{%- endif %}
|
||||||
]
|
]
|
||||||
|
|
||||||
LOCAL_APPS = [
|
LOCAL_APPS = [
|
||||||
|
@ -154,14 +155,13 @@ MIDDLEWARE = [
|
||||||
"django.middleware.csrf.CsrfViewMiddleware",
|
"django.middleware.csrf.CsrfViewMiddleware",
|
||||||
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
||||||
"django.contrib.messages.middleware.MessageMiddleware",
|
"django.contrib.messages.middleware.MessageMiddleware",
|
||||||
"django.middleware.common.BrokenLinkEmailsMiddleware",
|
|
||||||
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||||
]
|
]
|
||||||
|
|
||||||
# STATIC
|
# STATIC
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#static-root
|
# https://docs.djangoproject.com/en/dev/ref/settings/#static-root
|
||||||
STATIC_ROOT = str(ROOT_DIR / "staticfiles")
|
STATIC_ROOT = str(BASE_DIR / "staticfiles")
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#static-url
|
# https://docs.djangoproject.com/en/dev/ref/settings/#static-url
|
||||||
STATIC_URL = "/static/"
|
STATIC_URL = "/static/"
|
||||||
# https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#std:setting-STATICFILES_DIRS
|
# https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#std:setting-STATICFILES_DIRS
|
||||||
|
@ -285,6 +285,11 @@ CELERY_BROKER_URL = env("CELERY_BROKER_URL")
|
||||||
CELERY_RESULT_BACKEND = CELERY_BROKER_URL
|
CELERY_RESULT_BACKEND = CELERY_BROKER_URL
|
||||||
# https://docs.celeryq.dev/en/stable/userguide/configuration.html#result-extended
|
# https://docs.celeryq.dev/en/stable/userguide/configuration.html#result-extended
|
||||||
CELERY_RESULT_EXTENDED = True
|
CELERY_RESULT_EXTENDED = True
|
||||||
|
# https://docs.celeryq.dev/en/stable/userguide/configuration.html#result-backend-always-retry
|
||||||
|
# https://github.com/celery/celery/pull/6122
|
||||||
|
CELERY_RESULT_BACKEND_ALWAYS_RETRY = True
|
||||||
|
# https://docs.celeryq.dev/en/stable/userguide/configuration.html#result-backend-max-retries
|
||||||
|
CELERY_RESULT_BACKEND_MAX_RETRIES = 10
|
||||||
# https://docs.celeryq.dev/en/stable/userguide/configuration.html#std:setting-accept_content
|
# https://docs.celeryq.dev/en/stable/userguide/configuration.html#std:setting-accept_content
|
||||||
CELERY_ACCEPT_CONTENT = ["json"]
|
CELERY_ACCEPT_CONTENT = ["json"]
|
||||||
# https://docs.celeryq.dev/en/stable/userguide/configuration.html#std:setting-task_serializer
|
# https://docs.celeryq.dev/en/stable/userguide/configuration.html#std:setting-task_serializer
|
||||||
|
@ -299,6 +304,10 @@ CELERY_TASK_TIME_LIMIT = 5 * 60
|
||||||
CELERY_TASK_SOFT_TIME_LIMIT = 60
|
CELERY_TASK_SOFT_TIME_LIMIT = 60
|
||||||
# https://docs.celeryq.dev/en/stable/userguide/configuration.html#beat-scheduler
|
# https://docs.celeryq.dev/en/stable/userguide/configuration.html#beat-scheduler
|
||||||
CELERY_BEAT_SCHEDULER = "django_celery_beat.schedulers:DatabaseScheduler"
|
CELERY_BEAT_SCHEDULER = "django_celery_beat.schedulers:DatabaseScheduler"
|
||||||
|
# https://docs.celeryq.dev/en/stable/userguide/configuration.html#worker-send-task-events
|
||||||
|
CELERY_WORKER_SEND_TASK_EVENTS = True
|
||||||
|
# https://docs.celeryq.dev/en/stable/userguide/configuration.html#std-setting-task_send_sent_event
|
||||||
|
CELERY_TASK_SEND_SENT_EVENT = True
|
||||||
|
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
# django-allauth
|
# django-allauth
|
||||||
|
@ -354,11 +363,20 @@ SPECTACULAR_SETTINGS = {
|
||||||
"DESCRIPTION": "Documentation of API endpoints of {{ cookiecutter.project_name }}",
|
"DESCRIPTION": "Documentation of API endpoints of {{ cookiecutter.project_name }}",
|
||||||
"VERSION": "1.0.0",
|
"VERSION": "1.0.0",
|
||||||
"SERVE_PERMISSIONS": ["rest_framework.permissions.IsAdminUser"],
|
"SERVE_PERMISSIONS": ["rest_framework.permissions.IsAdminUser"],
|
||||||
"SERVERS": [
|
|
||||||
{"url": "http://127.0.0.1:8000", "description": "Local Development server"},
|
|
||||||
{"url": "https://{{ cookiecutter.domain_name }}", "description": "Production server"},
|
|
||||||
],
|
|
||||||
}
|
}
|
||||||
|
{%- endif %}
|
||||||
|
{%- if cookiecutter.frontend_pipeline == 'Webpack' %}
|
||||||
|
# django-webpack-loader
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
WEBPACK_LOADER = {
|
||||||
|
"DEFAULT": {
|
||||||
|
"CACHE": not DEBUG,
|
||||||
|
"STATS_FILE": BASE_DIR / "webpack-stats.json",
|
||||||
|
"POLL_INTERVAL": 0.1,
|
||||||
|
"IGNORE": [r".+\.hot-update.js", r".+\.map"],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
# Your stuff...
|
# Your stuff...
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
|
@ -69,7 +69,7 @@ if env("USE_DOCKER") == "yes":
|
||||||
|
|
||||||
hostname, _, ips = socket.gethostbyname_ex(socket.gethostname())
|
hostname, _, ips = socket.gethostbyname_ex(socket.gethostname())
|
||||||
INTERNAL_IPS += [".".join(ip.split(".")[:-1] + ["1"]) for ip in ips]
|
INTERNAL_IPS += [".".join(ip.split(".")[:-1] + ["1"]) for ip in ips]
|
||||||
{%- if cookiecutter.frontend_pipeline == 'Gulp' %}
|
{%- if cookiecutter.frontend_pipeline in ['Gulp', 'Webpack'] %}
|
||||||
try:
|
try:
|
||||||
_, _, ips = socket.gethostbyname_ex("node")
|
_, _, ips = socket.gethostbyname_ex("node")
|
||||||
INTERNAL_IPS.extend(ips)
|
INTERNAL_IPS.extend(ips)
|
||||||
|
@ -94,6 +94,12 @@ CELERY_TASK_ALWAYS_EAGER = True
|
||||||
# https://docs.celeryq.dev/en/stable/userguide/configuration.html#task-eager-propagates
|
# https://docs.celeryq.dev/en/stable/userguide/configuration.html#task-eager-propagates
|
||||||
CELERY_TASK_EAGER_PROPAGATES = True
|
CELERY_TASK_EAGER_PROPAGATES = True
|
||||||
|
|
||||||
|
{%- endif %}
|
||||||
|
{%- if cookiecutter.frontend_pipeline == 'Webpack' %}
|
||||||
|
# django-webpack-loader
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
WEBPACK_LOADER["DEFAULT"]["CACHE"] = not DEBUG # noqa F405
|
||||||
|
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
# Your stuff...
|
# Your stuff...
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
|
@ -22,8 +22,6 @@ ALLOWED_HOSTS = env.list("DJANGO_ALLOWED_HOSTS", default=["{{ cookiecutter.domai
|
||||||
|
|
||||||
# DATABASES
|
# DATABASES
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
DATABASES["default"] = env.db("DATABASE_URL") # noqa F405
|
|
||||||
DATABASES["default"]["ATOMIC_REQUESTS"] = True # noqa F405
|
|
||||||
DATABASES["default"]["CONN_MAX_AGE"] = env.int("CONN_MAX_AGE", default=60) # noqa F405
|
DATABASES["default"]["CONN_MAX_AGE"] = env.int("CONN_MAX_AGE", default=60) # noqa F405
|
||||||
|
|
||||||
# CACHES
|
# CACHES
|
||||||
|
@ -100,6 +98,10 @@ aws_s3_domain = AWS_S3_CUSTOM_DOMAIN or f"{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws
|
||||||
{% 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"
|
||||||
|
{% elif cookiecutter.cloud_provider == 'Azure' %}
|
||||||
|
AZURE_ACCOUNT_KEY = env("DJANGO_AZURE_ACCOUNT_KEY")
|
||||||
|
AZURE_ACCOUNT_NAME = env("DJANGO_AZURE_ACCOUNT_NAME")
|
||||||
|
AZURE_CONTAINER = env("DJANGO_AZURE_CONTAINER_NAME")
|
||||||
{% endif -%}
|
{% endif -%}
|
||||||
|
|
||||||
{% if cookiecutter.cloud_provider != 'None' or cookiecutter.use_whitenoise == 'y' -%}
|
{% if cookiecutter.cloud_provider != 'None' or cookiecutter.use_whitenoise == 'y' -%}
|
||||||
|
@ -116,6 +118,9 @@ STATIC_URL = f"https://{aws_s3_domain}/static/"
|
||||||
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"
|
||||||
STATIC_URL = f"https://storage.googleapis.com/{GS_BUCKET_NAME}/static/"
|
STATIC_URL = f"https://storage.googleapis.com/{GS_BUCKET_NAME}/static/"
|
||||||
|
{% elif cookiecutter.cloud_provider == 'Azure' -%}
|
||||||
|
STATICFILES_STORAGE = "{{cookiecutter.project_slug}}.utils.storages.StaticRootAzureStorage"
|
||||||
|
STATIC_URL = f"https://{AZURE_ACCOUNT_NAME}.blob.core.windows.net/static/"
|
||||||
{% endif -%}
|
{% endif -%}
|
||||||
|
|
||||||
# MEDIA
|
# MEDIA
|
||||||
|
@ -126,6 +131,9 @@ 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/"
|
||||||
|
{%- elif cookiecutter.cloud_provider == 'Azure' %}
|
||||||
|
DEFAULT_FILE_STORAGE = "{{cookiecutter.project_slug}}.utils.storages.MediaRootAzureStorage"
|
||||||
|
MEDIA_URL = f"https://{AZURE_ACCOUNT_NAME}.blob.core.windows.net/media/"
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
||||||
# EMAIL
|
# EMAIL
|
||||||
|
@ -228,7 +236,7 @@ COMPRESS_ENABLED = env.bool("COMPRESS_ENABLED", default=True)
|
||||||
{%- if cookiecutter.cloud_provider == 'None' %}
|
{%- if cookiecutter.cloud_provider == 'None' %}
|
||||||
# https://django-compressor.readthedocs.io/en/latest/settings/#django.conf.settings.COMPRESS_STORAGE
|
# https://django-compressor.readthedocs.io/en/latest/settings/#django.conf.settings.COMPRESS_STORAGE
|
||||||
COMPRESS_STORAGE = "compressor.storage.GzipCompressorFileStorage"
|
COMPRESS_STORAGE = "compressor.storage.GzipCompressorFileStorage"
|
||||||
{%- elif cookiecutter.cloud_provider in ('AWS', 'GCP') and cookiecutter.use_whitenoise == 'n' %}
|
{%- elif cookiecutter.cloud_provider in ('AWS', 'GCP', 'Azure') and cookiecutter.use_whitenoise == 'n' %}
|
||||||
# https://django-compressor.readthedocs.io/en/latest/settings/#django.conf.settings.COMPRESS_STORAGE
|
# https://django-compressor.readthedocs.io/en/latest/settings/#django.conf.settings.COMPRESS_STORAGE
|
||||||
COMPRESS_STORAGE = STATICFILES_STORAGE
|
COMPRESS_STORAGE = STATICFILES_STORAGE
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
@ -360,5 +368,15 @@ sentry_sdk.init(
|
||||||
traces_sample_rate=env.float("SENTRY_TRACES_SAMPLE_RATE", default=0.0),
|
traces_sample_rate=env.float("SENTRY_TRACES_SAMPLE_RATE", default=0.0),
|
||||||
)
|
)
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if cookiecutter.use_drf == "y" -%}
|
||||||
|
|
||||||
|
# django-rest-framework
|
||||||
|
# -------------------------------------------------------------------------------
|
||||||
|
# Tools that generate code samples can use SERVERS to point to the correct domain
|
||||||
|
SPECTACULAR_SETTINGS["SERVERS"] = [ # noqa F405
|
||||||
|
{"url": "https://{{ cookiecutter.domain_name }}", "description": "Production server"}
|
||||||
|
]
|
||||||
|
|
||||||
|
{%- endif %}
|
||||||
# Your stuff...
|
# Your stuff...
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
|
@ -25,9 +25,17 @@ PASSWORD_HASHERS = ["django.contrib.auth.hashers.MD5PasswordHasher"]
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#email-backend
|
# https://docs.djangoproject.com/en/dev/ref/settings/#email-backend
|
||||||
EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend"
|
EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend"
|
||||||
|
|
||||||
# DEBUGING FOR TEMPLATES
|
# DEBUGGING FOR TEMPLATES
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
TEMPLATES[0]["OPTIONS"]["debug"] = True # type: ignore # noqa F405
|
TEMPLATES[0]["OPTIONS"]["debug"] = True # type: ignore # noqa F405
|
||||||
|
|
||||||
|
{%- if cookiecutter.frontend_pipeline == 'Webpack' %}
|
||||||
|
# django-webpack-loader
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
WEBPACK_LOADER["DEFAULT"][ # noqa F405
|
||||||
|
"LOADER_CLASS"
|
||||||
|
] = "webpack_loader.loader.FakeWebpackLoader"
|
||||||
|
|
||||||
|
{%- endif %}
|
||||||
# Your stuff...
|
# Your stuff...
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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.
|
||||||
ROOT_DIR = Path(__file__).resolve(strict=True).parent.parent
|
BASE_DIR = Path(__file__).resolve(strict=True).parent.parent
|
||||||
sys.path.append(str(ROOT_DIR / "{{ cookiecutter.project_slug }}"))
|
sys.path.append(str(BASE_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 @@ const pjson = require('./package.json')
|
||||||
const autoprefixer = require('autoprefixer')
|
const autoprefixer = require('autoprefixer')
|
||||||
const browserSync = require('browser-sync').create()
|
const browserSync = require('browser-sync').create()
|
||||||
const concat = require('gulp-concat')
|
const concat = require('gulp-concat')
|
||||||
|
const tildeImporter = require('node-sass-tilde-importer');
|
||||||
const cssnano = require ('cssnano')
|
const cssnano = require ('cssnano')
|
||||||
const imagemin = require('gulp-imagemin')
|
const imagemin = require('gulp-imagemin')
|
||||||
const pixrem = require('pixrem')
|
const pixrem = require('pixrem')
|
||||||
|
@ -27,7 +28,6 @@ function pathsConfig(appName) {
|
||||||
const vendorsRoot = 'node_modules'
|
const vendorsRoot = 'node_modules'
|
||||||
|
|
||||||
return {
|
return {
|
||||||
bootstrapSass: `${vendorsRoot}/bootstrap/scss`,
|
|
||||||
vendorsJs: [
|
vendorsJs: [
|
||||||
`${vendorsRoot}/@popperjs/core/dist/umd/popper.js`,
|
`${vendorsRoot}/@popperjs/core/dist/umd/popper.js`,
|
||||||
`${vendorsRoot}/bootstrap/dist/js/bootstrap.js`,
|
`${vendorsRoot}/bootstrap/dist/js/bootstrap.js`,
|
||||||
|
@ -61,8 +61,8 @@ function styles() {
|
||||||
|
|
||||||
return src(`${paths.sass}/project.scss`)
|
return src(`${paths.sass}/project.scss`)
|
||||||
.pipe(sass({
|
.pipe(sass({
|
||||||
|
importer: tildeImporter,
|
||||||
includePaths: [
|
includePaths: [
|
||||||
paths.bootstrapSass,
|
|
||||||
paths.sass
|
paths.sass
|
||||||
]
|
]
|
||||||
}).on('error', sass.logError))
|
}).on('error', sass.logError))
|
||||||
|
@ -85,13 +85,13 @@ function scripts() {
|
||||||
|
|
||||||
// Vendor Javascript minification
|
// Vendor Javascript minification
|
||||||
function vendorScripts() {
|
function vendorScripts() {
|
||||||
return src(paths.vendorsJs)
|
return src(paths.vendorsJs, { sourcemaps: true })
|
||||||
.pipe(concat('vendors.js'))
|
.pipe(concat('vendors.js'))
|
||||||
.pipe(dest(paths.js))
|
.pipe(dest(paths.js))
|
||||||
.pipe(plumber()) // Checks for errors
|
.pipe(plumber()) // Checks for errors
|
||||||
.pipe(uglify()) // Minifies the js
|
.pipe(uglify()) // Minifies the js
|
||||||
.pipe(rename({ suffix: '.min' }))
|
.pipe(rename({ suffix: '.min' }))
|
||||||
.pipe(dest(paths.js))
|
.pipe(dest(paths.js, { sourcemaps: '.' }))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Image compression
|
// Image compression
|
||||||
|
|
|
@ -11,7 +11,6 @@ services:
|
||||||
dockerfile: ./compose/local/django/Dockerfile
|
dockerfile: ./compose/local/django/Dockerfile
|
||||||
image: {{ cookiecutter.project_slug }}_local_django
|
image: {{ cookiecutter.project_slug }}_local_django
|
||||||
container_name: {{ cookiecutter.project_slug }}_local_django
|
container_name: {{ cookiecutter.project_slug }}_local_django
|
||||||
platform: linux/x86_64
|
|
||||||
depends_on:
|
depends_on:
|
||||||
- postgres
|
- postgres
|
||||||
{%- if cookiecutter.use_celery == 'y' %}
|
{%- if cookiecutter.use_celery == 'y' %}
|
||||||
|
@ -36,15 +35,14 @@ services:
|
||||||
image: {{ cookiecutter.project_slug }}_production_postgres
|
image: {{ cookiecutter.project_slug }}_production_postgres
|
||||||
container_name: {{ cookiecutter.project_slug }}_local_postgres
|
container_name: {{ cookiecutter.project_slug }}_local_postgres
|
||||||
volumes:
|
volumes:
|
||||||
- {{ cookiecutter.project_slug }}_local_postgres_data:/var/lib/postgresql/data:Z
|
- {{ cookiecutter.project_slug }}_local_postgres_data:/var/lib/postgresql/data
|
||||||
- {{ cookiecutter.project_slug }}_local_postgres_data_backups:/backups:z
|
- {{ cookiecutter.project_slug }}_local_postgres_data_backups:/backups
|
||||||
env_file:
|
env_file:
|
||||||
- ./.envs/.local/.postgres
|
- ./.envs/.local/.postgres
|
||||||
|
|
||||||
docs:
|
docs:
|
||||||
image: {{ cookiecutter.project_slug }}_local_docs
|
image: {{ cookiecutter.project_slug }}_local_docs
|
||||||
container_name: {{ cookiecutter.project_slug }}_local_docs
|
container_name: {{ cookiecutter.project_slug }}_local_docs
|
||||||
platform: linux/x86_64
|
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: ./compose/local/docs/Dockerfile
|
dockerfile: ./compose/local/docs/Dockerfile
|
||||||
|
@ -107,7 +105,7 @@ services:
|
||||||
command: /start-flower
|
command: /start-flower
|
||||||
|
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{%- if cookiecutter.frontend_pipeline == 'Gulp' %}
|
{%- if cookiecutter.frontend_pipeline in ['Gulp', 'Webpack'] %}
|
||||||
|
|
||||||
node:
|
node:
|
||||||
build:
|
build:
|
||||||
|
@ -124,7 +122,9 @@ services:
|
||||||
command: npm run dev
|
command: npm run dev
|
||||||
ports:
|
ports:
|
||||||
- "3000:3000"
|
- "3000:3000"
|
||||||
|
{%- if cookiecutter.frontend_pipeline == 'Gulp' %}
|
||||||
# Expose browsersync UI: https://www.browsersync.io/docs/options/#option-ui
|
# Expose browsersync UI: https://www.browsersync.io/docs/options/#option-ui
|
||||||
- "3001:3001"
|
- "3001:3001"
|
||||||
|
{%- endif %}
|
||||||
|
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
|
@ -2,66 +2,25 @@ import os
|
||||||
from collections.abc import Sequence
|
from collections.abc import Sequence
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import pytest
|
BASE_DIR = Path(__file__).parent.resolve()
|
||||||
|
PRODUCTION_DOTENVS_DIR = BASE_DIR / ".envs" / ".production"
|
||||||
ROOT_DIR_PATH = Path(__file__).parent.resolve()
|
PRODUCTION_DOTENV_FILES = [
|
||||||
PRODUCTION_DOTENVS_DIR_PATH = ROOT_DIR_PATH / ".envs" / ".production"
|
PRODUCTION_DOTENVS_DIR / ".django",
|
||||||
PRODUCTION_DOTENV_FILE_PATHS = [
|
PRODUCTION_DOTENVS_DIR / ".postgres",
|
||||||
PRODUCTION_DOTENVS_DIR_PATH / ".django",
|
|
||||||
PRODUCTION_DOTENVS_DIR_PATH / ".postgres",
|
|
||||||
]
|
]
|
||||||
DOTENV_FILE_PATH = ROOT_DIR_PATH / ".env"
|
DOTENV_FILE = BASE_DIR / ".env"
|
||||||
|
|
||||||
|
|
||||||
def merge(
|
def merge(
|
||||||
output_file_path: str, merged_file_paths: Sequence[str], append_linesep: bool = True
|
output_file: Path,
|
||||||
|
files_to_merge: Sequence[Path],
|
||||||
) -> None:
|
) -> None:
|
||||||
with open(output_file_path, "w") as output_file:
|
merged_content = ""
|
||||||
for merged_file_path in merged_file_paths:
|
for merge_file in files_to_merge:
|
||||||
with open(merged_file_path) as merged_file:
|
merged_content += merge_file.read_text()
|
||||||
merged_file_content = merged_file.read()
|
merged_content += os.linesep
|
||||||
output_file.write(merged_file_content)
|
output_file.write_text(merged_content)
|
||||||
if append_linesep:
|
|
||||||
output_file.write(os.linesep)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
merge(DOTENV_FILE_PATH, PRODUCTION_DOTENV_FILE_PATHS)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("merged_file_count", range(3))
|
|
||||||
@pytest.mark.parametrize("append_linesep", [True, False])
|
|
||||||
def test_merge(tmpdir_factory, merged_file_count: int, append_linesep: bool):
|
|
||||||
tmp_dir_path = Path(str(tmpdir_factory.getbasetemp()))
|
|
||||||
|
|
||||||
output_file_path = tmp_dir_path / ".env"
|
|
||||||
|
|
||||||
expected_output_file_content = ""
|
|
||||||
merged_file_paths = []
|
|
||||||
for i in range(merged_file_count):
|
|
||||||
merged_file_ord = i + 1
|
|
||||||
|
|
||||||
merged_filename = f".service{merged_file_ord}"
|
|
||||||
merged_file_path = tmp_dir_path / merged_filename
|
|
||||||
|
|
||||||
merged_file_content = merged_filename * merged_file_ord
|
|
||||||
|
|
||||||
with open(merged_file_path, "w+") as file:
|
|
||||||
file.write(merged_file_content)
|
|
||||||
|
|
||||||
expected_output_file_content += merged_file_content
|
|
||||||
if append_linesep:
|
|
||||||
expected_output_file_content += os.linesep
|
|
||||||
|
|
||||||
merged_file_paths.append(merged_file_path)
|
|
||||||
|
|
||||||
merge(output_file_path, merged_file_paths, append_linesep)
|
|
||||||
|
|
||||||
with open(output_file_path) as output_file:
|
|
||||||
actual_output_file_content = output_file.read()
|
|
||||||
|
|
||||||
assert actual_output_file_content == expected_output_file_content
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
merge(DOTENV_FILE, PRODUCTION_DOTENV_FILES)
|
||||||
|
|
|
@ -1,13 +1,17 @@
|
||||||
{
|
{
|
||||||
"name": "{{cookiecutter.project_slug}}",
|
"name": "{{cookiecutter.project_slug}}",
|
||||||
"version": "{{ cookiecutter.version }}",
|
"version": "{{ cookiecutter.version }}",
|
||||||
"dependencies": {},
|
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"bootstrap": "^5.1.3",
|
"@babel/core": "^7.16.5",
|
||||||
"gulp-concat": "^2.6.1",
|
"@babel/preset-env": "^7.16.5",
|
||||||
"@popperjs/core": "^2.10.2",
|
"@popperjs/core": "^2.10.2",
|
||||||
"autoprefixer": "^10.4.0",
|
"autoprefixer": "^10.4.0",
|
||||||
|
"babel-loader": "^9.1.2",
|
||||||
|
"bootstrap": "^5.1.3",
|
||||||
"browser-sync": "^2.27.7",
|
"browser-sync": "^2.27.7",
|
||||||
|
"css-loader": "^6.5.1",
|
||||||
|
"gulp-concat": "^2.6.1",
|
||||||
|
"concurrently": "^7.0.0",
|
||||||
"cssnano": "^5.0.11",
|
"cssnano": "^5.0.11",
|
||||||
"gulp": "^4.0.2",
|
"gulp": "^4.0.2",
|
||||||
"gulp-imagemin": "^7.1.0",
|
"gulp-imagemin": "^7.1.0",
|
||||||
|
@ -16,9 +20,19 @@
|
||||||
"gulp-rename": "^2.0.0",
|
"gulp-rename": "^2.0.0",
|
||||||
"gulp-sass": "^5.0.0",
|
"gulp-sass": "^5.0.0",
|
||||||
"gulp-uglify-es": "^3.0.0",
|
"gulp-uglify-es": "^3.0.0",
|
||||||
|
"mini-css-extract-plugin": "^2.4.5",
|
||||||
|
"node-sass-tilde-importer": "^1.0.2",
|
||||||
"pixrem": "^5.0.0",
|
"pixrem": "^5.0.0",
|
||||||
"postcss": "^8.3.11",
|
"postcss": "^8.3.11",
|
||||||
"sass": "^1.43.4"
|
"postcss-loader": "^7.0.2",
|
||||||
|
"postcss-preset-env": "^8.0.1",
|
||||||
|
"sass": "^1.43.4",
|
||||||
|
"sass-loader": "^13.2.0",
|
||||||
|
"webpack": "^5.65.0",
|
||||||
|
"webpack-bundle-tracker": "^1.4.0",
|
||||||
|
"webpack-cli": "^5.0.1",
|
||||||
|
"webpack-dev-server": "^4.6.0",
|
||||||
|
"webpack-merge": "^5.8.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "16"
|
"node": "16"
|
||||||
|
@ -26,8 +40,11 @@
|
||||||
"browserslist": [
|
"browserslist": [
|
||||||
"last 2 versions"
|
"last 2 versions"
|
||||||
],
|
],
|
||||||
|
"babel": {
|
||||||
|
"presets": ["@babel/preset-env"]
|
||||||
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "gulp",
|
"dev": "",
|
||||||
"build": "gulp generate-assets"
|
"build": ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,14 +4,33 @@ volumes:
|
||||||
production_postgres_data: {}
|
production_postgres_data: {}
|
||||||
production_postgres_data_backups: {}
|
production_postgres_data_backups: {}
|
||||||
production_traefik: {}
|
production_traefik: {}
|
||||||
|
{%- if cookiecutter.cloud_provider == 'None' %}
|
||||||
|
production_django_media: {}
|
||||||
|
{%- endif %}
|
||||||
|
|
||||||
services:
|
services:
|
||||||
django:{% if cookiecutter.use_celery == 'y' %} &django{% endif %}
|
django:{% if cookiecutter.use_celery == 'y' %} &django{% endif %}
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: ./compose/production/django/Dockerfile
|
dockerfile: ./compose/production/django/Dockerfile
|
||||||
|
{%- if cookiecutter.frontend_pipeline == 'Webpack' and cookiecutter.use_whitenoise == 'n' %}
|
||||||
|
args:
|
||||||
|
# These variable can be defined in an .env file in the root of the repo
|
||||||
|
{%- if cookiecutter.cloud_provider == 'AWS' %}
|
||||||
|
DJANGO_AWS_STORAGE_BUCKET_NAME: ${DJANGO_AWS_STORAGE_BUCKET_NAME}
|
||||||
|
DJANGO_AWS_S3_CUSTOM_DOMAIN: ${DJANGO_AWS_S3_CUSTOM_DOMAIN}
|
||||||
|
{%- elif cookiecutter.cloud_provider == 'GCP' %}
|
||||||
|
DJANGO_GCP_STORAGE_BUCKET_NAME: ${DJANGO_GCP_STORAGE_BUCKET_NAME}
|
||||||
|
{%- elif cookiecutter.cloud_provider == 'Azure' %}
|
||||||
|
DJANGO_AZURE_ACCOUNT_NAME: ${DJANGO_AZURE_ACCOUNT_NAME}
|
||||||
|
{%- endif %}
|
||||||
|
{%- endif %}
|
||||||
|
|
||||||
image: {{ cookiecutter.project_slug }}_production_django
|
image: {{ cookiecutter.project_slug }}_production_django
|
||||||
platform: linux/x86_64
|
{%- if cookiecutter.cloud_provider == 'None' %}
|
||||||
|
volumes:
|
||||||
|
- production_django_media:/app/{{ cookiecutter.project_slug }}/media
|
||||||
|
{%- endif %}
|
||||||
depends_on:
|
depends_on:
|
||||||
- postgres
|
- postgres
|
||||||
- redis
|
- redis
|
||||||
|
@ -26,8 +45,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:
|
||||||
- production_postgres_data:/var/lib/postgresql/data:Z
|
- production_postgres_data:/var/lib/postgresql/data
|
||||||
- production_postgres_data_backups:/backups:z
|
- production_postgres_data_backups:/backups
|
||||||
env_file:
|
env_file:
|
||||||
- ./.envs/.production/.postgres
|
- ./.envs/.production/.postgres
|
||||||
|
|
||||||
|
@ -39,7 +58,7 @@ services:
|
||||||
depends_on:
|
depends_on:
|
||||||
- django
|
- django
|
||||||
volumes:
|
volumes:
|
||||||
- production_traefik:/etc/traefik/acme:z
|
- production_traefik:/etc/traefik/acme
|
||||||
ports:
|
ports:
|
||||||
- "0.0.0.0:80:80"
|
- "0.0.0.0:80:80"
|
||||||
- "0.0.0.0:443:443"
|
- "0.0.0.0:443:443"
|
||||||
|
@ -77,3 +96,14 @@ services:
|
||||||
volumes:
|
volumes:
|
||||||
- production_postgres_data_backups:/backups:z
|
- production_postgres_data_backups:/backups:z
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
{%- if cookiecutter.cloud_provider == 'None' %}
|
||||||
|
nginx:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: ./compose/production/nginx/Dockerfile
|
||||||
|
image: {{ cookiecutter.project_slug }}_local_nginx
|
||||||
|
depends_on:
|
||||||
|
- django
|
||||||
|
volumes:
|
||||||
|
- production_django_media:/usr/share/nginx/media:ro
|
||||||
|
{%- endif %}
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
pytz==2022.6 # https://github.com/stub42/pytz
|
pytz==2022.7.1 # https://github.com/stub42/pytz
|
||||||
python-slugify==7.0.0 # https://github.com/un33k/python-slugify
|
python-slugify==8.0.1 # https://github.com/un33k/python-slugify
|
||||||
Pillow==9.3.0 # https://github.com/python-pillow/Pillow
|
Pillow==9.4.0 # https://github.com/python-pillow/Pillow
|
||||||
{%- if cookiecutter.frontend_pipeline == 'Django Compressor' %}
|
{%- if cookiecutter.frontend_pipeline == 'Django Compressor' %}
|
||||||
{%- if cookiecutter.windows == 'y' and cookiecutter.use_docker == 'n' %}
|
{%- if cookiecutter.windows == 'y' and cookiecutter.use_docker == 'n' %}
|
||||||
rcssmin==1.1.0 --install-option="--without-c-extensions" # https://github.com/ndparker/rcssmin
|
rcssmin==1.1.0 --install-option="--without-c-extensions" # https://github.com/ndparker/rcssmin
|
||||||
{%- else %}
|
{%- else %}
|
||||||
rcssmin==1.1.0 # https://github.com/ndparker/rcssmin
|
rcssmin==1.1.1 # https://github.com/ndparker/rcssmin
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
argon2-cffi==21.3.0 # https://github.com/hynek/argon2_cffi
|
argon2-cffi==21.3.0 # https://github.com/hynek/argon2_cffi
|
||||||
{%- if cookiecutter.use_whitenoise == 'y' %}
|
{%- if cookiecutter.use_whitenoise == 'y' %}
|
||||||
whitenoise==6.2.0 # https://github.com/evansd/whitenoise
|
whitenoise==6.4.0 # https://github.com/evansd/whitenoise
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
redis==4.3.5 # https://github.com/redis/redis-py
|
redis==4.5.1 # https://github.com/redis/redis-py
|
||||||
{%- if cookiecutter.use_docker == "y" or cookiecutter.windows == "n" %}
|
{%- if cookiecutter.use_docker == "y" or cookiecutter.windows == "n" %}
|
||||||
hiredis==2.0.0 # https://github.com/redis/hiredis-py
|
hiredis==2.2.2 # https://github.com/redis/hiredis-py
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{%- if cookiecutter.use_celery == "y" %}
|
{%- if cookiecutter.use_celery == "y" %}
|
||||||
celery==5.2.7 # pyup: < 6.0 # https://github.com/celery/celery
|
celery==5.2.7 # pyup: < 6.0 # https://github.com/celery/celery
|
||||||
|
@ -29,20 +29,23 @@ uvicorn[standard]==0.20.0 # https://github.com/encode/uvicorn
|
||||||
|
|
||||||
# Django
|
# Django
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
django==4.0.8 # pyup: < 4.1 # https://www.djangoproject.com/
|
django==4.0.10 # pyup: < 4.1 # https://www.djangoproject.com/
|
||||||
django-environ==0.9.0 # https://github.com/joke2k/django-environ
|
django-environ==0.10.0 # https://github.com/joke2k/django-environ
|
||||||
django-model-utils==4.2.0 # https://github.com/jazzband/django-model-utils
|
django-model-utils==4.3.1 # https://github.com/jazzband/django-model-utils
|
||||||
django-allauth==0.51.0 # https://github.com/pennersr/django-allauth
|
django-allauth==0.52.0 # https://github.com/pennersr/django-allauth
|
||||||
django-crispy-forms==1.14.0 # https://github.com/django-crispy-forms/django-crispy-forms
|
django-crispy-forms==2.0 # https://github.com/django-crispy-forms/django-crispy-forms
|
||||||
crispy-bootstrap5==0.7 # https://github.com/django-crispy-forms/crispy-bootstrap5
|
crispy-bootstrap5==0.7 # https://github.com/django-crispy-forms/crispy-bootstrap5
|
||||||
{%- if cookiecutter.frontend_pipeline == 'Django Compressor' %}
|
{%- if cookiecutter.frontend_pipeline == 'Django Compressor' %}
|
||||||
django-compressor==4.1 # https://github.com/django-compressor/django-compressor
|
django-compressor==4.3.1 # https://github.com/django-compressor/django-compressor
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
django-redis==5.2.0 # https://github.com/jazzband/django-redis
|
django-redis==5.2.0 # https://github.com/jazzband/django-redis
|
||||||
{%- if cookiecutter.use_drf == 'y' %}
|
{%- if cookiecutter.use_drf == 'y' %}
|
||||||
# Django REST Framework
|
# Django REST Framework
|
||||||
djangorestframework==3.14.0 # https://github.com/encode/django-rest-framework
|
djangorestframework==3.14.0 # https://github.com/encode/django-rest-framework
|
||||||
django-cors-headers==3.13.0 # https://github.com/adamchainz/django-cors-headers
|
django-cors-headers==3.14.0 # https://github.com/adamchainz/django-cors-headers
|
||||||
# DRF-spectacular for api documentation
|
# DRF-spectacular for api documentation
|
||||||
drf-spectacular==0.24.2 # https://github.com/tfranzel/drf-spectacular
|
drf-spectacular==0.26.0 # https://github.com/tfranzel/drf-spectacular
|
||||||
|
{%- endif %}
|
||||||
|
{%- if cookiecutter.frontend_pipeline == 'Webpack' %}
|
||||||
|
django-webpack-loader==1.8.1 # https://github.com/django-webpack/django-webpack-loader
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
-r base.txt
|
-r base.txt
|
||||||
|
|
||||||
Werkzeug[watchdog]==2.2.2 # https://github.com/pallets/werkzeug
|
Werkzeug[watchdog]==2.2.3 # https://github.com/pallets/werkzeug
|
||||||
ipdb==0.13.9 # https://github.com/gotcha/ipdb
|
ipdb==0.13.13 # https://github.com/gotcha/ipdb
|
||||||
{%- if cookiecutter.use_docker == 'y' %}
|
{%- if cookiecutter.use_docker == 'y' %}
|
||||||
psycopg2==2.9.5 # https://github.com/psycopg/psycopg2
|
psycopg2==2.9.5 # https://github.com/psycopg/psycopg2
|
||||||
{%- else %}
|
{%- else %}
|
||||||
|
@ -13,36 +13,36 @@ watchfiles==0.18.1 # https://github.com/samuelcolvin/watchfiles
|
||||||
|
|
||||||
# Testing
|
# Testing
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
mypy==0.982 # https://github.com/python/mypy
|
mypy==1.1.1 # https://github.com/python/mypy
|
||||||
django-stubs==1.12.0 # https://github.com/typeddjango/django-stubs
|
django-stubs==1.15.0 # https://github.com/typeddjango/django-stubs
|
||||||
pytest==7.2.0 # https://github.com/pytest-dev/pytest
|
pytest==7.2.2 # https://github.com/pytest-dev/pytest
|
||||||
pytest-sugar==0.9.6 # https://github.com/Frozenball/pytest-sugar
|
pytest-sugar==0.9.6 # https://github.com/Frozenball/pytest-sugar
|
||||||
{%- if cookiecutter.use_drf == "y" %}
|
{%- if cookiecutter.use_drf == "y" %}
|
||||||
djangorestframework-stubs==1.7.0 # https://github.com/typeddjango/djangorestframework-stubs
|
djangorestframework-stubs==1.9.1 # https://github.com/typeddjango/djangorestframework-stubs
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
||||||
# Documentation
|
# Documentation
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
sphinx==5.3.0 # https://github.com/sphinx-doc/sphinx
|
sphinx==6.1.3 # https://github.com/sphinx-doc/sphinx
|
||||||
sphinx-autobuild==2021.3.14 # https://github.com/GaretJax/sphinx-autobuild
|
sphinx-autobuild==2021.3.14 # https://github.com/GaretJax/sphinx-autobuild
|
||||||
|
|
||||||
# Code quality
|
# Code quality
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
flake8==5.0.4 # https://github.com/PyCQA/flake8
|
flake8==6.0.0 # https://github.com/PyCQA/flake8
|
||||||
flake8-isort==5.0.0 # https://github.com/gforcada/flake8-isort
|
flake8-isort==6.0.0 # https://github.com/gforcada/flake8-isort
|
||||||
coverage==6.5.0 # https://github.com/nedbat/coveragepy
|
coverage==7.2.1 # https://github.com/nedbat/coveragepy
|
||||||
black==22.10.0 # https://github.com/psf/black
|
black==23.1.0 # https://github.com/psf/black
|
||||||
pylint-django==2.5.3 # https://github.com/PyCQA/pylint-django
|
pylint-django==2.5.3 # 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.20.0 # https://github.com/pre-commit/pre-commit
|
pre-commit==3.1.1 # https://github.com/pre-commit/pre-commit
|
||||||
|
|
||||||
# Django
|
# Django
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
factory-boy==3.2.1 # https://github.com/FactoryBoy/factory_boy
|
factory-boy==3.2.1 # https://github.com/FactoryBoy/factory_boy
|
||||||
|
|
||||||
django-debug-toolbar==3.7.0 # https://github.com/jazzband/django-debug-toolbar
|
django-debug-toolbar==3.8.1 # https://github.com/jazzband/django-debug-toolbar
|
||||||
django-extensions==3.2.1 # https://github.com/django-extensions/django-extensions
|
django-extensions==3.2.1 # https://github.com/django-extensions/django-extensions
|
||||||
django-coverage-plugin==2.0.4 # https://github.com/nedbat/django_coverage_plugin
|
django-coverage-plugin==3.0.0 # https://github.com/nedbat/django_coverage_plugin
|
||||||
pytest-django==4.5.2 # https://github.com/pytest-dev/pytest-django
|
pytest-django==4.5.2 # https://github.com/pytest-dev/pytest-django
|
||||||
|
|
|
@ -8,35 +8,37 @@ psycopg2==2.9.5 # https://github.com/psycopg/psycopg2
|
||||||
Collectfast==2.2.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==1.11.1 # https://github.com/getsentry/sentry-python
|
sentry-sdk==1.16.0 # https://github.com/getsentry/sentry-python
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{%- if cookiecutter.use_docker == "n" and cookiecutter.windows == "y" %}
|
{%- if cookiecutter.use_docker == "n" and cookiecutter.windows == "y" %}
|
||||||
hiredis==2.0.0 # https://github.com/redis/hiredis-py
|
hiredis==2.2.2 # https://github.com/redis/hiredis-py
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
||||||
# Django
|
# Django
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
{%- if cookiecutter.cloud_provider == 'AWS' %}
|
{%- if cookiecutter.cloud_provider == 'AWS' %}
|
||||||
django-storages[boto3]==1.13.1 # https://github.com/jschneier/django-storages
|
django-storages[boto3]==1.13.2 # https://github.com/jschneier/django-storages
|
||||||
{%- elif cookiecutter.cloud_provider == 'GCP' %}
|
{%- elif cookiecutter.cloud_provider == 'GCP' %}
|
||||||
django-storages[google]==1.13.1 # https://github.com/jschneier/django-storages
|
django-storages[google]==1.13.2 # https://github.com/jschneier/django-storages
|
||||||
|
{%- elif cookiecutter.cloud_provider == 'Azure' %}
|
||||||
|
django-storages[azure]==1.13.2 # https://github.com/jschneier/django-storages
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{%- if cookiecutter.mail_service == 'Mailgun' %}
|
{%- if cookiecutter.mail_service == 'Mailgun' %}
|
||||||
django-anymail[mailgun]==8.6 # https://github.com/anymail/django-anymail
|
django-anymail[mailgun]==9.0 # https://github.com/anymail/django-anymail
|
||||||
{%- elif cookiecutter.mail_service == 'Amazon SES' %}
|
{%- elif cookiecutter.mail_service == 'Amazon SES' %}
|
||||||
django-anymail[amazon_ses]==8.6 # https://github.com/anymail/django-anymail
|
django-anymail[amazon_ses]==9.0 # https://github.com/anymail/django-anymail
|
||||||
{%- elif cookiecutter.mail_service == 'Mailjet' %}
|
{%- elif cookiecutter.mail_service == 'Mailjet' %}
|
||||||
django-anymail[mailjet]==8.6 # https://github.com/anymail/django-anymail
|
django-anymail[mailjet]==9.0 # https://github.com/anymail/django-anymail
|
||||||
{%- elif cookiecutter.mail_service == 'Mandrill' %}
|
{%- elif cookiecutter.mail_service == 'Mandrill' %}
|
||||||
django-anymail[mandrill]==8.6 # https://github.com/anymail/django-anymail
|
django-anymail[mandrill]==9.0 # https://github.com/anymail/django-anymail
|
||||||
{%- elif cookiecutter.mail_service == 'Postmark' %}
|
{%- elif cookiecutter.mail_service == 'Postmark' %}
|
||||||
django-anymail[postmark]==8.6 # https://github.com/anymail/django-anymail
|
django-anymail[postmark]==9.0 # https://github.com/anymail/django-anymail
|
||||||
{%- elif cookiecutter.mail_service == 'Sendgrid' %}
|
{%- elif cookiecutter.mail_service == 'Sendgrid' %}
|
||||||
django-anymail[sendgrid]==8.6 # https://github.com/anymail/django-anymail
|
django-anymail[sendgrid]==9.0 # https://github.com/anymail/django-anymail
|
||||||
{%- elif cookiecutter.mail_service == 'SendinBlue' %}
|
{%- elif cookiecutter.mail_service == 'SendinBlue' %}
|
||||||
django-anymail[sendinblue]==8.6 # https://github.com/anymail/django-anymail
|
django-anymail[sendinblue]==9.0 # https://github.com/anymail/django-anymail
|
||||||
{%- elif cookiecutter.mail_service == 'SparkPost' %}
|
{%- elif cookiecutter.mail_service == 'SparkPost' %}
|
||||||
django-anymail[sparkpost]==8.6 # https://github.com/anymail/django-anymail
|
django-anymail[sparkpost]==9.0 # https://github.com/anymail/django-anymail
|
||||||
{%- elif cookiecutter.mail_service == 'Other SMTP' %}
|
{%- elif cookiecutter.mail_service == 'Other SMTP' %}
|
||||||
django-anymail==8.6 # https://github.com/anymail/django-anymail
|
django-anymail==9.0 # https://github.com/anymail/django-anymail
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
[flake8]
|
[flake8]
|
||||||
max-line-length = 120
|
max-line-length = 120
|
||||||
exclude = .tox,.git,*/migrations/*,*/static/CACHE/*,docs,node_modules,venv
|
exclude = .tox,.git,*/migrations/*,*/static/CACHE/*,docs,node_modules,venv,.venv
|
||||||
|
|
||||||
[pycodestyle]
|
[pycodestyle]
|
||||||
max-line-length = 120
|
max-line-length = 120
|
||||||
exclude = .tox,.git,*/migrations/*,*/static/CACHE/*,docs,node_modules,venv
|
exclude = .tox,.git,*/migrations/*,*/static/CACHE/*,docs,node_modules,venv,.venv
|
||||||
|
|
||||||
[isort]
|
[isort]
|
||||||
line_length = 88
|
line_length = 88
|
||||||
|
@ -34,7 +34,7 @@ django_settings_module = config.settings.test
|
||||||
ignore_errors = True
|
ignore_errors = True
|
||||||
|
|
||||||
[coverage:run]
|
[coverage:run]
|
||||||
include = {{cookiecutter.project_slug}}/*
|
include = {{cookiecutter.project_slug}}/**
|
||||||
omit = *migrations*, *tests*
|
omit = */migrations/*, */tests/*
|
||||||
plugins =
|
plugins =
|
||||||
django_coverage_plugin
|
django_coverage_plugin
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from merge_production_dotenvs_in_dotenv import merge
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("input_contents", "expected_output"),
|
||||||
|
[
|
||||||
|
([], ""),
|
||||||
|
([""], "\n"),
|
||||||
|
(["JANE=doe"], "JANE=doe\n"),
|
||||||
|
(["SEP=true", "AR=ator"], "SEP=true\nAR=ator\n"),
|
||||||
|
(["A=0", "B=1", "C=2"], "A=0\nB=1\nC=2\n"),
|
||||||
|
(["X=x\n", "Y=y", "Z=z\n"], "X=x\n\nY=y\nZ=z\n\n"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_merge(
|
||||||
|
tmp_path: Path,
|
||||||
|
input_contents: list[str],
|
||||||
|
expected_output: str,
|
||||||
|
):
|
||||||
|
output_file = tmp_path / ".env"
|
||||||
|
|
||||||
|
files_to_merge = []
|
||||||
|
for num, input_content in enumerate(input_contents, start=1):
|
||||||
|
merge_file = tmp_path / f".service{num}"
|
||||||
|
merge_file.write_text(input_content)
|
||||||
|
files_to_merge.append(merge_file)
|
||||||
|
|
||||||
|
merge(output_file, files_to_merge)
|
||||||
|
|
||||||
|
assert output_file.read_text() == expected_output
|
55
{{cookiecutter.project_slug}}/webpack/common.config.js
Normal file
55
{{cookiecutter.project_slug}}/webpack/common.config.js
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
const path = require('path');
|
||||||
|
const BundleTracker = require('webpack-bundle-tracker');
|
||||||
|
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
target: "web",
|
||||||
|
context: path.join(__dirname, '../'),
|
||||||
|
entry: {
|
||||||
|
'project': path.resolve(__dirname, '../{{cookiecutter.project_slug}}/static/js/project'),
|
||||||
|
'vendors': path.resolve(__dirname, '../{{cookiecutter.project_slug}}/static/js/vendors'),
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
path: path.resolve(__dirname, '../{{cookiecutter.project_slug}}/static/webpack_bundles/'),
|
||||||
|
publicPath: '/static/webpack_bundles/',
|
||||||
|
filename: 'js/[name]-[fullhash].js',
|
||||||
|
chunkFilename: 'js/[name]-[hash].js',
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new BundleTracker({filename: path.resolve(__dirname, '../webpack-stats.json')}),
|
||||||
|
new MiniCssExtractPlugin({ filename: 'css/[name].[contenthash].css' }),
|
||||||
|
],
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
// we pass the output from babel loader to react-hot loader
|
||||||
|
{
|
||||||
|
test: /\.js$/,
|
||||||
|
loader: 'babel-loader',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.s?css$/i,
|
||||||
|
use: [
|
||||||
|
MiniCssExtractPlugin.loader,
|
||||||
|
'css-loader',
|
||||||
|
{
|
||||||
|
loader: 'postcss-loader',
|
||||||
|
options: {
|
||||||
|
postcssOptions: {
|
||||||
|
plugins: [
|
||||||
|
'postcss-preset-env',
|
||||||
|
'autoprefixer',
|
||||||
|
'pixrem',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'sass-loader',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
modules: ['node_modules'],
|
||||||
|
extensions: ['.js', '.jsx'],
|
||||||
|
},
|
||||||
|
};
|
20
{{cookiecutter.project_slug}}/webpack/dev.config.js
Normal file
20
{{cookiecutter.project_slug}}/webpack/dev.config.js
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
const { merge } = require('webpack-merge');
|
||||||
|
const commonConfig = require('./common.config');
|
||||||
|
|
||||||
|
module.exports = merge(commonConfig, {
|
||||||
|
mode: 'development',
|
||||||
|
devtool: 'inline-source-map',
|
||||||
|
devServer: {
|
||||||
|
port: 3000,
|
||||||
|
proxy: {
|
||||||
|
{%- if cookiecutter.use_docker == 'n' %}
|
||||||
|
'/': 'http://0.0.0.0:8000',
|
||||||
|
{%- else %}
|
||||||
|
'/': 'http://django:8000',
|
||||||
|
{%- endif %}
|
||||||
|
},
|
||||||
|
// We need hot=false (Disable HMR) to set liveReload=true
|
||||||
|
hot: false,
|
||||||
|
liveReload: true,
|
||||||
|
},
|
||||||
|
});
|
28
{{cookiecutter.project_slug}}/webpack/prod.config.js
Normal file
28
{{cookiecutter.project_slug}}/webpack/prod.config.js
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
const { merge } = require('webpack-merge');
|
||||||
|
const commonConfig = require('./common.config');
|
||||||
|
|
||||||
|
// This variable should mirror the one from config/settings/production.py
|
||||||
|
{%- if cookiecutter.use_whitenoise == 'n' %}
|
||||||
|
{%- if cookiecutter.cloud_provider == 'AWS' %}
|
||||||
|
const s3BucketName = process.env.DJANGO_AWS_STORAGE_BUCKET_NAME;
|
||||||
|
const awsS3Domain = process.env.DJANGO_AWS_S3_CUSTOM_DOMAIN ?
|
||||||
|
process.env.DJANGO_AWS_S3_CUSTOM_DOMAIN
|
||||||
|
: `${s3BucketName}.s3.amazonaws.com`;
|
||||||
|
const staticUrl = `https://${awsS3Domain}/static/`;
|
||||||
|
{%- elif cookiecutter.cloud_provider == 'GCP' %}
|
||||||
|
const staticUrl = `https://storage.googleapis.com/${process.env.DJANGO_GCP_STORAGE_BUCKET_NAME}/static/`;
|
||||||
|
{%- elif cookiecutter.cloud_provider == 'Azure' %}
|
||||||
|
const staticUrl = `https://${process.env.DJANGO_AZURE_ACCOUNT_NAME}.blob.core.windows.net/static/`;
|
||||||
|
{%- endif %}
|
||||||
|
{%- else %}
|
||||||
|
const staticUrl = '/static/';
|
||||||
|
{%- endif %}
|
||||||
|
|
||||||
|
module.exports = merge(commonConfig, {
|
||||||
|
mode: 'production',
|
||||||
|
devtool: 'source-map',
|
||||||
|
bail: true,
|
||||||
|
output: {
|
||||||
|
publicPath: `${staticUrl}webpack_bundles/`,
|
||||||
|
},
|
||||||
|
});
|
|
@ -1 +1,5 @@
|
||||||
|
{%- if cookiecutter.frontend_pipeline == 'Webpack' %}
|
||||||
|
import '../sass/project.scss';
|
||||||
|
{%- endif %}
|
||||||
|
|
||||||
/* Project specific Javascript goes here. */
|
/* Project specific Javascript goes here. */
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
import '@popperjs/core';
|
||||||
|
import 'bootstrap';
|
|
@ -1,5 +1,5 @@
|
||||||
@import "custom_bootstrap_vars";
|
@import "custom_bootstrap_vars";
|
||||||
@import "bootstrap";
|
@import "~bootstrap/scss/bootstrap";
|
||||||
|
|
||||||
|
|
||||||
// project specific CSS goes here
|
// project specific CSS goes here
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
{% raw %}{% load static i18n {% endraw %}{% if cookiecutter.frontend_pipeline == 'Django Compressor' %}compress{% endif %}{% raw %}%}<!DOCTYPE html>
|
{% raw %}{% load static i18n {% endraw %}
|
||||||
|
{%- if cookiecutter.frontend_pipeline == 'Django Compressor' %}compress
|
||||||
|
{%- endif %}{% raw %}%}{% endraw %}
|
||||||
|
{%- if cookiecutter.frontend_pipeline == 'Webpack' %}{% raw %}{% load render_bundle from webpack_loader %}{% endraw %}
|
||||||
|
{%- endif %}{% raw %}<!DOCTYPE html>
|
||||||
{% get_current_language as LANGUAGE_CODE %}
|
{% get_current_language as LANGUAGE_CODE %}
|
||||||
<html lang="{{ LANGUAGE_CODE }}">
|
<html lang="{{ LANGUAGE_CODE }}">
|
||||||
<head>
|
<head>
|
||||||
|
@ -13,7 +17,7 @@
|
||||||
|
|
||||||
{% block css %}
|
{% block css %}
|
||||||
{%- endraw %}
|
{%- endraw %}
|
||||||
{%- if cookiecutter.frontend_pipeline != 'Gulp' %}
|
{%- if cookiecutter.frontend_pipeline in ['None', 'Django Compressor'] %}
|
||||||
{%- raw %}
|
{%- raw %}
|
||||||
<!-- Latest compiled and minified Bootstrap CSS -->
|
<!-- Latest compiled and minified Bootstrap CSS -->
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.3/css/bootstrap.min.css" integrity="sha512-GQGU0fMMi238uA+a/bdWJfpUGKUkBdgfFdgBm72SUQ6BeyWjoY/ton0tEjH+OSH9iP4Dfh+7HM0I9f5eR0L/4w==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.3/css/bootstrap.min.css" integrity="sha512-GQGU0fMMi238uA+a/bdWJfpUGKUkBdgfFdgBm72SUQ6BeyWjoY/ton0tEjH+OSH9iP4Dfh+7HM0I9f5eR0L/4w==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
||||||
|
@ -31,6 +35,8 @@
|
||||||
{% endcompress %}
|
{% endcompress %}
|
||||||
{%- endraw %}{% elif cookiecutter.frontend_pipeline == 'Gulp' %}{% raw %}
|
{%- endraw %}{% elif cookiecutter.frontend_pipeline == 'Gulp' %}{% raw %}
|
||||||
<link href="{% static 'css/project.min.css' %}" rel="stylesheet">
|
<link href="{% static 'css/project.min.css' %}" rel="stylesheet">
|
||||||
|
{%- endraw %}{% elif cookiecutter.frontend_pipeline == "Webpack" %}{% raw %}
|
||||||
|
{% render_bundle 'project' 'css' %}
|
||||||
{%- endraw %}{% endif %}{% raw %}
|
{%- endraw %}{% endif %}{% raw %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
<!-- Le javascript
|
<!-- Le javascript
|
||||||
|
@ -38,8 +44,11 @@
|
||||||
{# Placed at the top of the document so pages load faster with defer #}
|
{# Placed at the top of the document so pages load faster with defer #}
|
||||||
{% block javascript %}
|
{% block javascript %}
|
||||||
{%- endraw %}{% if cookiecutter.frontend_pipeline == 'Gulp' %}{% raw %}
|
{%- endraw %}{% if cookiecutter.frontend_pipeline == 'Gulp' %}{% raw %}
|
||||||
<!-- Vendor dependencies bundled as one file-->
|
<!-- Vendor dependencies bundled as one file -->
|
||||||
<script defer src="{% static 'js/vendors.min.js' %}"></script>
|
<script defer src="{% static 'js/vendors.min.js' %}"></script>
|
||||||
|
{%- endraw %}{% elif cookiecutter.frontend_pipeline == "Webpack" %}{% raw %}
|
||||||
|
<!-- Vendor dependencies bundled as one file -->
|
||||||
|
{% render_bundle 'vendors' 'js' attrs='defer' %}
|
||||||
{%- endraw %}{% else %}{% raw %}
|
{%- endraw %}{% else %}{% raw %}
|
||||||
<!-- Bootstrap JS -->
|
<!-- Bootstrap JS -->
|
||||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.3/js/bootstrap.min.js" integrity="sha512-OvBgP9A2JBgiRad/mM36mkzXSXaJE9BEIENnVEmeZdITvwT09xnxLtT4twkCa8m/loMbPHsvPl0T8lRGVBwjlQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.3/js/bootstrap.min.js" integrity="sha512-OvBgP9A2JBgiRad/mM36mkzXSXaJE9BEIENnVEmeZdITvwT09xnxLtT4twkCa8m/loMbPHsvPl0T8lRGVBwjlQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||||
|
@ -55,6 +64,8 @@
|
||||||
{% endcompress %}
|
{% endcompress %}
|
||||||
{%- endraw %}{% elif cookiecutter.frontend_pipeline == 'Gulp' %}{% raw %}
|
{%- endraw %}{% elif cookiecutter.frontend_pipeline == 'Gulp' %}{% raw %}
|
||||||
<script defer src="{% static 'js/project.min.js' %}"></script>
|
<script defer src="{% static 'js/project.min.js' %}"></script>
|
||||||
|
{%- endraw %}{% elif cookiecutter.frontend_pipeline == "Webpack" %}{% raw %}
|
||||||
|
{% render_bundle 'project' 'js' attrs='defer' %}
|
||||||
{%- endraw %}{% endif %}{% raw %}
|
{%- endraw %}{% endif %}{% raw %}
|
||||||
|
|
||||||
{% endblock javascript %}
|
{% endblock javascript %}
|
||||||
|
|
|
@ -10,7 +10,6 @@ User = get_user_model()
|
||||||
|
|
||||||
@admin.register(User)
|
@admin.register(User)
|
||||||
class UserAdmin(auth_admin.UserAdmin):
|
class UserAdmin(auth_admin.UserAdmin):
|
||||||
|
|
||||||
form = UserAdminChangeForm
|
form = UserAdminChangeForm
|
||||||
add_form = UserAdminCreationForm
|
add_form = UserAdminCreationForm
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
|
|
|
@ -1,27 +1,32 @@
|
||||||
from django.test import RequestFactory
|
import pytest
|
||||||
|
from rest_framework.test import APIRequestFactory
|
||||||
|
|
||||||
from {{ cookiecutter.project_slug }}.users.api.views import UserViewSet
|
from {{ cookiecutter.project_slug }}.users.api.views import UserViewSet
|
||||||
from {{ cookiecutter.project_slug }}.users.models import User
|
from {{ cookiecutter.project_slug }}.users.models import User
|
||||||
|
|
||||||
|
|
||||||
class TestUserViewSet:
|
class TestUserViewSet:
|
||||||
def test_get_queryset(self, user: User, rf: RequestFactory):
|
@pytest.fixture
|
||||||
|
def api_rf(self) -> APIRequestFactory:
|
||||||
|
return APIRequestFactory()
|
||||||
|
|
||||||
|
def test_get_queryset(self, user: User, api_rf: APIRequestFactory):
|
||||||
view = UserViewSet()
|
view = UserViewSet()
|
||||||
request = rf.get("/fake-url/")
|
request = api_rf.get("/fake-url/")
|
||||||
request.user = user
|
request.user = user
|
||||||
|
|
||||||
view.request = request
|
view.request = request
|
||||||
|
|
||||||
assert user in view.get_queryset()
|
assert user in view.get_queryset()
|
||||||
|
|
||||||
def test_me(self, user: User, rf: RequestFactory):
|
def test_me(self, user: User, api_rf: APIRequestFactory):
|
||||||
view = UserViewSet()
|
view = UserViewSet()
|
||||||
request = rf.get("/fake-url/")
|
request = api_rf.get("/fake-url/")
|
||||||
request.user = user
|
request.user = user
|
||||||
|
|
||||||
view.request = request
|
view.request = request
|
||||||
|
|
||||||
response = view.me(request)
|
response = view.me(request) # type: ignore
|
||||||
|
|
||||||
assert response.data == {
|
assert response.data == {
|
||||||
{% if cookiecutter.username_type == "email" -%}
|
{% if cookiecutter.username_type == "email" -%}
|
||||||
|
|
|
@ -9,7 +9,6 @@ User = get_user_model()
|
||||||
|
|
||||||
|
|
||||||
class UserDetailView(LoginRequiredMixin, DetailView):
|
class UserDetailView(LoginRequiredMixin, DetailView):
|
||||||
|
|
||||||
model = User
|
model = User
|
||||||
{%- if cookiecutter.username_type == "email" -%}
|
{%- if cookiecutter.username_type == "email" -%}
|
||||||
slug_field = "id"
|
slug_field = "id"
|
||||||
|
@ -24,7 +23,6 @@ user_detail_view = UserDetailView.as_view()
|
||||||
|
|
||||||
|
|
||||||
class UserUpdateView(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
|
class UserUpdateView(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
|
||||||
|
|
||||||
model = User
|
model = User
|
||||||
fields = ["name"]
|
fields = ["name"]
|
||||||
success_message = _("Information successfully updated")
|
success_message = _("Information successfully updated")
|
||||||
|
@ -43,7 +41,6 @@ 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):
|
||||||
|
|
|
@ -22,4 +22,15 @@ class StaticRootGoogleCloudStorage(GoogleCloudStorage):
|
||||||
class MediaRootGoogleCloudStorage(GoogleCloudStorage):
|
class MediaRootGoogleCloudStorage(GoogleCloudStorage):
|
||||||
location = "media"
|
location = "media"
|
||||||
file_overwrite = False
|
file_overwrite = False
|
||||||
|
{%- elif cookiecutter.cloud_provider == 'Azure' -%}
|
||||||
|
from storages.backends.azure_storage import AzureStorage
|
||||||
|
|
||||||
|
|
||||||
|
class StaticRootAzureStorage(AzureStorage):
|
||||||
|
location = "static"
|
||||||
|
|
||||||
|
|
||||||
|
class MediaRootAzureStorage(AzureStorage):
|
||||||
|
location = "media"
|
||||||
|
file_overwrite = False
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user