diff --git a/.flake8 b/.flake8
index 84b4b4411..3a87b269b 100644
--- a/.flake8
+++ b/.flake8
@@ -1,3 +1,4 @@
[flake8]
exclude = docs
max-line-length = 119
+extend-ignore = E203
diff --git a/.github/ISSUE_TEMPLATE/bug.md b/.github/ISSUE_TEMPLATE/bug.md
index 0e5ec12c4..da0480f1e 100644
--- a/.github/ISSUE_TEMPLATE/bug.md
+++ b/.github/ISSUE_TEMPLATE/bug.md
@@ -42,7 +42,7 @@ labels: bug
- Python version, run `python3 -V`:
- Docker version (if using Docker), run `docker --version`:
- - docker-compose version (if using Docker), run `docker-compose --version`:
+ - docker compose version (if using Docker), run `docker compose --version`:
- ...
- Options selected and/or [replay file](https://cookiecutter.readthedocs.io/en/latest/advanced/replay.html):
diff --git a/.github/contributors.json b/.github/contributors.json
index e08ce0b05..c95797b18 100644
--- a/.github/contributors.json
+++ b/.github/contributors.json
@@ -1408,5 +1408,115 @@
"name": "Joseph Hanna",
"github_login": "sanchimenea",
"twitter_username": ""
+ },
+ {
+ "name": "tmajerech",
+ "github_login": "tmajerech",
+ "twitter_username": ""
+ },
+ {
+ "name": "villancikos",
+ "github_login": "villancikos",
+ "twitter_username": ""
+ },
+ {
+ "name": "Imran Rahman",
+ "github_login": "infraredCoding",
+ "twitter_username": ""
+ },
+ {
+ "name": "hleroy",
+ "github_login": "hleroy",
+ "twitter_username": ""
+ },
+ {
+ "name": "Shayan Karimi",
+ "github_login": "shywn-mrk",
+ "twitter_username": "shywn_mrk"
+ },
+ {
+ "name": "Sadra Yahyapour",
+ "github_login": "lnxpy",
+ "twitter_username": "lnxpylnxpy"
+ },
+ {
+ "name": "Tharushan",
+ "github_login": "Tharushan",
+ "twitter_username": ""
+ },
+ {
+ "name": "Fateme Fouladkar",
+ "github_login": "FatemeFouladkar",
+ "twitter_username": ""
+ },
+ {
+ "name": "zhaoruibing",
+ "github_login": "zhaoruibing",
+ "twitter_username": ""
+ },
+ {
+ "name": "MinWoo Sung",
+ "github_login": "SungMinWoo",
+ "twitter_username": ""
+ },
+ {
+ "name": "itisnotyourenv",
+ "github_login": "itisnotyourenv",
+ "twitter_username": ""
+ },
+ {
+ "name": "Vageeshan Mankala",
+ "github_login": "vagi8",
+ "twitter_username": ""
+ },
+ {
+ "name": "Jakub Boukal",
+ "github_login": "SukiCZ",
+ "twitter_username": ""
+ },
+ {
+ "name": "Christian Jauvin",
+ "github_login": "cjauvin",
+ "twitter_username": ""
+ },
+ {
+ "name": "Plurific",
+ "github_login": "paulschwenn",
+ "twitter_username": ""
+ },
+ {
+ "name": "GitBib",
+ "github_login": "GitBib",
+ "twitter_username": ""
+ },
+ {
+ "name": "Freddy",
+ "github_login": "Hraesvelg",
+ "twitter_username": ""
+ },
+ {
+ "name": "aiden",
+ "github_login": "anyidea",
+ "twitter_username": ""
+ },
+ {
+ "name": "Michael V. Battista",
+ "github_login": "mvbattista",
+ "twitter_username": "mvbattista"
+ },
+ {
+ "name": "Nix Siow",
+ "github_login": "nixsiow",
+ "twitter_username": "nixsiow"
+ },
+ {
+ "name": "Jens Kaeske",
+ "github_login": "jkaeske",
+ "twitter_username": ""
+ },
+ {
+ "name": "henningbra",
+ "github_login": "henningbra",
+ "twitter_username": ""
}
]
\ No newline at end of file
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 7642a3f2d..e6590469a 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -9,7 +9,7 @@ updates:
schedule:
interval: "daily"
labels:
- - "update"
+ - "project infrastructure"
# Update npm packages
- package-ecosystem: "npm"
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index dbda77b5e..82f7887f2 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -22,8 +22,8 @@ jobs:
name: "pytest ${{ matrix.os }}"
runs-on: ${{ matrix.os }}
steps:
- - uses: actions/checkout@v3
- - uses: actions/setup-python@v4
+ - uses: actions/checkout@v4
+ - uses: actions/setup-python@v5
with:
python-version: "3.11"
cache: pip
@@ -53,8 +53,8 @@ jobs:
COMPOSE_DOCKER_CLI_BUILD: 1
steps:
- - uses: actions/checkout@v3
- - uses: actions/setup-python@v4
+ - uses: actions/checkout@v4
+ - uses: actions/setup-python@v5
with:
python-version: "3.11"
cache: pip
@@ -75,7 +75,7 @@ jobs:
- name: Webpack
args: "frontend_pipeline=Webpack use_heroku=y"
- name: Email Username
- args: "username_type=email ci_tool=Github"
+ args: "username_type=email ci_tool=Github project_name='Something superduper long - the great amazing project' project_slug=my_awesome_project"
name: "Bare metal ${{ matrix.script.name }}"
runs-on: ubuntu-latest
@@ -97,8 +97,8 @@ jobs:
DATABASE_URL: "postgres://postgres:postgres@localhost:5432/postgres"
steps:
- - uses: actions/checkout@v3
- - uses: actions/setup-python@v4
+ - uses: actions/checkout@v4
+ - uses: actions/setup-python@v5
with:
python-version: "3.11"
cache: pip
@@ -108,8 +108,8 @@ jobs:
{{cookiecutter.project_slug}}/requirements/local.txt
- name: Install dependencies
run: pip install -r requirements.txt
- - uses: actions/setup-node@v3
+ - uses: actions/setup-node@v4
with:
- node-version: "18"
+ node-version: "20"
- name: Bare Metal ${{ matrix.script.name }}
run: sh tests/test_bare.sh ${{ matrix.script.args }}
diff --git a/.github/workflows/django-issue-checker.yml b/.github/workflows/django-issue-checker.yml
index cbfea922d..e1b36f292 100644
--- a/.github/workflows/django-issue-checker.yml
+++ b/.github/workflows/django-issue-checker.yml
@@ -16,8 +16,8 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
- - uses: actions/setup-python@v4
+ - uses: actions/checkout@v4
+ - uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install dependencies
diff --git a/.github/workflows/issue-manager.yml b/.github/workflows/issue-manager.yml
index a6e074137..103612cfe 100644
--- a/.github/workflows/issue-manager.yml
+++ b/.github/workflows/issue-manager.yml
@@ -23,18 +23,25 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: tiangolo/issue-manager@0.4.0
+ - uses: tiangolo/issue-manager@0.5.0
with:
token: ${{ secrets.GITHUB_TOKEN }}
config: >
{
"answered": {
+ "delay": 864000,
"message": "Assuming the question was answered, this will be automatically closed now."
},
"solved": {
+ "delay": 864000,
"message": "Assuming the original issue was solved, it will be automatically closed now."
},
"waiting": {
+ "delay": 864000,
"message": "Automatically closing after waiting for additional info. To re-open, please provide the additional information requested."
+ },
+ "wontfix": {
+ "delay": 864000,
+ "message": "As discussed, we won't be implementing this. Automatically closing."
}
}
diff --git a/.github/workflows/pre-commit-autoupdate.yml b/.github/workflows/pre-commit-autoupdate.yml
index 75bfe0a20..0ad414398 100644
--- a/.github/workflows/pre-commit-autoupdate.yml
+++ b/.github/workflows/pre-commit-autoupdate.yml
@@ -21,8 +21,8 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
- - uses: actions/setup-python@v4
+ - uses: actions/checkout@v4
+ - uses: actions/setup-python@v5
with:
python-version: "3.11"
@@ -37,7 +37,7 @@ jobs:
run: pre-commit autoupdate
- name: Create Pull Request
- uses: peter-evans/create-pull-request@v5
+ uses: peter-evans/create-pull-request@v6
with:
token: ${{ secrets.GITHUB_TOKEN }}
branch: update/pre-commit-autoupdate
diff --git a/.github/workflows/update-changelog.yml b/.github/workflows/update-changelog.yml
index f48f297aa..b0150507d 100644
--- a/.github/workflows/update-changelog.yml
+++ b/.github/workflows/update-changelog.yml
@@ -14,10 +14,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Set up Python
- uses: actions/setup-python@v4
+ uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install dependencies
diff --git a/.github/workflows/update-contributors.yml b/.github/workflows/update-contributors.yml
index 78d72c241..0cda836dc 100644
--- a/.github/workflows/update-contributors.yml
+++ b/.github/workflows/update-contributors.yml
@@ -17,10 +17,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Set up Python
- uses: actions/setup-python@v4
+ uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install dependencies
@@ -33,7 +33,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Commit changes
- uses: stefanzweifel/git-auto-commit-action@v4.16.0
+ uses: stefanzweifel/git-auto-commit-action@v5.0.0
with:
commit_message: Update Contributors
file_pattern: CONTRIBUTORS.md .github/contributors.json
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 3acfca53d..baafb694f 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,9 +1,12 @@
exclude: "{{cookiecutter.project_slug}}|.github/contributors.json|CHANGELOG.md|CONTRIBUTORS.md"
default_stages: [commit]
+default_language_version:
+ python: python3.11
+
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
- rev: v4.4.0
+ rev: v4.5.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
@@ -17,30 +20,30 @@ repos:
- id: detect-private-key
- repo: https://github.com/pre-commit/mirrors-prettier
- rev: "v3.0.0-alpha.9-for-vscode"
+ rev: "v4.0.0-alpha.8"
hooks:
- id: prettier
args: ["--tab-width", "2"]
- repo: https://github.com/asottile/pyupgrade
- rev: v3.8.0
+ rev: v3.15.0
hooks:
- id: pyupgrade
args: [--py311-plus]
exclude: hooks/
- repo: https://github.com/psf/black
- rev: 23.3.0
+ rev: 24.1.1
hooks:
- id: black
- repo: https://github.com/PyCQA/isort
- rev: 5.12.0
+ rev: 5.13.2
hooks:
- id: isort
- repo: https://github.com/PyCQA/flake8
- rev: 6.0.0
+ rev: 7.0.0
hooks:
- id: flake8
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2ef5b220d..c5e20748a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,1083 @@ All enhancements and patches to Cookiecutter Django will be documented in this f
+## 2024.02.09
+
+
+### Updated
+
+- Update sentry-sdk to 1.40.3 ([#4847](https://github.com/cookiecutter/cookiecutter-django/pull/4847))
+
+- Update django-allauth to 0.61.1 ([#4846](https://github.com/cookiecutter/cookiecutter-django/pull/4846))
+
+- Update python-slugify to 8.0.4 ([#4844](https://github.com/cookiecutter/cookiecutter-django/pull/4844))
+
+## 2024.02.08
+
+
+### Updated
+
+- Bump python to 3.11.8 in compose/local/docs ([#4840](https://github.com/cookiecutter/cookiecutter-django/pull/4840))
+
+- Bump python to 3.11.8 in compose/local/django ([#4841](https://github.com/cookiecutter/cookiecutter-django/pull/4841))
+
+- Bump python to 3.11.8 in compose/production/django ([#4842](https://github.com/cookiecutter/cookiecutter-django/pull/4842))
+
+## 2024.02.07
+
+
+### Changed
+
+- Extend docker test with deploy check ([#4838](https://github.com/cookiecutter/cookiecutter-django/pull/4838))
+
+- Generic UserManager ([#4836](https://github.com/cookiecutter/cookiecutter-django/pull/4836))
+
+### Updated
+
+- Update django-allauth to 0.61.0 ([#4839](https://github.com/cookiecutter/cookiecutter-django/pull/4839))
+
+- Bump gulp-postcss to 10.0.0 ([#4835](https://github.com/cookiecutter/cookiecutter-django/pull/4835))
+
+- Update sentry-sdk to 1.40.2 ([#4837](https://github.com/cookiecutter/cookiecutter-django/pull/4837))
+
+- Update django to 4.2.10 ([#4833](https://github.com/cookiecutter/cookiecutter-django/pull/4833))
+
+## 2024.02.05
+
+
+### Updated
+
+- Update pytest to 8.0.0 ([#4813](https://github.com/cookiecutter/cookiecutter-django/pull/4813))
+
+- Update pytest-sugar to 1.0.0 ([#4828](https://github.com/cookiecutter/cookiecutter-django/pull/4828))
+
+- Update sphinx-autobuild to 2024.2.4 ([#4830](https://github.com/cookiecutter/cookiecutter-django/pull/4830))
+
+- Update django-debug-toolbar to 4.3.0 ([#4829](https://github.com/cookiecutter/cookiecutter-django/pull/4829))
+
+- Update psycopg to 3.1.18 ([#4831](https://github.com/cookiecutter/cookiecutter-django/pull/4831))
+
+## 2024.01.31
+
+
+### Updated
+
+- Update python-slugify to 8.0.3 ([#4826](https://github.com/cookiecutter/cookiecutter-django/pull/4826))
+
+## 2024.01.30
+
+
+### Updated
+
+- Update pytest-django to 4.8.0 ([#4823](https://github.com/cookiecutter/cookiecutter-django/pull/4823))
+
+- Update sentry-sdk to 1.40.0 ([#4822](https://github.com/cookiecutter/cookiecutter-django/pull/4822))
+
+- Update uvicorn to 0.27.0.post1 ([#4818](https://github.com/cookiecutter/cookiecutter-django/pull/4818))
+
+## 2024.01.29
+
+
+### Changed
+
+- Fix deprecation warning about renaming of `webpack_loader.loader` to `webpack_loader.loaders` ([#4815](https://github.com/cookiecutter/cookiecutter-django/pull/4815))
+
+### Documentation
+
+- Update mention of coverage config file to `pyproject.toml` in documentation ([#4816](https://github.com/cookiecutter/cookiecutter-django/pull/4816))
+
+### Updated
+
+- Update black to 24.1.1 ([#4814](https://github.com/cookiecutter/cookiecutter-django/pull/4814))
+
+- Auto-update pre-commit hooks ([#4817](https://github.com/cookiecutter/cookiecutter-django/pull/4817))
+
+## 2024.01.27
+
+
+### Changed
+
+- Do not show webpack devserver overlay for warnings ([#4809](https://github.com/cookiecutter/cookiecutter-django/pull/4809))
+
+### Updated
+
+- Update python-slugify to 8.0.2 ([#4805](https://github.com/cookiecutter/cookiecutter-django/pull/4805))
+
+- Update coverage to 7.4.1 ([#4807](https://github.com/cookiecutter/cookiecutter-django/pull/4807))
+
+## 2024.01.26
+
+
+### Updated
+
+- Update black to 24.1.0 ([#4806](https://github.com/cookiecutter/cookiecutter-django/pull/4806))
+
+## 2024.01.25
+
+
+### Changed
+
+- Replace custom static & media storage classes by passing options in the `STORAGES` setting ([#4803](https://github.com/cookiecutter/cookiecutter-django/pull/4803))
+
+- Add registry to Docker images names ([#4804](https://github.com/cookiecutter/cookiecutter-django/pull/4804))
+
+## 2024.01.24
+
+
+### Changed
+
+- Migrate to the unified `STORAGES` setting added in Django 4.2 ([#4477](https://github.com/cookiecutter/cookiecutter-django/pull/4477))
+
+### Updated
+
+- Update uvicorn to 0.27.0 ([#4800](https://github.com/cookiecutter/cookiecutter-django/pull/4800))
+
+## 2024.01.21
+
+
+### Documentation
+
+- Update traefik doc links ([#4798](https://github.com/cookiecutter/cookiecutter-django/pull/4798))
+
+### Updated
+
+- Bump browser-sync from 2.29.3 to 3.0.2 in /{{cookiecutter.project_slug}} ([#4765](https://github.com/cookiecutter/cookiecutter-django/pull/4765))
+
+## 2024.01.19
+
+
+### Updated
+
+- Update drf-spectacular to 0.27.1 ([#4797](https://github.com/cookiecutter/cookiecutter-django/pull/4797))
+
+## 2024.01.17
+
+
+### Changed
+
+- Add a test to cover `DJANGO_ADMIN_FORCE_ALLAUTH` ([#4790](https://github.com/cookiecutter/cookiecutter-django/pull/4790))
+
+### Updated
+
+- Bump webpack-bundle-tracker to 3.0.1 ([#4781](https://github.com/cookiecutter/cookiecutter-django/pull/4781))
+
+- Update django-webpack-loader to 3.0.1 ([#4793](https://github.com/cookiecutter/cookiecutter-django/pull/4793))
+
+- Bump postcss-loader to 8.0.0 ([#4795](https://github.com/cookiecutter/cookiecutter-django/pull/4795))
+
+- Update uvicorn to 0.26.0 ([#4794](https://github.com/cookiecutter/cookiecutter-django/pull/4794))
+
+## 2024.01.16
+
+
+### Updated
+
+- Bump sass-loader from 13.3.3 to 14.0.0 in /{{cookiecutter.project_slug}} ([#4791](https://github.com/cookiecutter/cookiecutter-django/pull/4791))
+
+## 2024.01.15
+
+
+### Documentation
+
+- Update allauth documentation links ([#4786](https://github.com/cookiecutter/cookiecutter-django/pull/4786))
+
+### Updated
+
+- Update django-allauth to 0.60.1 ([#4787](https://github.com/cookiecutter/cookiecutter-django/pull/4787))
+
+## 2024.01.11
+
+
+### Updated
+
+- Update jinja2 to 3.1.3 ([#4784](https://github.com/cookiecutter/cookiecutter-django/pull/4784))
+
+## 2024.01.10
+
+
+### Updated
+
+- Update sentry-sdk to 1.39.2 ([#4782](https://github.com/cookiecutter/cookiecutter-django/pull/4782))
+
+## 2024.01.09
+
+
+### Documentation
+
+- Update allauth settings documentation links ([#4769](https://github.com/cookiecutter/cookiecutter-django/pull/4769))
+
+### Updated
+
+- Update django-allauth to 0.60.0 ([#4776](https://github.com/cookiecutter/cookiecutter-django/pull/4776))
+
+- Update psycopg to 3.1.17 ([#4777](https://github.com/cookiecutter/cookiecutter-django/pull/4777))
+
+## 2024.01.05
+
+
+### Updated
+
+- Auto-update pre-commit hooks ([#4774](https://github.com/cookiecutter/cookiecutter-django/pull/4774))
+
+- Update flake8 to 7.0.0 ([#4775](https://github.com/cookiecutter/cookiecutter-django/pull/4775))
+
+## 2024.01.02
+
+
+### Updated
+
+- Update psycopg to 3.1.16 ([#4753](https://github.com/cookiecutter/cookiecutter-django/pull/4753))
+
+- Update djlint to 1.34.1 ([#4773](https://github.com/cookiecutter/cookiecutter-django/pull/4773))
+
+- Update uvicorn to 0.25.0 ([#4760](https://github.com/cookiecutter/cookiecutter-django/pull/4760))
+
+- Auto-update pre-commit hooks ([#4749](https://github.com/cookiecutter/cookiecutter-django/pull/4749))
+
+- Update black to 23.12.1 ([#4772](https://github.com/cookiecutter/cookiecutter-django/pull/4772))
+
+- Update pillow to 10.2.0 ([#4770](https://github.com/cookiecutter/cookiecutter-django/pull/4770))
+
+- Update django to 4.2.9 ([#4771](https://github.com/cookiecutter/cookiecutter-django/pull/4771))
+
+- Update pytest to 7.4.4 ([#4767](https://github.com/cookiecutter/cookiecutter-django/pull/4767))
+
+- Update coverage to 7.4.0 ([#4764](https://github.com/cookiecutter/cookiecutter-django/pull/4764))
+
+## 2023.12.19
+
+
+### Changed
+
+- Upgrade debian to 12 bookworm ([#4745](https://github.com/cookiecutter/cookiecutter-django/pull/4745))
+
+### Updated
+
+- Update hiredis to 2.3.2 ([#4750](https://github.com/cookiecutter/cookiecutter-django/pull/4750))
+
+## 2023.12.15
+
+
+### Updated
+
+- Update coverage to 7.3.3 ([#4748](https://github.com/cookiecutter/cookiecutter-django/pull/4748))
+
+- Update psycopg to 3.1.15 ([#4747](https://github.com/cookiecutter/cookiecutter-django/pull/4747))
+
+- Update sentry-sdk to 1.39.1 ([#4746](https://github.com/cookiecutter/cookiecutter-django/pull/4746))
+
+- Auto-update pre-commit hooks ([#4743](https://github.com/cookiecutter/cookiecutter-django/pull/4743))
+
+## 2023.12.13
+
+
+### Updated
+
+- Auto-update pre-commit hooks ([#4740](https://github.com/cookiecutter/cookiecutter-django/pull/4740))
+
+## 2023.12.12
+
+
+### Updated
+
+- Update django-allauth to 0.59.0 ([#4739](https://github.com/cookiecutter/cookiecutter-django/pull/4739))
+
+- Update sentry-sdk to 1.39.0 ([#4738](https://github.com/cookiecutter/cookiecutter-django/pull/4738))
+
+- Update black to 23.12.0 ([#4737](https://github.com/cookiecutter/cookiecutter-django/pull/4737))
+
+- Auto-update pre-commit hooks ([#4736](https://github.com/cookiecutter/cookiecutter-django/pull/4736))
+
+- Update drf-spectacular to 0.27.0 ([#4735](https://github.com/cookiecutter/cookiecutter-django/pull/4735))
+
+## 2023.12.11
+
+
+### Updated
+
+- Auto-update pre-commit hooks ([#4730](https://github.com/cookiecutter/cookiecutter-django/pull/4730))
+
+## 2023.12.10
+
+
+### Updated
+
+- Update pre-commit to 3.6.0 ([#4728](https://github.com/cookiecutter/cookiecutter-django/pull/4728))
+
+- Auto-update pre-commit hooks ([#4729](https://github.com/cookiecutter/cookiecutter-django/pull/4729))
+
+## 2023.12.09
+
+
+### Changed
+
+- Add missing __init__.py file to api module ([#4726](https://github.com/cookiecutter/cookiecutter-django/pull/4726))
+
+## 2023.12.07
+
+
+### Updated
+
+- Bump actions/setup-python from 4 to 5 ([#4723](https://github.com/cookiecutter/cookiecutter-django/pull/4723))
+
+- Auto-update pre-commit hooks ([#4709](https://github.com/cookiecutter/cookiecutter-django/pull/4709))
+
+- Bump traefik from 2.10.6 to 2.10.7 ([#4722](https://github.com/cookiecutter/cookiecutter-django/pull/4722))
+
+## 2023.12.06
+
+
+### Updated
+
+- Bump python from 3.11.6 to 3.11.7 ([#4719](https://github.com/cookiecutter/cookiecutter-django/pull/4719))
+
+- Update mypy to 1.7.1, django-stubs to 4.2.7 and djangorestframework-stubs to 3.14.5 ([#4694](https://github.com/cookiecutter/cookiecutter-django/pull/4694))
+
+## 2023.12.04
+
+
+### Updated
+
+- Update django to 4.2.8 ([#4713](https://github.com/cookiecutter/cookiecutter-django/pull/4713))
+
+- Bump node from 18 to 20 ([#4283](https://github.com/cookiecutter/cookiecutter-django/pull/4283))
+
+- Update psycopg to 3.1.14 ([#4711](https://github.com/cookiecutter/cookiecutter-django/pull/4711))
+
+## 2023.12.02
+
+
+### Updated
+
+- Update mailpit to latest ([#4710](https://github.com/cookiecutter/cookiecutter-django/pull/4710))
+
+## 2023.11.30
+
+
+### Fixed
+
+- Removed tmp mount in devcontainer.json. Fix #4686 ([#4708](https://github.com/cookiecutter/cookiecutter-django/pull/4708))
+
+### Updated
+
+- Bump traefik from 2.10.5 to 2.10.6 ([#4706](https://github.com/cookiecutter/cookiecutter-django/pull/4706))
+
+## 2023.11.29
+
+
+### Updated
+
+- Update sentry-sdk to 1.38.0 ([#4705](https://github.com/cookiecutter/cookiecutter-django/pull/4705))
+
+## 2023.11.28
+
+
+### Fixed
+
+- Excludes devcontainer.json from the pre-commit ([#4702](https://github.com/cookiecutter/cookiecutter-django/pull/4702))
+
+### Updated
+
+- Update sphinx-rtd-theme to 2.0.0 ([#4700](https://github.com/cookiecutter/cookiecutter-django/pull/4700))
+
+## 2023.11.24
+
+
+### Updated
+
+- Update sentry-sdk to 1.37.1 ([#4696](https://github.com/cookiecutter/cookiecutter-django/pull/4696))
+
+- Update sentry-sdk to 1.37.0 ([#4695](https://github.com/cookiecutter/cookiecutter-django/pull/4695))
+
+## 2023.11.22
+
+
+### Updated
+
+- Update celery to 5.3.6 ([#4693](https://github.com/cookiecutter/cookiecutter-django/pull/4693))
+
+## 2023.11.21
+
+
+### Updated
+
+- Update sentry-sdk to 1.36.0 ([#4687](https://github.com/cookiecutter/cookiecutter-django/pull/4687))
+
+## 2023.11.20
+
+
+### Fixed
+
+- Fix bug with social account adapter name override, in very specific conditions ([#4650](https://github.com/cookiecutter/cookiecutter-django/pull/4650))
+
+### Updated
+
+- Update django-cors-headers to 4.3.1 ([#4684](https://github.com/cookiecutter/cookiecutter-django/pull/4684))
+
+- Update psycopg to 3.1.13 ([#4685](https://github.com/cookiecutter/cookiecutter-django/pull/4685))
+
+## 2023.11.14
+
+
+### Updated
+
+- Update sentry-sdk to 1.35.0 ([#4681](https://github.com/cookiecutter/cookiecutter-django/pull/4681))
+
+- Auto-update pre-commit hooks ([#4683](https://github.com/cookiecutter/cookiecutter-django/pull/4683))
+
+## 2023.11.11
+
+
+### Updated
+
+- Update celery to 5.3.5 ([#4678](https://github.com/cookiecutter/cookiecutter-django/pull/4678))
+
+## 2023.11.09
+
+
+### Updated
+
+- Auto-update pre-commit hooks ([#4673](https://github.com/cookiecutter/cookiecutter-django/pull/4673))
+
+- Update black to 23.11.0 ([#4674](https://github.com/cookiecutter/cookiecutter-django/pull/4674))
+
+## 2023.11.08
+
+
+### Updated
+
+- Update pytest-django to 4.7.0 ([#4672](https://github.com/cookiecutter/cookiecutter-django/pull/4672))
+
+## 2023.11.06
+
+
+### Changed
+
+- Add `rmbackup` script to remove backups from `postgres/backups`. Fixes: #4663 ([#4664](https://github.com/cookiecutter/cookiecutter-django/pull/4664))
+
+### Updated
+
+- Update django-allauth to 0.58.2 ([#4667](https://github.com/cookiecutter/cookiecutter-django/pull/4667))
+
+- Update uvicorn to 0.24.0.post1 ([#4666](https://github.com/cookiecutter/cookiecutter-django/pull/4666))
+
+## 2023.11.04
+
+
+### Updated
+
+- Update uvicorn to 0.24.0 ([#4665](https://github.com/cookiecutter/cookiecutter-django/pull/4665))
+
+## 2023.11.03
+
+
+### Updated
+
+- Update flake8-isort to 6.1.1 ([#4662](https://github.com/cookiecutter/cookiecutter-django/pull/4662))
+
+## 2023.11.02
+
+
+### Updated
+
+- Update sentry-sdk to 1.34.0 ([#4660](https://github.com/cookiecutter/cookiecutter-django/pull/4660))
+
+## 2023.11.01
+
+
+### Updated
+
+- Update django to 4.2.7 ([#4658](https://github.com/cookiecutter/cookiecutter-django/pull/4658))
+
+- Update django-stubs to 4.2.6 ([#4657](https://github.com/cookiecutter/cookiecutter-django/pull/4657))
+
+## 2023.10.31
+
+
+### Updated
+
+- Update pytest-django to 4.6.0 ([#4656](https://github.com/cookiecutter/cookiecutter-django/pull/4656))
+
+- Update pytest to 7.4.3 ([#4654](https://github.com/cookiecutter/cookiecutter-django/pull/4654))
+
+- Update werkzeug to 3.0.1 ([#4655](https://github.com/cookiecutter/cookiecutter-django/pull/4655))
+
+- Update sentry-sdk to 1.33.1 ([#4653](https://github.com/cookiecutter/cookiecutter-django/pull/4653))
+
+- Update sentry-sdk to 1.33.0 ([#4652](https://github.com/cookiecutter/cookiecutter-django/pull/4652))
+
+- Update crispy-bootstrap5 to 2023.10 ([#4651](https://github.com/cookiecutter/cookiecutter-django/pull/4651))
+
+## 2023.10.26
+
+
+### Updated
+
+- Update django-anymail to 10.2 ([#4645](https://github.com/cookiecutter/cookiecutter-django/pull/4645))
+
+## 2023.10.24
+
+
+### Updated
+
+- Update black to 23.10.1 ([#4639](https://github.com/cookiecutter/cookiecutter-django/pull/4639))
+
+- Auto-update pre-commit hooks ([#4641](https://github.com/cookiecutter/cookiecutter-django/pull/4641))
+
+## 2023.10.23
+
+
+### Updated
+
+- Update pylint-django to 2.5.5 ([#4638](https://github.com/cookiecutter/cookiecutter-django/pull/4638))
+
+## 2023.10.19
+
+
+### Updated
+
+- Update mypy to 1.6.1 ([#4634](https://github.com/cookiecutter/cookiecutter-django/pull/4634))
+
+- Update djangorestframework-stubs to 3.14.4 ([#4637](https://github.com/cookiecutter/cookiecutter-django/pull/4637))
+
+- Update django-stubs to 4.2.5 ([#4636](https://github.com/cookiecutter/cookiecutter-django/pull/4636))
+
+## 2023.10.17
+
+
+### Updated
+
+- Auto-update pre-commit hooks ([#4633](https://github.com/cookiecutter/cookiecutter-django/pull/4633))
+
+- Update black to 23.10.0 ([#4632](https://github.com/cookiecutter/cookiecutter-django/pull/4632))
+
+- Update pillow to 10.1.0 ([#4630](https://github.com/cookiecutter/cookiecutter-django/pull/4630))
+
+- Update django-crispy-forms to 2.1 ([#4629](https://github.com/cookiecutter/cookiecutter-django/pull/4629))
+
+## 2023.10.13
+
+
+### Updated
+
+- Update pre-commit to 3.5.0 ([#4628](https://github.com/cookiecutter/cookiecutter-django/pull/4628))
+
+- Update watchfiles to 0.21.0 ([#4627](https://github.com/cookiecutter/cookiecutter-django/pull/4627))
+
+## 2023.10.12
+
+
+### Updated
+
+- Update django-cors-headers to 4.3.0 ([#4625](https://github.com/cookiecutter/cookiecutter-django/pull/4625))
+
+- Update whitenoise to 6.6.0 ([#4624](https://github.com/cookiecutter/cookiecutter-django/pull/4624))
+
+- Update sentry-sdk to 1.32.0 ([#4623](https://github.com/cookiecutter/cookiecutter-django/pull/4623))
+
+- Bump traefik from 2.10.4 to 2.10.5 ([#4626](https://github.com/cookiecutter/cookiecutter-django/pull/4626))
+
+## 2023.10.09
+
+
+### Updated
+
+- Bump stefanzweifel/git-auto-commit-action from 4.16.0 to 5.0.0 ([#4621](https://github.com/cookiecutter/cookiecutter-django/pull/4621))
+
+- Update django-storages to 1.14.2 ([#4620](https://github.com/cookiecutter/cookiecutter-django/pull/4620))
+
+## 2023.10.08
+
+
+### Updated
+
+- Auto-update pre-commit hooks ([#4619](https://github.com/cookiecutter/cookiecutter-django/pull/4619))
+
+## 2023.10.05
+
+
+### Updated
+
+- Update djangorestframework-stubs to 3.14.3 ([#4618](https://github.com/cookiecutter/cookiecutter-django/pull/4618))
+
+- Update django-stubs to 4.2.4 ([#4566](https://github.com/cookiecutter/cookiecutter-django/pull/4566))
+
+- Update mypy to 1.5.1 ([#4568](https://github.com/cookiecutter/cookiecutter-django/pull/4568))
+
+## 2023.10.04
+
+
+### Updated
+
+- Update django to 4.2.6 ([#4617](https://github.com/cookiecutter/cookiecutter-django/pull/4617))
+
+- Update coverage to 7.3.2 ([#4616](https://github.com/cookiecutter/cookiecutter-django/pull/4616))
+
+- Update werkzeug to 3.0.0 ([#4608](https://github.com/cookiecutter/cookiecutter-django/pull/4608))
+
+- Update django-redis to 5.4.0 ([#4609](https://github.com/cookiecutter/cookiecutter-django/pull/4609))
+
+- Bump docs Python docker image from 3.11.5 to 3.11.6 ([#4615](https://github.com/cookiecutter/cookiecutter-django/pull/4615))
+
+## 2023.10.03
+
+
+### Changed
+
+- [pre-commit.ci] pre-commit autoupdate ([#4613](https://github.com/cookiecutter/cookiecutter-django/pull/4613))
+
+### Updated
+
+- Bump prod Python docker image from 3.11.5 to 3.11.6 ([#4611](https://github.com/cookiecutter/cookiecutter-django/pull/4611))
+
+- Bump local Python docker image from 3.11.5 to 3.11.6 ([#4612](https://github.com/cookiecutter/cookiecutter-django/pull/4612))
+
+- Auto-update pre-commit hooks ([#4610](https://github.com/cookiecutter/cookiecutter-django/pull/4610))
+
+## 2023.09.29
+
+
+### Updated
+
+- Update django-storages to 1.14.1 ([#4604](https://github.com/cookiecutter/cookiecutter-django/pull/4604))
+
+## 2023.09.28
+
+
+### Updated
+
+- Update psycopg to 3.1.12 ([#4601](https://github.com/cookiecutter/cookiecutter-django/pull/4601))
+
+## 2023.09.27
+
+
+### Fixed
+
+- Fix ownership for /start-flower script in production Dockerfile ([#4603](https://github.com/cookiecutter/cookiecutter-django/pull/4603))
+
+## 2023.09.26
+
+
+### Updated
+
+- Update redis to 5.0.1 ([#4600](https://github.com/cookiecutter/cookiecutter-django/pull/4600))
+
+## 2023.09.25
+
+
+### Updated
+
+- Update django-upgrade to 1.15.0 ([#4598](https://github.com/cookiecutter/cookiecutter-django/pull/4598))
+
+- Update django-allauth to 0.57.0 ([#4597](https://github.com/cookiecutter/cookiecutter-django/pull/4597))
+
+- Auto-update pre-commit hooks ([#4596](https://github.com/cookiecutter/cookiecutter-django/pull/4596))
+
+## 2023.09.23
+
+
+### Updated
+
+- Update psycopg to 3.1.11 ([#4595](https://github.com/cookiecutter/cookiecutter-django/pull/4595))
+
+- Auto-update pre-commit hooks ([#4591](https://github.com/cookiecutter/cookiecutter-django/pull/4591))
+
+- Update drf-spectacular to 0.26.5 ([#4594](https://github.com/cookiecutter/cookiecutter-django/pull/4594))
+
+## 2023.09.21
+
+
+### Updated
+
+- Auto-update pre-commit hooks ([#4589](https://github.com/cookiecutter/cookiecutter-django/pull/4589))
+
+- Update djlint to 1.34.0 ([#4590](https://github.com/cookiecutter/cookiecutter-django/pull/4590))
+
+## 2023.09.19
+
+
+### Updated
+
+- Auto-update pre-commit hooks ([#4588](https://github.com/cookiecutter/cookiecutter-django/pull/4588))
+
+- Update djlint to 1.33.0 ([#4587](https://github.com/cookiecutter/cookiecutter-django/pull/4587))
+
+## 2023.09.16
+
+
+### Updated
+
+- Auto-update pre-commit hooks ([#4586](https://github.com/cookiecutter/cookiecutter-django/pull/4586))
+
+## 2023.09.15
+
+
+### Updated
+
+- Update flake8-isort to 6.1.0 ([#4585](https://github.com/cookiecutter/cookiecutter-django/pull/4585))
+
+- Update pillow to 10.0.1 ([#4584](https://github.com/cookiecutter/cookiecutter-django/pull/4584))
+
+## 2023.09.14
+
+
+### Updated
+
+- Update sphinx to 7.2.6 ([#4583](https://github.com/cookiecutter/cookiecutter-django/pull/4583))
+
+## 2023.09.13
+
+
+### Updated
+
+- Update sentry-sdk to 1.31.0 ([#4582](https://github.com/cookiecutter/cookiecutter-django/pull/4582))
+
+## 2023.09.12
+
+
+### Updated
+
+- Update django-storages to 1.14 ([#4564](https://github.com/cookiecutter/cookiecutter-django/pull/4564))
+
+## 2023.09.11
+
+
+### Updated
+
+- Auto-update pre-commit hooks ([#4579](https://github.com/cookiecutter/cookiecutter-django/pull/4579))
+
+- Update black to 23.9.1 ([#4580](https://github.com/cookiecutter/cookiecutter-django/pull/4580))
+
+- Update django-allauth to 0.56.1 ([#4576](https://github.com/cookiecutter/cookiecutter-django/pull/4576))
+
+## 2023.09.08
+
+
+### Updated
+
+- Update pytest to 7.4.2 ([#4573](https://github.com/cookiecutter/cookiecutter-django/pull/4573))
+
+## 2023.09.07
+
+
+### Updated
+
+- Update django-allauth to 0.56.0 ([#4571](https://github.com/cookiecutter/cookiecutter-django/pull/4571))
+
+## 2023.09.06
+
+
+### Changed
+
+- Replace Mailhog with Mailpit ([#4551](https://github.com/cookiecutter/cookiecutter-django/pull/4551))
+
+### Updated
+
+- Update sphinx to 7.2.5 ([#4569](https://github.com/cookiecutter/cookiecutter-django/pull/4569))
+
+- Bump actions/checkout from 3 to 4 ([#4565](https://github.com/cookiecutter/cookiecutter-django/pull/4565))
+
+- Update coverage to 7.3.1 ([#4567](https://github.com/cookiecutter/cookiecutter-django/pull/4567))
+
+## 2023.09.04
+
+
+### Updated
+
+- Update django to 4.2.5 ([#4563](https://github.com/cookiecutter/cookiecutter-django/pull/4563))
+
+## 2023.09.03
+
+
+### Updated
+
+- Update celery to 5.3.4 ([#4562](https://github.com/cookiecutter/cookiecutter-django/pull/4562))
+
+## 2023.09.02
+
+
+### Updated
+
+- Update pytest to 7.4.1 ([#4561](https://github.com/cookiecutter/cookiecutter-django/pull/4561))
+
+- Update pre-commit to 3.4.0 ([#4560](https://github.com/cookiecutter/cookiecutter-django/pull/4560))
+
+- Update django-environ to 0.11.2 ([#4558](https://github.com/cookiecutter/cookiecutter-django/pull/4558))
+
+## 2023.09.01
+
+
+## 2023.08.31
+
+
+### Updated
+
+- Auto-update pre-commit hooks ([#4550](https://github.com/cookiecutter/cookiecutter-django/pull/4550))
+
+- Update django-allauth to 0.55.2 ([#4549](https://github.com/cookiecutter/cookiecutter-django/pull/4549))
+
+- Update celery to 5.3.3 ([#4553](https://github.com/cookiecutter/cookiecutter-django/pull/4553))
+
+## 2023.08.30
+
+
+### Updated
+
+- Update django-environ to 0.11.0 ([#4548](https://github.com/cookiecutter/cookiecutter-django/pull/4548))
+
+## 2023.08.29
+
+
+### Updated
+
+- Update sentry-sdk to 1.30.0 ([#4546](https://github.com/cookiecutter/cookiecutter-django/pull/4546))
+
+## 2023.08.28
+
+
+### Changed
+
+- Add French translations ([#4454](https://github.com/cookiecutter/cookiecutter-django/pull/4454))
+
+- Change `MEDIA_URL` to an absolute URL in tests ([#4460](https://github.com/cookiecutter/cookiecutter-django/pull/4460))
+
+### Fixed
+
+- Fix a small compatibility issue between black and flake8 ([#4541](https://github.com/cookiecutter/cookiecutter-django/pull/4541))
+
+### Updated
+
+- Update django-allauth to 0.55.0 ([#4535](https://github.com/cookiecutter/cookiecutter-django/pull/4535))
+
+- Update watchfiles to 0.20.0 ([#4537](https://github.com/cookiecutter/cookiecutter-django/pull/4537))
+
+- Update Python version from 3.11.4 to 3.11.5 ([#4542](https://github.com/cookiecutter/cookiecutter-django/pull/4542))
+
+## 2023.08.19
+
+
+### Changed
+
+- Override `_after_postgeneration` to force save in `UserFactory` ([#4534](https://github.com/cookiecutter/cookiecutter-django/pull/4534))
+
+## 2023.08.17
+
+
+### Updated
+
+- Update argon2-cffi to 23.1.0 ([#4527](https://github.com/cookiecutter/cookiecutter-django/pull/4527))
+
+- Auto-update pre-commit hooks ([#4530](https://github.com/cookiecutter/cookiecutter-django/pull/4530))
+
+## 2023.08.16
+
+
+### Updated
+
+- Update django-upgrade to 1.14.1 ([#4528](https://github.com/cookiecutter/cookiecutter-django/pull/4528))
+
+## 2023.08.15
+
+
+### Updated
+
+- Update redis to 5.0.0 ([#4526](https://github.com/cookiecutter/cookiecutter-django/pull/4526))
+
+## 2023.08.14
+
+
+### Changed
+
+- Install Django and DRF stubs with `compatible-mypy` extra (as per offical recommendation) ([#4361](https://github.com/cookiecutter/cookiecutter-django/pull/4361))
+
+- Fix `overrideCommand` value in `devcontainer` so that the `django` container can run (#4517) ([#4517](https://github.com/cookiecutter/cookiecutter-django/pull/4517))
+
+### Fixed
+
+- Prevent error in data migration caused by long project name ([#4525](https://github.com/cookiecutter/cookiecutter-django/pull/4525))
+
+- Remove unused gulp-concat when Webpack is selected ([#4520](https://github.com/cookiecutter/cookiecutter-django/pull/4520))
+
+- Exclude env files from container image (add .envs/ to .dockerignore) ([#4476](https://github.com/cookiecutter/cookiecutter-django/pull/4476))
+
+### Updated
+
+- Update werkzeug to 2.3.7 ([#4521](https://github.com/cookiecutter/cookiecutter-django/pull/4521))
+
+- Update coverage to 7.3.0 ([#4516](https://github.com/cookiecutter/cookiecutter-django/pull/4516))
+
+- Update django-debug-toolbar to 4.2.0 ([#4511](https://github.com/cookiecutter/cookiecutter-django/pull/4511))
+
+- Update flower to 2.0.1 ([#4518](https://github.com/cookiecutter/cookiecutter-django/pull/4518))
+
+## 2023.08.10
+
+
+### Fixed
+
+- Corrected 'or' translation to pt-br ([#4507](https://github.com/cookiecutter/cookiecutter-django/pull/4507))
+
+## 2023.08.04
+
+
+### Updated
+
+- Auto-update pre-commit hooks ([#4503](https://github.com/cookiecutter/cookiecutter-django/pull/4503))
+
+## 2023.08.01
+
+
+### Updated
+
+- Auto-update pre-commit hooks ([#4499](https://github.com/cookiecutter/cookiecutter-django/pull/4499))
+
+- Update django-anymail to 10.1 ([#4497](https://github.com/cookiecutter/cookiecutter-django/pull/4497))
+
+- Update sentry-sdk to 1.29.2 ([#4496](https://github.com/cookiecutter/cookiecutter-django/pull/4496))
+
+- Update django to 4.2.4 ([#4495](https://github.com/cookiecutter/cookiecutter-django/pull/4495))
+
+- Update flake8 to 6.1.0 ([#4489](https://github.com/cookiecutter/cookiecutter-django/pull/4489))
+
+- Update uvicorn to 0.23.2 ([#4490](https://github.com/cookiecutter/cookiecutter-django/pull/4490))
+
+- Update sentry-sdk to 1.29.1 ([#4494](https://github.com/cookiecutter/cookiecutter-django/pull/4494))
+
+## 2023.07.30
+
+
+### Fixed
+
+- Fix `README.md` file extension in `setup.py` ([#4488](https://github.com/cookiecutter/cookiecutter-django/pull/4488))
+
+## 2023.07.28
+
+
+### Changed
+
+- Add support for Drone CI ([#4382](https://github.com/cookiecutter/cookiecutter-django/pull/4382))
+
+## 2023.07.27
+
+
+### Documentation
+
+- Document that `docker exec` does not work for running management commands ([#4487](https://github.com/cookiecutter/cookiecutter-django/pull/4487))
+
+- Add Webpack instructions for developping locally with HTTPS ([#4486](https://github.com/cookiecutter/cookiecutter-django/pull/4486))
+
+## 2023.07.25
+
+
+### Updated
+
+- Upgrade to traefik 2.10.4 ([#4483](https://github.com/cookiecutter/cookiecutter-django/pull/4483))
+
+## 2023.07.24
+
+
+### Fixed
+
+- Add missing custom CRSF error page in prod ([#4464](https://github.com/cookiecutter/cookiecutter-django/pull/4464))
+
+### Documentation
+
+- Replace `docker-compose` by `docker compose` in docs ([#4463](https://github.com/cookiecutter/cookiecutter-django/pull/4463))
+
+### Updated
+
+- Update drf-spectacular to 0.26.4 ([#4481](https://github.com/cookiecutter/cookiecutter-django/pull/4481))
+
+## 2023.07.20
+
+
+### Updated
+
+- Update djlint to 1.32.1 ([#4475](https://github.com/cookiecutter/cookiecutter-django/pull/4475))
+
+## 2023.07.19
+
+
+### Updated
+
+- Update factory-boy to 3.3.0 ([#4472](https://github.com/cookiecutter/cookiecutter-django/pull/4472))
+
+- Update gunicorn to 21.2.0 ([#4473](https://github.com/cookiecutter/cookiecutter-django/pull/4473))
+
+- Update djlint to 1.32.0 ([#4471](https://github.com/cookiecutter/cookiecutter-django/pull/4471))
+
+## 2023.07.18
+
+
+### Updated
+
+- Update gunicorn to 21.1.0 ([#4470](https://github.com/cookiecutter/cookiecutter-django/pull/4470))
+
+- Update uvicorn to 0.23.1 ([#4468](https://github.com/cookiecutter/cookiecutter-django/pull/4468))
+
+- Update gunicorn to 21.0.1 ([#4466](https://github.com/cookiecutter/cookiecutter-django/pull/4466))
+
+## 2023.07.13
+
+
+### Updated
+
+- Update sentry-sdk to 1.28.1 ([#4458](https://github.com/cookiecutter/cookiecutter-django/pull/4458))
+
+## 2023.07.11
+
+
+### Changed
+
+- Improve type hints for `UserSerializer` ([#4429](https://github.com/cookiecutter/cookiecutter-django/pull/4429))
+
+- [pre-commit.ci] pre-commit autoupdate ([#4453](https://github.com/cookiecutter/cookiecutter-django/pull/4453))
+
+### Fixed
+
+- Fix `/tmp` bind mount in devcontainer config ([#4455](https://github.com/cookiecutter/cookiecutter-django/pull/4455))
+
+### Updated
+
+- Update black to 23.7.0 ([#4452](https://github.com/cookiecutter/cookiecutter-django/pull/4452))
+
+## 2023.07.10
+
+
+### Fixed
+
+- Prevent user's name being shown twice on user details page if username is set to email ([#4436](https://github.com/cookiecutter/cookiecutter-django/pull/4436))
+
+- Add missing trailing space in `EMAIL_SUBJECT_PREFIX` setting ([#4434](https://github.com/cookiecutter/cookiecutter-django/pull/4434))
+
+### Documentation
+
+- Clarify documentation on which port to use to access the application when using Webpack or Gulp ([#4413](https://github.com/cookiecutter/cookiecutter-django/pull/4413))
+
+### Updated
+
+- Update django-coverage-plugin to 3.1.0 ([#4446](https://github.com/cookiecutter/cookiecutter-django/pull/4446))
+
+- Update pillow to 10.0.0 ([#4432](https://github.com/cookiecutter/cookiecutter-django/pull/4432))
+
+- Update django-cors-headers to 4.2.0 ([#4445](https://github.com/cookiecutter/cookiecutter-django/pull/4445))
+
+- Update sentry-sdk to 1.28.0 ([#4444](https://github.com/cookiecutter/cookiecutter-django/pull/4444))
+
+## 2023.07.09
+
+
+### Fixed
+
+- Fix missing run configurations when PyCharm is selected ([#4441](https://github.com/cookiecutter/cookiecutter-django/pull/4441))
+
+## 2023.07.08
+
+
+### Updated
+
+- Update sentry-sdk to 1.27.1 ([#4440](https://github.com/cookiecutter/cookiecutter-django/pull/4440))
+
## 2023.07.04
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index 184d445d5..7b778f439 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -194,6 +194,13 @@ Listed in alphabetical order.
scaramagus |
+
+ aiden |
+
+ anyidea
+ |
+ |
+
Alberto Sanchez |
@@ -509,6 +516,13 @@ Listed in alphabetical order.
|
|
+
+ Christian Jauvin |
+
+ cjauvin
+ |
+ |
+
Christopher Clarke |
@@ -796,6 +810,13 @@ Listed in alphabetical order.
|
fabaff |
+
+ Fateme Fouladkar |
+
+ FatemeFouladkar
+ |
+ |
+
Felipe Arruda |
@@ -817,6 +838,13 @@ Listed in alphabetical order.
|
|
+
+ Freddy |
+
+ Hraesvelg
+ |
+ |
+
Fuzzwah |
@@ -859,6 +887,13 @@ Listed in alphabetical order.
|
|
+
+ GitBib |
+
+ GitBib
+ |
+ |
+
Glenn Wiskur |
@@ -929,6 +964,13 @@ Listed in alphabetical order.
|
|
+
+ henningbra |
+
+ henningbra
+ |
+ |
+
Henrique G. G. Pereira |
@@ -936,6 +978,13 @@ Listed in alphabetical order.
|
|
+
+ hleroy |
+
+ hleroy
+ |
+ |
+
Hoai-Thu Vuong |
@@ -957,6 +1006,13 @@ Listed in alphabetical order.
|
|
+
+ Imran Rahman |
+
+ infraredCoding
+ |
+ |
+
innicoder |
@@ -978,6 +1034,13 @@ Listed in alphabetical order.
|
|
+
+ itisnotyourenv |
+
+ itisnotyourenv
+ |
+ |
+
Ivan Khomutov |
@@ -985,6 +1048,13 @@ Listed in alphabetical order.
|
|
+
+ Jakub Boukal |
+
+ SukiCZ
+ |
+ |
+
Jakub Musko |
@@ -1013,6 +1083,13 @@ Listed in alphabetical order.
|
|
+
+ Jens Kaeske |
+
+ jkaeske
+ |
+ |
+
Jens Nilsson |
@@ -1433,6 +1510,13 @@ Listed in alphabetical order.
|
|
+
+ Michael V. Battista |
+
+ mvbattista
+ |
+ mvbattista |
+
Mike97M |
@@ -1447,6 +1531,13 @@ Listed in alphabetical order.
|
|
+
+ MinWoo Sung |
+
+ SungMinWoo
+ |
+ |
+
monosans |
@@ -1503,6 +1594,13 @@ Listed in alphabetical order.
|
|
+
+ Nix Siow |
+
+ nixsiow
+ |
+ nixsiow |
+
Noah H |
@@ -1601,6 +1699,13 @@ Listed in alphabetical order.
|
|
+
+ Plurific |
+
+ paulschwenn
+ |
+ |
+
Raony Guimarães Corrêa |
@@ -1685,6 +1790,13 @@ Listed in alphabetical order.
|
|
+
+ Sadra Yahyapour |
+
+ lnxpy
+ |
+ lnxpylnxpy |
+
Sam Collins |
@@ -1706,6 +1818,13 @@ Listed in alphabetical order.
|
sebastianreyese |
+
+ Shayan Karimi |
+
+ shywn-mrk
+ |
+ shywn_mrk |
+
Simon Rey |
@@ -1790,6 +1909,13 @@ Listed in alphabetical order.
|
|
+
+ Tharushan |
+
+ Tharushan
+ |
+ |
+
Thibault J. |
@@ -1839,6 +1965,13 @@ Listed in alphabetical order.
|
|
+
+ tmajerech |
+
+ tmajerech
+ |
+ |
+
Tom Atkins |
@@ -1881,6 +2014,13 @@ Listed in alphabetical order.
|
egregors |
+
+ Vageeshan Mankala |
+
+ vagi8
+ |
+ |
+
vascop |
@@ -1902,6 +2042,13 @@ Listed in alphabetical order.
|
|
+
+ villancikos |
+
+ villancikos
+ |
+ |
+
Vitaly Babiy |
@@ -1986,6 +2133,13 @@ Listed in alphabetical order.
|
|
+
+ zhaoruibing |
+
+ zhaoruibing
+ |
+ |
+
### Special Thanks
diff --git a/README.md b/README.md
index 0a39fb084..a9bf1990f 100644
--- a/README.md
+++ b/README.md
@@ -23,7 +23,7 @@ production-ready Django projects quickly.
- Works with Python 3.11
- Renders Django projects with 100% starting test coverage
- Twitter [Bootstrap](https://github.com/twbs/bootstrap) v5
-- [12-Factor](http://12factor.net/) based settings via [django-environ](https://github.com/joke2k/django-environ)
+- [12-Factor](https://12factor.net) based settings via [django-environ](https://github.com/joke2k/django-environ)
- Secure by default. We believe in SSL.
- Optimized development and production settings
- Registration via [django-allauth](https://github.com/pennersr/django-allauth)
@@ -45,7 +45,7 @@ _These features can be enabled during initial project setup._
- 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)
-- Integration with [MailHog](https://github.com/mailhog/MailHog) for local email testing
+- Integration with [Mailpit](https://github.com/axllent/mailpit/) for local email testing
- Integration with [Sentry](https://sentry.io/welcome/) for error logging
## Constraints
@@ -165,7 +165,7 @@ Answer the prompts with your own desired [options](http://cookiecutter-django.re
4 - Webpack
Choose from 1, 2, 3, 4 [1]: 1
use_celery [n]: y
- use_mailhog [n]: n
+ use_mailpit [n]: n
use_sentry [n]: y
use_whitenoise [n]: n
use_heroku [n]: y
@@ -204,6 +204,8 @@ For local development, see the following:
- If you think you found a bug or want to request a feature, please open an [issue](https://github.com/cookiecutter/cookiecutter-django/issues).
- For anything else, you can chat with us on [Discord](https://discord.gg/uFXweDQc5a).
+
+
## For Readers of Two Scoops of Django
You may notice that some elements of this project do not exactly match what we describe in chapter 3. The reason for that is this project, amongst other things, serves as a test bed for trying out new ideas and concepts. Sometimes they work, sometimes they don't, but the end result is that it won't necessarily match precisely what is described in the book I co-authored.
@@ -247,6 +249,7 @@ experience better.
## Articles
+- [How to Make Your Own Django Cookiecutter Template!](https://medium.com/@FatemeFouladkar/how-to-make-your-own-django-cookiecutter-template-a753d4cbb8c2) - Aug. 10, 2023
- [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
diff --git a/cookiecutter.json b/cookiecutter.json
index 3fcab4a78..e343617d1 100644
--- a/cookiecutter.json
+++ b/cookiecutter.json
@@ -35,11 +35,11 @@
"use_drf": "n",
"frontend_pipeline": ["None", "Django Compressor", "Gulp", "Webpack"],
"use_celery": "n",
- "use_mailhog": "n",
+ "use_mailpit": "n",
"use_sentry": "n",
"use_whitenoise": "n",
"use_heroku": "n",
- "ci_tool": ["None", "Travis", "Gitlab", "Github"],
+ "ci_tool": ["None", "Travis", "Gitlab", "Github", "Drone"],
"keep_local_envs_in_vcs": "y",
"debug": "n"
}
diff --git a/docs/deployment-with-docker.rst b/docs/deployment-with-docker.rst
index c1b8c6d7b..3d2f9f813 100644
--- a/docs/deployment-with-docker.rst
+++ b/docs/deployment-with-docker.rst
@@ -1,7 +1,7 @@
Deployment with Docker
======================
-.. index:: deployment, docker, docker-compose, compose
+.. index:: deployment, docker, docker compose, compose
Prerequisites
@@ -89,7 +89,7 @@ You can read more about this feature and how to configure it, at `Automatic HTTP
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:
+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``
@@ -107,7 +107,7 @@ To solve this, you can either:
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``.
+ 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.
@@ -122,42 +122,42 @@ Building & Running Production Stack
You will need to build the stack first. To do that, run::
- docker-compose -f production.yml build
+ docker compose -f production.yml build
Once this is ready, you can run it with::
- docker-compose -f production.yml up
+ docker compose -f production.yml up
To run the stack and detach the containers, run::
- docker-compose -f production.yml up -d
+ docker compose -f production.yml up -d
To run a migration, open up a second terminal and run::
- docker-compose -f production.yml run --rm django python manage.py migrate
+ docker compose -f production.yml run --rm django python manage.py migrate
To create a superuser, run::
- docker-compose -f production.yml run --rm django python manage.py createsuperuser
+ docker compose -f production.yml run --rm django python manage.py createsuperuser
If you need a shell, run::
- docker-compose -f production.yml run --rm django python manage.py shell
+ docker compose -f production.yml run --rm django python manage.py shell
To check the logs out, run::
- docker-compose -f production.yml logs
+ docker compose -f production.yml logs
If you want to scale your application, run::
- docker-compose -f production.yml up --scale django=4
- docker-compose -f production.yml up --scale celeryworker=2
+ docker compose -f production.yml up --scale django=4
+ docker compose -f production.yml up --scale celeryworker=2
.. warning:: don't try to scale ``postgres``, ``celerybeat``, or ``traefik``.
To see how your containers are doing run::
- docker-compose -f production.yml ps
+ docker compose -f production.yml ps
Example: Supervisor
@@ -165,12 +165,12 @@ Example: Supervisor
Once you are ready with your initial setup, you want to make sure that your application is run by a process manager to
survive reboots and auto restarts in case of an error. You can use the process manager you are most familiar with. All
-it needs to do is to run ``docker-compose -f production.yml up`` in your projects root directory.
+it needs to do is to run ``docker compose -f production.yml up`` in your projects root directory.
If you are using ``supervisor``, you can use this file as a starting point::
[program:{{cookiecutter.project_slug}}]
- command=docker-compose -f production.yml up
+ command=docker compose -f production.yml up
directory=/path/to/{{cookiecutter.project_slug}}
redirect_stderr=true
autostart=true
diff --git a/docs/developing-locally-docker.rst b/docs/developing-locally-docker.rst
index 3dbe6e47d..a8f945adf 100644
--- a/docs/developing-locally-docker.rst
+++ b/docs/developing-locally-docker.rst
@@ -32,7 +32,7 @@ Build the Stack
This can take a while, especially the first time you run this particular command on your development system::
- $ docker-compose -f local.yml build
+ $ docker compose -f local.yml build
Generally, if you want to emulate production environment use ``production.yml`` instead. And this is true for any other actions you might need to perform: whenever a switch is required, just do it!
@@ -51,7 +51,7 @@ This brings up both Django and PostgreSQL. The first time it is run it might tak
Open a terminal at the project root and run the following for local development::
- $ docker-compose -f local.yml up
+ $ docker compose -f local.yml up
You can also set the environment variable ``COMPOSE_FILE`` pointing to ``local.yml`` like this::
@@ -59,23 +59,25 @@ You can also set the environment variable ``COMPOSE_FILE`` pointing to ``local.y
And then run::
- $ docker-compose up
+ $ docker compose up
To run in a detached (background) mode, just::
- $ docker-compose up -d
+ $ docker compose up -d
+The site should start and be accessible at http://localhost:3000 if you selected Webpack or Gulp as frontend pipeline and http://localhost:8000 otherwise.
+
Execute Management Commands
---------------------------
-As with any shell command that we wish to run in our container, this is done using the ``docker-compose -f local.yml run --rm`` command: ::
+As with any shell command that we wish to run in our container, this is done using the ``docker compose -f local.yml run --rm`` command: ::
- $ docker-compose -f local.yml run --rm django python manage.py migrate
- $ docker-compose -f local.yml run --rm django python manage.py createsuperuser
+ $ docker compose -f local.yml run --rm django python manage.py migrate
+ $ docker compose -f local.yml run --rm django python manage.py createsuperuser
Here, ``django`` is the target service we are executing the commands against.
-
+Also, please note that the ``docker exec`` does not work for running management commands.
(Optionally) Designate your Docker Development Server IP
--------------------------------------------------------
@@ -154,8 +156,8 @@ You have to modify the relevant requirement file: base, local or production by a
To get this change picked up, you'll need to rebuild the image(s) and restart the running container: ::
- docker-compose -f local.yml build
- docker-compose -f local.yml up
+ docker compose -f local.yml build
+ docker compose -f local.yml up
Debugging
~~~~~~~~~
@@ -169,7 +171,7 @@ If you are using the following within your code to debug: ::
Then you may need to run the following for it to work as desired: ::
- $ docker-compose -f local.yml run --rm --service-ports django
+ $ docker compose -f local.yml run --rm --service-ports django
django-debug-toolbar
@@ -189,16 +191,16 @@ The ``container_name`` from the yml file can be used to check on containers with
Notice that the ``container_name`` is generated dynamically using your project slug as a prefix
-Mailhog
+Mailpit
~~~~~~~
-When developing locally you can go with MailHog_ for email testing provided ``use_mailhog`` was set to ``y`` on setup. To proceed,
+When developing locally you can go with Mailpit_ for email testing provided ``use_mailpit`` was set to ``y`` on setup. To proceed,
-#. make sure ``_local_mailhog`` container is up and running;
+#. make sure ``_local_mailpit`` container is up and running;
#. open up ``http://127.0.0.1:8025``.
-.. _Mailhog: https://github.com/mailhog/MailHog/
+.. _Mailpit: https://github.com/axllent/mailpit/
.. _`CeleryTasks`:
@@ -229,7 +231,12 @@ By default, it's enabled both in local and production environments (``local.yml`
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.
+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 your 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.
+
+The stack comes with a dedicated node service to build the static assets, watch for changes and proxy requests to the Django app with live reloading scripts injected in the response. For everything to work smoothly, you need to access the application at the port served by the node service, which is http://localhost:3000 by default.
+
+.. _Sass: https://sass-lang.com/
+.. _live reloading: https://browsersync.io
Developing locally with HTTPS
-----------------------------
@@ -309,7 +316,7 @@ You should allow the new hostname. ::
Rebuild your ``docker`` application. ::
- $ docker-compose -f local.yml up -d --build
+ $ docker compose -f local.yml up -d --build
Go to your browser and type in your URL bar ``https://my-dev-env.local``
@@ -323,3 +330,26 @@ See `https with nginx`_ for more information on this configuration.
Add ``certs/*`` to the ``.gitignore`` file. This allows the folder to be included in the repo but its contents to be ignored.
*This configuration is for local development environments only. Do not use this for production since you might expose your local* ``rootCA-key.pem``.
+
+Webpack
+~~~~~~~
+
+If you are using Webpack:
+
+1. On the ``nginx-proxy`` service in ``local.yml``, change ``depends_on`` to ``node`` instead of ``django``.
+
+2. On the ``node`` service in ``local.yml``, add the following environment configuration:
+
+ ::
+
+ environment:
+ - VIRTUAL_HOST=my-dev-env.local
+ - VIRTUAL_PORT=3000
+
+3. Add the following configuration to the ``devServer`` section of ``webpack/dev.config.js``:
+
+ ::
+
+ client: {
+ webSocketURL: 'auto://0.0.0.0:0/ws', // note the `:0` after `0.0.0.0`
+ },
diff --git a/docs/developing-locally.rst b/docs/developing-locally.rst
index b79033aaa..92379f4fd 100644
--- a/docs/developing-locally.rst
+++ b/docs/developing-locally.rst
@@ -80,10 +80,12 @@ First things first.
$ python manage.py runserver 0.0.0.0:8000
-or if you're running asynchronously: ::
+ or if you're running asynchronously: ::
$ uvicorn config.asgi:application --host 0.0.0.0 --reload --reload-include '*.html'
+ If you've opted for Webpack or Gulp as frontend pipeline, please see the :ref:`dedicated section ` below.
+
.. _PostgreSQL: https://www.postgresql.org/download/
.. _Redis: https://redis.io/download
.. _CookieCutter: https://github.com/cookiecutter/cookiecutter
@@ -97,39 +99,37 @@ or if you're running asynchronously: ::
Setup Email Backend
-------------------
-MailHog
+Mailpit
~~~~~~~
-.. note:: In order for the project to support MailHog_ it must have been bootstrapped with ``use_mailhog`` set to ``y``.
+.. note:: In order for the project to support Mailpit_ it must have been bootstrapped with ``use_mailpit`` set to ``y``.
-MailHog is used to receive emails during development, it is written in Go and has no external dependencies.
+Mailpit is used to receive emails during development, it is written in Go and has no external dependencies.
For instance, one of the packages we depend upon, ``django-allauth`` sends verification emails to new users signing up as well as to the existing ones who have not yet verified themselves.
-#. `Download the latest MailHog release`_ for your OS.
+#. `Download the latest Mailpit release`_ for your OS.
-#. Rename the build to ``MailHog``.
-
-#. Copy the file to the project root.
+#. Copy the binary file to the project root.
#. Make it executable: ::
- $ chmod +x MailHog
+ $ chmod +x mailpit
#. Spin up another terminal window and start it there: ::
- ./MailHog
+ ./mailpit
#. Check out ``_ to see how it goes.
Now you have your own mail server running locally, ready to receive whatever you send it.
-.. _`Download the latest MailHog release`: https://github.com/mailhog/MailHog
+.. _`Download the latest Mailpit release`: https://github.com/axllent/mailpit
Console
~~~~~~~
-.. note:: If you have generated your project with ``use_mailhog`` set to ``n`` this will be a default setup.
+.. note:: If you have generated your project with ``use_mailpit`` set to ``n`` this will be a default setup.
Alternatively, deliver emails over console via ``EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'``.
@@ -169,10 +169,12 @@ You can also use Django admin to queue up tasks, thanks to the `django-celerybea
.. _django-celerybeat: https://django-celery-beat.readthedocs.io/en/latest/
-Sass Compilation & Live Reloading
----------------------------------
+.. _bare-metal-webpack-gulp:
-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.
+Using Webpack or Gulp
+---------------------
+
+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 your 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`_ v18 is installed on your machine.
#. In the project root, install the JS dependencies with::
@@ -183,9 +185,12 @@ If you've opted for Gulp or Webpack as front-end pipeline, the project comes con
$ npm run dev
- The app will now run with live reloading enabled, applying front-end changes dynamically.
+ This will start 2 processes in parallel: the static assets build loop on one side, and the Django server on the other.
+
+#. Access your application at the address of the ``node`` service in order to see your correct styles. This is http://localhost:3000 by default.
+
+ .. note:: Do NOT access the application using the Django port (8000 by default), as it will result in broken styles and 404s when accessing static assets.
-.. note:: The task will start 2 processes in parallel: the static assets build loop on one side, and the Django server on the other. You do NOT need to run Django as your would normally with ``manage.py runserver``.
.. _Node.js: http://nodejs.org/download/
.. _Sass: https://sass-lang.com/
diff --git a/docs/docker-postgres-backups.rst b/docs/docker-postgres-backups.rst
index 875d737eb..fdf446030 100644
--- a/docs/docker-postgres-backups.rst
+++ b/docs/docker-postgres-backups.rst
@@ -8,7 +8,7 @@ Prerequisites
-------------
#. the project was generated with ``use_docker`` set to ``y``;
-#. the stack is up and running: ``docker-compose -f local.yml up -d postgres``.
+#. the stack is up and running: ``docker compose -f local.yml up -d postgres``.
Creating a Backup
@@ -16,7 +16,7 @@ Creating a Backup
To create a backup, run::
- $ docker-compose -f local.yml exec postgres backup
+ $ docker compose -f local.yml exec postgres backup
Assuming your project's database is named ``my_project`` here is what you will see: ::
@@ -31,7 +31,7 @@ Viewing the Existing Backups
To list existing backups, ::
- $ docker-compose -f local.yml exec postgres backups
+ $ docker compose -f local.yml exec postgres backups
These are the sample contents of ``/backups``: ::
@@ -55,9 +55,9 @@ With a single backup file copied to ``.`` that would be ::
$ docker cp 9c5c3f055843:/backups/backup_2018_03_13T09_05_07.sql.gz .
-You can also get the container ID using ``docker-compose -f local.yml ps -q postgres`` so if you want to automate your backups, you don't have to check the container ID manually every time. Here is the full command ::
+You can also get the container ID using ``docker compose -f local.yml ps -q postgres`` so if you want to automate your backups, you don't have to check the container ID manually every time. Here is the full command ::
- $ docker cp $(docker-compose -f local.yml ps -q postgres):/backups ./backups
+ $ docker cp $(docker compose -f local.yml ps -q postgres):/backups ./backups
.. _`command`: https://docs.docker.com/engine/reference/commandline/cp/
@@ -66,7 +66,7 @@ Restoring from the Existing Backup
To restore from one of the backups you have already got (take the ``backup_2018_03_13T09_05_07.sql.gz`` for example), ::
- $ docker-compose -f local.yml exec postgres restore backup_2018_03_13T09_05_07.sql.gz
+ $ docker compose -f local.yml exec postgres restore backup_2018_03_13T09_05_07.sql.gz
You will see something like ::
@@ -92,7 +92,15 @@ You will see something like ::
Backup to Amazon S3
----------------------------------
+
For uploading your backups to Amazon S3 you can use the aws cli container. There is an upload command for uploading the postgres /backups directory recursively and there is a download command for downloading a specific backup. The default S3 environment variables are used. ::
- $ docker-compose -f production.yml run --rm awscli upload
- $ docker-compose -f production.yml run --rm awscli download backup_2018_03_13T09_05_07.sql.gz
+ $ docker compose -f production.yml run --rm awscli upload
+ $ docker compose -f production.yml run --rm awscli download backup_2018_03_13T09_05_07.sql.gz
+
+Remove Backup
+----------------------------------
+
+To remove backup you can use the ``rmbackup`` command. This will remove the backup from the ``/backups`` directory. ::
+
+ $ docker compose -f local.yml exec postgres rmbackup backup_2018_03_13T09_05_07.sql.gz
diff --git a/docs/document.rst b/docs/document.rst
index 974c66c69..26f5d56a1 100644
--- a/docs/document.rst
+++ b/docs/document.rst
@@ -11,7 +11,7 @@ After you have set up to `develop locally`_, run the following command from the
If you set up your project to `develop locally with docker`_, run the following command: ::
- $ docker-compose -f local.yml up docs
+ $ docker compose -f local.yml up docs
Navigate to port 9000 on your host to see the documentation. This will be opened automatically at `localhost`_ for local, non-docker development.
diff --git a/docs/project-generation-options.rst b/docs/project-generation-options.rst
index edf2306d4..967b42426 100644
--- a/docs/project-generation-options.rst
+++ b/docs/project-generation-options.rst
@@ -115,8 +115,8 @@ Both Gulp and Webpack support Bootstrap recompilation with real-time variables a
use_celery:
Indicates whether the project should be configured to use Celery_.
-use_mailhog:
- Indicates whether the project should be configured to use MailHog_.
+use_mailpit:
+ Indicates whether the project should be configured to use Mailpit_.
use_sentry:
Indicates whether the project should be configured to use Sentry_.
@@ -135,6 +135,7 @@ ci_tool:
2. `Travis CI`_
3. `Gitlab CI`_
4. `Github Actions`_
+ 5. `Drone CI`_
keep_local_envs_in_vcs:
Indicates whether the project's ``.envs/.local/`` should be kept in VCS
@@ -184,7 +185,7 @@ debug:
.. _Celery: https://github.com/celery/celery
-.. _MailHog: https://github.com/mailhog/MailHog
+.. _Mailpit: https://github.com/axllent/mailpit
.. _Sentry: https://github.com/getsentry/sentry
@@ -196,4 +197,6 @@ debug:
.. _GitLab CI: https://docs.gitlab.com/ee/ci/
+.. _Drone CI: https://docs.drone.io/pipeline/overview/
+
.. _Github Actions: https://docs.github.com/en/actions
diff --git a/docs/requirements.txt b/docs/requirements.txt
index d06b651b3..d002affa7 100644
--- a/docs/requirements.txt
+++ b/docs/requirements.txt
@@ -1,3 +1,3 @@
-sphinx==6.2.1
-sphinx-rtd-theme==1.2.2
+sphinx==7.2.6
+sphinx-rtd-theme==2.0.0
myst-parser==2.0.0
diff --git a/docs/testing.rst b/docs/testing.rst
index bea45c6dd..d403a30eb 100644
--- a/docs/testing.rst
+++ b/docs/testing.rst
@@ -19,7 +19,7 @@ You will get a readout of the `users` app that has already been set up with test
If you set up your project to `develop locally with docker`_, run the following command: ::
- $ docker-compose -f local.yml run --rm django pytest
+ $ docker compose -f local.yml run --rm django pytest
Targeting particular apps for testing in ``docker`` follows a similar pattern as previously shown above.
@@ -36,14 +36,14 @@ Once the tests are complete, in order to see the code coverage, run the followin
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 run -m pytest
+ $ docker compose -f local.yml run --rm django coverage report
.. note::
At the root of the project folder, you will find the `pytest.ini` file. You can use this to customize_ the ``pytest`` to your liking.
- There is also the `.coveragerc`. This is the configuration file for the ``coverage`` tool. You can find out more about `configuring`_ ``coverage``.
+ The configuration for ``coverage`` can be found in ``pyproject.toml``. You can find out more about `configuring`_ ``coverage``.
.. seealso::
diff --git a/docs/troubleshooting.rst b/docs/troubleshooting.rst
index 293e9b652..80bab2e29 100644
--- a/docs/troubleshooting.rst
+++ b/docs/troubleshooting.rst
@@ -24,13 +24,13 @@ Examples of logs::
If you recreate the project multiple times with the same name, Docker would preserve the volumes for the postgres container between projects. Here is what happens:
#. You generate the project the first time. The .env postgres file is populated with the random password
-#. You run the docker-compose and the containers are created. The postgres container creates the database based on the .env file credentials
+#. You run the docker compose and the containers are created. The postgres container creates the database based on the .env file credentials
#. You "regenerate" the project with the same name, so the postgres .env file is populated with a new random password
-#. You run docker-compose. Since the names of the containers are the same, docker will try to start them (not create them from scratch i.e. it won't execute the Dockerfile to recreate the database). When this happens, it tries to start the database based on the new credentials which do not match the ones that the database was created with, and you get the error message above.
+#. You run docker compose. Since the names of the containers are the same, docker will try to start them (not create them from scratch i.e. it won't execute the Dockerfile to recreate the database). When this happens, it tries to start the database based on the new credentials which do not match the ones that the database was created with, and you get the error message above.
To fix this, you can either:
-- Clear your project-related Docker cache with ``docker-compose -f local.yml down --volumes --rmi all``.
+- Clear your project-related Docker cache with ``docker compose -f local.yml down --volumes --rmi all``.
- Use the Docker volume sub-commands to find volumes (`ls`_) and remove them (`rm`_).
- Use the `prune`_ command to clear system-wide (use with care!).
diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py
index 292609403..1ddab0636 100644
--- a/hooks/post_gen_project.py
+++ b/hooks/post_gen_project.py
@@ -8,6 +8,7 @@ NOTE:
TODO: restrict Cookiecutter Django project initialization to
Python 3.x environments only
"""
+
from __future__ import print_function
import json
@@ -80,7 +81,7 @@ def remove_docker_files():
file_names = ["local.yml", "production.yml", ".dockerignore"]
for file_name in file_names:
os.remove(file_name)
- if "{{ cookiecutter.editor }}".lower() == "PyCharm":
+ if "{{ cookiecutter.editor }}" == "PyCharm":
file_names = ["docker_compose_up_django.xml", "docker_compose_up_docs.xml"]
for file_name in file_names:
os.remove(os.path.join(".idea", "runConfigurations", file_name))
@@ -183,6 +184,7 @@ def handle_js_runner(choice, use_docker, use_async):
"browser-sync",
"cssnano",
"gulp",
+ "gulp-concat",
"gulp-imagemin",
"gulp-plumber",
"gulp-postcss",
@@ -207,6 +209,24 @@ def handle_js_runner(choice, use_docker, use_async):
remove_gulp_files()
+def remove_prettier_pre_commit():
+ with open(".pre-commit-config.yaml", "r") as fd:
+ content = fd.readlines()
+
+ removing = False
+ new_lines = []
+ for line in content:
+ if removing and "- repo:" in line:
+ removing = False
+ if "mirrors-prettier" in line:
+ removing = True
+ if not removing:
+ new_lines.append(line)
+
+ with open(".pre-commit-config.yaml", "w") as fd:
+ fd.writelines(new_lines)
+
+
def remove_celery_files():
file_names = [
os.path.join("config", "celery_app.py"),
@@ -238,6 +258,10 @@ def remove_dotgithub_folder():
shutil.rmtree(".github")
+def remove_dotdrone_file():
+ os.remove(".drone.yml")
+
+
def generate_random_string(length, using_digits=False, using_ascii_letters=False, using_punctuation=False):
"""
Example:
@@ -406,10 +430,6 @@ def remove_drf_starter_files():
os.remove(os.path.join("{{cookiecutter.project_slug}}", "users", "tests", "test_swagger.py"))
-def remove_storages_module():
- os.remove(os.path.join("{{cookiecutter.project_slug}}", "utils", "storages.py"))
-
-
def main():
debug = "{{ cookiecutter.debug }}".lower() == "y"
@@ -428,7 +448,7 @@ def main():
if "{{ cookiecutter.username_type }}" == "username":
remove_custom_user_manager_files()
- if "{{ cookiecutter.editor }}".lower() != "PyCharm":
+ if "{{ cookiecutter.editor }}" != "PyCharm":
remove_pycharm_files()
if "{{ cookiecutter.use_docker }}".lower() == "y":
@@ -461,6 +481,7 @@ def main():
remove_webpack_files()
remove_sass_files()
remove_packagejson_file()
+ remove_prettier_pre_commit()
if "{{ cookiecutter.use_docker }}".lower() == "y":
remove_node_dockerfile()
else:
@@ -475,7 +496,6 @@ def main():
WARNING + "You chose to not use any cloud providers nor Docker, "
"media files won't be served in production." + TERMINATOR
)
- remove_storages_module()
if "{{ cookiecutter.use_celery }}".lower() == "n":
remove_celery_files()
@@ -491,6 +511,9 @@ def main():
if "{{ cookiecutter.ci_tool }}" != "Github":
remove_dotgithub_folder()
+ if "{{ cookiecutter.ci_tool }}" != "Drone":
+ remove_dotdrone_file()
+
if "{{ cookiecutter.use_drf }}".lower() == "n":
remove_drf_starter_files()
diff --git a/hooks/pre_gen_project.py b/hooks/pre_gen_project.py
index 33dc2e834..2956b9ab4 100644
--- a/hooks/pre_gen_project.py
+++ b/hooks/pre_gen_project.py
@@ -7,6 +7,7 @@ NOTE:
TODO: restrict Cookiecutter Django project initialization
to Python 3.x environments only
"""
+
from __future__ import print_function
import sys
diff --git a/requirements.txt b/requirements.txt
index d6d0ca754..18ae8f05e 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,28 +1,28 @@
-cookiecutter==2.1.1
-sh==2.0.4; sys_platform != "win32"
+cookiecutter==2.5.0
+sh==2.0.6; sys_platform != "win32"
binaryornot==0.4.4
# Code quality
# ------------------------------------------------------------------------------
-black==23.3.0
-isort==5.12.0
-flake8==6.0.0
-django-upgrade==1.14.0
-djlint==1.31.1
-pre-commit==3.3.3
+black==24.1.1
+isort==5.13.2
+flake8==7.0.0
+django-upgrade==1.16.0
+djlint==1.34.1
+pre-commit==3.6.1
# Testing
# ------------------------------------------------------------------------------
-tox==4.6.3
-pytest==7.4.0
-pytest-xdist==3.3.1
+tox==4.12.1
+pytest==8.0.0
+pytest-xdist==3.5.0
pytest-cookies==0.7.0
pytest-instafail==0.5.0
-pyyaml==6.0
+pyyaml==6.0.1
# Scripting
# ------------------------------------------------------------------------------
-PyGithub==1.59.0
-gitpython==3.1.31
-jinja2==3.1.2
+PyGithub==2.2.0
+gitpython==3.1.41
+jinja2==3.1.3
requests==2.31.0
diff --git a/scripts/create_django_issue.py b/scripts/create_django_issue.py
index d3b3c3792..2e59f18b0 100644
--- a/scripts/create_django_issue.py
+++ b/scripts/create_django_issue.py
@@ -6,6 +6,7 @@ patches, only comparing major and minor version numbers.
This script handles when there are multiple Django versions that need
to keep up to date.
"""
+
from __future__ import annotations
import os
@@ -182,9 +183,8 @@ class GitHubManager:
if not matches:
continue
issue_version = DjVersion.parse(matches.group(1))
- if self.base_dj_version > issue_version:
- issue.edit(state="closed")
- print(f"Closed issue {issue.title} (ID: [{issue.id}]({issue.url}))")
+ if self.base_dj_version >= issue_version:
+ self.close_issue(issue)
else:
self.existing_issues[issue_version] = issue
@@ -213,7 +213,7 @@ class GitHubManager:
for classifier in package_info["info"]["classifiers"]:
# Usually in the form of "Framework :: Django :: 3.2"
tokens = classifier.split(" ")
- if len(tokens) >= 5 and tokens[2].lower() == "django":
+ if len(tokens) >= 5 and tokens[2].lower() == "django" and "." in tokens[4]:
version = DjVersion.parse(tokens[4])
if len(version) == 2:
supported_dj_versions.append(version)
@@ -269,6 +269,11 @@ class GitHubManager:
issue = self.repo.create_issue(f"[Update Django] Django {needed_dj_version}", description)
issue.add_to_labels(f"django{needed_dj_version}")
+ @staticmethod
+ def close_issue(issue: Issue):
+ issue.edit(state="closed")
+ print(f"Closed issue {issue.title} (ID: [{issue.id}]({issue.url}))")
+
def generate(self):
for version in self.needed_dj_versions:
print(f"Handling GitHub issue for Django {version}")
@@ -280,10 +285,15 @@ class GitHubManager:
def main(django_max_version=None) -> None:
# Check if there are any djs
current_dj, latest_djs = get_all_latest_django_versions(django_max_version=django_max_version)
- if not latest_djs:
- sys.exit(0)
+
+ # Run the setup, which might close old issues
manager = GitHubManager(current_dj, latest_djs)
manager.setup()
+
+ if not latest_djs:
+ print("No new Django versions to update. Exiting...")
+ sys.exit(0)
+
manager.generate()
diff --git a/scripts/update_changelog.py b/scripts/update_changelog.py
index 7d43a0b57..5f3ad5ec3 100644
--- a/scripts/update_changelog.py
+++ b/scripts/update_changelog.py
@@ -32,6 +32,9 @@ def main() -> None:
# Group pull requests by type of change
grouped_pulls = group_pulls_by_change_type(merged_pulls)
+ if not any(grouped_pulls.values()):
+ print("Pull requests merged aren't worth a changelog mention.")
+ return
# Generate portion of markdown
release_changes_summary = generate_md(grouped_pulls)
diff --git a/setup.py b/setup.py
index f5705ab4b..b5182fce7 100644
--- a/setup.py
+++ b/setup.py
@@ -5,9 +5,9 @@ except ImportError:
from distutils.core import setup
# We use calendar versioning
-version = "2023.07.04"
+version = "2024.02.09"
-with open("README.rst") as readme_file:
+with open("README.md") as readme_file:
long_description = readme_file.read()
setup(
diff --git a/tests/test_cookiecutter_generation.py b/tests/test_cookiecutter_generation.py
index 2eb7ae52e..31d006bed 100755
--- a/tests/test_cookiecutter_generation.py
+++ b/tests/test_cookiecutter_generation.py
@@ -115,8 +115,8 @@ SUPPORTED_COMBINATIONS = [
{"frontend_pipeline": "Webpack"},
{"use_celery": "y"},
{"use_celery": "n"},
- {"use_mailhog": "y"},
- {"use_mailhog": "n"},
+ {"use_mailpit": "y"},
+ {"use_mailpit": "n"},
{"use_sentry": "y"},
{"use_sentry": "n"},
{"use_whitenoise": "y"},
@@ -127,6 +127,7 @@ SUPPORTED_COMBINATIONS = [
{"ci_tool": "Travis"},
{"ci_tool": "Gitlab"},
{"ci_tool": "Github"},
+ {"ci_tool": "Drone"},
{"keep_local_envs_in_vcs": "y"},
{"keep_local_envs_in_vcs": "n"},
{"debug": "y"},
@@ -271,7 +272,7 @@ def test_djlint_check_passes(cookies, context_override):
["use_docker", "expected_test_script"],
[
("n", "pytest"),
- ("y", "docker-compose -f local.yml run django pytest"),
+ ("y", "docker compose -f local.yml run django pytest"),
],
)
def test_travis_invokes_pytest(cookies, context, use_docker, expected_test_script):
@@ -296,7 +297,7 @@ def test_travis_invokes_pytest(cookies, context, use_docker, expected_test_scrip
["use_docker", "expected_test_script"],
[
("n", "pytest"),
- ("y", "docker-compose -f local.yml run django pytest"),
+ ("y", "docker compose -f local.yml run django pytest"),
],
)
def test_gitlab_invokes_precommit_and_pytest(cookies, context, use_docker, expected_test_script):
@@ -323,7 +324,7 @@ def test_gitlab_invokes_precommit_and_pytest(cookies, context, use_docker, expec
["use_docker", "expected_test_script"],
[
("n", "pytest"),
- ("y", "docker-compose -f local.yml run django pytest"),
+ ("y", "docker compose -f local.yml run django pytest"),
],
)
def test_github_invokes_linter_and_pytest(cookies, context, use_docker, expected_test_script):
diff --git a/tests/test_docker.sh b/tests/test_docker.sh
index 5c60d20d3..c3cad3b37 100755
--- a/tests/test_docker.sh
+++ b/tests/test_docker.sh
@@ -15,28 +15,38 @@ cookiecutter ../../ --no-input --overwrite-if-exists use_docker=y "$@"
cd my_awesome_project
# make sure all images build
-docker-compose -f local.yml build
+docker compose -f local.yml build
# run the project's type checks
-docker-compose -f local.yml run django mypy my_awesome_project
+docker compose -f local.yml run django mypy my_awesome_project
# run the project's tests
-docker-compose -f local.yml run django pytest
+docker compose -f local.yml run django pytest
# return non-zero status code if there are migrations that have not been created
-docker-compose -f local.yml run django python manage.py makemigrations --dry-run --check || { echo "ERROR: there were changes in the models, but migration listed above have not been created and are not saved in version control"; exit 1; }
+docker compose -f local.yml run django python manage.py makemigrations --dry-run --check || { echo "ERROR: there were changes in the models, but migration listed above have not been created and are not saved in version control"; exit 1; }
# Test support for translations
-docker-compose -f local.yml run django python manage.py makemessages --all
+docker compose -f local.yml run django python manage.py makemessages --all
# Make sure the check doesn't raise any warnings
-docker-compose -f local.yml run django python manage.py check --fail-level WARNING
+docker compose -f local.yml run \
+ -e DJANGO_SECRET_KEY="$(openssl rand -base64 64)" \
+ -e REDIS_URL=redis://redis:6379/0 \
+ -e CELERY_BROKER_URL=redis://redis:6379/0 \
+ -e DJANGO_AWS_ACCESS_KEY_ID=x \
+ -e DJANGO_AWS_SECRET_ACCESS_KEY=x \
+ -e DJANGO_AWS_STORAGE_BUCKET_NAME=x \
+ -e DJANGO_ADMIN_URL=x \
+ -e MAILGUN_API_KEY=x \
+ -e MAILGUN_DOMAIN=x \
+ django python manage.py check --settings=config.settings.production --deploy --database default --fail-level WARNING
# 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
+ docker compose -f local.yml run node npm run build
fi
diff --git a/tests/test_hooks.py b/tests/test_hooks.py
index 6afdc400b..2ccac84b2 100644
--- a/tests/test_hooks.py
+++ b/tests/test_hooks.py
@@ -1,4 +1,5 @@
"""Unit tests for the hooks"""
+
import os
from pathlib import Path
diff --git a/{{cookiecutter.project_slug}}/.devcontainer/devcontainer.json b/{{cookiecutter.project_slug}}/.devcontainer/devcontainer.json
index c11b8dd9a..c4158dc10 100644
--- a/{{cookiecutter.project_slug}}/.devcontainer/devcontainer.json
+++ b/{{cookiecutter.project_slug}}/.devcontainer/devcontainer.json
@@ -11,11 +11,6 @@
"target": "/home/dev-user/.bash_history",
"type": "bind"
},
- {
- "source": "~/.ssh",
- "target": "/tmp",
- "type": "bind"
- },
{
"source": "~/.ssh",
"target": "/home/dev-user/.ssh",
@@ -24,7 +19,7 @@
],
// Tells devcontainer.json supporting services / tools whether they should run
// /bin/sh -c "while sleep 1000; do :; done" when starting the container instead of the container’s default command
- "overrideCommand": true,
+ "overrideCommand": false,
"service": "django",
// "remoteEnv": {"PATH": "/home/dev-user/.local/bin:${containerEnv:PATH}"},
"remoteUser": "dev-user",
diff --git a/{{cookiecutter.project_slug}}/.dockerignore b/{{cookiecutter.project_slug}}/.dockerignore
index 7369480e3..a602416cd 100644
--- a/{{cookiecutter.project_slug}}/.dockerignore
+++ b/{{cookiecutter.project_slug}}/.dockerignore
@@ -9,3 +9,4 @@
.travis.yml
venv
.git
+.envs/
diff --git a/{{cookiecutter.project_slug}}/.drone.yml b/{{cookiecutter.project_slug}}/.drone.yml
new file mode 100644
index 000000000..dc08bfbab
--- /dev/null
+++ b/{{cookiecutter.project_slug}}/.drone.yml
@@ -0,0 +1,48 @@
+kind: pipeline
+name: default
+
+environment:
+ POSTGRES_USER: '{{ cookiecutter.project_slug }}'
+ POSTGRES_PASSWORD: ''
+ POSTGRES_DB: 'test_{{ cookiecutter.project_slug }}'
+ POSTGRES_HOST_AUTH_METHOD: trust
+ {%- if cookiecutter.use_celery == 'y' %}
+ CELERY_BROKER_URL: 'redis://redis:6379/0'
+ {%- endif %}
+
+steps:
+- name: lint
+ pull: if-not-exists
+ image: python:3.11
+ environment:
+ PRE_COMMIT_HOME: ${CI_PROJECT_DIR}/.cache/pre-commit
+ volumes:
+ - name: pre-commit cache
+ path: ${PRE_COMMIT_HOME}
+ commands:
+ - export PRE_COMMIT_HOME=$CI_PROJECT_DIR/.cache/pre-commit
+ - pip install -q pre-commit
+ - pre-commit run --show-diff-on-failure --color=always --all-files
+
+- name: test
+ pull: if-not-exists
+ {%- if cookiecutter.use_docker == 'y' %}
+ image: docker/compose:1.29.2
+ environment:
+ DATABASE_URL: pgsql://$POSTGRES_USER:$POSTGRES_PASSWORD@postgres/$POSTGRES_DB
+ commands:
+ - docker-compose -f local.yml build
+ - docker-compose -f local.yml run --rm django python manage.py migrate
+ - docker-compose -f local.yml up -d
+ - docker-compose -f local.yml run django pytest
+ {%- else %}
+ image: python:3.11
+ commands:
+ - pip install -r requirements/local.txt
+ - pytest
+ {%- endif%}
+
+volumes:
+- name: pre-commit cache
+ host:
+ path: /tmp/drone/cache/pre-commit
diff --git a/{{cookiecutter.project_slug}}/.github/workflows/ci.yml b/{{cookiecutter.project_slug}}/.github/workflows/ci.yml
index 8f9824e8f..e39933fe1 100644
--- a/{{cookiecutter.project_slug}}/.github/workflows/ci.yml
+++ b/{{cookiecutter.project_slug}}/.github/workflows/ci.yml
@@ -23,7 +23,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout Code Repository
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v4
@@ -65,20 +65,20 @@ jobs:
steps:
- name: Checkout Code Repository
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
{%- if cookiecutter.use_docker == 'y' %}
- name: Build the Stack
- run: docker-compose -f local.yml build
+ run: docker compose -f local.yml build
- name: Run DB Migrations
- run: docker-compose -f local.yml run --rm django python manage.py migrate
+ run: docker compose -f local.yml run --rm django python manage.py migrate
- name: Run Django Tests
- run: docker-compose -f local.yml run django pytest
+ run: docker compose -f local.yml run django pytest
- name: Tear down the Stack
- run: docker-compose -f local.yml down
+ run: docker compose -f local.yml down
{%- else %}
- name: Set up Python
diff --git a/{{cookiecutter.project_slug}}/.gitignore b/{{cookiecutter.project_slug}}/.gitignore
index 541f40846..0bb322186 100644
--- a/{{cookiecutter.project_slug}}/.gitignore
+++ b/{{cookiecutter.project_slug}}/.gitignore
@@ -329,8 +329,8 @@ tags
dump.rdb
### Project template
-{%- if cookiecutter.use_mailhog == 'y' and cookiecutter.use_docker == 'n' %}
-MailHog
+{%- if cookiecutter.use_mailpit == 'y' and cookiecutter.use_docker == 'n' %}
+mailpit
{%- endif %}
{{ cookiecutter.project_slug }}/media/
diff --git a/{{cookiecutter.project_slug}}/.gitlab-ci.yml b/{{cookiecutter.project_slug}}/.gitlab-ci.yml
index a312a41ae..350212003 100644
--- a/{{cookiecutter.project_slug}}/.gitlab-ci.yml
+++ b/{{cookiecutter.project_slug}}/.gitlab-ci.yml
@@ -33,12 +33,12 @@ pytest:
services:
- docker:dind
before_script:
- - docker-compose -f local.yml build
+ - docker compose -f local.yml build
# Ensure celerybeat does not crash due to non-existent tables
- - docker-compose -f local.yml run --rm django python manage.py migrate
- - docker-compose -f local.yml up -d
+ - docker compose -f local.yml run --rm django python manage.py migrate
+ - docker compose -f local.yml up -d
script:
- - docker-compose -f local.yml run django pytest
+ - docker compose -f local.yml run django pytest
{%- else %}
image: python:3.11
tags:
diff --git a/{{cookiecutter.project_slug}}/.pre-commit-config.yaml b/{{cookiecutter.project_slug}}/.pre-commit-config.yaml
index 0d1265ac2..d32ac6b84 100644
--- a/{{cookiecutter.project_slug}}/.pre-commit-config.yaml
+++ b/{{cookiecutter.project_slug}}/.pre-commit-config.yaml
@@ -1,9 +1,12 @@
-exclude: '^docs/|/migrations/'
+exclude: '^docs/|/migrations/|devcontainer.json'
default_stages: [commit]
+default_language_version:
+ python: python3.11
+
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
- rev: v4.4.0
+ rev: v4.5.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
@@ -16,45 +19,43 @@ repos:
- id: check-case-conflict
- id: check-docstring-first
- id: detect-private-key
-{%- if cookiecutter.frontend_pipeline in ["Webpack", "Gulp"] %}
- repo: https://github.com/pre-commit/mirrors-prettier
- rev: v3.0.0-alpha.9-for-vscode
+ rev: v4.0.0-alpha.8
hooks:
- id: prettier
args: ['--tab-width', '2', '--single-quote']
exclude: '{{cookiecutter.project_slug}}/templates/'
-{%- endif %}
- repo: https://github.com/adamchainz/django-upgrade
- rev: '1.14.0'
+ rev: '1.16.0'
hooks:
- id: django-upgrade
args: ['--target-version', '4.2']
- repo: https://github.com/asottile/pyupgrade
- rev: v3.7.0
+ rev: v3.15.0
hooks:
- id: pyupgrade
args: [--py311-plus]
- repo: https://github.com/psf/black
- rev: 23.3.0
+ rev: 24.1.1
hooks:
- id: black
- repo: https://github.com/PyCQA/isort
- rev: 5.12.0
+ rev: 5.13.2
hooks:
- id: isort
- repo: https://github.com/PyCQA/flake8
- rev: 6.0.0
+ rev: 7.0.0
hooks:
- id: flake8
- repo: https://github.com/Riverside-Healthcare/djLint
- rev: v1.31.1
+ rev: v1.34.1
hooks:
- id: djlint-reformat-django
- id: djlint-django
diff --git a/{{cookiecutter.project_slug}}/.travis.yml b/{{cookiecutter.project_slug}}/.travis.yml
index 5e5f92ff5..cd703d3ad 100644
--- a/{{cookiecutter.project_slug}}/.travis.yml
+++ b/{{cookiecutter.project_slug}}/.travis.yml
@@ -17,16 +17,16 @@ jobs:
- name: "Django Test"
{%- if cookiecutter.use_docker == 'y' %}
before_script:
- - docker-compose -v
+ - docker compose -v
- docker -v
- - docker-compose -f local.yml build
+ - docker compose -f local.yml build
# Ensure celerybeat does not crash due to non-existent tables
- - docker-compose -f local.yml run --rm django python manage.py migrate
- - docker-compose -f local.yml up -d
+ - docker compose -f local.yml run --rm django python manage.py migrate
+ - docker compose -f local.yml up -d
script:
- - "docker-compose -f local.yml run django pytest"
+ - "docker compose -f local.yml run django pytest"
after_failure:
- - docker-compose -f local.yml logs
+ - docker compose -f local.yml logs
{%- else %}
before_install:
- sudo apt-get update -qq
diff --git a/{{cookiecutter.project_slug}}/README.md b/{{cookiecutter.project_slug}}/README.md
index 56853f8f7..ccf245a2f 100644
--- a/{{cookiecutter.project_slug}}/README.md
+++ b/{{cookiecutter.project_slug}}/README.md
@@ -78,37 +78,35 @@ celery -A config.celery_app worker -B -l info
```
{%- endif %}
-{%- if cookiecutter.use_mailhog == "y" %}
+{%- if cookiecutter.use_mailpit == "y" %}
### Email Server
{%- if cookiecutter.use_docker == "y" %}
-In development, it is often nice to be able to see emails that are being sent from your application. For that reason local SMTP server [MailHog](https://github.com/mailhog/MailHog) with a web interface is available as docker container.
+In development, it is often nice to be able to see emails that are being sent from your application. For that reason local SMTP server [Mailpit](https://github.com/axllent/mailpit) with a web interface is available as docker container.
-Container mailhog will start automatically when you will run all docker containers.
+Container mailpit will start automatically when you will run all docker containers.
Please check [cookiecutter-django Docker documentation](http://cookiecutter-django.readthedocs.io/en/latest/deployment-with-docker.html) for more details how to start all containers.
-With MailHog running, to view messages that are sent by your application, open your browser and go to `http://127.0.0.1:8025`
+With Mailpit running, to view messages that are sent by your application, open your browser and go to `http://127.0.0.1:8025`
{%- else %}
-In development, it is often nice to be able to see emails that are being sent from your application. If you choose to use [MailHog](https://github.com/mailhog/MailHog) when generating the project a local SMTP server with a web interface will be available.
+In development, it is often nice to be able to see emails that are being sent from your application. If you choose to use [Mailpit](https://github.com/axllent/mailpit) when generating the project a local SMTP server with a web interface will be available.
-1. [Download the latest MailHog release](https://github.com/mailhog/MailHog/releases) for your OS.
+1. [Download the latest Mailpit release](https://github.com/axllent/mailpit/releases) for your OS.
-2. Rename the build to `MailHog`.
+2. Copy the binary file to the project root.
-3. Copy the file to the project root.
+3. Make it executable:
-4. Make it executable:
+ $ chmod +x mailpit
- $ chmod +x MailHog
+4. Spin up another terminal window and start it there:
-5. Spin up another terminal window and start it there:
+ ./mailpit
- ./MailHog
-
-6. Check out to see how it goes.
+5. Check out to see how it goes.
Now you have your own mail server running locally, ready to receive whatever you send it.
diff --git a/{{cookiecutter.project_slug}}/compose/local/django/Dockerfile b/{{cookiecutter.project_slug}}/compose/local/django/Dockerfile
index 3636ce1ef..75d5cbb9b 100644
--- a/{{cookiecutter.project_slug}}/compose/local/django/Dockerfile
+++ b/{{cookiecutter.project_slug}}/compose/local/django/Dockerfile
@@ -1,8 +1,8 @@
# define an alias for the specific python version used in this file.
-FROM python:3.11.4-slim-bullseye as python
+FROM docker.io/python:3.11.8-slim-bookworm as python
# Python build stage
-FROM python as python-build-stage
+FROM docker.io/python as python-build-stage
ARG BUILD_ENVIRONMENT=local
@@ -22,7 +22,7 @@ RUN pip wheel --wheel-dir /usr/src/app/wheels \
# Python 'run' stage
-FROM python as python-run-stage
+FROM docker.io/python as python-run-stage
ARG BUILD_ENVIRONMENT=local
ARG APP_HOME=/app
diff --git a/{{cookiecutter.project_slug}}/compose/local/docs/Dockerfile b/{{cookiecutter.project_slug}}/compose/local/docs/Dockerfile
index f9895a083..87a1b2465 100644
--- a/{{cookiecutter.project_slug}}/compose/local/docs/Dockerfile
+++ b/{{cookiecutter.project_slug}}/compose/local/docs/Dockerfile
@@ -1,9 +1,9 @@
# define an alias for the specific python version used in this file.
-FROM python:3.11.4-slim-bullseye as python
+FROM docker.io/python:3.11.8-slim-bookworm as python
# Python build stage
-FROM python as python-build-stage
+FROM docker.io/python as python-build-stage
ENV PYTHONDONTWRITEBYTECODE 1
@@ -26,7 +26,7 @@ RUN pip wheel --no-cache-dir --wheel-dir /usr/src/app/wheels \
# Python 'run' stage
-FROM python as python-run-stage
+FROM docker.io/python as python-run-stage
ARG BUILD_ENVIRONMENT
ENV PYTHONUNBUFFERED 1
diff --git a/{{cookiecutter.project_slug}}/compose/local/node/Dockerfile b/{{cookiecutter.project_slug}}/compose/local/node/Dockerfile
index 707ed0c9d..0848ecaf8 100644
--- a/{{cookiecutter.project_slug}}/compose/local/node/Dockerfile
+++ b/{{cookiecutter.project_slug}}/compose/local/node/Dockerfile
@@ -1,4 +1,4 @@
-FROM node:18-bullseye-slim
+FROM docker.io/node:20-bookworm-slim
WORKDIR /app
diff --git a/{{cookiecutter.project_slug}}/compose/production/aws/Dockerfile b/{{cookiecutter.project_slug}}/compose/production/aws/Dockerfile
index 4d1ecbb20..36eea7f8c 100644
--- a/{{cookiecutter.project_slug}}/compose/production/aws/Dockerfile
+++ b/{{cookiecutter.project_slug}}/compose/production/aws/Dockerfile
@@ -1,4 +1,4 @@
-FROM garland/aws-cli-docker:1.16.140
+FROM docker.io/garland/aws-cli-docker:1.16.140
COPY ./compose/production/aws/maintenance /usr/local/bin/maintenance
COPY ./compose/production/postgres/maintenance/_sourced /usr/local/bin/maintenance/_sourced
diff --git a/{{cookiecutter.project_slug}}/compose/production/aws/maintenance/download b/{{cookiecutter.project_slug}}/compose/production/aws/maintenance/download
index 0c515935f..9561d917a 100644
--- a/{{cookiecutter.project_slug}}/compose/production/aws/maintenance/download
+++ b/{{cookiecutter.project_slug}}/compose/production/aws/maintenance/download
@@ -3,7 +3,7 @@
### Download a file from your Amazon S3 bucket to the postgres /backups folder
###
### Usage:
-### $ docker-compose -f production.yml run --rm awscli <1>
+### $ docker compose -f production.yml run --rm awscli <1>
set -o errexit
set -o pipefail
diff --git a/{{cookiecutter.project_slug}}/compose/production/aws/maintenance/upload b/{{cookiecutter.project_slug}}/compose/production/aws/maintenance/upload
index 9446b9304..73c1b9bec 100644
--- a/{{cookiecutter.project_slug}}/compose/production/aws/maintenance/upload
+++ b/{{cookiecutter.project_slug}}/compose/production/aws/maintenance/upload
@@ -3,7 +3,7 @@
### Upload the /backups folder to Amazon S3
###
### Usage:
-### $ docker-compose -f production.yml run --rm awscli upload
+### $ docker compose -f production.yml run --rm awscli upload
set -o errexit
set -o pipefail
diff --git a/{{cookiecutter.project_slug}}/compose/production/django/Dockerfile b/{{cookiecutter.project_slug}}/compose/production/django/Dockerfile
index a48cbc4af..fb7fec50f 100644
--- a/{{cookiecutter.project_slug}}/compose/production/django/Dockerfile
+++ b/{{cookiecutter.project_slug}}/compose/production/django/Dockerfile
@@ -1,5 +1,5 @@
{% if cookiecutter.frontend_pipeline in ['Gulp', 'Webpack'] -%}
-FROM node:18-bullseye-slim as client-builder
+FROM docker.io/node:20-bookworm-slim as client-builder
ARG APP_HOME=/app
WORKDIR ${APP_HOME}
@@ -25,10 +25,10 @@ RUN npm run build
{%- endif %}
# define an alias for the specific python version used in this file.
-FROM python:3.11.4-slim-bullseye as python
+FROM docker.io/python:3.11.8-slim-bookworm as python
# Python build stage
-FROM python as python-build-stage
+FROM docker.io/python as python-build-stage
ARG BUILD_ENVIRONMENT=production
@@ -48,7 +48,7 @@ RUN pip wheel --wheel-dir /usr/src/app/wheels \
# Python 'run' stage
-FROM python as python-run-stage
+FROM docker.io/python as python-run-stage
ARG BUILD_ENVIRONMENT=production
ARG APP_HOME=/app
@@ -103,7 +103,7 @@ RUN sed -i 's/\r$//g' /start-celerybeat
RUN chmod +x /start-celerybeat
-COPY ./compose/production/django/celery/flower/start /start-flower
+COPY --chown=django:django ./compose/production/django/celery/flower/start /start-flower
RUN sed -i 's/\r$//g' /start-flower
RUN chmod +x /start-flower
{%- endif %}
diff --git a/{{cookiecutter.project_slug}}/compose/production/nginx/Dockerfile b/{{cookiecutter.project_slug}}/compose/production/nginx/Dockerfile
index 911b16f71..ec2ad35cb 100644
--- a/{{cookiecutter.project_slug}}/compose/production/nginx/Dockerfile
+++ b/{{cookiecutter.project_slug}}/compose/production/nginx/Dockerfile
@@ -1,2 +1,2 @@
-FROM nginx:1.17.8-alpine
+FROM docker.io/nginx:1.17.8-alpine
COPY ./compose/production/nginx/default.conf /etc/nginx/conf.d/default.conf
diff --git a/{{cookiecutter.project_slug}}/compose/production/postgres/Dockerfile b/{{cookiecutter.project_slug}}/compose/production/postgres/Dockerfile
index eca29bada..5da8982f4 100644
--- a/{{cookiecutter.project_slug}}/compose/production/postgres/Dockerfile
+++ b/{{cookiecutter.project_slug}}/compose/production/postgres/Dockerfile
@@ -1,4 +1,4 @@
-FROM postgres:{{ cookiecutter.postgresql_version }}
+FROM docker.io/postgres:{{ cookiecutter.postgresql_version }}
COPY ./compose/production/postgres/maintenance /usr/local/bin/maintenance
RUN chmod +x /usr/local/bin/maintenance/*
diff --git a/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/backup b/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/backup
index ee0c9d63c..f72304c05 100644
--- a/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/backup
+++ b/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/backup
@@ -4,7 +4,7 @@
### Create a database backup.
###
### Usage:
-### $ docker-compose -f .yml (exec |run --rm) postgres backup
+### $ docker compose -f .yml (exec |run --rm) postgres backup
set -o errexit
diff --git a/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/backups b/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/backups
index 0484ccff5..a18937d62 100644
--- a/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/backups
+++ b/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/backups
@@ -4,7 +4,7 @@
### View backups.
###
### Usage:
-### $ docker-compose -f .yml (exec |run --rm) postgres backups
+### $ docker compose -f .yml (exec |run --rm) postgres backups
set -o errexit
diff --git a/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/restore b/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/restore
index 9661ca7f1..c68f17d71 100644
--- a/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/restore
+++ b/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/restore
@@ -7,7 +7,7 @@
### <1> filename of an existing backup.
###
### Usage:
-### $ docker-compose -f .yml (exec |run --rm) postgres restore <1>
+### $ docker compose -f .yml (exec |run --rm) postgres restore <1>
set -o errexit
diff --git a/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/rmbackup b/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/rmbackup
new file mode 100644
index 000000000..fdfd20e14
--- /dev/null
+++ b/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/rmbackup
@@ -0,0 +1,36 @@
+#!/usr/bin/env bash
+
+### Remove a database backup.
+###
+### Parameters:
+### <1> filename of a backup to remove.
+###
+### Usage:
+### $ docker-compose -f .yml (exec |run --rm) postgres rmbackup <1>
+
+
+set -o errexit
+set -o pipefail
+set -o nounset
+
+
+working_dir="$(dirname ${0})"
+source "${working_dir}/_sourced/constants.sh"
+source "${working_dir}/_sourced/messages.sh"
+
+
+if [[ -z ${1+x} ]]; then
+ message_error "Backup filename is not specified yet it is a required parameter. Make sure you provide one and try again."
+ exit 1
+fi
+backup_filename="${BACKUP_DIR_PATH}/${1}"
+if [[ ! -f "${backup_filename}" ]]; then
+ message_error "No backup with the specified filename found. Check out the 'backups' maintenance script output to see if there is one and try again."
+ exit 1
+fi
+
+message_welcome "Removing the '${backup_filename}' backup file..."
+
+rm -r "${backup_filename}"
+
+message_success "The '${backup_filename}' database backup has been removed."
diff --git a/{{cookiecutter.project_slug}}/compose/production/traefik/Dockerfile b/{{cookiecutter.project_slug}}/compose/production/traefik/Dockerfile
index bdedff720..c32b15873 100644
--- a/{{cookiecutter.project_slug}}/compose/production/traefik/Dockerfile
+++ b/{{cookiecutter.project_slug}}/compose/production/traefik/Dockerfile
@@ -1,4 +1,4 @@
-FROM traefik:2.10.3
+FROM docker.io/traefik:2.10.7
RUN mkdir -p /etc/traefik/acme \
&& touch /etc/traefik/acme/acme.json \
&& chmod 600 /etc/traefik/acme/acme.json
diff --git a/{{cookiecutter.project_slug}}/compose/production/traefik/traefik.yml b/{{cookiecutter.project_slug}}/compose/production/traefik/traefik.yml
index 724c95cdf..f5d9e52fc 100644
--- a/{{cookiecutter.project_slug}}/compose/production/traefik/traefik.yml
+++ b/{{cookiecutter.project_slug}}/compose/production/traefik/traefik.yml
@@ -6,7 +6,7 @@ entryPoints:
# http
address: ':80'
http:
- # https://docs.traefik.io/routing/entrypoints/#entrypoint
+ # https://doc.traefik.io/traefik/routing/entrypoints/#entrypoint
redirections:
entryPoint:
to: web-secure
@@ -22,11 +22,11 @@ entryPoints:
certificatesResolvers:
letsencrypt:
- # https://docs.traefik.io/master/https/acme/#lets-encrypt
+ # https://doc.traefik.io/traefik/https/acme/#lets-encrypt
acme:
email: '{{ cookiecutter.email }}'
storage: /etc/traefik/acme/acme.json
- # https://docs.traefik.io/master/https/acme/#httpchallenge
+ # https://doc.traefik.io/traefik/https/acme/#httpchallenge
httpChallenge:
entryPoint: web
@@ -44,7 +44,7 @@ http:
- csrf
service: django
tls:
- # https://docs.traefik.io/master/routing/routers/#certresolver
+ # https://doc.traefik.io/traefik/routing/routers/#certresolver
certResolver: letsencrypt
{%- if cookiecutter.use_celery == 'y' %}
@@ -54,7 +54,7 @@ http:
- flower
service: flower
tls:
- # https://docs.traefik.io/master/routing/routers/#certresolver
+ # https://doc.traefik.io/traefik/master/routing/routers/#certresolver
certResolver: letsencrypt
{%- endif %}
{%- if cookiecutter.cloud_provider == 'None' %}
@@ -76,7 +76,7 @@ http:
middlewares:
csrf:
- # https://docs.traefik.io/master/middlewares/headers/#hostsproxyheaders
+ # https://doc.traefik.io/traefik/master/middlewares/http/headers/#hostsproxyheaders
# https://docs.djangoproject.com/en/dev/ref/csrf/#ajax
headers:
hostsProxyHeaders: ['X-CSRFToken']
@@ -102,7 +102,7 @@ http:
{%- endif %}
providers:
- # https://docs.traefik.io/master/providers/file/
+ # https://doc.traefik.io/traefik/master/providers/file/
file:
filename: /etc/traefik/traefik.yml
watch: true
diff --git a/{{cookiecutter.project_slug}}/config/asgi.py b/{{cookiecutter.project_slug}}/config/asgi.py
index 65e76ca0a..c391bf87b 100644
--- a/{{cookiecutter.project_slug}}/config/asgi.py
+++ b/{{cookiecutter.project_slug}}/config/asgi.py
@@ -7,6 +7,7 @@ For more information on this file, see
https://docs.djangoproject.com/en/dev/howto/deployment/asgi/
"""
+
import os
import sys
from pathlib import Path
diff --git a/{{cookiecutter.project_slug}}/config/settings/base.py b/{{cookiecutter.project_slug}}/config/settings/base.py
index c9feedea1..3bf3a73cc 100644
--- a/{{cookiecutter.project_slug}}/config/settings/base.py
+++ b/{{cookiecutter.project_slug}}/config/settings/base.py
@@ -1,6 +1,5 @@
-"""
-Base settings to build other settings files upon.
-"""
+"""Base settings to build other settings files upon."""
+
from pathlib import Path
import environ
@@ -30,7 +29,8 @@ LANGUAGE_CODE = "en-us"
# from django.utils.translation import gettext_lazy as _
# LANGUAGES = [
# ('en', _('English')),
-# ('pt-br', _('Português')),
+# ('fr-fr', _('French')),
+# ('pt-br', _('Portuguese')),
# ]
# https://docs.djangoproject.com/en/dev/ref/settings/#site-id
SITE_ID = 1
@@ -160,6 +160,7 @@ MIDDLEWARE = [
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
+ "allauth.account.middleware.AccountMiddleware",
]
# STATIC
@@ -252,7 +253,7 @@ ADMINS = [("""{{cookiecutter.author_name}}""", "{{cookiecutter.email}}")]
MANAGERS = ADMINS
# https://cookiecutter-django.readthedocs.io/en/latest/settings.html#other-environment-settings
# Force the `admin` sign in process to go through the `django-allauth` workflow
-DJANGO_ADMIN_FORCE_ALLAUTH = env.bool('DJANGO_ADMIN_FORCE_ALLAUTH', default=False)
+DJANGO_ADMIN_FORCE_ALLAUTH = env.bool("DJANGO_ADMIN_FORCE_ALLAUTH", default=False)
# LOGGING
# ------------------------------------------------------------------------------
@@ -317,25 +318,25 @@ CELERY_TASK_SEND_SENT_EVENT = True
# django-allauth
# ------------------------------------------------------------------------------
ACCOUNT_ALLOW_REGISTRATION = env.bool("DJANGO_ACCOUNT_ALLOW_REGISTRATION", True)
-# https://django-allauth.readthedocs.io/en/latest/configuration.html
+# https://docs.allauth.org/en/latest/account/configuration.html
ACCOUNT_AUTHENTICATION_METHOD = "{{cookiecutter.username_type}}"
-# https://django-allauth.readthedocs.io/en/latest/configuration.html
+# https://docs.allauth.org/en/latest/account/configuration.html
ACCOUNT_EMAIL_REQUIRED = True
{%- if cookiecutter.username_type == "email" %}
-# https://django-allauth.readthedocs.io/en/latest/configuration.html
+# https://docs.allauth.org/en/latest/account/configuration.html
ACCOUNT_USERNAME_REQUIRED = False
-# https://django-allauth.readthedocs.io/en/latest/configuration.html
+# https://docs.allauth.org/en/latest/account/configuration.html
ACCOUNT_USER_MODEL_USERNAME_FIELD = None
{%- endif %}
-# https://django-allauth.readthedocs.io/en/latest/configuration.html
+# https://docs.allauth.org/en/latest/account/configuration.html
ACCOUNT_EMAIL_VERIFICATION = "mandatory"
-# https://django-allauth.readthedocs.io/en/latest/configuration.html
+# https://docs.allauth.org/en/latest/account/configuration.html
ACCOUNT_ADAPTER = "{{cookiecutter.project_slug}}.users.adapters.AccountAdapter"
-# https://django-allauth.readthedocs.io/en/latest/forms.html
+# https://docs.allauth.org/en/latest/account/forms.html
ACCOUNT_FORMS = {"signup": "{{cookiecutter.project_slug}}.users.forms.UserSignupForm"}
-# https://django-allauth.readthedocs.io/en/latest/configuration.html
+# https://docs.allauth.org/en/latest/socialaccount/configuration.html
SOCIALACCOUNT_ADAPTER = "{{cookiecutter.project_slug}}.users.adapters.SocialAccountAdapter"
-# https://django-allauth.readthedocs.io/en/latest/forms.html
+# https://docs.allauth.org/en/latest/socialaccount/configuration.html
SOCIALACCOUNT_FORMS = {"signup": "{{cookiecutter.project_slug}}.users.forms.UserSocialSignupForm"}
{% if cookiecutter.frontend_pipeline == 'Django Compressor' -%}
# django-compressor
diff --git a/{{cookiecutter.project_slug}}/config/settings/local.py b/{{cookiecutter.project_slug}}/config/settings/local.py
index adab6087a..0304d6cd4 100644
--- a/{{cookiecutter.project_slug}}/config/settings/local.py
+++ b/{{cookiecutter.project_slug}}/config/settings/local.py
@@ -25,12 +25,12 @@ CACHES = {
# EMAIL
# ------------------------------------------------------------------------------
-{% if cookiecutter.use_mailhog == 'y' and cookiecutter.use_docker == 'y' -%}
+{% if cookiecutter.use_mailpit == 'y' and cookiecutter.use_docker == 'y' -%}
# https://docs.djangoproject.com/en/dev/ref/settings/#email-host
-EMAIL_HOST = env("EMAIL_HOST", default="mailhog")
+EMAIL_HOST = env("EMAIL_HOST", default="mailpit")
# https://docs.djangoproject.com/en/dev/ref/settings/#email-port
EMAIL_PORT = 1025
-{%- elif cookiecutter.use_mailhog == 'y' and cookiecutter.use_docker == 'n' -%}
+{%- elif cookiecutter.use_mailpit == 'y' and cookiecutter.use_docker == 'n' -%}
# https://docs.djangoproject.com/en/dev/ref/settings/#email-host
EMAIL_HOST = "localhost"
# https://docs.djangoproject.com/en/dev/ref/settings/#email-port
diff --git a/{{cookiecutter.project_slug}}/config/settings/production.py b/{{cookiecutter.project_slug}}/config/settings/production.py
index e76b63993..7f6293571 100644
--- a/{{cookiecutter.project_slug}}/config/settings/production.py
+++ b/{{cookiecutter.project_slug}}/config/settings/production.py
@@ -103,35 +103,75 @@ AZURE_CONTAINER = env("DJANGO_AZURE_CONTAINER_NAME")
{% endif -%}
{% if cookiecutter.cloud_provider != 'None' or cookiecutter.use_whitenoise == 'y' -%}
-# STATIC
+# STATIC & MEDIA
# ------------------------
-{% endif -%}
-{% if cookiecutter.use_whitenoise == 'y' -%}
-STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage"
-{% elif cookiecutter.cloud_provider == 'AWS' -%}
-STATICFILES_STORAGE = "{{cookiecutter.project_slug}}.utils.storages.StaticRootS3Boto3Storage"
+STORAGES = {
+{%- if cookiecutter.use_whitenoise == 'y' %}
+ "default": {
+ "BACKEND": "django.core.files.storage.FileSystemStorage",
+ },
+ "staticfiles": {
+ "BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage",
+ },
+{%- elif cookiecutter.cloud_provider == 'AWS' %}
+ "default": {
+ "BACKEND": "storages.backends.s3.S3Storage",
+ "OPTIONS": {
+ "location": "media",
+ "file_overwrite": False,
+ },
+ },
+ "staticfiles": {
+ "BACKEND": "storages.backends.s3.S3Storage",
+ "OPTIONS": {
+ "location": "static",
+ "default_acl": "public-read",
+ },
+ },
+{%- elif cookiecutter.cloud_provider == 'GCP' %}
+ "default": {
+ "BACKEND": "storages.backends.gcloud.GoogleCloudStorage",
+ "OPTIONS": {
+ "location": "media",
+ "file_overwrite": False,
+ },
+ },
+ "staticfiles": {
+ "BACKEND": "storages.backends.gcloud.GoogleCloudStorage",
+ "OPTIONS": {
+ "location": "static",
+ "default_acl": "publicRead",
+ },
+ },
+{%- elif cookiecutter.cloud_provider == 'Azure' %}
+ "default": {
+ "BACKEND": "storages.backends.azure_storage.AzureStorage",
+ "OPTIONS": {
+ "location": "media",
+ "file_overwrite": False,
+ },
+ },
+ "staticfiles": {
+ "BACKEND": "storages.backends.azure_storage.AzureStorage",
+ "OPTIONS": {
+ "location": "static",
+ },
+ },
+{%- endif %}
+}
+{%- endif %}
+
+{%- if cookiecutter.cloud_provider == 'AWS' %}
+MEDIA_URL = f"https://{aws_s3_domain}/media/"
COLLECTFAST_STRATEGY = "collectfast.strategies.boto3.Boto3Strategy"
STATIC_URL = f"https://{aws_s3_domain}/static/"
-{% elif cookiecutter.cloud_provider == 'GCP' -%}
-STATICFILES_STORAGE = "{{cookiecutter.project_slug}}.utils.storages.StaticRootGoogleCloudStorage"
+{%- elif cookiecutter.cloud_provider == 'GCP' %}
+MEDIA_URL = f"https://storage.googleapis.com/{GS_BUCKET_NAME}/media/"
COLLECTFAST_STRATEGY = "collectfast.strategies.gcloud.GoogleCloudStrategy"
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 -%}
-
-# MEDIA
-# ------------------------------------------------------------------------------
-{%- if cookiecutter.cloud_provider == 'AWS' %}
-DEFAULT_FILE_STORAGE = "{{cookiecutter.project_slug}}.utils.storages.MediaRootS3Boto3Storage"
-MEDIA_URL = f"https://{aws_s3_domain}/media/"
-{%- elif cookiecutter.cloud_provider == 'GCP' %}
-DEFAULT_FILE_STORAGE = "{{cookiecutter.project_slug}}.utils.storages.MediaRootGoogleCloudStorage"
-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/"
+STATIC_URL = f"https://{AZURE_ACCOUNT_NAME}.blob.core.windows.net/static/"
{%- endif %}
# EMAIL
@@ -146,7 +186,7 @@ SERVER_EMAIL = env("DJANGO_SERVER_EMAIL", default=DEFAULT_FROM_EMAIL)
# https://docs.djangoproject.com/en/dev/ref/settings/#email-subject-prefix
EMAIL_SUBJECT_PREFIX = env(
"DJANGO_EMAIL_SUBJECT_PREFIX",
- default="[{{cookiecutter.project_name}}]",
+ default="[{{cookiecutter.project_name}}] ",
)
# ADMIN
@@ -230,7 +270,7 @@ COMPRESS_ENABLED = env.bool("COMPRESS_ENABLED", default=True)
COMPRESS_STORAGE = "compressor.storage.GzipCompressorFileStorage"
{%- 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
-COMPRESS_STORAGE = STATICFILES_STORAGE
+COMPRESS_STORAGE = STORAGES["staticfiles"]["BACKEND"]
{%- endif %}
# https://django-compressor.readthedocs.io/en/latest/settings/#django.conf.settings.COMPRESS_URL
COMPRESS_URL = STATIC_URL{% if cookiecutter.use_whitenoise == 'y' or cookiecutter.cloud_provider == 'None' %} # noqa: F405{% endif %}
diff --git a/{{cookiecutter.project_slug}}/config/settings/test.py b/{{cookiecutter.project_slug}}/config/settings/test.py
index 92211ec76..7c54e0217 100644
--- a/{{cookiecutter.project_slug}}/config/settings/test.py
+++ b/{{cookiecutter.project_slug}}/config/settings/test.py
@@ -29,10 +29,15 @@ EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend"
# ------------------------------------------------------------------------------
TEMPLATES[0]["OPTIONS"]["debug"] = True # type: ignore # noqa: F405
+# MEDIA
+# ------------------------------------------------------------------------------
+# https://docs.djangoproject.com/en/dev/ref/settings/#media-url
+MEDIA_URL = "http://media.testserver"
+
{%- if cookiecutter.frontend_pipeline == 'Webpack' %}
# django-webpack-loader
# ------------------------------------------------------------------------------
-WEBPACK_LOADER["DEFAULT"]["LOADER_CLASS"] = "webpack_loader.loader.FakeWebpackLoader" # noqa: F405
+WEBPACK_LOADER["DEFAULT"]["LOADER_CLASS"] = "webpack_loader.loaders.FakeWebpackLoader" # noqa: F405
{%- endif %}
# Your stuff...
diff --git a/{{cookiecutter.project_slug}}/config/wsgi.py b/{{cookiecutter.project_slug}}/config/wsgi.py
index 3fd809ef3..1dbd8a8d8 100644
--- a/{{cookiecutter.project_slug}}/config/wsgi.py
+++ b/{{cookiecutter.project_slug}}/config/wsgi.py
@@ -13,6 +13,7 @@ middleware here, or combine a Django application with an application of another
framework.
"""
+
import os
import sys
from pathlib import Path
diff --git a/{{cookiecutter.project_slug}}/docs/howto.rst b/{{cookiecutter.project_slug}}/docs/howto.rst
index 7f2d26a1e..7d86351cf 100644
--- a/{{cookiecutter.project_slug}}/docs/howto.rst
+++ b/{{cookiecutter.project_slug}}/docs/howto.rst
@@ -8,14 +8,14 @@ Documentation can be written as rst files in `{{cookiecutter.project_slug}}/docs
{% if cookiecutter.use_docker == 'n' %}
To build and serve docs, use the command::
-
- make livehtml
-
-from inside the `{{cookiecutter.project_slug}}/docs` directory.
+
+ make livehtml
+
+from inside the `{{cookiecutter.project_slug}}/docs` directory.
{% else %}
To build and serve docs, use the commands::
-
- docker-compose -f local.yml up docs
+
+ docker compose -f local.yml up docs
{% endif %}
@@ -34,12 +34,12 @@ For an in-use example, see the `page source <_sources/users.rst.txt>`_ for :ref:
To compile all docstrings automatically into documentation source files, use the command:
::
-
+
make apidocs
{% if cookiecutter.use_docker == 'y' %}
This can be done in the docker container:
- ::
-
+ ::
+
docker run --rm docs make apidocs
{% endif -%}
diff --git a/{{cookiecutter.project_slug}}/local.yml b/{{cookiecutter.project_slug}}/local.yml
index e55e18d32..d924b739f 100644
--- a/{{cookiecutter.project_slug}}/local.yml
+++ b/{{cookiecutter.project_slug}}/local.yml
@@ -16,8 +16,8 @@ services:
{%- if cookiecutter.use_celery == 'y' %}
- redis
{%- endif %}
- {%- if cookiecutter.use_mailhog == 'y' %}
- - mailhog
+ {%- if cookiecutter.use_mailpit == 'y' %}
+ - mailpit
{%- endif %}
volumes:
- .:/app:z
@@ -55,11 +55,11 @@ services:
ports:
- '9000:9000'
command: /start-docs
- {%- if cookiecutter.use_mailhog == 'y' %}
+ {%- if cookiecutter.use_mailpit == 'y' %}
- mailhog:
- image: mailhog/mailhog:v1.0.0
- container_name: {{ cookiecutter.project_slug }}_local_mailhog
+ mailpit:
+ image: docker.io/axllent/mailpit:latest
+ container_name: {{ cookiecutter.project_slug }}_local_mailpit
ports:
- "8025:8025"
@@ -67,7 +67,7 @@ services:
{%- if cookiecutter.use_celery == 'y' %}
redis:
- image: redis:6
+ image: docker.io/redis:6
container_name: {{ cookiecutter.project_slug }}_local_redis
celeryworker:
@@ -77,8 +77,8 @@ services:
depends_on:
- redis
- postgres
- {%- if cookiecutter.use_mailhog == 'y' %}
- - mailhog
+ {%- if cookiecutter.use_mailpit == 'y' %}
+ - mailpit
{%- endif %}
ports: []
command: /start-celeryworker
@@ -90,8 +90,8 @@ services:
depends_on:
- redis
- postgres
- {%- if cookiecutter.use_mailhog == 'y' %}
- - mailhog
+ {%- if cookiecutter.use_mailpit == 'y' %}
+ - mailpit
{%- endif %}
ports: []
command: /start-celerybeat
diff --git a/{{cookiecutter.project_slug}}/locale/README.md b/{{cookiecutter.project_slug}}/locale/README.md
index b2a8a0ef2..a514ad10c 100644
--- a/{{cookiecutter.project_slug}}/locale/README.md
+++ b/{{cookiecutter.project_slug}}/locale/README.md
@@ -3,7 +3,7 @@
Start by configuring the `LANGUAGES` settings in `base.py`, by uncommenting languages you are willing to support. Then, translations strings will be placed in this folder when running:
```bash
-{% if cookiecutter.use_docker == 'y' %}docker-compose -f local.yml run --rm django {% endif %}python manage.py makemessages -all --no-location
+{% if cookiecutter.use_docker == 'y' %}docker compose -f local.yml run --rm django {% endif %}python manage.py makemessages -all --no-location
```
This should generate `django.po` (stands for Portable Object) files under each locale `/LC_MESSAGES/django.po`. Each translatable string in the codebase is collected with its `msgid` and need to be translated as `msgstr`, for example:
@@ -16,7 +16,7 @@ msgstr "utilisateurs"
Once all translations are done, they need to be compiled into `.mo` files (stands for Machine Object), which are the actual binary files used by the application:
```bash
-{% if cookiecutter.use_docker == 'y' %}docker-compose -f local.yml run --rm django {% endif %}python manage.py compilemessages
+{% if cookiecutter.use_docker == 'y' %}docker compose -f local.yml run --rm django {% endif %}python manage.py compilemessages
```
Note that the `.po` files are NOT used by the application directly, so if the `.mo` files are out of dates, the content won't appear as translated even if the `.po` files are up-to-date.
diff --git a/{{cookiecutter.project_slug}}/locale/fr_FR/LC_MESSAGES/django.po b/{{cookiecutter.project_slug}}/locale/fr_FR/LC_MESSAGES/django.po
new file mode 100644
index 000000000..67434d505
--- /dev/null
+++ b/{{cookiecutter.project_slug}}/locale/fr_FR/LC_MESSAGES/django.po
@@ -0,0 +1,335 @@
+# Translations for the {{ cookiecutter.project_name }} project
+# Copyright (C) {% now 'utc', '%Y' %} {{ cookiecutter.author_name }}
+# {{ cookiecutter.author_name }} <{{ cookiecutter.email }}>, {% now 'utc', '%Y' %}.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: {{ cookiecutter.version }}\n"
+"Language: fr-FR\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+#: {{cookiecutter.project_slug}}/templates/account/account_inactive.html:5
+#: {{cookiecutter.project_slug}}/templates/account/account_inactive.html:8
+msgid "Account Inactive"
+msgstr "Compte inactif"
+
+#: {{cookiecutter.project_slug}}/templates/account/account_inactive.html:10
+msgid "This account is inactive."
+msgstr "Ce compte est inactif."
+
+#: {{cookiecutter.project_slug}}/templates/account/email.html:7
+msgid "Account"
+msgstr "Compte"
+
+#: {{cookiecutter.project_slug}}/templates/account/email.html:10
+msgid "E-mail Addresses"
+msgstr "Adresses e-mail"
+
+#: {{cookiecutter.project_slug}}/templates/account/email.html:13
+msgid "The following e-mail addresses are associated with your account:"
+msgstr "Les adresses e-mail suivantes sont associées à votre compte :"
+
+#: {{cookiecutter.project_slug}}/templates/account/email.html:27
+msgid "Verified"
+msgstr "Vérifié"
+
+#: {{cookiecutter.project_slug}}/templates/account/email.html:29
+msgid "Unverified"
+msgstr "Non vérifié"
+
+#: {{cookiecutter.project_slug}}/templates/account/email.html:31
+msgid "Primary"
+msgstr "Primaire"
+
+#: {{cookiecutter.project_slug}}/templates/account/email.html:37
+msgid "Make Primary"
+msgstr "Changer Primaire"
+
+#: {{cookiecutter.project_slug}}/templates/account/email.html:38
+msgid "Re-send Verification"
+msgstr "Renvoyer vérification"
+
+#: {{cookiecutter.project_slug}}/templates/account/email.html:39
+msgid "Remove"
+msgstr "Supprimer"
+
+#: {{cookiecutter.project_slug}}/templates/account/email.html:46
+msgid "Warning:"
+msgstr "Avertissement:"
+
+#: {{cookiecutter.project_slug}}/templates/account/email.html:46
+msgid ""
+"You currently do not have any e-mail address set up. You should really add "
+"an e-mail address so you can receive notifications, reset your password, etc."
+msgstr ""
+"Vous n'avez actuellement aucune adresse e-mail configurée. Vous devriez ajouter "
+"une adresse e-mail pour reçevoir des notifications, réinitialiser votre mot "
+"de passe, etc."
+
+#: {{cookiecutter.project_slug}}/templates/account/email.html:51
+msgid "Add E-mail Address"
+msgstr "Ajouter une adresse e-mail"
+
+#: {{cookiecutter.project_slug}}/templates/account/email.html:56
+msgid "Add E-mail"
+msgstr "Ajouter e-mail"
+
+#: {{cookiecutter.project_slug}}/templates/account/email.html:66
+msgid "Do you really want to remove the selected e-mail address?"
+msgstr "Voulez-vous vraiment supprimer l'adresse e-mail sélectionnée ?"
+
+#: {{cookiecutter.project_slug}}/templates/account/email_confirm.html:6
+#: {{cookiecutter.project_slug}}/templates/account/email_confirm.html:10
+msgid "Confirm E-mail Address"
+msgstr "Confirmez votre adresse email"
+
+#: {{cookiecutter.project_slug}}/templates/account/email_confirm.html:16
+#, python-format
+msgid ""
+"Please confirm that %(email)s is an e-mail "
+"address for user %(user_display)s."
+msgstr ""
+"Veuillez confirmer que %(email)s est un e-mail "
+"adresse de l'utilisateur %(user_display)s."
+
+#: {{cookiecutter.project_slug}}/templates/account/email_confirm.html:20
+msgid "Confirm"
+msgstr "Confirm"
+
+#: {{cookiecutter.project_slug}}/templates/account/email_confirm.html:27
+#, python-format
+msgid ""
+"This e-mail confirmation link expired or is invalid. Please issue a new e-mail confirmation request."
+msgstr ""
+"Ce lien de confirmation par e-mail a expiré ou n'est pas valide. Veuillez"
+ "émettre une nouvelle demande de confirmation "
+"par e-mail."
+
+#: {{cookiecutter.project_slug}}/templates/account/login.html:7
+#: {{cookiecutter.project_slug}}/templates/account/login.html:11
+#: {{cookiecutter.project_slug}}/templates/account/login.html:56
+#: {{cookiecutter.project_slug}}/templates/base.html:72
+msgid "Sign In"
+msgstr "S'identifier"
+
+#: {{cookiecutter.project_slug}}/templates/account/login.html:17
+msgid "Please sign in with one of your existing third party accounts:"
+msgstr "Veuillez vous connecter avec l'un de vos comptes tiers existants :"
+
+#: {{cookiecutter.project_slug}}/templates/account/login.html:19
+#, python-format
+msgid ""
+"Or, sign up for a %(site_name)s account and "
+"sign in below:"
+msgstr ""
+"Ou, créez un compte %(site_name)s et "
+"connectez-vous ci-dessous :"
+
+#: {{cookiecutter.project_slug}}/templates/account/login.html:32
+msgid "or"
+msgstr "ou"
+
+#: {{cookiecutter.project_slug}}/templates/account/login.html:41
+#, python-format
+msgid ""
+"If you have not created an account yet, then please sign up first."
+msgstr ""
+"Si vous n'avez pas encore créé de compte, veuillez d'abord vous inscrire."
+
+#: {{cookiecutter.project_slug}}/templates/account/login.html:55
+msgid "Forgot Password?"
+msgstr "Mot de passe oublié?"
+
+#: {{cookiecutter.project_slug}}/templates/account/logout.html:5
+#: {{cookiecutter.project_slug}}/templates/account/logout.html:8
+#: {{cookiecutter.project_slug}}/templates/account/logout.html:17
+#: {{cookiecutter.project_slug}}/templates/base.html:61
+msgid "Sign Out"
+msgstr "Se déconnecter"
+
+#: {{cookiecutter.project_slug}}/templates/account/logout.html:10
+msgid "Are you sure you want to sign out?"
+msgstr "Êtes-vous certain de vouloir vous déconnecter?"
+
+#: {{cookiecutter.project_slug}}/templates/account/password_change.html:6
+#: {{cookiecutter.project_slug}}/templates/account/password_change.html:9
+#: {{cookiecutter.project_slug}}/templates/account/password_change.html:14
+#: {{cookiecutter.project_slug}}/templates/account/password_reset_from_key.html:5
+#: {{cookiecutter.project_slug}}/templates/account/password_reset_from_key.html:8
+#: {{cookiecutter.project_slug}}/templates/account/password_reset_from_key_done.html:4
+#: {{cookiecutter.project_slug}}/templates/account/password_reset_from_key_done.html:7
+msgid "Change Password"
+msgstr "Changer le mot de passe"
+
+#: {{cookiecutter.project_slug}}/templates/account/password_reset.html:7
+#: {{cookiecutter.project_slug}}/templates/account/password_reset.html:11
+#: {{cookiecutter.project_slug}}/templates/account/password_reset_done.html:6
+#: {{cookiecutter.project_slug}}/templates/account/password_reset_done.html:9
+msgid "Password Reset"
+msgstr "Réinitialisation du mot de passe"
+
+#: {{cookiecutter.project_slug}}/templates/account/password_reset.html:16
+msgid ""
+"Forgotten your password? Enter your e-mail address below, and we'll send you "
+"an e-mail allowing you to reset it."
+msgstr ""
+"Mot de passe oublié? Entrez votre adresse e-mail ci-dessous, et nous vous "
+"enverrons un e-mail vous permettant de le réinitialiser."
+
+#: {{cookiecutter.project_slug}}/templates/account/password_reset.html:21
+msgid "Reset My Password"
+msgstr "Réinitialiser mon mot de passe"
+
+#: {{cookiecutter.project_slug}}/templates/account/password_reset.html:24
+msgid "Please contact us if you have any trouble resetting your password."
+msgstr ""
+"Veuillez nous contacter si vous rencontrez des difficultés pour réinitialiser"
+"votre mot de passe."
+
+#: {{cookiecutter.project_slug}}/templates/account/password_reset_done.html:15
+msgid ""
+"We have sent you an e-mail. Please contact us if you do not receive it "
+"within a few minutes."
+msgstr ""
+"Nous vous avons envoyé un e-mail. Veuillez nous contacter si vous ne le "
+"recevez pas d'ici quelques minutes."
+
+#: {{cookiecutter.project_slug}}/templates/account/password_reset_from_key.html:8
+msgid "Bad Token"
+msgstr "Token Invalide"
+
+#: {{cookiecutter.project_slug}}/templates/account/password_reset_from_key.html:12
+#, python-format
+msgid ""
+"The password reset link was invalid, possibly because it has already been "
+"used. Please request a new password reset"
+"a>."
+msgstr ""
+"Le lien de réinitialisation du mot de passe n'était pas valide, peut-être parce "
+"qu'il a déjà été utilisé. Veuillez faire une "
+"nouvelle demande de réinitialisation de mot de passe."
+
+#: {{cookiecutter.project_slug}}/templates/account/password_reset_from_key.html:18
+msgid "change password"
+msgstr "changer le mot de passe"
+
+#: {{cookiecutter.project_slug}}/templates/account/password_reset_from_key.html:21
+#: {{cookiecutter.project_slug}}/templates/account/password_reset_from_key_done.html:8
+msgid "Your password is now changed."
+msgstr "Votre mot de passe est maintenant modifié."
+
+#: {{cookiecutter.project_slug}}/templates/account/password_set.html:6
+#: {{cookiecutter.project_slug}}/templates/account/password_set.html:9
+#: {{cookiecutter.project_slug}}/templates/account/password_set.html:14
+msgid "Set Password"
+msgstr "Définir le mot de passe"
+
+#: {{cookiecutter.project_slug}}/templates/account/signup.html:6
+msgid "Signup"
+msgstr "S'inscrire"
+
+#: {{cookiecutter.project_slug}}/templates/account/signup.html:9
+#: {{cookiecutter.project_slug}}/templates/account/signup.html:19
+#: {{cookiecutter.project_slug}}/templates/base.html:67
+msgid "Sign Up"
+msgstr "S'inscrire"
+
+#: {{cookiecutter.project_slug}}/templates/account/signup.html:11
+#, python-format
+msgid ""
+"Already have an account? Then please sign in."
+msgstr ""
+"Vous avez déjà un compte? Alors veuillez vous connecter."
+
+#: {{cookiecutter.project_slug}}/templates/account/signup_closed.html:5
+#: {{cookiecutter.project_slug}}/templates/account/signup_closed.html:8
+msgid "Sign Up Closed"
+msgstr "Inscriptions closes"
+
+#: {{cookiecutter.project_slug}}/templates/account/signup_closed.html:10
+msgid "We are sorry, but the sign up is currently closed."
+msgstr "Désolé, mais l'inscription est actuellement fermée."
+
+#: {{cookiecutter.project_slug}}/templates/account/verification_sent.html:5
+#: {{cookiecutter.project_slug}}/templates/account/verification_sent.html:8
+#: {{cookiecutter.project_slug}}/templates/account/verified_email_required.html:5
+#: {{cookiecutter.project_slug}}/templates/account/verified_email_required.html:8
+msgid "Verify Your E-mail Address"
+msgstr "Vérifiez votre adresse e-mail"
+
+#: {{cookiecutter.project_slug}}/templates/account/verification_sent.html:10
+msgid ""
+"We have sent an e-mail to you for verification. Follow the link provided to "
+"finalize the signup process. Please contact us if you do not receive it "
+"within a few minutes."
+msgstr "Nous vous avons envoyé un e-mail pour vérification. Suivez le lien fourni "
+"pour finalisez le processus d'inscription. Veuillez nous contacter si vous ne le "
+"recevez pas d'ici quelques minutes."
+
+#: {{cookiecutter.project_slug}}/templates/account/verified_email_required.html:12
+msgid ""
+"This part of the site requires us to verify that\n"
+"you are who you claim to be. For this purpose, we require that you\n"
+"verify ownership of your e-mail address. "
+msgstr ""
+"Cette partie du site nous oblige à vérifier que\n"
+"vous êtes qui vous prétendez être. Nous vous demandons donc de\n"
+"vérifier la propriété de votre adresse e-mail."
+
+#: {{cookiecutter.project_slug}}/templates/account/verified_email_required.html:16
+msgid ""
+"We have sent an e-mail to you for\n"
+"verification. Please click on the link inside this e-mail. Please\n"
+"contact us if you do not receive it within a few minutes."
+msgstr ""
+"Nous vous avons envoyé un e-mail pour\n"
+"vérification. Veuillez cliquer sur le lien contenu dans cet e-mail. Veuillez nous\n"
+"contacter si vous ne le recevez pas d'ici quelques minutes."
+
+#: {{cookiecutter.project_slug}}/templates/account/verified_email_required.html:20
+#, python-format
+msgid ""
+"Note: you can still change your e-"
+"mail address."
+msgstr ""
+"Remarque : vous pouvez toujours changer votre e-"
+"adresse e-mail."
+
+#: {{cookiecutter.project_slug}}/templates/base.html:57
+msgid "My Profile"
+msgstr "Mon Profil"
+
+#: {{cookiecutter.project_slug}}/users/admin.py:17
+msgid "Personal info"
+msgstr "Personal info"
+
+#: {{cookiecutter.project_slug}}/users/admin.py:19
+msgid "Permissions"
+msgstr "Permissions"
+
+#: {{cookiecutter.project_slug}}/users/admin.py:30
+msgid "Important dates"
+msgstr "Dates importantes"
+
+#: {{cookiecutter.project_slug}}/users/apps.py:7
+msgid "Users"
+msgstr "Utilisateurs"
+
+#: {{cookiecutter.project_slug}}/users/forms.py:24
+#: {{cookiecutter.project_slug}}/users/tests/test_forms.py:36
+msgid "This username has already been taken."
+msgstr "Ce nom d'utilisateur est déjà pris."
+
+#: {{cookiecutter.project_slug}}/users/models.py:15
+msgid "Name of User"
+msgstr "Nom de l'utilisateur"
+
+#: {{cookiecutter.project_slug}}/users/views.py:23
+msgid "Information successfully updated"
+msgstr "Informations mises à jour avec succès"
diff --git a/{{cookiecutter.project_slug}}/locale/pt_BR/LC_MESSAGES/django.po b/{{cookiecutter.project_slug}}/locale/pt_BR/LC_MESSAGES/django.po
index 2556abba8..1681e0f57 100644
--- a/{{cookiecutter.project_slug}}/locale/pt_BR/LC_MESSAGES/django.po
+++ b/{{cookiecutter.project_slug}}/locale/pt_BR/LC_MESSAGES/django.po
@@ -127,7 +127,7 @@ msgstr "Ou, cadastre-se para uma conta em %(site_
#: {{cookiecutter.project_slug}}/templates/account/login.html:32
msgid "or"
-msgstr "or"
+msgstr "ou"
#: {{cookiecutter.project_slug}}/templates/account/login.html:41
#, python-format
diff --git a/{{cookiecutter.project_slug}}/package.json b/{{cookiecutter.project_slug}}/package.json
index 99b984da6..efa2136e5 100644
--- a/{{cookiecutter.project_slug}}/package.json
+++ b/{{cookiecutter.project_slug}}/package.json
@@ -8,7 +8,7 @@
"autoprefixer": "^10.4.0",
"babel-loader": "^9.1.2",
"bootstrap": "^5.2.3",
- "browser-sync": "^2.27.7",
+ "browser-sync": "^3.0.2",
"css-loader": "^6.5.1",
"gulp-concat": "^2.6.1",
"concurrently": "^8.0.1",
@@ -16,7 +16,7 @@
"gulp": "^4.0.2",
"gulp-imagemin": "^7.1.0",
"gulp-plumber": "^1.2.1",
- "gulp-postcss": "^9.0.1",
+ "gulp-postcss": "^10.0.0",
"gulp-rename": "^2.0.0",
"gulp-sass": "^5.0.0",
"gulp-uglify-es": "^3.0.0",
@@ -24,18 +24,18 @@
"node-sass-tilde-importer": "^1.0.2",
"pixrem": "^5.0.0",
"postcss": "^8.3.11",
- "postcss-loader": "^7.0.2",
+ "postcss-loader": "^8.0.0",
"postcss-preset-env": "^9.0.0",
"sass": "^1.43.4",
- "sass-loader": "^13.2.0",
+ "sass-loader": "^14.0.0",
"webpack": "^5.65.0",
- "webpack-bundle-tracker": "^2.0.0",
+ "webpack-bundle-tracker": "^3.0.1",
"webpack-cli": "^5.0.1",
"webpack-dev-server": "^4.6.0",
"webpack-merge": "^5.8.0"
},
"engines": {
- "node": "18"
+ "node": "20"
},
"browserslist": [
"last 2 versions"
diff --git a/{{cookiecutter.project_slug}}/production.yml b/{{cookiecutter.project_slug}}/production.yml
index 30d72d61e..f7bf5284f 100644
--- a/{{cookiecutter.project_slug}}/production.yml
+++ b/{{cookiecutter.project_slug}}/production.yml
@@ -67,7 +67,7 @@ services:
{%- endif %}
redis:
- image: redis:6
+ image: docker.io/redis:6
{%- if cookiecutter.use_celery == 'y' %}
celeryworker:
diff --git a/{{cookiecutter.project_slug}}/requirements/base.txt b/{{cookiecutter.project_slug}}/requirements/base.txt
index 47a0bc34b..e260bc922 100644
--- a/{{cookiecutter.project_slug}}/requirements/base.txt
+++ b/{{cookiecutter.project_slug}}/requirements/base.txt
@@ -1,5 +1,5 @@
-python-slugify==8.0.1 # https://github.com/un33k/python-slugify
-Pillow==9.5.0 # https://github.com/python-pillow/Pillow
+python-slugify==8.0.4 # https://github.com/un33k/python-slugify
+Pillow==10.2.0 # https://github.com/python-pillow/Pillow
{%- if cookiecutter.frontend_pipeline == 'Django Compressor' %}
{%- if cookiecutter.windows == 'y' and cookiecutter.use_docker == 'n' %}
rcssmin==1.1.0 --install-option="--without-c-extensions" # https://github.com/ndparker/rcssmin
@@ -7,44 +7,44 @@ rcssmin==1.1.0 --install-option="--without-c-extensions" # https://github.com/n
rcssmin==1.1.1 # https://github.com/ndparker/rcssmin
{%- endif %}
{%- endif %}
-argon2-cffi==21.3.0 # https://github.com/hynek/argon2_cffi
+argon2-cffi==23.1.0 # https://github.com/hynek/argon2_cffi
{%- if cookiecutter.use_whitenoise == 'y' %}
-whitenoise==6.5.0 # https://github.com/evansd/whitenoise
+whitenoise==6.6.0 # https://github.com/evansd/whitenoise
{%- endif %}
-redis==4.6.0 # https://github.com/redis/redis-py
+redis==5.0.1 # https://github.com/redis/redis-py
{%- if cookiecutter.use_docker == "y" or cookiecutter.windows == "n" %}
-hiredis==2.2.3 # https://github.com/redis/hiredis-py
+hiredis==2.3.2 # https://github.com/redis/hiredis-py
{%- endif %}
{%- if cookiecutter.use_celery == "y" %}
-celery==5.3.1 # pyup: < 6.0 # https://github.com/celery/celery
+celery==5.3.6 # pyup: < 6.0 # https://github.com/celery/celery
django-celery-beat==2.5.0 # https://github.com/celery/django-celery-beat
{%- if cookiecutter.use_docker == 'y' %}
-flower==2.0.0 # https://github.com/mher/flower
+flower==2.0.1 # https://github.com/mher/flower
{%- endif %}
{%- endif %}
{%- if cookiecutter.use_async == 'y' %}
-uvicorn[standard]==0.22.0 # https://github.com/encode/uvicorn
+uvicorn[standard]==0.27.0.post1 # https://github.com/encode/uvicorn
{%- endif %}
# Django
# ------------------------------------------------------------------------------
-django==4.2.3 # pyup: < 5.0 # https://www.djangoproject.com/
-django-environ==0.10.0 # https://github.com/joke2k/django-environ
-django-model-utils==4.3.1 # https://github.com/jazzband/django-model-utils
-django-allauth==0.54.0 # https://github.com/pennersr/django-allauth
-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
+django==4.2.10 # pyup: < 5.0 # https://www.djangoproject.com/
+django-environ==0.11.2 # https://github.com/joke2k/django-environ
+django-model-utils==4.4.0 # https://github.com/jazzband/django-model-utils
+django-allauth==0.61.1 # https://github.com/pennersr/django-allauth
+django-crispy-forms==2.1 # https://github.com/django-crispy-forms/django-crispy-forms
+crispy-bootstrap5==2023.10 # https://github.com/django-crispy-forms/crispy-bootstrap5
{%- if cookiecutter.frontend_pipeline == 'Django Compressor' %}
django-compressor==4.4 # https://github.com/django-compressor/django-compressor
{%- endif %}
-django-redis==5.3.0 # https://github.com/jazzband/django-redis
+django-redis==5.4.0 # https://github.com/jazzband/django-redis
{%- if cookiecutter.use_drf == 'y' %}
# Django REST Framework
djangorestframework==3.14.0 # https://github.com/encode/django-rest-framework
-django-cors-headers==4.1.0 # https://github.com/adamchainz/django-cors-headers
+django-cors-headers==4.3.1 # https://github.com/adamchainz/django-cors-headers
# DRF-spectacular for api documentation
-drf-spectacular==0.26.3 # https://github.com/tfranzel/drf-spectacular
+drf-spectacular==0.27.1 # https://github.com/tfranzel/drf-spectacular
{%- endif %}
{%- if cookiecutter.frontend_pipeline == 'Webpack' %}
-django-webpack-loader==2.0.1 # https://github.com/django-webpack/django-webpack-loader
+django-webpack-loader==3.0.1 # https://github.com/django-webpack/django-webpack-loader
{%- endif %}
diff --git a/{{cookiecutter.project_slug}}/requirements/local.txt b/{{cookiecutter.project_slug}}/requirements/local.txt
index fe9231f03..ef26dcc8c 100644
--- a/{{cookiecutter.project_slug}}/requirements/local.txt
+++ b/{{cookiecutter.project_slug}}/requirements/local.txt
@@ -1,49 +1,49 @@
--r base.txt
+-r production.txt
-Werkzeug[watchdog]==2.3.6 # https://github.com/pallets/werkzeug
+Werkzeug[watchdog]==3.0.1 # https://github.com/pallets/werkzeug
ipdb==0.13.13 # https://github.com/gotcha/ipdb
{%- if cookiecutter.use_docker == 'y' %}
-psycopg[c]==3.1.9 # https://github.com/psycopg/psycopg
+psycopg[c]==3.1.18 # https://github.com/psycopg/psycopg
{%- else %}
-psycopg[binary]==3.1.9 # https://github.com/psycopg/psycopg
+psycopg[binary]==3.1.18 # https://github.com/psycopg/psycopg
{%- endif %}
{%- if cookiecutter.use_async == 'y' or cookiecutter.use_celery == 'y' %}
-watchfiles==0.19.0 # https://github.com/samuelcolvin/watchfiles
+watchfiles==0.21.0 # https://github.com/samuelcolvin/watchfiles
{%- endif %}
# Testing
# ------------------------------------------------------------------------------
-mypy==1.4.1 # https://github.com/python/mypy
-django-stubs==4.2.3 # https://github.com/typeddjango/django-stubs
-pytest==7.4.0 # https://github.com/pytest-dev/pytest
-pytest-sugar==0.9.7 # https://github.com/Frozenball/pytest-sugar
+mypy==1.7.1 # https://github.com/python/mypy
+django-stubs[compatible-mypy]==4.2.7 # https://github.com/typeddjango/django-stubs
+pytest==8.0.0 # https://github.com/pytest-dev/pytest
+pytest-sugar==1.0.0 # https://github.com/Frozenball/pytest-sugar
{%- if cookiecutter.use_drf == "y" %}
-djangorestframework-stubs==3.14.2 # https://github.com/typeddjango/djangorestframework-stubs
+djangorestframework-stubs[compatible-mypy]==3.14.5 # https://github.com/typeddjango/djangorestframework-stubs
{%- endif %}
# Documentation
# ------------------------------------------------------------------------------
-sphinx==6.2.1 # https://github.com/sphinx-doc/sphinx
-sphinx-autobuild==2021.3.14 # https://github.com/GaretJax/sphinx-autobuild
+sphinx==7.2.6 # https://github.com/sphinx-doc/sphinx
+sphinx-autobuild==2024.2.4 # https://github.com/GaretJax/sphinx-autobuild
# Code quality
# ------------------------------------------------------------------------------
-flake8==6.0.0 # https://github.com/PyCQA/flake8
-flake8-isort==6.0.0 # https://github.com/gforcada/flake8-isort
-coverage==7.2.7 # https://github.com/nedbat/coveragepy
-black==23.3.0 # https://github.com/psf/black
-djlint==1.31.1 # https://github.com/Riverside-Healthcare/djLint
-pylint-django==2.5.3 # https://github.com/PyCQA/pylint-django
+flake8==7.0.0 # https://github.com/PyCQA/flake8
+flake8-isort==6.1.1 # https://github.com/gforcada/flake8-isort
+coverage==7.4.1 # https://github.com/nedbat/coveragepy
+black==24.1.1 # https://github.com/psf/black
+djlint==1.34.1 # https://github.com/Riverside-Healthcare/djLint
+pylint-django==2.5.5 # https://github.com/PyCQA/pylint-django
{%- if cookiecutter.use_celery == 'y' %}
pylint-celery==0.3 # https://github.com/PyCQA/pylint-celery
{%- endif %}
-pre-commit==3.3.3 # https://github.com/pre-commit/pre-commit
+pre-commit==3.6.1 # https://github.com/pre-commit/pre-commit
# Django
# ------------------------------------------------------------------------------
-factory-boy==3.2.1 # https://github.com/FactoryBoy/factory_boy
+factory-boy==3.3.0 # https://github.com/FactoryBoy/factory_boy
-django-debug-toolbar==4.1.0 # https://github.com/jazzband/django-debug-toolbar
+django-debug-toolbar==4.3.0 # https://github.com/jazzband/django-debug-toolbar
django-extensions==3.2.3 # https://github.com/django-extensions/django-extensions
-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
+django-coverage-plugin==3.1.0 # https://github.com/nedbat/django_coverage_plugin
+pytest-django==4.8.0 # https://github.com/pytest-dev/pytest-django
diff --git a/{{cookiecutter.project_slug}}/requirements/production.txt b/{{cookiecutter.project_slug}}/requirements/production.txt
index eb6a14c28..b6e793e11 100644
--- a/{{cookiecutter.project_slug}}/requirements/production.txt
+++ b/{{cookiecutter.project_slug}}/requirements/production.txt
@@ -2,43 +2,43 @@
-r base.txt
-gunicorn==20.1.0 # https://github.com/benoitc/gunicorn
-psycopg[c]==3.1.9 # https://github.com/psycopg/psycopg
+gunicorn==21.2.0 # https://github.com/benoitc/gunicorn
+psycopg[c]==3.1.18 # https://github.com/psycopg/psycopg
{%- if cookiecutter.use_whitenoise == 'n' %}
Collectfast==2.2.0 # https://github.com/antonagestam/collectfast
{%- endif %}
{%- if cookiecutter.use_sentry == "y" %}
-sentry-sdk==1.27.0 # https://github.com/getsentry/sentry-python
+sentry-sdk==1.40.3 # https://github.com/getsentry/sentry-python
{%- endif %}
{%- if cookiecutter.use_docker == "n" and cookiecutter.windows == "y" %}
-hiredis==2.2.3 # https://github.com/redis/hiredis-py
+hiredis==2.3.2 # https://github.com/redis/hiredis-py
{%- endif %}
# Django
# ------------------------------------------------------------------------------
{%- if cookiecutter.cloud_provider == 'AWS' %}
-django-storages[boto3]==1.13.2 # https://github.com/jschneier/django-storages
+django-storages[s3]==1.14.2 # https://github.com/jschneier/django-storages
{%- elif cookiecutter.cloud_provider == 'GCP' %}
-django-storages[google]==1.13.2 # https://github.com/jschneier/django-storages
+django-storages[google]==1.14.2 # https://github.com/jschneier/django-storages
{%- elif cookiecutter.cloud_provider == 'Azure' %}
-django-storages[azure]==1.13.2 # https://github.com/jschneier/django-storages
+django-storages[azure]==1.14.2 # https://github.com/jschneier/django-storages
{%- endif %}
{%- if cookiecutter.mail_service == 'Mailgun' %}
-django-anymail[mailgun]==10.0 # https://github.com/anymail/django-anymail
+django-anymail[mailgun]==10.2 # https://github.com/anymail/django-anymail
{%- elif cookiecutter.mail_service == 'Amazon SES' %}
-django-anymail[amazon-ses]==10.0 # https://github.com/anymail/django-anymail
+django-anymail[amazon-ses]==10.2 # https://github.com/anymail/django-anymail
{%- elif cookiecutter.mail_service == 'Mailjet' %}
-django-anymail[mailjet]==10.0 # https://github.com/anymail/django-anymail
+django-anymail[mailjet]==10.2 # https://github.com/anymail/django-anymail
{%- elif cookiecutter.mail_service == 'Mandrill' %}
-django-anymail[mandrill]==10.0 # https://github.com/anymail/django-anymail
+django-anymail[mandrill]==10.2 # https://github.com/anymail/django-anymail
{%- elif cookiecutter.mail_service == 'Postmark' %}
-django-anymail[postmark]==10.0 # https://github.com/anymail/django-anymail
+django-anymail[postmark]==10.2 # https://github.com/anymail/django-anymail
{%- elif cookiecutter.mail_service == 'Sendgrid' %}
-django-anymail[sendgrid]==10.0 # https://github.com/anymail/django-anymail
+django-anymail[sendgrid]==10.2 # https://github.com/anymail/django-anymail
{%- elif cookiecutter.mail_service == 'SendinBlue' %}
-django-anymail[sendinblue]==10.0 # https://github.com/anymail/django-anymail
+django-anymail[sendinblue]==10.2 # https://github.com/anymail/django-anymail
{%- elif cookiecutter.mail_service == 'SparkPost' %}
-django-anymail[sparkpost]==10.0 # https://github.com/anymail/django-anymail
+django-anymail[sparkpost]==10.2 # https://github.com/anymail/django-anymail
{%- elif cookiecutter.mail_service == 'Other SMTP' %}
-django-anymail==10.0 # https://github.com/anymail/django-anymail
+django-anymail==10.2 # https://github.com/anymail/django-anymail
{%- endif %}
diff --git a/{{cookiecutter.project_slug}}/runtime.txt b/{{cookiecutter.project_slug}}/runtime.txt
index 431fc7e8c..1f79d441f 100644
--- a/{{cookiecutter.project_slug}}/runtime.txt
+++ b/{{cookiecutter.project_slug}}/runtime.txt
@@ -1 +1 @@
-python-3.11.4
+python-3.11.7
diff --git a/{{cookiecutter.project_slug}}/setup.cfg b/{{cookiecutter.project_slug}}/setup.cfg
index 829064213..2412f1746 100644
--- a/{{cookiecutter.project_slug}}/setup.cfg
+++ b/{{cookiecutter.project_slug}}/setup.cfg
@@ -4,6 +4,7 @@
[flake8]
max-line-length = 119
exclude = .tox,.git,*/migrations/*,*/static/CACHE/*,docs,node_modules,venv,.venv
+extend-ignore = E203
[pycodestyle]
max-line-length = 119
diff --git a/{{cookiecutter.project_slug}}/utility/requirements-bookworm.apt b/{{cookiecutter.project_slug}}/utility/requirements-bookworm.apt
new file mode 100644
index 000000000..a4910eb6d
--- /dev/null
+++ b/{{cookiecutter.project_slug}}/utility/requirements-bookworm.apt
@@ -0,0 +1,23 @@
+##basic build dependencies of various Django apps for Debian Bookworm 12.x
+#build-essential metapackage install: make, gcc, g++,
+build-essential
+#required to translate
+gettext
+python3-dev
+
+##shared dependencies of:
+##Pillow, pylibmc
+zlib1g-dev
+
+##Postgresql and psycopg2 dependencies
+libpq-dev
+
+##Pillow dependencies
+libtiff5-dev
+libjpeg62-turbo-dev
+libfreetype6-dev
+liblcms2-dev
+libwebp-dev
+
+##django-extensions
+libgraphviz-dev
diff --git a/{{cookiecutter.project_slug}}/webpack/dev.config.js b/{{cookiecutter.project_slug}}/webpack/dev.config.js
index c2f14abb1..8276c3489 100644
--- a/{{cookiecutter.project_slug}}/webpack/dev.config.js
+++ b/{{cookiecutter.project_slug}}/webpack/dev.config.js
@@ -13,6 +13,13 @@ module.exports = merge(commonConfig, {
'/': 'http://django:8000',
{%- endif %}
},
+ client: {
+ overlay: {
+ errors: true,
+ warnings: false,
+ runtimeErrors: true,
+ },
+ },
// We need hot=false (Disable HMR) to set liveReload=true
hot: false,
liveReload: true,
diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/contrib/sites/migrations/0003_set_site_domain_and_name.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/contrib/sites/migrations/0003_set_site_domain_and_name.py
index 080c734bb..e1822375b 100644
--- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/contrib/sites/migrations/0003_set_site_domain_and_name.py
+++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/contrib/sites/migrations/0003_set_site_domain_and_name.py
@@ -40,8 +40,8 @@ def update_site_forward(apps, schema_editor):
_update_or_create_site_with_sequence(
Site,
schema_editor.connection,
- "{{cookiecutter.domain_name}}",
- "{{cookiecutter.project_name}}",
+ "{{ cookiecutter.domain_name }}",
+ "{{ cookiecutter.project_name[:50] }}",
)
diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/403_csrf.html b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/403_csrf.html
new file mode 100644
index 000000000..d90b33f9b
--- /dev/null
+++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/403_csrf.html
@@ -0,0 +1,14 @@
+{% raw %}{% extends "base.html" %}
+
+{% block title %}Forbidden (403){% endblock title %}
+{% block content %}
+ Forbidden (403)
+
+ {% if exception %}
+ {{ exception }}
+ {% else %}
+ You're not allowed to access this page.
+ {% endif %}
+
+{% endblock content %}
+{%- endraw %}
diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/users/user_detail.html b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/users/user_detail.html
index 4e632b015..ab36ba56b 100644
--- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/users/user_detail.html
+++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/users/user_detail.html
@@ -22,11 +22,17 @@
{% else %}
{% raw %}{{ object.username }}{% endraw %}
{% endif %}
- {% raw %}
- {% if object.name %}{{ object.name }}
{% endif %}
+ {%- if cookiecutter.username_type == "username" %}
+ {%- raw %}
+ {% if object.name %}
+ {{ object.name }}
+ {% endif %}
+ {%- endraw %}
+ {%- endif %}
+ {%- raw %}
{% if object == request.user %}
diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/adapters.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/adapters.py
index c5c824bda..f9ae43a8e 100644
--- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/adapters.py
+++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/adapters.py
@@ -25,13 +25,14 @@ class SocialAccountAdapter(DefaultSocialAccountAdapter):
"""
Populates user information from social provider info.
- See: https://django-allauth.readthedocs.io/en/latest/advanced.html?#creating-and-populating-user-instances
+ See: https://docs.allauth.org/en/latest/socialaccount/advanced.html#creating-and-populating-user-instances
"""
- user = sociallogin.user
- if name := data.get("name"):
- user.name = name
- elif first_name := data.get("first_name"):
- user.name = first_name
- if last_name := data.get("last_name"):
- user.name += f" {last_name}"
- return super().populate_user(request, sociallogin, data)
+ user = super().populate_user(request, sociallogin, data)
+ if not user.name:
+ if name := data.get("name"):
+ user.name = name
+ elif first_name := data.get("first_name"):
+ user.name = first_name
+ if last_name := data.get("last_name"):
+ user.name += f" {last_name}"
+ return user
diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/admin.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/admin.py
index a5f89dd67..7fd49fa92 100644
--- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/admin.py
+++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/admin.py
@@ -10,7 +10,7 @@ User = get_user_model()
if settings.DJANGO_ADMIN_FORCE_ALLAUTH:
# Force the `admin` sign in process to go through the `django-allauth` workflow:
- # https://django-allauth.readthedocs.io/en/stable/advanced.html#admin
+ # https://docs.allauth.org/en/latest/common/admin.html#admin
admin.site.login = decorators.login_required(admin.site.login) # type: ignore[method-assign]
diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/utils/__init__.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/api/__init__.py
similarity index 100%
rename from {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/utils/__init__.py
rename to {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/api/__init__.py
diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/api/serializers.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/api/serializers.py
index 6b26367d0..0872d06f4 100644
--- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/api/serializers.py
+++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/api/serializers.py
@@ -1,10 +1,13 @@
from django.contrib.auth import get_user_model
from rest_framework import serializers
+from {{ cookiecutter.project_slug }}.users.models import User as UserType
+
+
User = get_user_model()
-class UserSerializer(serializers.ModelSerializer):
+class UserSerializer(serializers.ModelSerializer[UserType]):
class Meta:
model = User
{%- if cookiecutter.username_type == "email" %}
diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/managers.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/managers.py
index 017ab14e7..03ac29548 100644
--- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/managers.py
+++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/managers.py
@@ -1,8 +1,13 @@
+from typing import TYPE_CHECKING
+
from django.contrib.auth.hashers import make_password
from django.contrib.auth.models import UserManager as DjangoUserManager
+if TYPE_CHECKING:
+ from {{ cookiecutter.project_slug }}.users.models import User # noqa: F401
-class UserManager(DjangoUserManager):
+
+class UserManager(DjangoUserManager["User"]):
"""Custom manager for the User model."""
def _create_user(self, email: str, password: str | None, **extra_fields):
@@ -17,12 +22,12 @@ class UserManager(DjangoUserManager):
user.save(using=self._db)
return user
- def create_user(self, email: str, password: str | None = None, **extra_fields):
+ def create_user(self, email: str, password: str | None = None, **extra_fields): # type: ignore[override]
extra_fields.setdefault("is_staff", False)
extra_fields.setdefault("is_superuser", False)
return self._create_user(email, password, **extra_fields)
- def create_superuser(self, email: str, password: str | None = None, **extra_fields):
+ def create_superuser(self, email: str, password: str | None = None, **extra_fields): # type: ignore[override]
extra_fields.setdefault("is_staff", True)
extra_fields.setdefault("is_superuser", True)
diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/models.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/models.py
index 1e4807510..ccb6b78ae 100644
--- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/models.py
+++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/models.py
@@ -1,3 +1,7 @@
+{%- if cookiecutter.username_type == "email" %}
+from typing import ClassVar
+{%- endif %}
+
from django.contrib.auth.models import AbstractUser
from django.db.models import CharField{% if cookiecutter.username_type == "email" %}, EmailField{% endif %}
from django.urls import reverse
@@ -26,7 +30,7 @@ class User(AbstractUser):
USERNAME_FIELD = "email"
REQUIRED_FIELDS = []
- objects = UserManager()
+ objects: ClassVar[UserManager] = UserManager()
{%- endif %}
def get_absolute_url(self) -> str:
diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/factories.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/factories.py
index 4b86f7985..bebd8adcf 100644
--- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/factories.py
+++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/factories.py
@@ -29,6 +29,13 @@ class UserFactory(DjangoModelFactory):
)
self.set_password(password)
+ @classmethod
+ def _after_postgeneration(cls, instance, create, results=None):
+ """Save again the instance if creating and at least one hook ran."""
+ if create and results and not cls._meta.skip_postgeneration_save:
+ # Some post-generation hooks ran, and may have modified us.
+ instance.save()
+
class Meta:
model = get_user_model()
django_get_or_create = ["{{cookiecutter.username_type}}"]
diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_admin.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_admin.py
index 2991d18a9..75917ab34 100644
--- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_admin.py
+++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_admin.py
@@ -1,4 +1,10 @@
+from importlib import reload
+
+import pytest
+from django.contrib import admin
+from django.contrib.auth.models import AnonymousUser
from django.urls import reverse
+from pytest_django.asserts import assertRedirects
from {{ cookiecutter.project_slug }}.users.models import User
@@ -47,3 +53,25 @@ class TestUserAdmin:
url = reverse("admin:users_user_change", kwargs={"object_id": user.pk})
response = admin_client.get(url)
assert response.status_code == 200
+
+ @pytest.fixture
+ def force_allauth(self, settings):
+ settings.DJANGO_ADMIN_FORCE_ALLAUTH = True
+ # Reload the admin module to apply the setting change
+ import {{ cookiecutter.project_slug }}.users.admin as users_admin # pylint: disable=import-outside-toplevel
+
+ try:
+ reload(users_admin)
+ except admin.sites.AlreadyRegistered:
+ pass
+
+ @pytest.mark.django_db
+ @pytest.mark.usefixtures("force_allauth")
+ def test_allauth_login(self, rf, settings):
+ request = rf.get("/fake-url")
+ request.user = AnonymousUser()
+ response = admin.site.login(request)
+
+ # The `admin` login view should redirect to the `allauth` login view
+ target_url = reverse(settings.LOGIN_URL) + "?next=" + request.path
+ assertRedirects(response, target_url, fetch_redirect_response=False)
diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_forms.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_forms.py
index 023aad056..ca624c89a 100644
--- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_forms.py
+++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_forms.py
@@ -1,6 +1,5 @@
-"""
-Module for all Form Tests.
-"""
+"""Module for all Form Tests."""
+
from django.utils.translation import gettext_lazy as _
from {{ cookiecutter.project_slug }}.users.forms import UserAdminCreationForm
diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/utils/storages.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/utils/storages.py
deleted file mode 100644
index 27595ad1a..000000000
--- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/utils/storages.py
+++ /dev/null
@@ -1,36 +0,0 @@
-{% if cookiecutter.cloud_provider == 'AWS' -%}
-from storages.backends.s3boto3 import S3Boto3Storage
-
-
-class StaticRootS3Boto3Storage(S3Boto3Storage):
- location = "static"
- default_acl = "public-read"
-
-
-class MediaRootS3Boto3Storage(S3Boto3Storage):
- location = "media"
- file_overwrite = False
-{%- elif cookiecutter.cloud_provider == 'GCP' -%}
-from storages.backends.gcloud import GoogleCloudStorage
-
-
-class StaticRootGoogleCloudStorage(GoogleCloudStorage):
- location = "static"
- default_acl = "publicRead"
-
-
-class MediaRootGoogleCloudStorage(GoogleCloudStorage):
- location = "media"
- 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 %}