mirror of
https://github.com/cookiecutter/cookiecutter-django.git
synced 2025-08-08 14:04:52 +03:00
Merge branch 'cookiecutter:master' into main
This commit is contained in:
commit
fb6f148f41
1
.flake8
1
.flake8
|
@ -1,3 +1,4 @@
|
||||||
[flake8]
|
[flake8]
|
||||||
exclude = docs
|
exclude = docs
|
||||||
max-line-length = 119
|
max-line-length = 119
|
||||||
|
extend-ignore = E203
|
||||||
|
|
2
.github/ISSUE_TEMPLATE/bug.md
vendored
2
.github/ISSUE_TEMPLATE/bug.md
vendored
|
@ -42,7 +42,7 @@ labels: bug
|
||||||
|
|
||||||
- Python version, run `python3 -V`:
|
- Python version, run `python3 -V`:
|
||||||
- Docker version (if using Docker), run `docker --version`:
|
- 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):
|
- Options selected and/or [replay file](https://cookiecutter.readthedocs.io/en/latest/advanced/replay.html):
|
||||||
|
|
110
.github/contributors.json
vendored
110
.github/contributors.json
vendored
|
@ -1408,5 +1408,115 @@
|
||||||
"name": "Joseph Hanna",
|
"name": "Joseph Hanna",
|
||||||
"github_login": "sanchimenea",
|
"github_login": "sanchimenea",
|
||||||
"twitter_username": ""
|
"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": ""
|
||||||
}
|
}
|
||||||
]
|
]
|
2
.github/dependabot.yml
vendored
2
.github/dependabot.yml
vendored
|
@ -9,7 +9,7 @@ updates:
|
||||||
schedule:
|
schedule:
|
||||||
interval: "daily"
|
interval: "daily"
|
||||||
labels:
|
labels:
|
||||||
- "update"
|
- "project infrastructure"
|
||||||
|
|
||||||
# Update npm packages
|
# Update npm packages
|
||||||
- package-ecosystem: "npm"
|
- package-ecosystem: "npm"
|
||||||
|
|
18
.github/workflows/ci.yml
vendored
18
.github/workflows/ci.yml
vendored
|
@ -22,8 +22,8 @@ jobs:
|
||||||
name: "pytest ${{ matrix.os }}"
|
name: "pytest ${{ matrix.os }}"
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-python@v4
|
- uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: "3.11"
|
python-version: "3.11"
|
||||||
cache: pip
|
cache: pip
|
||||||
|
@ -53,8 +53,8 @@ jobs:
|
||||||
COMPOSE_DOCKER_CLI_BUILD: 1
|
COMPOSE_DOCKER_CLI_BUILD: 1
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-python@v4
|
- uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: "3.11"
|
python-version: "3.11"
|
||||||
cache: pip
|
cache: pip
|
||||||
|
@ -75,7 +75,7 @@ jobs:
|
||||||
- name: Webpack
|
- name: Webpack
|
||||||
args: "frontend_pipeline=Webpack use_heroku=y"
|
args: "frontend_pipeline=Webpack use_heroku=y"
|
||||||
- name: Email Username
|
- 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 }}"
|
name: "Bare metal ${{ matrix.script.name }}"
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
@ -97,8 +97,8 @@ jobs:
|
||||||
DATABASE_URL: "postgres://postgres:postgres@localhost:5432/postgres"
|
DATABASE_URL: "postgres://postgres:postgres@localhost:5432/postgres"
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-python@v4
|
- uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: "3.11"
|
python-version: "3.11"
|
||||||
cache: pip
|
cache: pip
|
||||||
|
@ -108,8 +108,8 @@ jobs:
|
||||||
{{cookiecutter.project_slug}}/requirements/local.txt
|
{{cookiecutter.project_slug}}/requirements/local.txt
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: pip install -r requirements.txt
|
run: pip install -r requirements.txt
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: "18"
|
node-version: "20"
|
||||||
- name: Bare Metal ${{ matrix.script.name }}
|
- name: Bare Metal ${{ matrix.script.name }}
|
||||||
run: sh tests/test_bare.sh ${{ matrix.script.args }}
|
run: sh tests/test_bare.sh ${{ matrix.script.args }}
|
||||||
|
|
4
.github/workflows/django-issue-checker.yml
vendored
4
.github/workflows/django-issue-checker.yml
vendored
|
@ -16,8 +16,8 @@ jobs:
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-python@v4
|
- uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: "3.11"
|
python-version: "3.11"
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
|
|
9
.github/workflows/issue-manager.yml
vendored
9
.github/workflows/issue-manager.yml
vendored
|
@ -23,18 +23,25 @@ jobs:
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: tiangolo/issue-manager@0.4.0
|
- uses: tiangolo/issue-manager@0.5.0
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
config: >
|
config: >
|
||||||
{
|
{
|
||||||
"answered": {
|
"answered": {
|
||||||
|
"delay": 864000,
|
||||||
"message": "Assuming the question was answered, this will be automatically closed now."
|
"message": "Assuming the question was answered, this will be automatically closed now."
|
||||||
},
|
},
|
||||||
"solved": {
|
"solved": {
|
||||||
|
"delay": 864000,
|
||||||
"message": "Assuming the original issue was solved, it will be automatically closed now."
|
"message": "Assuming the original issue was solved, it will be automatically closed now."
|
||||||
},
|
},
|
||||||
"waiting": {
|
"waiting": {
|
||||||
|
"delay": 864000,
|
||||||
"message": "Automatically closing after waiting for additional info. To re-open, please provide the additional information requested."
|
"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."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
6
.github/workflows/pre-commit-autoupdate.yml
vendored
6
.github/workflows/pre-commit-autoupdate.yml
vendored
|
@ -21,8 +21,8 @@ jobs:
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-python@v4
|
- uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: "3.11"
|
python-version: "3.11"
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ jobs:
|
||||||
run: pre-commit autoupdate
|
run: pre-commit autoupdate
|
||||||
|
|
||||||
- name: Create Pull Request
|
- name: Create Pull Request
|
||||||
uses: peter-evans/create-pull-request@v5
|
uses: peter-evans/create-pull-request@v6
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
branch: update/pre-commit-autoupdate
|
branch: update/pre-commit-autoupdate
|
||||||
|
|
4
.github/workflows/update-changelog.yml
vendored
4
.github/workflows/update-changelog.yml
vendored
|
@ -14,10 +14,10 @@ jobs:
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: "3.11"
|
python-version: "3.11"
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
|
|
6
.github/workflows/update-contributors.yml
vendored
6
.github/workflows/update-contributors.yml
vendored
|
@ -17,10 +17,10 @@ jobs:
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: "3.11"
|
python-version: "3.11"
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
|
@ -33,7 +33,7 @@ jobs:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Commit changes
|
- name: Commit changes
|
||||||
uses: stefanzweifel/git-auto-commit-action@v4.16.0
|
uses: stefanzweifel/git-auto-commit-action@v5.0.0
|
||||||
with:
|
with:
|
||||||
commit_message: Update Contributors
|
commit_message: Update Contributors
|
||||||
file_pattern: CONTRIBUTORS.md .github/contributors.json
|
file_pattern: CONTRIBUTORS.md .github/contributors.json
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
exclude: "{{cookiecutter.project_slug}}|.github/contributors.json|CHANGELOG.md|CONTRIBUTORS.md"
|
exclude: "{{cookiecutter.project_slug}}|.github/contributors.json|CHANGELOG.md|CONTRIBUTORS.md"
|
||||||
default_stages: [commit]
|
default_stages: [commit]
|
||||||
|
|
||||||
|
default_language_version:
|
||||||
|
python: python3.11
|
||||||
|
|
||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
rev: v4.4.0
|
rev: v4.5.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: trailing-whitespace
|
- id: trailing-whitespace
|
||||||
- id: end-of-file-fixer
|
- id: end-of-file-fixer
|
||||||
|
@ -17,30 +20,30 @@ repos:
|
||||||
- id: detect-private-key
|
- id: detect-private-key
|
||||||
|
|
||||||
- repo: https://github.com/pre-commit/mirrors-prettier
|
- repo: https://github.com/pre-commit/mirrors-prettier
|
||||||
rev: "v3.0.0-alpha.9-for-vscode"
|
rev: "v4.0.0-alpha.8"
|
||||||
hooks:
|
hooks:
|
||||||
- id: prettier
|
- id: prettier
|
||||||
args: ["--tab-width", "2"]
|
args: ["--tab-width", "2"]
|
||||||
|
|
||||||
- repo: https://github.com/asottile/pyupgrade
|
- repo: https://github.com/asottile/pyupgrade
|
||||||
rev: v3.8.0
|
rev: v3.15.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: pyupgrade
|
- id: pyupgrade
|
||||||
args: [--py311-plus]
|
args: [--py311-plus]
|
||||||
exclude: hooks/
|
exclude: hooks/
|
||||||
|
|
||||||
- repo: https://github.com/psf/black
|
- repo: https://github.com/psf/black
|
||||||
rev: 23.3.0
|
rev: 24.1.1
|
||||||
hooks:
|
hooks:
|
||||||
- id: black
|
- id: black
|
||||||
|
|
||||||
- repo: https://github.com/PyCQA/isort
|
- repo: https://github.com/PyCQA/isort
|
||||||
rev: 5.12.0
|
rev: 5.13.2
|
||||||
hooks:
|
hooks:
|
||||||
- id: isort
|
- id: isort
|
||||||
|
|
||||||
- repo: https://github.com/PyCQA/flake8
|
- repo: https://github.com/PyCQA/flake8
|
||||||
rev: 6.0.0
|
rev: 7.0.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: flake8
|
- id: flake8
|
||||||
|
|
||||||
|
|
1077
CHANGELOG.md
1077
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
154
CONTRIBUTORS.md
154
CONTRIBUTORS.md
|
@ -194,6 +194,13 @@ Listed in alphabetical order.
|
||||||
</td>
|
</td>
|
||||||
<td>scaramagus</td>
|
<td>scaramagus</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>aiden</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://github.com/anyidea">anyidea</a>
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Alberto Sanchez</td>
|
<td>Alberto Sanchez</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -509,6 +516,13 @@ Listed in alphabetical order.
|
||||||
</td>
|
</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Christian Jauvin</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://github.com/cjauvin">cjauvin</a>
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Christopher Clarke</td>
|
<td>Christopher Clarke</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -796,6 +810,13 @@ Listed in alphabetical order.
|
||||||
</td>
|
</td>
|
||||||
<td>fabaff</td>
|
<td>fabaff</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Fateme Fouladkar</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://github.com/FatemeFouladkar">FatemeFouladkar</a>
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Felipe Arruda</td>
|
<td>Felipe Arruda</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -817,6 +838,13 @@ Listed in alphabetical order.
|
||||||
</td>
|
</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Freddy</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://github.com/Hraesvelg">Hraesvelg</a>
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Fuzzwah</td>
|
<td>Fuzzwah</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -859,6 +887,13 @@ Listed in alphabetical order.
|
||||||
</td>
|
</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>GitBib</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://github.com/GitBib">GitBib</a>
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Glenn Wiskur</td>
|
<td>Glenn Wiskur</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -929,6 +964,13 @@ Listed in alphabetical order.
|
||||||
</td>
|
</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>henningbra</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://github.com/henningbra">henningbra</a>
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Henrique G. G. Pereira</td>
|
<td>Henrique G. G. Pereira</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -936,6 +978,13 @@ Listed in alphabetical order.
|
||||||
</td>
|
</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>hleroy</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://github.com/hleroy">hleroy</a>
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Hoai-Thu Vuong</td>
|
<td>Hoai-Thu Vuong</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -957,6 +1006,13 @@ Listed in alphabetical order.
|
||||||
</td>
|
</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Imran Rahman</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://github.com/infraredCoding">infraredCoding</a>
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>innicoder</td>
|
<td>innicoder</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -978,6 +1034,13 @@ Listed in alphabetical order.
|
||||||
</td>
|
</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>itisnotyourenv</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://github.com/itisnotyourenv">itisnotyourenv</a>
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Ivan Khomutov</td>
|
<td>Ivan Khomutov</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -985,6 +1048,13 @@ Listed in alphabetical order.
|
||||||
</td>
|
</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Jakub Boukal</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://github.com/SukiCZ">SukiCZ</a>
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Jakub Musko</td>
|
<td>Jakub Musko</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -1013,6 +1083,13 @@ Listed in alphabetical order.
|
||||||
</td>
|
</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Jens Kaeske</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://github.com/jkaeske">jkaeske</a>
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Jens Nilsson</td>
|
<td>Jens Nilsson</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -1433,6 +1510,13 @@ Listed in alphabetical order.
|
||||||
</td>
|
</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Michael V. Battista</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://github.com/mvbattista">mvbattista</a>
|
||||||
|
</td>
|
||||||
|
<td>mvbattista</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Mike97M</td>
|
<td>Mike97M</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -1447,6 +1531,13 @@ Listed in alphabetical order.
|
||||||
</td>
|
</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>MinWoo Sung</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://github.com/SungMinWoo">SungMinWoo</a>
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>monosans</td>
|
<td>monosans</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -1503,6 +1594,13 @@ Listed in alphabetical order.
|
||||||
</td>
|
</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Nix Siow</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://github.com/nixsiow">nixsiow</a>
|
||||||
|
</td>
|
||||||
|
<td>nixsiow</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Noah H</td>
|
<td>Noah H</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -1601,6 +1699,13 @@ Listed in alphabetical order.
|
||||||
</td>
|
</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Plurific</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://github.com/paulschwenn">paulschwenn</a>
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Raony Guimarães Corrêa</td>
|
<td>Raony Guimarães Corrêa</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -1685,6 +1790,13 @@ Listed in alphabetical order.
|
||||||
</td>
|
</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Sadra Yahyapour</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://github.com/lnxpy">lnxpy</a>
|
||||||
|
</td>
|
||||||
|
<td>lnxpylnxpy</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Sam Collins</td>
|
<td>Sam Collins</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -1706,6 +1818,13 @@ Listed in alphabetical order.
|
||||||
</td>
|
</td>
|
||||||
<td>sebastianreyese</td>
|
<td>sebastianreyese</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Shayan Karimi</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://github.com/shywn-mrk">shywn-mrk</a>
|
||||||
|
</td>
|
||||||
|
<td>shywn_mrk</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Simon Rey</td>
|
<td>Simon Rey</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -1790,6 +1909,13 @@ Listed in alphabetical order.
|
||||||
</td>
|
</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Tharushan</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://github.com/Tharushan">Tharushan</a>
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Thibault J.</td>
|
<td>Thibault J.</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -1839,6 +1965,13 @@ Listed in alphabetical order.
|
||||||
</td>
|
</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>tmajerech</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://github.com/tmajerech">tmajerech</a>
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Tom Atkins</td>
|
<td>Tom Atkins</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -1881,6 +2014,13 @@ Listed in alphabetical order.
|
||||||
</td>
|
</td>
|
||||||
<td>egregors</td>
|
<td>egregors</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Vageeshan Mankala</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://github.com/vagi8">vagi8</a>
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>vascop</td>
|
<td>vascop</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -1902,6 +2042,13 @@ Listed in alphabetical order.
|
||||||
</td>
|
</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>villancikos</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://github.com/villancikos">villancikos</a>
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Vitaly Babiy</td>
|
<td>Vitaly Babiy</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -1986,6 +2133,13 @@ Listed in alphabetical order.
|
||||||
</td>
|
</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>zhaoruibing</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://github.com/zhaoruibing">zhaoruibing</a>
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
### Special Thanks
|
### Special Thanks
|
||||||
|
|
|
@ -23,7 +23,7 @@ production-ready Django projects quickly.
|
||||||
- Works with Python 3.11
|
- Works with Python 3.11
|
||||||
- Renders Django projects with 100% starting test coverage
|
- Renders Django projects with 100% starting test coverage
|
||||||
- Twitter [Bootstrap](https://github.com/twbs/bootstrap) v5
|
- 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.
|
- Secure by default. We believe in SSL.
|
||||||
- Optimized development and production settings
|
- Optimized development and production settings
|
||||||
- Registration via [django-allauth](https://github.com/pennersr/django-allauth)
|
- 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/)
|
- Serve static files from Amazon S3, Google Cloud Storage, Azure Storage or [Whitenoise](https://whitenoise.readthedocs.io/)
|
||||||
- Configuration for [Celery](https://docs.celeryq.dev) and [Flower](https://github.com/mher/flower) (the latter in Docker setup only)
|
- Configuration for [Celery](https://docs.celeryq.dev) and [Flower](https://github.com/mher/flower) (the latter in Docker setup only)
|
||||||
- Integration with [MailHog](https://github.com/mailhog/MailHog) for local email testing
|
- Integration with [Mailpit](https://github.com/axllent/mailpit/) for local email testing
|
||||||
- Integration with [Sentry](https://sentry.io/welcome/) for error logging
|
- Integration with [Sentry](https://sentry.io/welcome/) for error logging
|
||||||
|
|
||||||
## Constraints
|
## Constraints
|
||||||
|
@ -165,7 +165,7 @@ Answer the prompts with your own desired [options](http://cookiecutter-django.re
|
||||||
4 - Webpack
|
4 - Webpack
|
||||||
Choose from 1, 2, 3, 4 [1]: 1
|
Choose from 1, 2, 3, 4 [1]: 1
|
||||||
use_celery [n]: y
|
use_celery [n]: y
|
||||||
use_mailhog [n]: n
|
use_mailpit [n]: n
|
||||||
use_sentry [n]: y
|
use_sentry [n]: y
|
||||||
use_whitenoise [n]: n
|
use_whitenoise [n]: n
|
||||||
use_heroku [n]: y
|
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).
|
- 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 anything else, you can chat with us on [Discord](https://discord.gg/uFXweDQc5a).
|
||||||
|
|
||||||
|
<img src="https://opencollective.com/cookiecutter-django/contributors.svg?width=890&button=false" alt="Contributors">
|
||||||
|
|
||||||
## For Readers of Two Scoops of Django
|
## 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.
|
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
|
## 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
|
- [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
|
- [Complete Walkthrough: Blue/Green Deployment to AWS ECS using GitHub actions](https://github.com/Andrew-Chen-Wang/cookiecutter-django-ecs-github) - June 10, 2020
|
||||||
- [Using cookiecutter-django with Google Cloud Storage](https://ahhda.github.io/cloud/gce/django/2019/03/12/using-django-cookiecutter-cloud-storage.html) - Mar. 12, 2019
|
- [Using cookiecutter-django with Google Cloud Storage](https://ahhda.github.io/cloud/gce/django/2019/03/12/using-django-cookiecutter-cloud-storage.html) - Mar. 12, 2019
|
||||||
|
|
|
@ -35,11 +35,11 @@
|
||||||
"use_drf": "n",
|
"use_drf": "n",
|
||||||
"frontend_pipeline": ["None", "Django Compressor", "Gulp", "Webpack"],
|
"frontend_pipeline": ["None", "Django Compressor", "Gulp", "Webpack"],
|
||||||
"use_celery": "n",
|
"use_celery": "n",
|
||||||
"use_mailhog": "n",
|
"use_mailpit": "n",
|
||||||
"use_sentry": "n",
|
"use_sentry": "n",
|
||||||
"use_whitenoise": "n",
|
"use_whitenoise": "n",
|
||||||
"use_heroku": "n",
|
"use_heroku": "n",
|
||||||
"ci_tool": ["None", "Travis", "Gitlab", "Github"],
|
"ci_tool": ["None", "Travis", "Gitlab", "Github", "Drone"],
|
||||||
"keep_local_envs_in_vcs": "y",
|
"keep_local_envs_in_vcs": "y",
|
||||||
"debug": "n"
|
"debug": "n"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
Deployment with Docker
|
Deployment with Docker
|
||||||
======================
|
======================
|
||||||
|
|
||||||
.. index:: deployment, docker, docker-compose, compose
|
.. index:: deployment, docker, docker compose, compose
|
||||||
|
|
||||||
|
|
||||||
Prerequisites
|
Prerequisites
|
||||||
|
@ -89,7 +89,7 @@ You can read more about this feature and how to configure it, at `Automatic HTTP
|
||||||
Webpack without Whitenoise limitation
|
Webpack without Whitenoise limitation
|
||||||
-------------------------------------
|
-------------------------------------
|
||||||
|
|
||||||
If you opt for Webpack without Whitenoise, Webpack needs to know the static URL at build time, when running ``docker-compose build`` (See ``webpack/prod.config.js``). Depending on your setup, this URL may come from the following environment variables:
|
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``
|
- ``AWS_STORAGE_BUCKET_NAME``
|
||||||
- ``DJANGO_AWS_S3_CUSTOM_DOMAIN``
|
- ``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).
|
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::
|
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.
|
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::
|
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::
|
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::
|
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::
|
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::
|
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::
|
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::
|
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::
|
If you want to scale your application, run::
|
||||||
|
|
||||||
docker-compose -f production.yml up --scale django=4
|
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 celeryworker=2
|
||||||
|
|
||||||
.. warning:: don't try to scale ``postgres``, ``celerybeat``, or ``traefik``.
|
.. warning:: don't try to scale ``postgres``, ``celerybeat``, or ``traefik``.
|
||||||
|
|
||||||
To see how your containers are doing run::
|
To see how your containers are doing run::
|
||||||
|
|
||||||
docker-compose -f production.yml ps
|
docker compose -f production.yml ps
|
||||||
|
|
||||||
|
|
||||||
Example: Supervisor
|
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
|
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
|
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::
|
If you are using ``supervisor``, you can use this file as a starting point::
|
||||||
|
|
||||||
[program:{{cookiecutter.project_slug}}]
|
[program:{{cookiecutter.project_slug}}]
|
||||||
command=docker-compose -f production.yml up
|
command=docker compose -f production.yml up
|
||||||
directory=/path/to/{{cookiecutter.project_slug}}
|
directory=/path/to/{{cookiecutter.project_slug}}
|
||||||
redirect_stderr=true
|
redirect_stderr=true
|
||||||
autostart=true
|
autostart=true
|
||||||
|
|
|
@ -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::
|
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!
|
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::
|
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::
|
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::
|
And then run::
|
||||||
|
|
||||||
$ docker-compose up
|
$ docker compose up
|
||||||
|
|
||||||
To run in a detached (background) mode, just::
|
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
|
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 migrate
|
||||||
$ docker-compose -f local.yml run --rm django python manage.py createsuperuser
|
$ docker compose -f local.yml run --rm django python manage.py createsuperuser
|
||||||
|
|
||||||
Here, ``django`` is the target service we are executing the commands against.
|
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
|
(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: ::
|
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 build
|
||||||
docker-compose -f local.yml up
|
docker compose -f local.yml up
|
||||||
|
|
||||||
Debugging
|
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: ::
|
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
|
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
|
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 ``<project_slug>_local_mailhog`` container is up and running;
|
#. make sure ``<project_slug>_local_mailpit`` container is up and running;
|
||||||
|
|
||||||
#. open up ``http://127.0.0.1:8025``.
|
#. open up ``http://127.0.0.1:8025``.
|
||||||
|
|
||||||
.. _Mailhog: https://github.com/mailhog/MailHog/
|
.. _Mailpit: https://github.com/axllent/mailpit/
|
||||||
|
|
||||||
.. _`CeleryTasks`:
|
.. _`CeleryTasks`:
|
||||||
|
|
||||||
|
@ -229,7 +231,12 @@ By default, it's enabled both in local and production environments (``local.yml`
|
||||||
Using Webpack or Gulp
|
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
|
Developing locally with HTTPS
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
@ -309,7 +316,7 @@ You should allow the new hostname. ::
|
||||||
|
|
||||||
Rebuild your ``docker`` application. ::
|
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``
|
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.
|
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``.
|
*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`
|
||||||
|
},
|
||||||
|
|
|
@ -80,10 +80,12 @@ First things first.
|
||||||
|
|
||||||
$ python manage.py runserver 0.0.0.0:8000
|
$ 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'
|
$ 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 <bare-metal-webpack-gulp>` below.
|
||||||
|
|
||||||
.. _PostgreSQL: https://www.postgresql.org/download/
|
.. _PostgreSQL: https://www.postgresql.org/download/
|
||||||
.. _Redis: https://redis.io/download
|
.. _Redis: https://redis.io/download
|
||||||
.. _CookieCutter: https://github.com/cookiecutter/cookiecutter
|
.. _CookieCutter: https://github.com/cookiecutter/cookiecutter
|
||||||
|
@ -97,39 +99,37 @@ or if you're running asynchronously: ::
|
||||||
Setup Email Backend
|
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.
|
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 binary file to the project root.
|
||||||
|
|
||||||
#. Copy the file to the project root.
|
|
||||||
|
|
||||||
#. Make it executable: ::
|
#. Make it executable: ::
|
||||||
|
|
||||||
$ chmod +x MailHog
|
$ chmod +x mailpit
|
||||||
|
|
||||||
#. Spin up another terminal window and start it there: ::
|
#. Spin up another terminal window and start it there: ::
|
||||||
|
|
||||||
./MailHog
|
./mailpit
|
||||||
|
|
||||||
#. Check out `<http://127.0.0.1:8025/>`_ to see how it goes.
|
#. Check out `<http://127.0.0.1:8025/>`_ to see how it goes.
|
||||||
|
|
||||||
Now you have your own mail server running locally, ready to receive whatever you send it.
|
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
|
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'``.
|
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/
|
.. _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.
|
#. Make sure that `Node.js`_ v18 is installed on your machine.
|
||||||
#. In the project root, install the JS dependencies with::
|
#. 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
|
$ 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/
|
.. _Node.js: http://nodejs.org/download/
|
||||||
.. _Sass: https://sass-lang.com/
|
.. _Sass: https://sass-lang.com/
|
||||||
|
|
|
@ -8,7 +8,7 @@ Prerequisites
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
#. the project was generated with ``use_docker`` set to ``y``;
|
#. 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
|
Creating a Backup
|
||||||
|
@ -16,7 +16,7 @@ Creating a Backup
|
||||||
|
|
||||||
To create a backup, run::
|
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: ::
|
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, ::
|
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``: ::
|
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 .
|
$ 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/
|
.. _`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), ::
|
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 ::
|
You will see something like ::
|
||||||
|
|
||||||
|
@ -92,7 +92,15 @@ You will see something like ::
|
||||||
|
|
||||||
Backup to Amazon S3
|
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. ::
|
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 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 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
|
||||||
|
|
|
@ -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: ::
|
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.
|
Navigate to port 9000 on your host to see the documentation. This will be opened automatically at `localhost`_ for local, non-docker development.
|
||||||
|
|
||||||
|
|
|
@ -115,8 +115,8 @@ Both Gulp and Webpack support Bootstrap recompilation with real-time variables a
|
||||||
use_celery:
|
use_celery:
|
||||||
Indicates whether the project should be configured to use Celery_.
|
Indicates whether the project should be configured to use Celery_.
|
||||||
|
|
||||||
use_mailhog:
|
use_mailpit:
|
||||||
Indicates whether the project should be configured to use MailHog_.
|
Indicates whether the project should be configured to use Mailpit_.
|
||||||
|
|
||||||
use_sentry:
|
use_sentry:
|
||||||
Indicates whether the project should be configured to use Sentry_.
|
Indicates whether the project should be configured to use Sentry_.
|
||||||
|
@ -135,6 +135,7 @@ ci_tool:
|
||||||
2. `Travis CI`_
|
2. `Travis CI`_
|
||||||
3. `Gitlab CI`_
|
3. `Gitlab CI`_
|
||||||
4. `Github Actions`_
|
4. `Github Actions`_
|
||||||
|
5. `Drone CI`_
|
||||||
|
|
||||||
keep_local_envs_in_vcs:
|
keep_local_envs_in_vcs:
|
||||||
Indicates whether the project's ``.envs/.local/`` should be kept in VCS
|
Indicates whether the project's ``.envs/.local/`` should be kept in VCS
|
||||||
|
@ -184,7 +185,7 @@ debug:
|
||||||
|
|
||||||
.. _Celery: https://github.com/celery/celery
|
.. _Celery: https://github.com/celery/celery
|
||||||
|
|
||||||
.. _MailHog: https://github.com/mailhog/MailHog
|
.. _Mailpit: https://github.com/axllent/mailpit
|
||||||
|
|
||||||
.. _Sentry: https://github.com/getsentry/sentry
|
.. _Sentry: https://github.com/getsentry/sentry
|
||||||
|
|
||||||
|
@ -196,4 +197,6 @@ debug:
|
||||||
|
|
||||||
.. _GitLab CI: https://docs.gitlab.com/ee/ci/
|
.. _GitLab CI: https://docs.gitlab.com/ee/ci/
|
||||||
|
|
||||||
|
.. _Drone CI: https://docs.drone.io/pipeline/overview/
|
||||||
|
|
||||||
.. _Github Actions: https://docs.github.com/en/actions
|
.. _Github Actions: https://docs.github.com/en/actions
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
sphinx==6.2.1
|
sphinx==7.2.6
|
||||||
sphinx-rtd-theme==1.2.2
|
sphinx-rtd-theme==2.0.0
|
||||||
myst-parser==2.0.0
|
myst-parser==2.0.0
|
||||||
|
|
|
@ -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: ::
|
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.
|
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: ::
|
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 run -m pytest
|
||||||
$ docker-compose -f local.yml run --rm django coverage report
|
$ docker compose -f local.yml run --rm django coverage report
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
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.
|
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::
|
.. seealso::
|
||||||
|
|
||||||
|
|
|
@ -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:
|
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 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 "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:
|
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 Docker volume sub-commands to find volumes (`ls`_) and remove them (`rm`_).
|
||||||
- Use the `prune`_ command to clear system-wide (use with care!).
|
- Use the `prune`_ command to clear system-wide (use with care!).
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ NOTE:
|
||||||
TODO: restrict Cookiecutter Django project initialization to
|
TODO: restrict Cookiecutter Django project initialization to
|
||||||
Python 3.x environments only
|
Python 3.x environments only
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
@ -80,7 +81,7 @@ def remove_docker_files():
|
||||||
file_names = ["local.yml", "production.yml", ".dockerignore"]
|
file_names = ["local.yml", "production.yml", ".dockerignore"]
|
||||||
for file_name in file_names:
|
for file_name in file_names:
|
||||||
os.remove(file_name)
|
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"]
|
file_names = ["docker_compose_up_django.xml", "docker_compose_up_docs.xml"]
|
||||||
for file_name in file_names:
|
for file_name in file_names:
|
||||||
os.remove(os.path.join(".idea", "runConfigurations", file_name))
|
os.remove(os.path.join(".idea", "runConfigurations", file_name))
|
||||||
|
@ -183,6 +184,7 @@ def handle_js_runner(choice, use_docker, use_async):
|
||||||
"browser-sync",
|
"browser-sync",
|
||||||
"cssnano",
|
"cssnano",
|
||||||
"gulp",
|
"gulp",
|
||||||
|
"gulp-concat",
|
||||||
"gulp-imagemin",
|
"gulp-imagemin",
|
||||||
"gulp-plumber",
|
"gulp-plumber",
|
||||||
"gulp-postcss",
|
"gulp-postcss",
|
||||||
|
@ -207,6 +209,24 @@ def handle_js_runner(choice, use_docker, use_async):
|
||||||
remove_gulp_files()
|
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():
|
def remove_celery_files():
|
||||||
file_names = [
|
file_names = [
|
||||||
os.path.join("config", "celery_app.py"),
|
os.path.join("config", "celery_app.py"),
|
||||||
|
@ -238,6 +258,10 @@ def remove_dotgithub_folder():
|
||||||
shutil.rmtree(".github")
|
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):
|
def generate_random_string(length, using_digits=False, using_ascii_letters=False, using_punctuation=False):
|
||||||
"""
|
"""
|
||||||
Example:
|
Example:
|
||||||
|
@ -406,10 +430,6 @@ def remove_drf_starter_files():
|
||||||
os.remove(os.path.join("{{cookiecutter.project_slug}}", "users", "tests", "test_swagger.py"))
|
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():
|
def main():
|
||||||
debug = "{{ cookiecutter.debug }}".lower() == "y"
|
debug = "{{ cookiecutter.debug }}".lower() == "y"
|
||||||
|
|
||||||
|
@ -428,7 +448,7 @@ def main():
|
||||||
if "{{ cookiecutter.username_type }}" == "username":
|
if "{{ cookiecutter.username_type }}" == "username":
|
||||||
remove_custom_user_manager_files()
|
remove_custom_user_manager_files()
|
||||||
|
|
||||||
if "{{ cookiecutter.editor }}".lower() != "PyCharm":
|
if "{{ cookiecutter.editor }}" != "PyCharm":
|
||||||
remove_pycharm_files()
|
remove_pycharm_files()
|
||||||
|
|
||||||
if "{{ cookiecutter.use_docker }}".lower() == "y":
|
if "{{ cookiecutter.use_docker }}".lower() == "y":
|
||||||
|
@ -461,6 +481,7 @@ def main():
|
||||||
remove_webpack_files()
|
remove_webpack_files()
|
||||||
remove_sass_files()
|
remove_sass_files()
|
||||||
remove_packagejson_file()
|
remove_packagejson_file()
|
||||||
|
remove_prettier_pre_commit()
|
||||||
if "{{ cookiecutter.use_docker }}".lower() == "y":
|
if "{{ cookiecutter.use_docker }}".lower() == "y":
|
||||||
remove_node_dockerfile()
|
remove_node_dockerfile()
|
||||||
else:
|
else:
|
||||||
|
@ -475,7 +496,6 @@ def main():
|
||||||
WARNING + "You chose to not use any cloud providers nor Docker, "
|
WARNING + "You chose to not use any cloud providers nor Docker, "
|
||||||
"media files won't be served in production." + TERMINATOR
|
"media files won't be served in production." + TERMINATOR
|
||||||
)
|
)
|
||||||
remove_storages_module()
|
|
||||||
|
|
||||||
if "{{ cookiecutter.use_celery }}".lower() == "n":
|
if "{{ cookiecutter.use_celery }}".lower() == "n":
|
||||||
remove_celery_files()
|
remove_celery_files()
|
||||||
|
@ -491,6 +511,9 @@ def main():
|
||||||
if "{{ cookiecutter.ci_tool }}" != "Github":
|
if "{{ cookiecutter.ci_tool }}" != "Github":
|
||||||
remove_dotgithub_folder()
|
remove_dotgithub_folder()
|
||||||
|
|
||||||
|
if "{{ cookiecutter.ci_tool }}" != "Drone":
|
||||||
|
remove_dotdrone_file()
|
||||||
|
|
||||||
if "{{ cookiecutter.use_drf }}".lower() == "n":
|
if "{{ cookiecutter.use_drf }}".lower() == "n":
|
||||||
remove_drf_starter_files()
|
remove_drf_starter_files()
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ NOTE:
|
||||||
TODO: restrict Cookiecutter Django project initialization
|
TODO: restrict Cookiecutter Django project initialization
|
||||||
to Python 3.x environments only
|
to Python 3.x environments only
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
|
@ -1,28 +1,28 @@
|
||||||
cookiecutter==2.1.1
|
cookiecutter==2.5.0
|
||||||
sh==2.0.4; sys_platform != "win32"
|
sh==2.0.6; sys_platform != "win32"
|
||||||
binaryornot==0.4.4
|
binaryornot==0.4.4
|
||||||
|
|
||||||
# Code quality
|
# Code quality
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
black==23.3.0
|
black==24.1.1
|
||||||
isort==5.12.0
|
isort==5.13.2
|
||||||
flake8==6.0.0
|
flake8==7.0.0
|
||||||
django-upgrade==1.14.0
|
django-upgrade==1.16.0
|
||||||
djlint==1.31.1
|
djlint==1.34.1
|
||||||
pre-commit==3.3.3
|
pre-commit==3.6.1
|
||||||
|
|
||||||
# Testing
|
# Testing
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
tox==4.6.3
|
tox==4.12.1
|
||||||
pytest==7.4.0
|
pytest==8.0.0
|
||||||
pytest-xdist==3.3.1
|
pytest-xdist==3.5.0
|
||||||
pytest-cookies==0.7.0
|
pytest-cookies==0.7.0
|
||||||
pytest-instafail==0.5.0
|
pytest-instafail==0.5.0
|
||||||
pyyaml==6.0
|
pyyaml==6.0.1
|
||||||
|
|
||||||
# Scripting
|
# Scripting
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
PyGithub==1.59.0
|
PyGithub==2.2.0
|
||||||
gitpython==3.1.31
|
gitpython==3.1.41
|
||||||
jinja2==3.1.2
|
jinja2==3.1.3
|
||||||
requests==2.31.0
|
requests==2.31.0
|
||||||
|
|
|
@ -6,6 +6,7 @@ patches, only comparing major and minor version numbers.
|
||||||
This script handles when there are multiple Django versions that need
|
This script handles when there are multiple Django versions that need
|
||||||
to keep up to date.
|
to keep up to date.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
@ -182,9 +183,8 @@ class GitHubManager:
|
||||||
if not matches:
|
if not matches:
|
||||||
continue
|
continue
|
||||||
issue_version = DjVersion.parse(matches.group(1))
|
issue_version = DjVersion.parse(matches.group(1))
|
||||||
if self.base_dj_version > issue_version:
|
if self.base_dj_version >= issue_version:
|
||||||
issue.edit(state="closed")
|
self.close_issue(issue)
|
||||||
print(f"Closed issue {issue.title} (ID: [{issue.id}]({issue.url}))")
|
|
||||||
else:
|
else:
|
||||||
self.existing_issues[issue_version] = issue
|
self.existing_issues[issue_version] = issue
|
||||||
|
|
||||||
|
@ -213,7 +213,7 @@ class GitHubManager:
|
||||||
for classifier in package_info["info"]["classifiers"]:
|
for classifier in package_info["info"]["classifiers"]:
|
||||||
# Usually in the form of "Framework :: Django :: 3.2"
|
# Usually in the form of "Framework :: Django :: 3.2"
|
||||||
tokens = classifier.split(" ")
|
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])
|
version = DjVersion.parse(tokens[4])
|
||||||
if len(version) == 2:
|
if len(version) == 2:
|
||||||
supported_dj_versions.append(version)
|
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 = self.repo.create_issue(f"[Update Django] Django {needed_dj_version}", description)
|
||||||
issue.add_to_labels(f"django{needed_dj_version}")
|
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):
|
def generate(self):
|
||||||
for version in self.needed_dj_versions:
|
for version in self.needed_dj_versions:
|
||||||
print(f"Handling GitHub issue for Django {version}")
|
print(f"Handling GitHub issue for Django {version}")
|
||||||
|
@ -280,10 +285,15 @@ class GitHubManager:
|
||||||
def main(django_max_version=None) -> None:
|
def main(django_max_version=None) -> None:
|
||||||
# Check if there are any djs
|
# Check if there are any djs
|
||||||
current_dj, latest_djs = get_all_latest_django_versions(django_max_version=django_max_version)
|
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 = GitHubManager(current_dj, latest_djs)
|
||||||
manager.setup()
|
manager.setup()
|
||||||
|
|
||||||
|
if not latest_djs:
|
||||||
|
print("No new Django versions to update. Exiting...")
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
manager.generate()
|
manager.generate()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,9 @@ def main() -> None:
|
||||||
|
|
||||||
# Group pull requests by type of change
|
# Group pull requests by type of change
|
||||||
grouped_pulls = group_pulls_by_change_type(merged_pulls)
|
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
|
# Generate portion of markdown
|
||||||
release_changes_summary = generate_md(grouped_pulls)
|
release_changes_summary = generate_md(grouped_pulls)
|
||||||
|
|
4
setup.py
4
setup.py
|
@ -5,9 +5,9 @@ except ImportError:
|
||||||
from distutils.core import setup
|
from distutils.core import setup
|
||||||
|
|
||||||
# We use calendar versioning
|
# 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()
|
long_description = readme_file.read()
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
|
|
|
@ -115,8 +115,8 @@ SUPPORTED_COMBINATIONS = [
|
||||||
{"frontend_pipeline": "Webpack"},
|
{"frontend_pipeline": "Webpack"},
|
||||||
{"use_celery": "y"},
|
{"use_celery": "y"},
|
||||||
{"use_celery": "n"},
|
{"use_celery": "n"},
|
||||||
{"use_mailhog": "y"},
|
{"use_mailpit": "y"},
|
||||||
{"use_mailhog": "n"},
|
{"use_mailpit": "n"},
|
||||||
{"use_sentry": "y"},
|
{"use_sentry": "y"},
|
||||||
{"use_sentry": "n"},
|
{"use_sentry": "n"},
|
||||||
{"use_whitenoise": "y"},
|
{"use_whitenoise": "y"},
|
||||||
|
@ -127,6 +127,7 @@ SUPPORTED_COMBINATIONS = [
|
||||||
{"ci_tool": "Travis"},
|
{"ci_tool": "Travis"},
|
||||||
{"ci_tool": "Gitlab"},
|
{"ci_tool": "Gitlab"},
|
||||||
{"ci_tool": "Github"},
|
{"ci_tool": "Github"},
|
||||||
|
{"ci_tool": "Drone"},
|
||||||
{"keep_local_envs_in_vcs": "y"},
|
{"keep_local_envs_in_vcs": "y"},
|
||||||
{"keep_local_envs_in_vcs": "n"},
|
{"keep_local_envs_in_vcs": "n"},
|
||||||
{"debug": "y"},
|
{"debug": "y"},
|
||||||
|
@ -271,7 +272,7 @@ def test_djlint_check_passes(cookies, context_override):
|
||||||
["use_docker", "expected_test_script"],
|
["use_docker", "expected_test_script"],
|
||||||
[
|
[
|
||||||
("n", "pytest"),
|
("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):
|
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"],
|
["use_docker", "expected_test_script"],
|
||||||
[
|
[
|
||||||
("n", "pytest"),
|
("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):
|
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"],
|
["use_docker", "expected_test_script"],
|
||||||
[
|
[
|
||||||
("n", "pytest"),
|
("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):
|
def test_github_invokes_linter_and_pytest(cookies, context, use_docker, expected_test_script):
|
||||||
|
|
|
@ -15,28 +15,38 @@ cookiecutter ../../ --no-input --overwrite-if-exists use_docker=y "$@"
|
||||||
cd my_awesome_project
|
cd my_awesome_project
|
||||||
|
|
||||||
# make sure all images build
|
# make sure all images build
|
||||||
docker-compose -f local.yml build
|
docker compose -f local.yml build
|
||||||
|
|
||||||
# run the project's type checks
|
# run the project's type checks
|
||||||
docker-compose -f local.yml run django mypy my_awesome_project
|
docker compose -f local.yml run django mypy my_awesome_project
|
||||||
|
|
||||||
# run the project's tests
|
# run the project's tests
|
||||||
docker-compose -f local.yml run django pytest
|
docker compose -f local.yml run django pytest
|
||||||
|
|
||||||
# return non-zero status code if there are migrations that have not been created
|
# 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
|
# 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
|
# 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
|
# 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
|
# Run npm build script if package.json is present
|
||||||
if [ -f "package.json" ]
|
if [ -f "package.json" ]
|
||||||
then
|
then
|
||||||
docker-compose -f local.yml run node npm run build
|
docker compose -f local.yml run node npm run build
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
"""Unit tests for the hooks"""
|
"""Unit tests for the hooks"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
|
@ -11,11 +11,6 @@
|
||||||
"target": "/home/dev-user/.bash_history",
|
"target": "/home/dev-user/.bash_history",
|
||||||
"type": "bind"
|
"type": "bind"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"source": "~/.ssh",
|
|
||||||
"target": "/tmp",
|
|
||||||
"type": "bind"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"source": "~/.ssh",
|
"source": "~/.ssh",
|
||||||
"target": "/home/dev-user/.ssh",
|
"target": "/home/dev-user/.ssh",
|
||||||
|
@ -24,7 +19,7 @@
|
||||||
],
|
],
|
||||||
// Tells devcontainer.json supporting services / tools whether they should run
|
// 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
|
// /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",
|
"service": "django",
|
||||||
// "remoteEnv": {"PATH": "/home/dev-user/.local/bin:${containerEnv:PATH}"},
|
// "remoteEnv": {"PATH": "/home/dev-user/.local/bin:${containerEnv:PATH}"},
|
||||||
"remoteUser": "dev-user",
|
"remoteUser": "dev-user",
|
||||||
|
|
|
@ -9,3 +9,4 @@
|
||||||
.travis.yml
|
.travis.yml
|
||||||
venv
|
venv
|
||||||
.git
|
.git
|
||||||
|
.envs/
|
||||||
|
|
48
{{cookiecutter.project_slug}}/.drone.yml
Normal file
48
{{cookiecutter.project_slug}}/.drone.yml
Normal file
|
@ -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
|
|
@ -23,7 +23,7 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Code Repository
|
- name: Checkout Code Repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v4
|
||||||
|
@ -65,20 +65,20 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Code Repository
|
- name: Checkout Code Repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
{%- if cookiecutter.use_docker == 'y' %}
|
{%- if cookiecutter.use_docker == 'y' %}
|
||||||
|
|
||||||
- name: Build the Stack
|
- name: Build the Stack
|
||||||
run: docker-compose -f local.yml build
|
run: docker compose -f local.yml build
|
||||||
|
|
||||||
- name: Run DB Migrations
|
- 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
|
- 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
|
- name: Tear down the Stack
|
||||||
run: docker-compose -f local.yml down
|
run: docker compose -f local.yml down
|
||||||
{%- else %}
|
{%- else %}
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
|
|
4
{{cookiecutter.project_slug}}/.gitignore
vendored
4
{{cookiecutter.project_slug}}/.gitignore
vendored
|
@ -329,8 +329,8 @@ tags
|
||||||
dump.rdb
|
dump.rdb
|
||||||
|
|
||||||
### Project template
|
### Project template
|
||||||
{%- if cookiecutter.use_mailhog == 'y' and cookiecutter.use_docker == 'n' %}
|
{%- if cookiecutter.use_mailpit == 'y' and cookiecutter.use_docker == 'n' %}
|
||||||
MailHog
|
mailpit
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{{ cookiecutter.project_slug }}/media/
|
{{ cookiecutter.project_slug }}/media/
|
||||||
|
|
||||||
|
|
|
@ -33,12 +33,12 @@ pytest:
|
||||||
services:
|
services:
|
||||||
- docker:dind
|
- docker:dind
|
||||||
before_script:
|
before_script:
|
||||||
- docker-compose -f local.yml build
|
- docker compose -f local.yml build
|
||||||
# Ensure celerybeat does not crash due to non-existent tables
|
# Ensure celerybeat does not crash due to non-existent tables
|
||||||
- docker-compose -f local.yml run --rm django python manage.py migrate
|
- docker compose -f local.yml run --rm django python manage.py migrate
|
||||||
- docker-compose -f local.yml up -d
|
- docker compose -f local.yml up -d
|
||||||
script:
|
script:
|
||||||
- docker-compose -f local.yml run django pytest
|
- docker compose -f local.yml run django pytest
|
||||||
{%- else %}
|
{%- else %}
|
||||||
image: python:3.11
|
image: python:3.11
|
||||||
tags:
|
tags:
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
exclude: '^docs/|/migrations/'
|
exclude: '^docs/|/migrations/|devcontainer.json'
|
||||||
default_stages: [commit]
|
default_stages: [commit]
|
||||||
|
|
||||||
|
default_language_version:
|
||||||
|
python: python3.11
|
||||||
|
|
||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
rev: v4.4.0
|
rev: v4.5.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: trailing-whitespace
|
- id: trailing-whitespace
|
||||||
- id: end-of-file-fixer
|
- id: end-of-file-fixer
|
||||||
|
@ -16,45 +19,43 @@ repos:
|
||||||
- id: check-case-conflict
|
- id: check-case-conflict
|
||||||
- id: check-docstring-first
|
- id: check-docstring-first
|
||||||
- id: detect-private-key
|
- id: detect-private-key
|
||||||
{%- if cookiecutter.frontend_pipeline in ["Webpack", "Gulp"] %}
|
|
||||||
|
|
||||||
- repo: https://github.com/pre-commit/mirrors-prettier
|
- repo: https://github.com/pre-commit/mirrors-prettier
|
||||||
rev: v3.0.0-alpha.9-for-vscode
|
rev: v4.0.0-alpha.8
|
||||||
hooks:
|
hooks:
|
||||||
- id: prettier
|
- id: prettier
|
||||||
args: ['--tab-width', '2', '--single-quote']
|
args: ['--tab-width', '2', '--single-quote']
|
||||||
exclude: '{{cookiecutter.project_slug}}/templates/'
|
exclude: '{{cookiecutter.project_slug}}/templates/'
|
||||||
{%- endif %}
|
|
||||||
|
|
||||||
- repo: https://github.com/adamchainz/django-upgrade
|
- repo: https://github.com/adamchainz/django-upgrade
|
||||||
rev: '1.14.0'
|
rev: '1.16.0'
|
||||||
hooks:
|
hooks:
|
||||||
- id: django-upgrade
|
- id: django-upgrade
|
||||||
args: ['--target-version', '4.2']
|
args: ['--target-version', '4.2']
|
||||||
|
|
||||||
- repo: https://github.com/asottile/pyupgrade
|
- repo: https://github.com/asottile/pyupgrade
|
||||||
rev: v3.7.0
|
rev: v3.15.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: pyupgrade
|
- id: pyupgrade
|
||||||
args: [--py311-plus]
|
args: [--py311-plus]
|
||||||
|
|
||||||
- repo: https://github.com/psf/black
|
- repo: https://github.com/psf/black
|
||||||
rev: 23.3.0
|
rev: 24.1.1
|
||||||
hooks:
|
hooks:
|
||||||
- id: black
|
- id: black
|
||||||
|
|
||||||
- repo: https://github.com/PyCQA/isort
|
- repo: https://github.com/PyCQA/isort
|
||||||
rev: 5.12.0
|
rev: 5.13.2
|
||||||
hooks:
|
hooks:
|
||||||
- id: isort
|
- id: isort
|
||||||
|
|
||||||
- repo: https://github.com/PyCQA/flake8
|
- repo: https://github.com/PyCQA/flake8
|
||||||
rev: 6.0.0
|
rev: 7.0.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: flake8
|
- id: flake8
|
||||||
|
|
||||||
- repo: https://github.com/Riverside-Healthcare/djLint
|
- repo: https://github.com/Riverside-Healthcare/djLint
|
||||||
rev: v1.31.1
|
rev: v1.34.1
|
||||||
hooks:
|
hooks:
|
||||||
- id: djlint-reformat-django
|
- id: djlint-reformat-django
|
||||||
- id: djlint-django
|
- id: djlint-django
|
||||||
|
|
|
@ -17,16 +17,16 @@ jobs:
|
||||||
- name: "Django Test"
|
- name: "Django Test"
|
||||||
{%- if cookiecutter.use_docker == 'y' %}
|
{%- if cookiecutter.use_docker == 'y' %}
|
||||||
before_script:
|
before_script:
|
||||||
- docker-compose -v
|
- docker compose -v
|
||||||
- docker -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
|
# 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 run --rm django python manage.py migrate
|
||||||
- docker-compose -f local.yml up -d
|
- docker compose -f local.yml up -d
|
||||||
script:
|
script:
|
||||||
- "docker-compose -f local.yml run django pytest"
|
- "docker compose -f local.yml run django pytest"
|
||||||
after_failure:
|
after_failure:
|
||||||
- docker-compose -f local.yml logs
|
- docker compose -f local.yml logs
|
||||||
{%- else %}
|
{%- else %}
|
||||||
before_install:
|
before_install:
|
||||||
- sudo apt-get update -qq
|
- sudo apt-get update -qq
|
||||||
|
|
|
@ -78,37 +78,35 @@ celery -A config.celery_app worker -B -l info
|
||||||
```
|
```
|
||||||
|
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{%- if cookiecutter.use_mailhog == "y" %}
|
{%- if cookiecutter.use_mailpit == "y" %}
|
||||||
|
|
||||||
### Email Server
|
### Email Server
|
||||||
|
|
||||||
{%- if cookiecutter.use_docker == "y" %}
|
{%- 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.
|
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 %}
|
{%- 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
|
5. Check out <http://127.0.0.1:8025/> to see how it goes.
|
||||||
|
|
||||||
6. Check out <http://127.0.0.1:8025/> to see how it goes.
|
|
||||||
|
|
||||||
Now you have your own mail server running locally, ready to receive whatever you send it.
|
Now you have your own mail server running locally, ready to receive whatever you send it.
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# define an alias for the specific python version used in this file.
|
# 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
|
# Python build stage
|
||||||
FROM python as python-build-stage
|
FROM docker.io/python as python-build-stage
|
||||||
|
|
||||||
ARG BUILD_ENVIRONMENT=local
|
ARG BUILD_ENVIRONMENT=local
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ RUN pip wheel --wheel-dir /usr/src/app/wheels \
|
||||||
|
|
||||||
|
|
||||||
# Python 'run' stage
|
# Python 'run' stage
|
||||||
FROM python as python-run-stage
|
FROM docker.io/python as python-run-stage
|
||||||
|
|
||||||
ARG BUILD_ENVIRONMENT=local
|
ARG BUILD_ENVIRONMENT=local
|
||||||
ARG APP_HOME=/app
|
ARG APP_HOME=/app
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
# define an alias for the specific python version used in this file.
|
# 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
|
# Python build stage
|
||||||
FROM python as python-build-stage
|
FROM docker.io/python as python-build-stage
|
||||||
|
|
||||||
ENV PYTHONDONTWRITEBYTECODE 1
|
ENV PYTHONDONTWRITEBYTECODE 1
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ RUN pip wheel --no-cache-dir --wheel-dir /usr/src/app/wheels \
|
||||||
|
|
||||||
|
|
||||||
# Python 'run' stage
|
# Python 'run' stage
|
||||||
FROM python as python-run-stage
|
FROM docker.io/python as python-run-stage
|
||||||
|
|
||||||
ARG BUILD_ENVIRONMENT
|
ARG BUILD_ENVIRONMENT
|
||||||
ENV PYTHONUNBUFFERED 1
|
ENV PYTHONUNBUFFERED 1
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
FROM node:18-bullseye-slim
|
FROM docker.io/node:20-bookworm-slim
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
|
|
|
@ -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/aws/maintenance /usr/local/bin/maintenance
|
||||||
COPY ./compose/production/postgres/maintenance/_sourced /usr/local/bin/maintenance/_sourced
|
COPY ./compose/production/postgres/maintenance/_sourced /usr/local/bin/maintenance/_sourced
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
### Download a file from your Amazon S3 bucket to the postgres /backups folder
|
### Download a file from your Amazon S3 bucket to the postgres /backups folder
|
||||||
###
|
###
|
||||||
### Usage:
|
### Usage:
|
||||||
### $ docker-compose -f production.yml run --rm awscli <1>
|
### $ docker compose -f production.yml run --rm awscli <1>
|
||||||
|
|
||||||
set -o errexit
|
set -o errexit
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
### Upload the /backups folder to Amazon S3
|
### Upload the /backups folder to Amazon S3
|
||||||
###
|
###
|
||||||
### Usage:
|
### Usage:
|
||||||
### $ docker-compose -f production.yml run --rm awscli upload
|
### $ docker compose -f production.yml run --rm awscli upload
|
||||||
|
|
||||||
set -o errexit
|
set -o errexit
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{% if cookiecutter.frontend_pipeline in ['Gulp', 'Webpack'] -%}
|
{% 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
|
ARG APP_HOME=/app
|
||||||
WORKDIR ${APP_HOME}
|
WORKDIR ${APP_HOME}
|
||||||
|
@ -25,10 +25,10 @@ RUN npm run build
|
||||||
|
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
# define an alias for the specific python version used in this file.
|
# 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
|
# Python build stage
|
||||||
FROM python as python-build-stage
|
FROM docker.io/python as python-build-stage
|
||||||
|
|
||||||
ARG BUILD_ENVIRONMENT=production
|
ARG BUILD_ENVIRONMENT=production
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ RUN pip wheel --wheel-dir /usr/src/app/wheels \
|
||||||
|
|
||||||
|
|
||||||
# Python 'run' stage
|
# Python 'run' stage
|
||||||
FROM python as python-run-stage
|
FROM docker.io/python as python-run-stage
|
||||||
|
|
||||||
ARG BUILD_ENVIRONMENT=production
|
ARG BUILD_ENVIRONMENT=production
|
||||||
ARG APP_HOME=/app
|
ARG APP_HOME=/app
|
||||||
|
@ -103,7 +103,7 @@ RUN sed -i 's/\r$//g' /start-celerybeat
|
||||||
RUN chmod +x /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 sed -i 's/\r$//g' /start-flower
|
||||||
RUN chmod +x /start-flower
|
RUN chmod +x /start-flower
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
|
@ -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
|
COPY ./compose/production/nginx/default.conf /etc/nginx/conf.d/default.conf
|
||||||
|
|
|
@ -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
|
COPY ./compose/production/postgres/maintenance /usr/local/bin/maintenance
|
||||||
RUN chmod +x /usr/local/bin/maintenance/*
|
RUN chmod +x /usr/local/bin/maintenance/*
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
### Create a database backup.
|
### Create a database backup.
|
||||||
###
|
###
|
||||||
### Usage:
|
### Usage:
|
||||||
### $ docker-compose -f <environment>.yml (exec |run --rm) postgres backup
|
### $ docker compose -f <environment>.yml (exec |run --rm) postgres backup
|
||||||
|
|
||||||
|
|
||||||
set -o errexit
|
set -o errexit
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
### View backups.
|
### View backups.
|
||||||
###
|
###
|
||||||
### Usage:
|
### Usage:
|
||||||
### $ docker-compose -f <environment>.yml (exec |run --rm) postgres backups
|
### $ docker compose -f <environment>.yml (exec |run --rm) postgres backups
|
||||||
|
|
||||||
|
|
||||||
set -o errexit
|
set -o errexit
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
### <1> filename of an existing backup.
|
### <1> filename of an existing backup.
|
||||||
###
|
###
|
||||||
### Usage:
|
### Usage:
|
||||||
### $ docker-compose -f <environment>.yml (exec |run --rm) postgres restore <1>
|
### $ docker compose -f <environment>.yml (exec |run --rm) postgres restore <1>
|
||||||
|
|
||||||
|
|
||||||
set -o errexit
|
set -o errexit
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
### Remove a database backup.
|
||||||
|
###
|
||||||
|
### Parameters:
|
||||||
|
### <1> filename of a backup to remove.
|
||||||
|
###
|
||||||
|
### Usage:
|
||||||
|
### $ docker-compose -f <environment>.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."
|
|
@ -1,4 +1,4 @@
|
||||||
FROM traefik:2.10.3
|
FROM docker.io/traefik:2.10.7
|
||||||
RUN mkdir -p /etc/traefik/acme \
|
RUN mkdir -p /etc/traefik/acme \
|
||||||
&& touch /etc/traefik/acme/acme.json \
|
&& touch /etc/traefik/acme/acme.json \
|
||||||
&& chmod 600 /etc/traefik/acme/acme.json
|
&& chmod 600 /etc/traefik/acme/acme.json
|
||||||
|
|
|
@ -6,7 +6,7 @@ entryPoints:
|
||||||
# http
|
# http
|
||||||
address: ':80'
|
address: ':80'
|
||||||
http:
|
http:
|
||||||
# https://docs.traefik.io/routing/entrypoints/#entrypoint
|
# https://doc.traefik.io/traefik/routing/entrypoints/#entrypoint
|
||||||
redirections:
|
redirections:
|
||||||
entryPoint:
|
entryPoint:
|
||||||
to: web-secure
|
to: web-secure
|
||||||
|
@ -22,11 +22,11 @@ entryPoints:
|
||||||
|
|
||||||
certificatesResolvers:
|
certificatesResolvers:
|
||||||
letsencrypt:
|
letsencrypt:
|
||||||
# https://docs.traefik.io/master/https/acme/#lets-encrypt
|
# https://doc.traefik.io/traefik/https/acme/#lets-encrypt
|
||||||
acme:
|
acme:
|
||||||
email: '{{ cookiecutter.email }}'
|
email: '{{ cookiecutter.email }}'
|
||||||
storage: /etc/traefik/acme/acme.json
|
storage: /etc/traefik/acme/acme.json
|
||||||
# https://docs.traefik.io/master/https/acme/#httpchallenge
|
# https://doc.traefik.io/traefik/https/acme/#httpchallenge
|
||||||
httpChallenge:
|
httpChallenge:
|
||||||
entryPoint: web
|
entryPoint: web
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ http:
|
||||||
- csrf
|
- csrf
|
||||||
service: django
|
service: django
|
||||||
tls:
|
tls:
|
||||||
# https://docs.traefik.io/master/routing/routers/#certresolver
|
# https://doc.traefik.io/traefik/routing/routers/#certresolver
|
||||||
certResolver: letsencrypt
|
certResolver: letsencrypt
|
||||||
{%- if cookiecutter.use_celery == 'y' %}
|
{%- if cookiecutter.use_celery == 'y' %}
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ http:
|
||||||
- flower
|
- flower
|
||||||
service: flower
|
service: flower
|
||||||
tls:
|
tls:
|
||||||
# https://docs.traefik.io/master/routing/routers/#certresolver
|
# https://doc.traefik.io/traefik/master/routing/routers/#certresolver
|
||||||
certResolver: letsencrypt
|
certResolver: letsencrypt
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{%- if cookiecutter.cloud_provider == 'None' %}
|
{%- if cookiecutter.cloud_provider == 'None' %}
|
||||||
|
@ -76,7 +76,7 @@ http:
|
||||||
|
|
||||||
middlewares:
|
middlewares:
|
||||||
csrf:
|
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
|
# https://docs.djangoproject.com/en/dev/ref/csrf/#ajax
|
||||||
headers:
|
headers:
|
||||||
hostsProxyHeaders: ['X-CSRFToken']
|
hostsProxyHeaders: ['X-CSRFToken']
|
||||||
|
@ -102,7 +102,7 @@ http:
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
||||||
providers:
|
providers:
|
||||||
# https://docs.traefik.io/master/providers/file/
|
# https://doc.traefik.io/traefik/master/providers/file/
|
||||||
file:
|
file:
|
||||||
filename: /etc/traefik/traefik.yml
|
filename: /etc/traefik/traefik.yml
|
||||||
watch: true
|
watch: true
|
||||||
|
|
|
@ -7,6 +7,7 @@ For more information on this file, see
|
||||||
https://docs.djangoproject.com/en/dev/howto/deployment/asgi/
|
https://docs.djangoproject.com/en/dev/howto/deployment/asgi/
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
"""
|
"""Base settings to build other settings files upon."""
|
||||||
Base settings to build other settings files upon.
|
|
||||||
"""
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import environ
|
import environ
|
||||||
|
@ -30,7 +29,8 @@ LANGUAGE_CODE = "en-us"
|
||||||
# from django.utils.translation import gettext_lazy as _
|
# from django.utils.translation import gettext_lazy as _
|
||||||
# LANGUAGES = [
|
# LANGUAGES = [
|
||||||
# ('en', _('English')),
|
# ('en', _('English')),
|
||||||
# ('pt-br', _('Português')),
|
# ('fr-fr', _('French')),
|
||||||
|
# ('pt-br', _('Portuguese')),
|
||||||
# ]
|
# ]
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#site-id
|
# https://docs.djangoproject.com/en/dev/ref/settings/#site-id
|
||||||
SITE_ID = 1
|
SITE_ID = 1
|
||||||
|
@ -160,6 +160,7 @@ MIDDLEWARE = [
|
||||||
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
||||||
"django.contrib.messages.middleware.MessageMiddleware",
|
"django.contrib.messages.middleware.MessageMiddleware",
|
||||||
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||||
|
"allauth.account.middleware.AccountMiddleware",
|
||||||
]
|
]
|
||||||
|
|
||||||
# STATIC
|
# STATIC
|
||||||
|
@ -252,7 +253,7 @@ ADMINS = [("""{{cookiecutter.author_name}}""", "{{cookiecutter.email}}")]
|
||||||
MANAGERS = ADMINS
|
MANAGERS = ADMINS
|
||||||
# https://cookiecutter-django.readthedocs.io/en/latest/settings.html#other-environment-settings
|
# 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
|
# 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
|
# LOGGING
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
@ -317,25 +318,25 @@ CELERY_TASK_SEND_SENT_EVENT = True
|
||||||
# django-allauth
|
# django-allauth
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
ACCOUNT_ALLOW_REGISTRATION = env.bool("DJANGO_ACCOUNT_ALLOW_REGISTRATION", True)
|
ACCOUNT_ALLOW_REGISTRATION = env.bool("DJANGO_ACCOUNT_ALLOW_REGISTRATION", True)
|
||||||
# https://django-allauth.readthedocs.io/en/latest/configuration.html
|
# https://docs.allauth.org/en/latest/account/configuration.html
|
||||||
ACCOUNT_AUTHENTICATION_METHOD = "{{cookiecutter.username_type}}"
|
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
|
ACCOUNT_EMAIL_REQUIRED = True
|
||||||
{%- if cookiecutter.username_type == "email" %}
|
{%- 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
|
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
|
ACCOUNT_USER_MODEL_USERNAME_FIELD = None
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
# https://django-allauth.readthedocs.io/en/latest/configuration.html
|
# https://docs.allauth.org/en/latest/account/configuration.html
|
||||||
ACCOUNT_EMAIL_VERIFICATION = "mandatory"
|
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"
|
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"}
|
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"
|
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"}
|
SOCIALACCOUNT_FORMS = {"signup": "{{cookiecutter.project_slug}}.users.forms.UserSocialSignupForm"}
|
||||||
{% if cookiecutter.frontend_pipeline == 'Django Compressor' -%}
|
{% if cookiecutter.frontend_pipeline == 'Django Compressor' -%}
|
||||||
# django-compressor
|
# django-compressor
|
||||||
|
|
|
@ -25,12 +25,12 @@ CACHES = {
|
||||||
|
|
||||||
# EMAIL
|
# 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
|
# 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
|
# https://docs.djangoproject.com/en/dev/ref/settings/#email-port
|
||||||
EMAIL_PORT = 1025
|
EMAIL_PORT = 1025
|
||||||
{%- elif cookiecutter.use_mailhog == 'y' and cookiecutter.use_docker == 'n' -%}
|
{%- elif cookiecutter.use_mailpit == 'y' and cookiecutter.use_docker == 'n' -%}
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#email-host
|
# https://docs.djangoproject.com/en/dev/ref/settings/#email-host
|
||||||
EMAIL_HOST = "localhost"
|
EMAIL_HOST = "localhost"
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#email-port
|
# https://docs.djangoproject.com/en/dev/ref/settings/#email-port
|
||||||
|
|
|
@ -103,35 +103,75 @@ AZURE_CONTAINER = env("DJANGO_AZURE_CONTAINER_NAME")
|
||||||
{% endif -%}
|
{% endif -%}
|
||||||
|
|
||||||
{% if cookiecutter.cloud_provider != 'None' or cookiecutter.use_whitenoise == 'y' -%}
|
{% if cookiecutter.cloud_provider != 'None' or cookiecutter.use_whitenoise == 'y' -%}
|
||||||
# STATIC
|
# STATIC & MEDIA
|
||||||
# ------------------------
|
# ------------------------
|
||||||
{% endif -%}
|
STORAGES = {
|
||||||
{% if cookiecutter.use_whitenoise == 'y' -%}
|
{%- if cookiecutter.use_whitenoise == 'y' %}
|
||||||
STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage"
|
"default": {
|
||||||
{% elif cookiecutter.cloud_provider == 'AWS' -%}
|
"BACKEND": "django.core.files.storage.FileSystemStorage",
|
||||||
STATICFILES_STORAGE = "{{cookiecutter.project_slug}}.utils.storages.StaticRootS3Boto3Storage"
|
},
|
||||||
|
"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"
|
COLLECTFAST_STRATEGY = "collectfast.strategies.boto3.Boto3Strategy"
|
||||||
STATIC_URL = f"https://{aws_s3_domain}/static/"
|
STATIC_URL = f"https://{aws_s3_domain}/static/"
|
||||||
{% elif cookiecutter.cloud_provider == 'GCP' -%}
|
{%- elif cookiecutter.cloud_provider == 'GCP' %}
|
||||||
STATICFILES_STORAGE = "{{cookiecutter.project_slug}}.utils.storages.StaticRootGoogleCloudStorage"
|
MEDIA_URL = f"https://storage.googleapis.com/{GS_BUCKET_NAME}/media/"
|
||||||
COLLECTFAST_STRATEGY = "collectfast.strategies.gcloud.GoogleCloudStrategy"
|
COLLECTFAST_STRATEGY = "collectfast.strategies.gcloud.GoogleCloudStrategy"
|
||||||
STATIC_URL = f"https://storage.googleapis.com/{GS_BUCKET_NAME}/static/"
|
STATIC_URL = f"https://storage.googleapis.com/{GS_BUCKET_NAME}/static/"
|
||||||
{% elif cookiecutter.cloud_provider == 'Azure' -%}
|
|
||||||
STATICFILES_STORAGE = "{{cookiecutter.project_slug}}.utils.storages.StaticRootAzureStorage"
|
|
||||||
STATIC_URL = f"https://{AZURE_ACCOUNT_NAME}.blob.core.windows.net/static/"
|
|
||||||
{% endif -%}
|
|
||||||
|
|
||||||
# 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' %}
|
{%- 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/"
|
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 %}
|
{%- endif %}
|
||||||
|
|
||||||
# EMAIL
|
# 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
|
# https://docs.djangoproject.com/en/dev/ref/settings/#email-subject-prefix
|
||||||
EMAIL_SUBJECT_PREFIX = env(
|
EMAIL_SUBJECT_PREFIX = env(
|
||||||
"DJANGO_EMAIL_SUBJECT_PREFIX",
|
"DJANGO_EMAIL_SUBJECT_PREFIX",
|
||||||
default="[{{cookiecutter.project_name}}]",
|
default="[{{cookiecutter.project_name}}] ",
|
||||||
)
|
)
|
||||||
|
|
||||||
# ADMIN
|
# ADMIN
|
||||||
|
@ -230,7 +270,7 @@ COMPRESS_ENABLED = env.bool("COMPRESS_ENABLED", default=True)
|
||||||
COMPRESS_STORAGE = "compressor.storage.GzipCompressorFileStorage"
|
COMPRESS_STORAGE = "compressor.storage.GzipCompressorFileStorage"
|
||||||
{%- elif cookiecutter.cloud_provider in ('AWS', 'GCP', 'Azure') and cookiecutter.use_whitenoise == 'n' %}
|
{%- elif cookiecutter.cloud_provider in ('AWS', 'GCP', 'Azure') and cookiecutter.use_whitenoise == 'n' %}
|
||||||
# https://django-compressor.readthedocs.io/en/latest/settings/#django.conf.settings.COMPRESS_STORAGE
|
# https://django-compressor.readthedocs.io/en/latest/settings/#django.conf.settings.COMPRESS_STORAGE
|
||||||
COMPRESS_STORAGE = STATICFILES_STORAGE
|
COMPRESS_STORAGE = STORAGES["staticfiles"]["BACKEND"]
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
# https://django-compressor.readthedocs.io/en/latest/settings/#django.conf.settings.COMPRESS_URL
|
# https://django-compressor.readthedocs.io/en/latest/settings/#django.conf.settings.COMPRESS_URL
|
||||||
COMPRESS_URL = STATIC_URL{% if cookiecutter.use_whitenoise == 'y' or cookiecutter.cloud_provider == 'None' %} # noqa: F405{% endif %}
|
COMPRESS_URL = STATIC_URL{% if cookiecutter.use_whitenoise == 'y' or cookiecutter.cloud_provider == 'None' %} # noqa: F405{% endif %}
|
||||||
|
|
|
@ -29,10 +29,15 @@ EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend"
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
TEMPLATES[0]["OPTIONS"]["debug"] = True # type: ignore # noqa: F405
|
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' %}
|
{%- if cookiecutter.frontend_pipeline == 'Webpack' %}
|
||||||
# django-webpack-loader
|
# 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 %}
|
{%- endif %}
|
||||||
# Your stuff...
|
# Your stuff...
|
||||||
|
|
|
@ -13,6 +13,7 @@ middleware here, or combine a Django application with an application of another
|
||||||
framework.
|
framework.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
|
@ -8,14 +8,14 @@ Documentation can be written as rst files in `{{cookiecutter.project_slug}}/docs
|
||||||
|
|
||||||
{% if cookiecutter.use_docker == 'n' %}
|
{% if cookiecutter.use_docker == 'n' %}
|
||||||
To build and serve docs, use the command::
|
To build and serve docs, use the command::
|
||||||
|
|
||||||
make livehtml
|
make livehtml
|
||||||
|
|
||||||
from inside the `{{cookiecutter.project_slug}}/docs` directory.
|
from inside the `{{cookiecutter.project_slug}}/docs` directory.
|
||||||
{% else %}
|
{% else %}
|
||||||
To build and serve docs, use the commands::
|
To build and serve docs, use the commands::
|
||||||
|
|
||||||
docker-compose -f local.yml up docs
|
docker compose -f local.yml up docs
|
||||||
|
|
||||||
{% endif %}
|
{% 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:
|
To compile all docstrings automatically into documentation source files, use the command:
|
||||||
::
|
::
|
||||||
|
|
||||||
make apidocs
|
make apidocs
|
||||||
|
|
||||||
{% if cookiecutter.use_docker == 'y' %}
|
{% if cookiecutter.use_docker == 'y' %}
|
||||||
This can be done in the docker container:
|
This can be done in the docker container:
|
||||||
::
|
::
|
||||||
|
|
||||||
docker run --rm docs make apidocs
|
docker run --rm docs make apidocs
|
||||||
{% endif -%}
|
{% endif -%}
|
||||||
|
|
|
@ -16,8 +16,8 @@ services:
|
||||||
{%- if cookiecutter.use_celery == 'y' %}
|
{%- if cookiecutter.use_celery == 'y' %}
|
||||||
- redis
|
- redis
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{%- if cookiecutter.use_mailhog == 'y' %}
|
{%- if cookiecutter.use_mailpit == 'y' %}
|
||||||
- mailhog
|
- mailpit
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
volumes:
|
volumes:
|
||||||
- .:/app:z
|
- .:/app:z
|
||||||
|
@ -55,11 +55,11 @@ services:
|
||||||
ports:
|
ports:
|
||||||
- '9000:9000'
|
- '9000:9000'
|
||||||
command: /start-docs
|
command: /start-docs
|
||||||
{%- if cookiecutter.use_mailhog == 'y' %}
|
{%- if cookiecutter.use_mailpit == 'y' %}
|
||||||
|
|
||||||
mailhog:
|
mailpit:
|
||||||
image: mailhog/mailhog:v1.0.0
|
image: docker.io/axllent/mailpit:latest
|
||||||
container_name: {{ cookiecutter.project_slug }}_local_mailhog
|
container_name: {{ cookiecutter.project_slug }}_local_mailpit
|
||||||
ports:
|
ports:
|
||||||
- "8025:8025"
|
- "8025:8025"
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ services:
|
||||||
{%- if cookiecutter.use_celery == 'y' %}
|
{%- if cookiecutter.use_celery == 'y' %}
|
||||||
|
|
||||||
redis:
|
redis:
|
||||||
image: redis:6
|
image: docker.io/redis:6
|
||||||
container_name: {{ cookiecutter.project_slug }}_local_redis
|
container_name: {{ cookiecutter.project_slug }}_local_redis
|
||||||
|
|
||||||
celeryworker:
|
celeryworker:
|
||||||
|
@ -77,8 +77,8 @@ services:
|
||||||
depends_on:
|
depends_on:
|
||||||
- redis
|
- redis
|
||||||
- postgres
|
- postgres
|
||||||
{%- if cookiecutter.use_mailhog == 'y' %}
|
{%- if cookiecutter.use_mailpit == 'y' %}
|
||||||
- mailhog
|
- mailpit
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
ports: []
|
ports: []
|
||||||
command: /start-celeryworker
|
command: /start-celeryworker
|
||||||
|
@ -90,8 +90,8 @@ services:
|
||||||
depends_on:
|
depends_on:
|
||||||
- redis
|
- redis
|
||||||
- postgres
|
- postgres
|
||||||
{%- if cookiecutter.use_mailhog == 'y' %}
|
{%- if cookiecutter.use_mailpit == 'y' %}
|
||||||
- mailhog
|
- mailpit
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
ports: []
|
ports: []
|
||||||
command: /start-celerybeat
|
command: /start-celerybeat
|
||||||
|
|
|
@ -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:
|
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
|
```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 `<locale name>/LC_MESSAGES/django.po`. Each translatable string in the codebase is collected with its `msgid` and need to be translated as `msgstr`, for example:
|
This should generate `django.po` (stands for Portable Object) files under each locale `<locale name>/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:
|
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
|
```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.
|
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.
|
||||||
|
|
335
{{cookiecutter.project_slug}}/locale/fr_FR/LC_MESSAGES/django.po
Normal file
335
{{cookiecutter.project_slug}}/locale/fr_FR/LC_MESSAGES/django.po
Normal file
|
@ -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 <a href=\"mailto:%(email)s\">%(email)s</a> is an e-mail "
|
||||||
|
"address for user %(user_display)s."
|
||||||
|
msgstr ""
|
||||||
|
"Veuillez confirmer que <a href=\"mailto:%(email)s\">%(email)s</a> 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 <a href="
|
||||||
|
"\"%(email_url)s\">issue a new e-mail confirmation request</a>."
|
||||||
|
msgstr ""
|
||||||
|
"Ce lien de confirmation par e-mail a expiré ou n'est pas valide. Veuillez"
|
||||||
|
"<a href=\"%(email_url)s\">émettre une nouvelle demande de confirmation "
|
||||||
|
"par e-mail</a>."
|
||||||
|
|
||||||
|
#: {{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, <a href=\"%(signup_url)s\">sign up</a> for a %(site_name)s account and "
|
||||||
|
"sign in below:"
|
||||||
|
msgstr ""
|
||||||
|
"Ou, <a href=\"%(signup_url)s\">créez</a> 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 <a href=\"%(signup_url)s"
|
||||||
|
"\">sign up</a> first."
|
||||||
|
msgstr ""
|
||||||
|
"Si vous n'avez pas encore créé de compte, veuillez d'abord <a href=\"%(signup_url)s"
|
||||||
|
"\">vous inscrire</a>."
|
||||||
|
|
||||||
|
#: {{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 <a href=\"%(passwd_reset_url)s\">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 <a href=\"%(passwd_reset_url)s\"> "
|
||||||
|
"nouvelle demande de réinitialisation de mot de passe</a>."
|
||||||
|
|
||||||
|
#: {{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 <a href=\"%(login_url)s\">sign in</a>."
|
||||||
|
msgstr ""
|
||||||
|
"Vous avez déjà un compte? Alors veuillez <a href=\"%(login_url)s\">vous connecter</a>."
|
||||||
|
|
||||||
|
#: {{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 ""
|
||||||
|
"<strong>Note:</strong> you can still <a href=\"%(email_url)s\">change your e-"
|
||||||
|
"mail address</a>."
|
||||||
|
msgstr ""
|
||||||
|
"<strong>Remarque :</strong> vous pouvez toujours <a href=\"%(email_url)s\">changer votre e-"
|
||||||
|
"adresse e-mail</a>."
|
||||||
|
|
||||||
|
#: {{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"
|
|
@ -127,7 +127,7 @@ msgstr "Ou, <a href=\"%(signup_url)s\">cadastre-se</a> para uma conta em %(site_
|
||||||
|
|
||||||
#: {{cookiecutter.project_slug}}/templates/account/login.html:32
|
#: {{cookiecutter.project_slug}}/templates/account/login.html:32
|
||||||
msgid "or"
|
msgid "or"
|
||||||
msgstr "or"
|
msgstr "ou"
|
||||||
|
|
||||||
#: {{cookiecutter.project_slug}}/templates/account/login.html:41
|
#: {{cookiecutter.project_slug}}/templates/account/login.html:41
|
||||||
#, python-format
|
#, python-format
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
"autoprefixer": "^10.4.0",
|
"autoprefixer": "^10.4.0",
|
||||||
"babel-loader": "^9.1.2",
|
"babel-loader": "^9.1.2",
|
||||||
"bootstrap": "^5.2.3",
|
"bootstrap": "^5.2.3",
|
||||||
"browser-sync": "^2.27.7",
|
"browser-sync": "^3.0.2",
|
||||||
"css-loader": "^6.5.1",
|
"css-loader": "^6.5.1",
|
||||||
"gulp-concat": "^2.6.1",
|
"gulp-concat": "^2.6.1",
|
||||||
"concurrently": "^8.0.1",
|
"concurrently": "^8.0.1",
|
||||||
|
@ -16,7 +16,7 @@
|
||||||
"gulp": "^4.0.2",
|
"gulp": "^4.0.2",
|
||||||
"gulp-imagemin": "^7.1.0",
|
"gulp-imagemin": "^7.1.0",
|
||||||
"gulp-plumber": "^1.2.1",
|
"gulp-plumber": "^1.2.1",
|
||||||
"gulp-postcss": "^9.0.1",
|
"gulp-postcss": "^10.0.0",
|
||||||
"gulp-rename": "^2.0.0",
|
"gulp-rename": "^2.0.0",
|
||||||
"gulp-sass": "^5.0.0",
|
"gulp-sass": "^5.0.0",
|
||||||
"gulp-uglify-es": "^3.0.0",
|
"gulp-uglify-es": "^3.0.0",
|
||||||
|
@ -24,18 +24,18 @@
|
||||||
"node-sass-tilde-importer": "^1.0.2",
|
"node-sass-tilde-importer": "^1.0.2",
|
||||||
"pixrem": "^5.0.0",
|
"pixrem": "^5.0.0",
|
||||||
"postcss": "^8.3.11",
|
"postcss": "^8.3.11",
|
||||||
"postcss-loader": "^7.0.2",
|
"postcss-loader": "^8.0.0",
|
||||||
"postcss-preset-env": "^9.0.0",
|
"postcss-preset-env": "^9.0.0",
|
||||||
"sass": "^1.43.4",
|
"sass": "^1.43.4",
|
||||||
"sass-loader": "^13.2.0",
|
"sass-loader": "^14.0.0",
|
||||||
"webpack": "^5.65.0",
|
"webpack": "^5.65.0",
|
||||||
"webpack-bundle-tracker": "^2.0.0",
|
"webpack-bundle-tracker": "^3.0.1",
|
||||||
"webpack-cli": "^5.0.1",
|
"webpack-cli": "^5.0.1",
|
||||||
"webpack-dev-server": "^4.6.0",
|
"webpack-dev-server": "^4.6.0",
|
||||||
"webpack-merge": "^5.8.0"
|
"webpack-merge": "^5.8.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "18"
|
"node": "20"
|
||||||
},
|
},
|
||||||
"browserslist": [
|
"browserslist": [
|
||||||
"last 2 versions"
|
"last 2 versions"
|
||||||
|
|
|
@ -67,7 +67,7 @@ services:
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
||||||
redis:
|
redis:
|
||||||
image: redis:6
|
image: docker.io/redis:6
|
||||||
{%- if cookiecutter.use_celery == 'y' %}
|
{%- if cookiecutter.use_celery == 'y' %}
|
||||||
|
|
||||||
celeryworker:
|
celeryworker:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
python-slugify==8.0.1 # https://github.com/un33k/python-slugify
|
python-slugify==8.0.4 # https://github.com/un33k/python-slugify
|
||||||
Pillow==9.5.0 # https://github.com/python-pillow/Pillow
|
Pillow==10.2.0 # https://github.com/python-pillow/Pillow
|
||||||
{%- if cookiecutter.frontend_pipeline == 'Django Compressor' %}
|
{%- if cookiecutter.frontend_pipeline == 'Django Compressor' %}
|
||||||
{%- if cookiecutter.windows == 'y' and cookiecutter.use_docker == 'n' %}
|
{%- if cookiecutter.windows == 'y' and cookiecutter.use_docker == 'n' %}
|
||||||
rcssmin==1.1.0 --install-option="--without-c-extensions" # https://github.com/ndparker/rcssmin
|
rcssmin==1.1.0 --install-option="--without-c-extensions" # https://github.com/ndparker/rcssmin
|
||||||
|
@ -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
|
rcssmin==1.1.1 # https://github.com/ndparker/rcssmin
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
argon2-cffi==21.3.0 # https://github.com/hynek/argon2_cffi
|
argon2-cffi==23.1.0 # https://github.com/hynek/argon2_cffi
|
||||||
{%- if cookiecutter.use_whitenoise == 'y' %}
|
{%- if cookiecutter.use_whitenoise == 'y' %}
|
||||||
whitenoise==6.5.0 # https://github.com/evansd/whitenoise
|
whitenoise==6.6.0 # https://github.com/evansd/whitenoise
|
||||||
{%- endif %}
|
{%- 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" %}
|
{%- 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 %}
|
{%- endif %}
|
||||||
{%- if cookiecutter.use_celery == "y" %}
|
{%- 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
|
django-celery-beat==2.5.0 # https://github.com/celery/django-celery-beat
|
||||||
{%- if cookiecutter.use_docker == 'y' %}
|
{%- 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 %}
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{%- if cookiecutter.use_async == 'y' %}
|
{%- 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 %}
|
{%- endif %}
|
||||||
|
|
||||||
# Django
|
# Django
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
django==4.2.3 # pyup: < 5.0 # https://www.djangoproject.com/
|
django==4.2.10 # pyup: < 5.0 # https://www.djangoproject.com/
|
||||||
django-environ==0.10.0 # https://github.com/joke2k/django-environ
|
django-environ==0.11.2 # https://github.com/joke2k/django-environ
|
||||||
django-model-utils==4.3.1 # https://github.com/jazzband/django-model-utils
|
django-model-utils==4.4.0 # https://github.com/jazzband/django-model-utils
|
||||||
django-allauth==0.54.0 # https://github.com/pennersr/django-allauth
|
django-allauth==0.61.1 # https://github.com/pennersr/django-allauth
|
||||||
django-crispy-forms==2.0 # https://github.com/django-crispy-forms/django-crispy-forms
|
django-crispy-forms==2.1 # https://github.com/django-crispy-forms/django-crispy-forms
|
||||||
crispy-bootstrap5==0.7 # https://github.com/django-crispy-forms/crispy-bootstrap5
|
crispy-bootstrap5==2023.10 # https://github.com/django-crispy-forms/crispy-bootstrap5
|
||||||
{%- if cookiecutter.frontend_pipeline == 'Django Compressor' %}
|
{%- if cookiecutter.frontend_pipeline == 'Django Compressor' %}
|
||||||
django-compressor==4.4 # https://github.com/django-compressor/django-compressor
|
django-compressor==4.4 # https://github.com/django-compressor/django-compressor
|
||||||
{%- endif %}
|
{%- 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' %}
|
{%- if cookiecutter.use_drf == 'y' %}
|
||||||
# Django REST Framework
|
# Django REST Framework
|
||||||
djangorestframework==3.14.0 # https://github.com/encode/django-rest-framework
|
djangorestframework==3.14.0 # https://github.com/encode/django-rest-framework
|
||||||
django-cors-headers==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 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 %}
|
{%- endif %}
|
||||||
{%- if cookiecutter.frontend_pipeline == 'Webpack' %}
|
{%- 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 %}
|
{%- endif %}
|
||||||
|
|
|
@ -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
|
ipdb==0.13.13 # https://github.com/gotcha/ipdb
|
||||||
{%- if cookiecutter.use_docker == 'y' %}
|
{%- 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 %}
|
{%- else %}
|
||||||
psycopg[binary]==3.1.9 # https://github.com/psycopg/psycopg
|
psycopg[binary]==3.1.18 # https://github.com/psycopg/psycopg
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{%- if cookiecutter.use_async == 'y' or cookiecutter.use_celery == 'y' %}
|
{%- 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 %}
|
{%- endif %}
|
||||||
|
|
||||||
# Testing
|
# Testing
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
mypy==1.4.1 # https://github.com/python/mypy
|
mypy==1.7.1 # https://github.com/python/mypy
|
||||||
django-stubs==4.2.3 # https://github.com/typeddjango/django-stubs
|
django-stubs[compatible-mypy]==4.2.7 # https://github.com/typeddjango/django-stubs
|
||||||
pytest==7.4.0 # https://github.com/pytest-dev/pytest
|
pytest==8.0.0 # https://github.com/pytest-dev/pytest
|
||||||
pytest-sugar==0.9.7 # https://github.com/Frozenball/pytest-sugar
|
pytest-sugar==1.0.0 # https://github.com/Frozenball/pytest-sugar
|
||||||
{%- if cookiecutter.use_drf == "y" %}
|
{%- 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 %}
|
{%- endif %}
|
||||||
|
|
||||||
# Documentation
|
# Documentation
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
sphinx==6.2.1 # https://github.com/sphinx-doc/sphinx
|
sphinx==7.2.6 # https://github.com/sphinx-doc/sphinx
|
||||||
sphinx-autobuild==2021.3.14 # https://github.com/GaretJax/sphinx-autobuild
|
sphinx-autobuild==2024.2.4 # https://github.com/GaretJax/sphinx-autobuild
|
||||||
|
|
||||||
# Code quality
|
# Code quality
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
flake8==6.0.0 # https://github.com/PyCQA/flake8
|
flake8==7.0.0 # https://github.com/PyCQA/flake8
|
||||||
flake8-isort==6.0.0 # https://github.com/gforcada/flake8-isort
|
flake8-isort==6.1.1 # https://github.com/gforcada/flake8-isort
|
||||||
coverage==7.2.7 # https://github.com/nedbat/coveragepy
|
coverage==7.4.1 # https://github.com/nedbat/coveragepy
|
||||||
black==23.3.0 # https://github.com/psf/black
|
black==24.1.1 # https://github.com/psf/black
|
||||||
djlint==1.31.1 # https://github.com/Riverside-Healthcare/djLint
|
djlint==1.34.1 # https://github.com/Riverside-Healthcare/djLint
|
||||||
pylint-django==2.5.3 # https://github.com/PyCQA/pylint-django
|
pylint-django==2.5.5 # https://github.com/PyCQA/pylint-django
|
||||||
{%- if cookiecutter.use_celery == 'y' %}
|
{%- if cookiecutter.use_celery == 'y' %}
|
||||||
pylint-celery==0.3 # https://github.com/PyCQA/pylint-celery
|
pylint-celery==0.3 # https://github.com/PyCQA/pylint-celery
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
pre-commit==3.3.3 # https://github.com/pre-commit/pre-commit
|
pre-commit==3.6.1 # https://github.com/pre-commit/pre-commit
|
||||||
|
|
||||||
# Django
|
# 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-extensions==3.2.3 # https://github.com/django-extensions/django-extensions
|
||||||
django-coverage-plugin==3.0.0 # https://github.com/nedbat/django_coverage_plugin
|
django-coverage-plugin==3.1.0 # https://github.com/nedbat/django_coverage_plugin
|
||||||
pytest-django==4.5.2 # https://github.com/pytest-dev/pytest-django
|
pytest-django==4.8.0 # https://github.com/pytest-dev/pytest-django
|
||||||
|
|
|
@ -2,43 +2,43 @@
|
||||||
|
|
||||||
-r base.txt
|
-r base.txt
|
||||||
|
|
||||||
gunicorn==20.1.0 # https://github.com/benoitc/gunicorn
|
gunicorn==21.2.0 # https://github.com/benoitc/gunicorn
|
||||||
psycopg[c]==3.1.9 # https://github.com/psycopg/psycopg
|
psycopg[c]==3.1.18 # https://github.com/psycopg/psycopg
|
||||||
{%- if cookiecutter.use_whitenoise == 'n' %}
|
{%- if cookiecutter.use_whitenoise == 'n' %}
|
||||||
Collectfast==2.2.0 # https://github.com/antonagestam/collectfast
|
Collectfast==2.2.0 # https://github.com/antonagestam/collectfast
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{%- if cookiecutter.use_sentry == "y" %}
|
{%- if cookiecutter.use_sentry == "y" %}
|
||||||
sentry-sdk==1.27.0 # https://github.com/getsentry/sentry-python
|
sentry-sdk==1.40.3 # https://github.com/getsentry/sentry-python
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{%- if cookiecutter.use_docker == "n" and cookiecutter.windows == "y" %}
|
{%- if cookiecutter.use_docker == "n" and cookiecutter.windows == "y" %}
|
||||||
hiredis==2.2.3 # https://github.com/redis/hiredis-py
|
hiredis==2.3.2 # https://github.com/redis/hiredis-py
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
||||||
# Django
|
# Django
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
{%- if cookiecutter.cloud_provider == 'AWS' %}
|
{%- if cookiecutter.cloud_provider == 'AWS' %}
|
||||||
django-storages[boto3]==1.13.2 # https://github.com/jschneier/django-storages
|
django-storages[s3]==1.14.2 # https://github.com/jschneier/django-storages
|
||||||
{%- elif cookiecutter.cloud_provider == 'GCP' %}
|
{%- 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' %}
|
{%- 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 %}
|
{%- endif %}
|
||||||
{%- if cookiecutter.mail_service == 'Mailgun' %}
|
{%- 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' %}
|
{%- 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' %}
|
{%- 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' %}
|
{%- 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' %}
|
{%- 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' %}
|
{%- 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' %}
|
{%- 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' %}
|
{%- 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' %}
|
{%- 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 %}
|
{%- endif %}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
python-3.11.4
|
python-3.11.7
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
[flake8]
|
[flake8]
|
||||||
max-line-length = 119
|
max-line-length = 119
|
||||||
exclude = .tox,.git,*/migrations/*,*/static/CACHE/*,docs,node_modules,venv,.venv
|
exclude = .tox,.git,*/migrations/*,*/static/CACHE/*,docs,node_modules,venv,.venv
|
||||||
|
extend-ignore = E203
|
||||||
|
|
||||||
[pycodestyle]
|
[pycodestyle]
|
||||||
max-line-length = 119
|
max-line-length = 119
|
||||||
|
|
|
@ -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
|
|
@ -13,6 +13,13 @@ module.exports = merge(commonConfig, {
|
||||||
'/': 'http://django:8000',
|
'/': 'http://django:8000',
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
},
|
},
|
||||||
|
client: {
|
||||||
|
overlay: {
|
||||||
|
errors: true,
|
||||||
|
warnings: false,
|
||||||
|
runtimeErrors: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
// We need hot=false (Disable HMR) to set liveReload=true
|
// We need hot=false (Disable HMR) to set liveReload=true
|
||||||
hot: false,
|
hot: false,
|
||||||
liveReload: true,
|
liveReload: true,
|
||||||
|
|
|
@ -40,8 +40,8 @@ def update_site_forward(apps, schema_editor):
|
||||||
_update_or_create_site_with_sequence(
|
_update_or_create_site_with_sequence(
|
||||||
Site,
|
Site,
|
||||||
schema_editor.connection,
|
schema_editor.connection,
|
||||||
"{{cookiecutter.domain_name}}",
|
"{{ cookiecutter.domain_name }}",
|
||||||
"{{cookiecutter.project_name}}",
|
"{{ cookiecutter.project_name[:50] }}",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
{% raw %}{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}Forbidden (403){% endblock title %}
|
||||||
|
{% block content %}
|
||||||
|
<h1>Forbidden (403)</h1>
|
||||||
|
<p>
|
||||||
|
{% if exception %}
|
||||||
|
{{ exception }}
|
||||||
|
{% else %}
|
||||||
|
You're not allowed to access this page.
|
||||||
|
{% endif %}
|
||||||
|
</p>
|
||||||
|
{% endblock content %}
|
||||||
|
{%- endraw %}
|
|
@ -22,11 +22,17 @@
|
||||||
{% else %}
|
{% else %}
|
||||||
{% raw %}{{ object.username }}{% endraw %}
|
{% raw %}{{ object.username }}{% endraw %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% raw %}
|
|
||||||
</h2>
|
</h2>
|
||||||
{% if object.name %}<p>{{ object.name }}</p>{% endif %}
|
{%- if cookiecutter.username_type == "username" %}
|
||||||
|
{%- raw %}
|
||||||
|
{% if object.name %}
|
||||||
|
<p>{{ object.name }}</p>
|
||||||
|
{% endif %}
|
||||||
|
{%- endraw %}
|
||||||
|
{%- endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{%- raw %}
|
||||||
{% if object == request.user %}
|
{% if object == request.user %}
|
||||||
<!-- Action buttons -->
|
<!-- Action buttons -->
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
|
@ -25,13 +25,14 @@ class SocialAccountAdapter(DefaultSocialAccountAdapter):
|
||||||
"""
|
"""
|
||||||
Populates user information from social provider info.
|
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
|
user = super().populate_user(request, sociallogin, data)
|
||||||
if name := data.get("name"):
|
if not user.name:
|
||||||
user.name = name
|
if name := data.get("name"):
|
||||||
elif first_name := data.get("first_name"):
|
user.name = name
|
||||||
user.name = first_name
|
elif first_name := data.get("first_name"):
|
||||||
if last_name := data.get("last_name"):
|
user.name = first_name
|
||||||
user.name += f" {last_name}"
|
if last_name := data.get("last_name"):
|
||||||
return super().populate_user(request, sociallogin, data)
|
user.name += f" {last_name}"
|
||||||
|
return user
|
||||||
|
|
|
@ -10,7 +10,7 @@ User = get_user_model()
|
||||||
|
|
||||||
if settings.DJANGO_ADMIN_FORCE_ALLAUTH:
|
if settings.DJANGO_ADMIN_FORCE_ALLAUTH:
|
||||||
# Force the `admin` sign in process to go through the `django-allauth` workflow:
|
# 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]
|
admin.site.login = decorators.login_required(admin.site.login) # type: ignore[method-assign]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
|
from {{ cookiecutter.project_slug }}.users.models import User as UserType
|
||||||
|
|
||||||
|
|
||||||
User = get_user_model()
|
User = get_user_model()
|
||||||
|
|
||||||
|
|
||||||
class UserSerializer(serializers.ModelSerializer):
|
class UserSerializer(serializers.ModelSerializer[UserType]):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = User
|
model = User
|
||||||
{%- if cookiecutter.username_type == "email" %}
|
{%- if cookiecutter.username_type == "email" %}
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from django.contrib.auth.hashers import make_password
|
from django.contrib.auth.hashers import make_password
|
||||||
from django.contrib.auth.models import UserManager as DjangoUserManager
|
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."""
|
"""Custom manager for the User model."""
|
||||||
|
|
||||||
def _create_user(self, email: str, password: str | None, **extra_fields):
|
def _create_user(self, email: str, password: str | None, **extra_fields):
|
||||||
|
@ -17,12 +22,12 @@ class UserManager(DjangoUserManager):
|
||||||
user.save(using=self._db)
|
user.save(using=self._db)
|
||||||
return user
|
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_staff", False)
|
||||||
extra_fields.setdefault("is_superuser", False)
|
extra_fields.setdefault("is_superuser", False)
|
||||||
return self._create_user(email, password, **extra_fields)
|
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_staff", True)
|
||||||
extra_fields.setdefault("is_superuser", True)
|
extra_fields.setdefault("is_superuser", True)
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
{%- if cookiecutter.username_type == "email" %}
|
||||||
|
from typing import ClassVar
|
||||||
|
{%- endif %}
|
||||||
|
|
||||||
from django.contrib.auth.models import AbstractUser
|
from django.contrib.auth.models import AbstractUser
|
||||||
from django.db.models import CharField{% if cookiecutter.username_type == "email" %}, EmailField{% endif %}
|
from django.db.models import CharField{% if cookiecutter.username_type == "email" %}, EmailField{% endif %}
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
@ -26,7 +30,7 @@ class User(AbstractUser):
|
||||||
USERNAME_FIELD = "email"
|
USERNAME_FIELD = "email"
|
||||||
REQUIRED_FIELDS = []
|
REQUIRED_FIELDS = []
|
||||||
|
|
||||||
objects = UserManager()
|
objects: ClassVar[UserManager] = UserManager()
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
||||||
def get_absolute_url(self) -> str:
|
def get_absolute_url(self) -> str:
|
||||||
|
|
|
@ -29,6 +29,13 @@ class UserFactory(DjangoModelFactory):
|
||||||
)
|
)
|
||||||
self.set_password(password)
|
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:
|
class Meta:
|
||||||
model = get_user_model()
|
model = get_user_model()
|
||||||
django_get_or_create = ["{{cookiecutter.username_type}}"]
|
django_get_or_create = ["{{cookiecutter.username_type}}"]
|
||||||
|
|
|
@ -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 django.urls import reverse
|
||||||
|
from pytest_django.asserts import assertRedirects
|
||||||
|
|
||||||
from {{ cookiecutter.project_slug }}.users.models import User
|
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})
|
url = reverse("admin:users_user_change", kwargs={"object_id": user.pk})
|
||||||
response = admin_client.get(url)
|
response = admin_client.get(url)
|
||||||
assert response.status_code == 200
|
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)
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
"""
|
"""Module for all Form Tests."""
|
||||||
Module for all Form Tests.
|
|
||||||
"""
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from {{ cookiecutter.project_slug }}.users.forms import UserAdminCreationForm
|
from {{ cookiecutter.project_slug }}.users.forms import UserAdminCreationForm
|
||||||
|
|
|
@ -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 %}
|
|
Loading…
Reference in New Issue
Block a user