mirror of
https://github.com/cookiecutter/cookiecutter-django.git
synced 2025-08-17 02:14:53 +03:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
e129a3cbc2
|
@ -12,7 +12,7 @@ trim_trailing_whitespace = true
|
|||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
[*.{html,css,scss,json,yml}]
|
||||
[*.{html,css,scss,json,yml,xml}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
|
|
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
|
@ -9,4 +9,4 @@ community_bridge: # Replace with a single Community Bridge project-name e.g., cl
|
|||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
custom: ['https://www.patreon.com/browniebroke']
|
||||
custom: ["https://www.patreon.com/browniebroke"]
|
||||
|
|
2
.github/ISSUE_TEMPLATE/bug.md
vendored
2
.github/ISSUE_TEMPLATE/bug.md
vendored
|
@ -51,7 +51,7 @@ labels: bug
|
|||
Logs:
|
||||
<details>
|
||||
<pre>
|
||||
$ cookiecutter https://github.com/pydanny/cookiecutter-django
|
||||
$ cookiecutter https://github.com/cookiecutter/cookiecutter-django
|
||||
project_name [Project Name]: ...
|
||||
</pre>
|
||||
</details>
|
||||
|
|
2
.github/ISSUE_TEMPLATE/paid-support.md
vendored
2
.github/ISSUE_TEMPLATE/paid-support.md
vendored
|
@ -3,7 +3,7 @@ name: Paid Support Request
|
|||
about: Ask Core Team members to help you out
|
||||
---
|
||||
|
||||
Provided your question goes beyond [regular support](https://github.com/pydanny/cookiecutter-django/issues/new?template=question.md), and/or the task at hand is of timely/high priority nature use the below information to reach out for contributors directly.
|
||||
Provided your question goes beyond [regular support](https://github.com/cookiecutter/cookiecutter-django/issues/new?template=question.md), and/or the task at hand is of timely/high priority nature use the below information to reach out for contributors directly.
|
||||
|
||||
* Daniel Roy Greenfeld, Project Lead ([GitHub](https://github.com/pydanny), [Patreon](https://www.patreon.com/danielroygreenfeld)): expertise in Django and AWS ELB.
|
||||
|
||||
|
|
10
.github/ISSUE_TEMPLATE/question.md
vendored
10
.github/ISSUE_TEMPLATE/question.md
vendored
|
@ -1,11 +1,11 @@
|
|||
---
|
||||
name: Question
|
||||
about: Please consider asking your question on StackOverflow or Slack
|
||||
about: Please ask your question on StackOverflow, Discord or GitHub Discussions.
|
||||
labels: question
|
||||
---
|
||||
|
||||
First, make sure to examine [the docs](https://cookiecutter-django.readthedocs.io/en/latest/).
|
||||
First, make sure to examine [the docs](https://cookiecutter-django.readthedocs.io/en/latest/). If that doesn't help, we recommend one of these 3 main channels:
|
||||
|
||||
If that doesn't help, post a question on [StackOverflow](https://stackoverflow.com/questions/tagged/cookiecutter-django) tagged with `cookiecutter-django`, you might get more visibility there than on our issue tracker.
|
||||
|
||||
Finally, feel free to join [Slack](https://join.slack.com/t/cookie-cutter/shared_invite/enQtNzI0Mzg5NjE5Nzk5LTRlYWI2YTZhYmQ4YmU1Y2Q2NmE1ZjkwOGM0NDQyNTIwY2M4ZTgyNDVkNjMxMDdhZGI5ZGE5YmJjM2M3ODJlY2U) and ask around.
|
||||
- If your issue is related to Django + something else but was generated with cookiecutter-django, the best is to post a question on [StackOverflow](https://stackoverflow.com/questions/tagged/cookiecutter-django) tagged with `cookiecutter-django`, you would get more visibility from other communities as well.
|
||||
- Join us on [Discord](https://discord.gg/bTfDa6Zz) and ask around.
|
||||
- Start [a discussion](https://github.com/cookiecutter/cookiecutter-django/discussions) on our project's GitHub.
|
||||
|
|
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
|
@ -7,7 +7,7 @@
|
|||
|
||||
Checklist:
|
||||
|
||||
- [ ] I've made sure that `tests/test_cookiecutter_generation.py` is updated accordingly (especially if adding or updating a template option)
|
||||
- [ ] I've made sure that tests are updated accordingly (especially if adding or updating a template option)
|
||||
- [ ] I've updated the documentation or confirm that my change doesn't require any updates
|
||||
|
||||
## Rationale
|
||||
|
|
3
.github/changelog-template.md
vendored
3
.github/changelog-template.md
vendored
|
@ -1,9 +1,8 @@
|
|||
## [{{merge_date.strftime('%Y-%m-%d')}}]
|
||||
{%- for change_type, pulls in grouped_pulls.items() %}
|
||||
{%- if pulls %}
|
||||
### {{ change_type }}
|
||||
{%- for pull_request in pulls %}
|
||||
- {{ pull_request.title }} ([#{{ pull_request.number }}]({{ pull_request.url }}))
|
||||
- {{ pull_request.title }} ([#{{ pull_request.number }}]({{ pull_request.html_url }}))
|
||||
{%- endfor -%}
|
||||
{% endif -%}
|
||||
{% endfor -%}
|
||||
|
|
100
.github/contributors.json
vendored
100
.github/contributors.json
vendored
|
@ -1127,5 +1127,105 @@
|
|||
"name": "Mike97M",
|
||||
"github_login": "Mike97M",
|
||||
"twitter_username": ""
|
||||
},
|
||||
{
|
||||
"name": "Charlie Macfarlane Brodie",
|
||||
"github_login": "tannart",
|
||||
"twitter_username": ""
|
||||
},
|
||||
{
|
||||
"name": "Floyd Hightower",
|
||||
"github_login": "fhightower",
|
||||
"twitter_username": ""
|
||||
},
|
||||
{
|
||||
"name": "Manjit Pardeshi",
|
||||
"github_login": "Manjit2003",
|
||||
"twitter_username": ""
|
||||
},
|
||||
{
|
||||
"name": "Meraj ",
|
||||
"github_login": "ichbinmeraj",
|
||||
"twitter_username": "merajsafari"
|
||||
},
|
||||
{
|
||||
"name": "dalrrard",
|
||||
"github_login": "dalrrard",
|
||||
"twitter_username": ""
|
||||
},
|
||||
{
|
||||
"name": "Liam Brenner",
|
||||
"github_login": "SableWalnut",
|
||||
"twitter_username": ""
|
||||
},
|
||||
{
|
||||
"name": "Noah H",
|
||||
"github_login": "nthall",
|
||||
"twitter_username": ""
|
||||
},
|
||||
{
|
||||
"name": "Diego Montes",
|
||||
"github_login": "d57montes",
|
||||
"twitter_username": ""
|
||||
},
|
||||
{
|
||||
"name": "Chao Yang Wu",
|
||||
"github_login": "goatwu1993",
|
||||
"twitter_username": ""
|
||||
},
|
||||
{
|
||||
"name": "mpoli",
|
||||
"github_login": "mpoli",
|
||||
"twitter_username": ""
|
||||
},
|
||||
{
|
||||
"name": "Zach Borboa",
|
||||
"github_login": "zachborboa",
|
||||
"twitter_username": ""
|
||||
},
|
||||
{
|
||||
"name": "Timm Simpkins",
|
||||
"github_login": "PoDuck",
|
||||
"twitter_username": ""
|
||||
},
|
||||
{
|
||||
"name": "Douglas",
|
||||
"github_login": "douglascdev",
|
||||
"twitter_username": ""
|
||||
},
|
||||
{
|
||||
"name": "Will Gordon",
|
||||
"github_login": "wgordon17",
|
||||
"twitter_username": ""
|
||||
},
|
||||
{
|
||||
"name": "Bogdan Mateescu",
|
||||
"github_login": "mateesville93",
|
||||
"twitter_username": ""
|
||||
},
|
||||
{
|
||||
"name": "Fuzzwah",
|
||||
"github_login": "Fuzzwah",
|
||||
"twitter_username": ""
|
||||
},
|
||||
{
|
||||
"name": "Thibault J.",
|
||||
"github_login": "thibault",
|
||||
"twitter_username": "thibault"
|
||||
},
|
||||
{
|
||||
"name": "Pedro Campos",
|
||||
"github_login": "pcampos119104",
|
||||
"twitter_username": ""
|
||||
},
|
||||
{
|
||||
"name": "Vikas Yadav",
|
||||
"github_login": "vik-y",
|
||||
"twitter_username": ""
|
||||
},
|
||||
{
|
||||
"name": "Abdullah Adeel",
|
||||
"github_login": "mabdullahadeel",
|
||||
"twitter_username": "abdadeel_"
|
||||
}
|
||||
]
|
||||
|
|
12
.github/dependabot.yml
vendored
12
.github/dependabot.yml
vendored
|
@ -1,12 +1,20 @@
|
|||
# Config for Dependabot updates. See Documentation here:
|
||||
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||
# https://docs.github.com/code-security/supply-chain-security/keeping-your-dependencies-updated-automatically/configuration-options-for-dependency-updates
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
# Update Github actions in workflows
|
||||
# Update GitHub actions in workflows
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
labels:
|
||||
- "update"
|
||||
|
||||
# Update npm packages
|
||||
- package-ecosystem: "npm"
|
||||
directory: "{{cookiecutter.project_slug}}/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
labels:
|
||||
- "update"
|
||||
|
|
29
.github/release-drafter.yml
vendored
29
.github/release-drafter.yml
vendored
|
@ -1,29 +0,0 @@
|
|||
categories:
|
||||
- title: 'Breaking Changes'
|
||||
labels:
|
||||
- 'breaking'
|
||||
- title: 'Major Changes'
|
||||
labels:
|
||||
- 'major'
|
||||
- title: 'Minor Changes'
|
||||
labels:
|
||||
- 'enhancement'
|
||||
- title: 'Bugfixes'
|
||||
labels:
|
||||
- 'bug'
|
||||
- title: 'Removals'
|
||||
labels:
|
||||
- 'removed'
|
||||
- title: 'Documentation updates'
|
||||
labels:
|
||||
- 'docs'
|
||||
|
||||
exclude-labels:
|
||||
- 'skip-changelog'
|
||||
- 'update'
|
||||
- 'project infrastructure'
|
||||
|
||||
template: |
|
||||
## Changes
|
||||
|
||||
$CHANGES
|
64
.github/workflows/ci.yml
vendored
64
.github/workflows/ci.yml
vendored
|
@ -2,33 +2,43 @@ name: CI
|
|||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
tox:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: "3.9"
|
||||
cache: pip
|
||||
- name: Run pre-commit
|
||||
uses: pre-commit/action@v2.0.3
|
||||
|
||||
tests:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
tox-env:
|
||||
- py39
|
||||
- black-template
|
||||
os:
|
||||
- ubuntu-latest
|
||||
- windows-latest
|
||||
- macOS-latest
|
||||
|
||||
name: "Run tests"
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2.2.2
|
||||
- uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.9
|
||||
python-version: "3.9"
|
||||
cache: pip
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install -U pip
|
||||
python -m pip install -U tox
|
||||
- name: Tox ${{ matrix.tox-env }}
|
||||
run: tox -e ${{ matrix.tox-env }}
|
||||
run: pip install -r requirements.txt
|
||||
- name: Run tests
|
||||
run: pytest tests
|
||||
|
||||
docker:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
@ -38,27 +48,35 @@ jobs:
|
|||
- name: Extended
|
||||
args: "use_celery=y use_drf=y js_task_runner=Gulp"
|
||||
|
||||
name: "${{ matrix.script.name }} Docker"
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DOCKER_BUILDKIT: 1
|
||||
COMPOSE_DOCKER_CLI_BUILD: 1
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2.2.2
|
||||
- uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.9
|
||||
python-version: "3.9"
|
||||
cache: pip
|
||||
- name: Install dependencies
|
||||
run: pip install -r requirements.txt
|
||||
- name: Docker ${{ matrix.script.name }}
|
||||
run: sh tests/test_docker.sh ${{ matrix.script.args }}
|
||||
|
||||
bare:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
script:
|
||||
- name: With Celery
|
||||
args: "use_celery=y use_compressor=y"
|
||||
- name: With Gulp
|
||||
args: "js_task_runner=Gulp custom_bootstrap_compilation=y"
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
name: "${{ matrix.script.name }} Bare metal"
|
||||
services:
|
||||
redis:
|
||||
image: redis:5.0
|
||||
|
@ -78,8 +96,18 @@ jobs:
|
|||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2.2.2
|
||||
- uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.9
|
||||
python-version: "3.9"
|
||||
cache: pip
|
||||
cache-dependency-path: |
|
||||
requirements.txt
|
||||
{{cookiecutter.project_slug}}/requirements/base.txt
|
||||
{{cookiecutter.project_slug}}/requirements/local.txt
|
||||
- name: Install dependencies
|
||||
run: pip install -r requirements.txt
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: "16"
|
||||
- name: Bare Metal ${{ matrix.script.name }}
|
||||
run: sh tests/test_bare.sh ${{ matrix.script.args }}
|
||||
|
|
30
.github/workflows/django-issue-checker.yml
vendored
Normal file
30
.github/workflows/django-issue-checker.yml
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
# Creates a new issue for Major/Minor Django updates that keeps track
|
||||
# of all dependencies that need to be updated/merged in order for the
|
||||
# latest Django version to also be merged.
|
||||
name: Django Issue Checker
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "28 5 * * *"
|
||||
# Manual trigger
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
issue-checker:
|
||||
# Disables this workflow from running in a repository that is not part of the indicated organization/user
|
||||
if: github.repository_owner == 'cookiecutter'
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: "3.9"
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -r requirements.txt
|
||||
- name: Create Django Major Issue
|
||||
run: python scripts/create_django_issue.py
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
14
.github/workflows/draft-release.yml
vendored
14
.github/workflows/draft-release.yml
vendored
|
@ -1,14 +0,0 @@
|
|||
name: Release Drafter
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
release_notes:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: release-drafter/release-drafter@v5
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
60
.github/workflows/issue-manager.yml
vendored
60
.github/workflows/issue-manager.yml
vendored
|
@ -1,62 +1,40 @@
|
|||
# Automatically close issues that have a keyword mark (an HTML comment)
|
||||
# in the last comment in the issue, by a group of predefined users, after a custom delay.
|
||||
# Automatically close issues or pull requests that have a label, after a custom delay, if no one replies.
|
||||
# https://github.com/tiangolo/issue-manager
|
||||
|
||||
# Default config:
|
||||
# <!-- issue-manager: answered -->
|
||||
# Wait 10 days and comment: "Assuming the original issue was solved, it will be automatically closed now"
|
||||
|
||||
# Extra config:
|
||||
# '<!-- issue-manager: waiting -->'
|
||||
# Wait 10 days and comment: "Automatically closing. To re-open, please provide the additional information requested"
|
||||
|
||||
name: Issue Manager
|
||||
|
||||
on:
|
||||
# Every day at midnight
|
||||
schedule:
|
||||
- cron: "0 0 * * *"
|
||||
# Manual trigger
|
||||
- cron: "12 0 * * *"
|
||||
issue_comment:
|
||||
types:
|
||||
- created
|
||||
issues:
|
||||
types:
|
||||
- labeled
|
||||
pull_request_target:
|
||||
types:
|
||||
- labeled
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
issue-manager:
|
||||
# Disables this workflow from running in a repository that is not part of the indicated organization/user
|
||||
if: github.repository_owner == 'cookiecutter'
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: tiangolo/issue-manager@0.4.0
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
config: >
|
||||
{
|
||||
"answered": {
|
||||
"delay": 864000,
|
||||
"message": "Assuming the original issue was solved, it will be automatically closed now.",
|
||||
"users": [
|
||||
"pydanny",
|
||||
"audreyr",
|
||||
"luzfcb",
|
||||
"theskumar",
|
||||
"jayfk",
|
||||
"burhan",
|
||||
"webyneter",
|
||||
"browniebroke",
|
||||
"sfdye"
|
||||
]
|
||||
"message": "Assuming the question was answered, this will be automatically closed now."
|
||||
},
|
||||
"solved": {
|
||||
"message": "Assuming the original issue was solved, it will be automatically closed now."
|
||||
},
|
||||
"waiting": {
|
||||
"delay": 864000,
|
||||
"message": "Automatically closing. To re-open, please provide the additional information requested.",
|
||||
"users": [
|
||||
"pydanny",
|
||||
"audreyr",
|
||||
"luzfcb",
|
||||
"theskumar",
|
||||
"jayfk",
|
||||
"burhan",
|
||||
"webyneter",
|
||||
"browniebroke",
|
||||
"sfdye"
|
||||
]
|
||||
"message": "Automatically closing after waiting for additional info. To re-open, please provide the additional information requested."
|
||||
}
|
||||
}
|
||||
|
|
17
.github/workflows/pre-commit-autoupdate.yml
vendored
17
.github/workflows/pre-commit-autoupdate.yml
vendored
|
@ -1,32 +1,37 @@
|
|||
# Run pre-commit autoupdate every day at midnight
|
||||
# and create a pull request if any changes
|
||||
|
||||
|
||||
name: Pre-commit auto-update
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 0 * * *"
|
||||
- cron: "15 2 * * *"
|
||||
workflow_dispatch: # to trigger manually
|
||||
|
||||
jobs:
|
||||
auto-update:
|
||||
# Disables this workflow from running in a repository that is not part of the indicated organization/user
|
||||
if: github.repository_owner == 'cookiecutter'
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2.2.2
|
||||
- uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.9
|
||||
python-version: "3.9"
|
||||
|
||||
- name: Install pre-commit
|
||||
run: pip install pre-commit
|
||||
|
||||
- name: Run pre-commit autoupdate
|
||||
- name: Autoupdate template
|
||||
run: pre-commit autoupdate
|
||||
|
||||
- name: Autoupdate generated projects
|
||||
working-directory: "{{cookiecutter.project_slug}}"
|
||||
run: pre-commit autoupdate
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v3.10.0
|
||||
uses: peter-evans/create-pull-request@v3.12.0
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
branch: update/pre-commit-autoupdate
|
||||
|
|
20
.github/workflows/update-changelog.yml
vendored
20
.github/workflows/update-changelog.yml
vendored
|
@ -8,27 +8,27 @@ on:
|
|||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
release:
|
||||
# Disables this workflow from running in a repository that is not part of the indicated organization/user
|
||||
if: github.repository_owner == 'cookiecutter'
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2.2.2
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.9
|
||||
python-version: "3.9"
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -r requirements.txt
|
||||
- name: Set git details
|
||||
run: |
|
||||
git config --global user.name "github-actions"
|
||||
git config --global user.email "action@github.com"
|
||||
- name: Update list
|
||||
run: python scripts/update_changelog.py
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Commit changes
|
||||
uses: stefanzweifel/git-auto-commit-action@v4.11.0
|
||||
with:
|
||||
commit_message: Update Changelog
|
||||
file_pattern: CHANGELOG.md
|
||||
|
|
10
.github/workflows/update-contributors.yml
vendored
10
.github/workflows/update-contributors.yml
vendored
|
@ -7,15 +7,17 @@ on:
|
|||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
# Disables this workflow from running in a repository that is not part of the indicated organization/user
|
||||
if: github.repository_owner == 'cookiecutter'
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2.2.2
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.9
|
||||
python-version: "3.9"
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
|
@ -24,7 +26,7 @@ jobs:
|
|||
run: python scripts/update_contributors.py
|
||||
|
||||
- name: Commit changes
|
||||
uses: stefanzweifel/git-auto-commit-action@v4.11.0
|
||||
uses: stefanzweifel/git-auto-commit-action@v4.13.1
|
||||
with:
|
||||
commit_message: Update Contributors
|
||||
file_pattern: CONTRIBUTORS.md .github/contributors.json
|
||||
|
|
29
.pre-commit-config.yaml
Normal file
29
.pre-commit-config.yaml
Normal file
|
@ -0,0 +1,29 @@
|
|||
exclude: "{{cookiecutter.project_slug}}"
|
||||
default_stages: [commit]
|
||||
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.1.0
|
||||
hooks:
|
||||
- id: trailing-whitespace
|
||||
- id: check-yaml
|
||||
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 21.12b0
|
||||
hooks:
|
||||
- id: black
|
||||
|
||||
- repo: https://github.com/PyCQA/isort
|
||||
rev: 5.10.1
|
||||
hooks:
|
||||
- id: isort
|
||||
|
||||
- repo: https://github.com/PyCQA/flake8
|
||||
rev: 4.0.1
|
||||
hooks:
|
||||
- id: flake8
|
||||
|
||||
ci:
|
||||
autoupdate_schedule: weekly
|
||||
skip: []
|
||||
submodules: false
|
|
@ -15,6 +15,7 @@ label_prs: update
|
|||
|
||||
requirements:
|
||||
- "requirements.txt"
|
||||
- "docs/requirements.txt"
|
||||
- "{{cookiecutter.project_slug}}/requirements/base.txt"
|
||||
- "{{cookiecutter.project_slug}}/requirements/local.txt"
|
||||
- "{{cookiecutter.project_slug}}/requirements/production.txt"
|
||||
|
|
15
.readthedocs.yaml
Normal file
15
.readthedocs.yaml
Normal file
|
@ -0,0 +1,15 @@
|
|||
# Read the Docs configuration file
|
||||
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
|
||||
|
||||
# Required
|
||||
version: 2
|
||||
|
||||
# Build documentation in the docs/ directory with Sphinx
|
||||
sphinx:
|
||||
configuration: docs/conf.py
|
||||
|
||||
# Version of Python and requirements required to build the docs
|
||||
python:
|
||||
version: "3.8"
|
||||
install:
|
||||
- requirements: docs/requirements.txt
|
1201
CHANGELOG.md
1201
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
42
CONTRIBUTING.md
Normal file
42
CONTRIBUTING.md
Normal file
|
@ -0,0 +1,42 @@
|
|||
# How to Contribute
|
||||
|
||||
Always happy to get issues identified and pull requests!
|
||||
|
||||
## Getting your pull request merged in
|
||||
|
||||
1. Keep it small. The smaller the pull request, the more likely we are to accept.
|
||||
2. Pull requests that fix a current issue get priority for review.
|
||||
|
||||
## Testing
|
||||
|
||||
### Installation
|
||||
|
||||
Please install [tox](https://tox.readthedocs.io/en/latest/), which is a generic virtualenv management and test command line tool.
|
||||
|
||||
[tox](https://tox.readthedocs.io/en/latest/) is available for download from [PyPI](https://pypi.python.org/pypi) via [pip](https://pypi.python.org/pypi/pip/):
|
||||
|
||||
$ pip install tox
|
||||
|
||||
It will automatically create a fresh virtual environment and install our test dependencies,
|
||||
such as [pytest-cookies](https://pypi.python.org/pypi/pytest-cookies/) and [flake8](https://pypi.python.org/pypi/flake8/).
|
||||
|
||||
### Run the Tests
|
||||
|
||||
Tox uses pytest under the hood, hence it supports the same syntax for selecting tests.
|
||||
|
||||
For further information please consult the [pytest usage docs](https://pytest.org/latest/usage.html#specifying-tests-selecting-tests).
|
||||
|
||||
To run all tests using various versions of python in virtualenvs defined in tox.ini, just run tox.:
|
||||
|
||||
$ tox
|
||||
|
||||
It is possible to test with a specific version of python. To do this, the command
|
||||
is:
|
||||
|
||||
$ tox -e py39
|
||||
|
||||
This will run pytest with the python3.9 interpreter, for example.
|
||||
|
||||
To run a particular test with tox for against your current Python version:
|
||||
|
||||
$ tox -e py -- -k test_default_configuration
|
|
@ -1,54 +0,0 @@
|
|||
How to Contribute
|
||||
=================
|
||||
|
||||
Always happy to get issues identified and pull requests!
|
||||
|
||||
Getting your pull request merged in
|
||||
------------------------------------
|
||||
|
||||
#. Keep it small. The smaller the pull request the more likely I'll pull it in.
|
||||
#. Pull requests that fix a current issue get priority for review.
|
||||
|
||||
Testing
|
||||
-------
|
||||
|
||||
Installation
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Please install `tox`_, which is a generic virtualenv management and test command line tool.
|
||||
|
||||
`tox`_ is available for download from `PyPI`_ via `pip`_::
|
||||
|
||||
$ pip install tox
|
||||
|
||||
It will automatically create a fresh virtual environment and install our test dependencies,
|
||||
such as `pytest-cookies`_ and `flake8`_.
|
||||
|
||||
Run the Tests
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
Tox uses py.test under the hood, hence it supports the same syntax for selecting tests.
|
||||
|
||||
For further information please consult the `pytest usage docs`_.
|
||||
|
||||
To run all tests using various versions of python in virtualenvs defined in tox.ini, just run tox.::
|
||||
|
||||
$ tox
|
||||
|
||||
It is possible to test with a specific version of python. To do this, the command
|
||||
is::
|
||||
|
||||
$ tox -e py39
|
||||
|
||||
This will run py.test with the python3.9 interpreter, for example.
|
||||
|
||||
To run a particular test with tox for against your current Python version::
|
||||
|
||||
$ tox -e py -- -k test_default_configuration
|
||||
|
||||
.. _`pytest usage docs`: https://pytest.org/latest/usage.html#specifying-tests-selecting-tests
|
||||
.. _`tox`: https://tox.readthedocs.io/en/latest/
|
||||
.. _`pip`: https://pypi.python.org/pypi/pip/
|
||||
.. _`pytest-cookies`: https://pypi.python.org/pypi/pytest-cookies/
|
||||
.. _`flake8`: https://pypi.python.org/pypi/flake8/
|
||||
.. _`PyPI`: https://pypi.python.org/pypi
|
140
CONTRIBUTORS.md
140
CONTRIBUTORS.md
|
@ -131,6 +131,13 @@ Listed in alphabetical order.
|
|||
</td>
|
||||
<td>Qoyyuum</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Abdullah Adeel</td>
|
||||
<td>
|
||||
<a href="https://github.com/mabdullahadeel">mabdullahadeel</a>
|
||||
</td>
|
||||
<td>abdadeel_</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Adam Bogdał</td>
|
||||
<td>
|
||||
|
@ -348,6 +355,13 @@ Listed in alphabetical order.
|
|||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Bogdan Mateescu</td>
|
||||
<td>
|
||||
<a href="https://github.com/mateesville93">mateesville93</a>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Bouke Haarsma</td>
|
||||
<td>
|
||||
|
@ -390,6 +404,20 @@ Listed in alphabetical order.
|
|||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Chao Yang Wu</td>
|
||||
<td>
|
||||
<a href="https://github.com/goatwu1993">goatwu1993</a>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Charlie Macfarlane Brodie</td>
|
||||
<td>
|
||||
<a href="https://github.com/tannart">tannart</a>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Charlie Smith</td>
|
||||
<td>
|
||||
|
@ -495,6 +523,13 @@ Listed in alphabetical order.
|
|||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>dalrrard</td>
|
||||
<td>
|
||||
<a href="https://github.com/dalrrard">dalrrard</a>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Dan Shultz</td>
|
||||
<td>
|
||||
|
@ -600,6 +635,13 @@ Listed in alphabetical order.
|
|||
</td>
|
||||
<td>purplediane88</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Diego Montes</td>
|
||||
<td>
|
||||
<a href="https://github.com/d57montes">d57montes</a>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Dong Huynh</td>
|
||||
<td>
|
||||
|
@ -607,6 +649,13 @@ Listed in alphabetical order.
|
|||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Douglas</td>
|
||||
<td>
|
||||
<a href="https://github.com/douglascdev">douglascdev</a>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Duda Nogueira</td>
|
||||
<td>
|
||||
|
@ -684,6 +733,20 @@ Listed in alphabetical order.
|
|||
</td>
|
||||
<td>windrush</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Floyd Hightower</td>
|
||||
<td>
|
||||
<a href="https://github.com/fhightower">fhightower</a>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Fuzzwah</td>
|
||||
<td>
|
||||
<a href="https://github.com/Fuzzwah">Fuzzwah</a>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Gabriel Mejia</td>
|
||||
<td>
|
||||
|
@ -1055,6 +1118,13 @@ Listed in alphabetical order.
|
|||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Liam Brenner</td>
|
||||
<td>
|
||||
<a href="https://github.com/SableWalnut">SableWalnut</a>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Lin Xianyi</td>
|
||||
<td>
|
||||
|
@ -1090,6 +1160,13 @@ Listed in alphabetical order.
|
|||
</td>
|
||||
<td>flyudvik</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Manjit Pardeshi</td>
|
||||
<td>
|
||||
<a href="https://github.com/Manjit2003">Manjit2003</a>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Martin Blech</td>
|
||||
<td>
|
||||
|
@ -1174,6 +1251,13 @@ Listed in alphabetical order.
|
|||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Meraj </td>
|
||||
<td>
|
||||
<a href="https://github.com/ichbinmeraj">ichbinmeraj</a>
|
||||
</td>
|
||||
<td>merajsafari</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Mesut Yılmaz</td>
|
||||
<td>
|
||||
|
@ -1223,6 +1307,13 @@ Listed in alphabetical order.
|
|||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>mpoli</td>
|
||||
<td>
|
||||
<a href="https://github.com/mpoli">mpoli</a>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Nico Stefani</td>
|
||||
<td>
|
||||
|
@ -1230,6 +1321,13 @@ Listed in alphabetical order.
|
|||
</td>
|
||||
<td>moby_dick91</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Noah H</td>
|
||||
<td>
|
||||
<a href="https://github.com/nthall">nthall</a>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Oleg Russkin</td>
|
||||
<td>
|
||||
|
@ -1258,6 +1356,13 @@ Listed in alphabetical order.
|
|||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Pedro Campos</td>
|
||||
<td>
|
||||
<a href="https://github.com/pcampos119104">pcampos119104</a>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Peter Bittner</td>
|
||||
<td>
|
||||
|
@ -1447,6 +1552,13 @@ Listed in alphabetical order.
|
|||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Thibault J.</td>
|
||||
<td>
|
||||
<a href="https://github.com/thibault">thibault</a>
|
||||
</td>
|
||||
<td>thibault</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Théo Segonds</td>
|
||||
<td>
|
||||
|
@ -1468,6 +1580,13 @@ Listed in alphabetical order.
|
|||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Timm Simpkins</td>
|
||||
<td>
|
||||
<a href="https://github.com/PoDuck">PoDuck</a>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Tom Atkins</td>
|
||||
<td>
|
||||
|
@ -1524,6 +1643,13 @@ Listed in alphabetical order.
|
|||
</td>
|
||||
<td>highcenburg</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Vikas Yadav</td>
|
||||
<td>
|
||||
<a href="https://github.com/vik-y">vik-y</a>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Vitaly Babiy</td>
|
||||
<td>
|
||||
|
@ -1559,6 +1685,13 @@ Listed in alphabetical order.
|
|||
</td>
|
||||
<td>g01dhand</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Will Gordon</td>
|
||||
<td>
|
||||
<a href="https://github.com/wgordon17">wgordon17</a>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>William Archinal</td>
|
||||
<td>
|
||||
|
@ -1594,6 +1727,13 @@ Listed in alphabetical order.
|
|||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Zach Borboa</td>
|
||||
<td>
|
||||
<a href="https://github.com/zachborboa">zachborboa</a>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
### Special Thanks
|
||||
|
|
252
README.md
Normal file
252
README.md
Normal file
|
@ -0,0 +1,252 @@
|
|||
# Cookiecutter Django
|
||||
|
||||
[](https://github.com/cookiecutter/cookiecutter-django/actions?query=workflow%3ACI)
|
||||
[](https://cookiecutter-django.readthedocs.io/en/latest/?badge=latest)
|
||||
[](https://pyup.io/repos/github/cookiecutter/cookiecutter-django/)
|
||||
[](https://discord.gg/9BrxzPKuEW)
|
||||
[](https://www.codetriage.com/cookiecutter/cookiecutter-django)
|
||||
[](https://github.com/ambv/black)
|
||||
|
||||
Powered by [Cookiecutter](https://github.com/cookiecutter/cookiecutter), Cookiecutter Django is a framework for jumpstarting
|
||||
production-ready Django projects quickly.
|
||||
|
||||
- Documentation: <https://cookiecutter-django.readthedocs.io/en/latest/>
|
||||
- See [Troubleshooting](https://cookiecutter-django.readthedocs.io/en/latest/troubleshooting.html) for common errors and obstacles
|
||||
- If you have problems with Cookiecutter Django, please open [issues](https://github.com/cookiecutter/cookiecutter-django/issues/new) don't send
|
||||
emails to the maintainers.
|
||||
|
||||
## Features
|
||||
|
||||
- For Django 3.2
|
||||
- Works with Python 3.9
|
||||
- Renders Django projects with 100% starting test coverage
|
||||
- Twitter [Bootstrap](https://github.com/twbs/bootstrap) v5
|
||||
- [12-Factor](http://12factor.net/) based settings via [django-environ](https://github.com/joke2k/django-environ)
|
||||
- Secure by default. We believe in SSL.
|
||||
- Optimized development and production settings
|
||||
- Registration via [django-allauth](https://github.com/pennersr/django-allauth)
|
||||
- Comes with custom user model ready to go
|
||||
- Optional basic ASGI setup for Websockets
|
||||
- Optional custom static build using Gulp and livereload
|
||||
- Send emails via [Anymail](https://github.com/anymail/django-anymail) (using [Mailgun](http://www.mailgun.com/) by default or Amazon SES if AWS is selected cloud provider, but switchable)
|
||||
- Media storage using Amazon S3 or Google Cloud Storage
|
||||
- Docker support using [docker-compose](https://github.com/docker/compose) for development and production (using [Traefik](https://traefik.io/) with [LetsEncrypt](https://letsencrypt.org/) support)
|
||||
- [Procfile](https://devcenter.heroku.com/articles/procfile) for deploying to Heroku
|
||||
- Instructions for deploying to [PythonAnywhere](https://www.pythonanywhere.com/)
|
||||
- Run tests with unittest or pytest
|
||||
- Customizable PostgreSQL version
|
||||
- Default integration with [pre-commit](https://github.com/pre-commit/pre-commit) for identifying simple issues before submission to code review
|
||||
|
||||
## Optional Integrations
|
||||
|
||||
*These features can be enabled during initial project setup.*
|
||||
|
||||
- Serve static files from Amazon S3, Google Cloud Storage or [Whitenoise](https://whitenoise.readthedocs.io/)
|
||||
- Configuration for [Celery](http://www.celeryproject.org/) 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 [Sentry](https://sentry.io/welcome/) for error logging
|
||||
|
||||
## Constraints
|
||||
|
||||
- Only maintained 3rd party libraries are used.
|
||||
- Uses PostgreSQL everywhere: 10.19 - 14.1 ([MySQL fork](https://github.com/mabdullahadeel/cookiecutter-django-mysql) also available).
|
||||
- Environment variables for configuration (This won't work with Apache/mod_wsgi).
|
||||
|
||||
## Support this Project!
|
||||
|
||||
This project is run by volunteers. Please support them in their efforts to maintain and improve Cookiecutter Django:
|
||||
|
||||
- Daniel Roy Greenfeld, Project Lead ([GitHub](https://github.com/pydanny), [Patreon](https://www.patreon.com/danielroygreenfeld)): expertise in Django and AWS ELB.
|
||||
- Nikita Shupeyko, Core Developer ([GitHub](https://github.com/webyneter)): expertise in Python/Django, hands-on DevOps and frontend experience.
|
||||
|
||||
Projects that provide financial support to the maintainers:
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
<p align="center">
|
||||
<a href="https://www.feldroy.com/products//two-scoops-of-django-3-x"><img src="https://cdn.shopify.com/s/files/1/0304/6901/products/Two-Scoops-of-Django-3-Alpha-Cover_540x_26507b15-e489-470b-8a97-02773dd498d1_1080x.jpg"></a>
|
||||
</p>
|
||||
|
||||
Two Scoops of Django 3.x is the best ice cream-themed Django reference in the universe!
|
||||
|
||||
### PyUp
|
||||
|
||||
<p align="center">
|
||||
<a href="https://pyup.io/"><img src="https://pyup.io/static/images/logo.png"></a>
|
||||
</p>
|
||||
|
||||
PyUp brings you automated security and dependency updates used by Google and other organizations. Free for open source projects!
|
||||
|
||||
## Usage
|
||||
|
||||
Let's pretend you want to create a Django project called "redditclone". Rather than using `startproject`
|
||||
and then editing the results to include your name, email, and various configuration issues that always get forgotten until the worst possible moment, get [cookiecutter](https://github.com/cookiecutter/cookiecutter) to do all the work.
|
||||
|
||||
First, get Cookiecutter. Trust me, it's awesome:
|
||||
|
||||
$ pip install "cookiecutter>=1.7.0"
|
||||
|
||||
Now run it against this repo:
|
||||
|
||||
$ cookiecutter https://github.com/cookiecutter/cookiecutter-django
|
||||
|
||||
You'll be prompted for some values. Provide them, then a Django project will be created for you.
|
||||
|
||||
**Warning**: After this point, change 'Daniel Greenfeld', 'pydanny', etc to your own information.
|
||||
|
||||
Answer the prompts with your own desired [options](http://cookiecutter-django.readthedocs.io/en/latest/project-generation-options.html). For example:
|
||||
|
||||
Cloning into 'cookiecutter-django'...
|
||||
remote: Counting objects: 550, done.
|
||||
remote: Compressing objects: 100% (310/310), done.
|
||||
remote: Total 550 (delta 283), reused 479 (delta 222)
|
||||
Receiving objects: 100% (550/550), 127.66 KiB | 58 KiB/s, done.
|
||||
Resolving deltas: 100% (283/283), done.
|
||||
project_name [My Awesome Project]: Reddit Clone
|
||||
project_slug [reddit_clone]: reddit
|
||||
description [Behold My Awesome Project!]: A reddit clone.
|
||||
author_name [Daniel Roy Greenfeld]: Daniel Greenfeld
|
||||
domain_name [example.com]: myreddit.com
|
||||
email [daniel-greenfeld@example.com]: pydanny@gmail.com
|
||||
version [0.1.0]: 0.0.1
|
||||
Select open_source_license:
|
||||
1 - MIT
|
||||
2 - BSD
|
||||
3 - GPLv3
|
||||
4 - Apache Software License 2.0
|
||||
5 - Not open source
|
||||
Choose from 1, 2, 3, 4, 5 [1]: 1
|
||||
timezone [UTC]: America/Los_Angeles
|
||||
windows [n]: n
|
||||
use_pycharm [n]: y
|
||||
use_docker [n]: n
|
||||
Select postgresql_version:
|
||||
1 - 14.1
|
||||
2 - 13.5
|
||||
3 - 12.9
|
||||
4 - 11.14
|
||||
5 - 10.19
|
||||
Choose from 1, 2, 3, 4, 5 [1]: 1
|
||||
Select js_task_runner:
|
||||
1 - None
|
||||
2 - Gulp
|
||||
Choose from 1, 2 [1]: 1
|
||||
Select cloud_provider:
|
||||
1 - AWS
|
||||
2 - GCP
|
||||
3 - None
|
||||
Choose from 1, 2, 3 [1]: 1
|
||||
Select mail_service:
|
||||
1 - Mailgun
|
||||
2 - Amazon SES
|
||||
3 - Mailjet
|
||||
4 - Mandrill
|
||||
5 - Postmark
|
||||
6 - Sendgrid
|
||||
7 - SendinBlue
|
||||
8 - SparkPost
|
||||
9 - Other SMTP
|
||||
Choose from 1, 2, 3, 4, 5, 6, 7, 8, 9 [1]: 1
|
||||
use_async [n]: n
|
||||
use_drf [n]: y
|
||||
custom_bootstrap_compilation [n]: n
|
||||
use_compressor [n]: n
|
||||
use_celery [n]: y
|
||||
use_mailhog [n]: n
|
||||
use_sentry [n]: y
|
||||
use_whitenoise [n]: n
|
||||
use_heroku [n]: y
|
||||
Select ci_tool:
|
||||
1 - None
|
||||
2 - Travis
|
||||
3 - Gitlab
|
||||
4 - Github
|
||||
Choose from 1, 2, 3, 4 [1]: 4
|
||||
keep_local_envs_in_vcs [y]: y
|
||||
debug [n]: n
|
||||
|
||||
Enter the project and take a look around:
|
||||
|
||||
$ cd reddit/
|
||||
$ ls
|
||||
|
||||
Create a git repo and push it there:
|
||||
|
||||
$ git init
|
||||
$ git add .
|
||||
$ git commit -m "first awesome commit"
|
||||
$ git remote add origin git@github.com:pydanny/redditclone.git
|
||||
$ git push -u origin master
|
||||
|
||||
Now take a look at your repo. Don't forget to carefully look at the generated README. Awesome, right?
|
||||
|
||||
For local development, see the following:
|
||||
|
||||
- [Developing locally](http://cookiecutter-django.readthedocs.io/en/latest/developing-locally.html)
|
||||
- [Developing locally using docker](http://cookiecutter-django.readthedocs.io/en/latest/developing-locally-docker.html)
|
||||
|
||||
## Community
|
||||
|
||||
- Have questions? **Before you ask questions anywhere else**, please post your question on [Stack Overflow](http://stackoverflow.com/questions/tagged/cookiecutter-django) under the *cookiecutter-django* tag. We check there periodically for questions.
|
||||
- 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/9BrxzPKuEW).
|
||||
|
||||
## 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.
|
||||
|
||||
## For PyUp Users
|
||||
|
||||
If you are using [PyUp](https://pyup.io) to keep your dependencies updated and secure, use the code *cookiecutter* during checkout to get 15% off every month.
|
||||
|
||||
## "Your Stuff"
|
||||
|
||||
Scattered throughout the Python and HTML of this project are places marked with "your stuff". This is where third-party libraries are to be integrated with your project.
|
||||
|
||||
## For MySQL users
|
||||
To get full MySQL support in addition to the default Postgresql, you can use this fork of the cookiecutter-django:
|
||||
https://github.com/mabdullahadeel/cookiecutter-django-mysql
|
||||
|
||||
## Releases
|
||||
|
||||
Need a stable release? You can find them at <https://github.com/cookiecutter/cookiecutter-django/releases>
|
||||
|
||||
## Not Exactly What You Want?
|
||||
|
||||
This is what I want. *It might not be what you want.* Don't worry, you have options:
|
||||
|
||||
### Fork This
|
||||
|
||||
If you have differences in your preferred setup, I encourage you to fork this to create your own version.
|
||||
Once you have your fork working, let me know and I'll add it to a '*Similar Cookiecutter Templates*' list here.
|
||||
It's up to you whether to rename your fork.
|
||||
|
||||
If you do rename your fork, I encourage you to submit it to the following places:
|
||||
|
||||
- [cookiecutter](https://github.com/cookiecutter/cookiecutter) so it gets listed in the README as a template.
|
||||
- The cookiecutter [grid](https://www.djangopackages.com/grids/g/cookiecutters/) on Django Packages.
|
||||
|
||||
### Submit a Pull Request
|
||||
|
||||
We accept pull requests if they're small, atomic, and make our own project development
|
||||
experience better.
|
||||
|
||||
## Articles
|
||||
|
||||
- [Using cookiecutter-django with Google Cloud Storage](https://ahhda.github.io/cloud/gce/django/2019/03/12/using-django-cookiecutter-cloud-storage.html) - Mar. 12, 2019
|
||||
- [cookiecutter-django with Nginx, Route 53 and ELB](https://msaizar.com/blog/cookiecutter-django-nginx-route-53-and-elb/) - Feb. 12, 2018
|
||||
- [cookiecutter-django and Amazon RDS](https://msaizar.com/blog/cookiecutter-django-and-amazon-rds/) - Feb. 7, 2018
|
||||
- [Using Cookiecutter to Jumpstart a Django Project on Windows with PyCharm](https://joshuahunter.com/posts/using-cookiecutter-to-jumpstart-a-django-project-on-windows-with-pycharm/) - May 19, 2017
|
||||
- [Exploring with Cookiecutter](http://www.snowboardingcoder.com/django/2016/12/03/exploring-with-cookiecutter/) - Dec. 3, 2016
|
||||
- [Introduction to Cookiecutter-Django](http://krzysztofzuraw.com/blog/2016/django-cookiecutter.html) - Feb. 19, 2016
|
||||
- [Django and GitLab - Running Continuous Integration and tests with your FREE account](http://dezoito.github.io/2016/05/11/django-gitlab-continuous-integration-phantomjs.html) - May. 11, 2016
|
||||
- [Development and Deployment of Cookiecutter-Django on Fedora](https://realpython.com/blog/python/development-and-deployment-of-cookiecutter-django-on-fedora/) - Jan. 18, 2016
|
||||
- [Development and Deployment of Cookiecutter-Django via Docker](https://realpython.com/blog/python/development-and-deployment-of-cookiecutter-django-via-docker/) - Dec. 29, 2015
|
||||
- [How to create a Django Application using Cookiecutter and Django 1.8](https://www.swapps.io/blog/how-to-create-a-django-application-using-cookiecutter-and-django-1-8/) - Sept. 12, 2015
|
||||
|
||||
Have a blog or online publication? Write about your cookiecutter-django tips and tricks, then send us a pull request with the link.
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
Everyone interacting in the Cookiecutter project's codebases, issue trackers, chat
|
||||
rooms, and mailing lists is expected to follow the [PyPA Code of Conduct](https://www.pypa.io/en/latest/code-of-conduct/).
|
326
README.rst
326
README.rst
|
@ -1,326 +0,0 @@
|
|||
Cookiecutter Django
|
||||
===================
|
||||
|
||||
.. image:: https://img.shields.io/github/workflow/status/pydanny/cookiecutter-django/CI/master
|
||||
:target: https://github.com/pydanny/cookiecutter-django/actions?query=workflow%3ACI
|
||||
:alt: Build Status
|
||||
|
||||
.. image:: https://readthedocs.org/projects/cookiecutter-django/badge/?version=latest
|
||||
:target: https://cookiecutter-django.readthedocs.io/en/latest/?badge=latest
|
||||
:alt: Documentation Status
|
||||
|
||||
.. image:: https://pyup.io/repos/github/pydanny/cookiecutter-django/shield.svg
|
||||
:target: https://pyup.io/repos/github/pydanny/cookiecutter-django/
|
||||
:alt: Updates
|
||||
|
||||
.. image:: https://img.shields.io/badge/cookiecutter-Join%20on%20Slack-green?style=flat&logo=slack
|
||||
:target: https://join.slack.com/t/cookie-cutter/shared_invite/enQtNzI0Mzg5NjE5Nzk5LTRlYWI2YTZhYmQ4YmU1Y2Q2NmE1ZjkwOGM0NDQyNTIwY2M4ZTgyNDVkNjMxMDdhZGI5ZGE5YmJjM2M3ODJlY2U
|
||||
|
||||
.. image:: https://www.codetriage.com/pydanny/cookiecutter-django/badges/users.svg
|
||||
:target: https://www.codetriage.com/pydanny/cookiecutter-django
|
||||
:alt: Code Helpers Badge
|
||||
|
||||
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
|
||||
:target: https://github.com/ambv/black
|
||||
:alt: Code style: black
|
||||
|
||||
Powered by Cookiecutter_, Cookiecutter Django is a framework for jumpstarting
|
||||
production-ready Django projects quickly.
|
||||
|
||||
* Documentation: https://cookiecutter-django.readthedocs.io/en/latest/
|
||||
* See Troubleshooting_ for common errors and obstacles
|
||||
* If you have problems with Cookiecutter Django, please open issues_ don't send
|
||||
emails to the maintainers.
|
||||
|
||||
.. _Troubleshooting: https://cookiecutter-django.readthedocs.io/en/latest/troubleshooting.html
|
||||
|
||||
.. _528: https://github.com/pydanny/cookiecutter-django/issues/528#issuecomment-212650373
|
||||
.. _issues: https://github.com/pydanny/cookiecutter-django/issues/new
|
||||
|
||||
Features
|
||||
---------
|
||||
|
||||
* For Django 3.1
|
||||
* Works with Python 3.9
|
||||
* Renders Django projects with 100% starting test coverage
|
||||
* Twitter Bootstrap_ v4 (`maintained Foundation fork`_ also available)
|
||||
* 12-Factor_ based settings via django-environ_
|
||||
* Secure by default. We believe in SSL.
|
||||
* Optimized development and production settings
|
||||
* Registration via django-allauth_
|
||||
* Comes with custom user model ready to go
|
||||
* Optional basic ASGI setup for Websockets
|
||||
* Optional custom static build using Gulp and livereload
|
||||
* Send emails via Anymail_ (using Mailgun_ by default or Amazon SES if AWS is selected cloud provider, but switchable)
|
||||
* Media storage using Amazon S3, Google Cloud Storage, or a local nginx docker instance
|
||||
* Docker support using docker-compose_ for development and production (using Traefik_ with LetsEncrypt_ support)
|
||||
* Procfile_ for deploying to Heroku
|
||||
* Instructions for deploying to PythonAnywhere_
|
||||
* Run tests with unittest or pytest
|
||||
* Customizable PostgreSQL version
|
||||
* Default integration with pre-commit_ for identifying simple issues before submission to code review
|
||||
|
||||
.. _`maintained Foundation fork`: https://github.com/Parbhat/cookiecutter-django-foundation
|
||||
|
||||
|
||||
Optional Integrations
|
||||
---------------------
|
||||
|
||||
*These features can be enabled during initial project setup.*
|
||||
|
||||
* Serve static files from Amazon S3, Google Cloud Storage or Whitenoise_
|
||||
* Configuration for Celery_ and Flower_ (the latter in Docker setup only)
|
||||
* Integration with MailHog_ for local email testing
|
||||
* Integration with Sentry_ for error logging
|
||||
|
||||
.. _Bootstrap: https://github.com/twbs/bootstrap
|
||||
.. _django-environ: https://github.com/joke2k/django-environ
|
||||
.. _12-Factor: http://12factor.net/
|
||||
.. _django-allauth: https://github.com/pennersr/django-allauth
|
||||
.. _django-avatar: https://github.com/grantmcconnaughey/django-avatar
|
||||
.. _Procfile: https://devcenter.heroku.com/articles/procfile
|
||||
.. _Mailgun: http://www.mailgun.com/
|
||||
.. _Whitenoise: https://whitenoise.readthedocs.io/
|
||||
.. _Celery: http://www.celeryproject.org/
|
||||
.. _Flower: https://github.com/mher/flower
|
||||
.. _Anymail: https://github.com/anymail/django-anymail
|
||||
.. _MailHog: https://github.com/mailhog/MailHog
|
||||
.. _Sentry: https://sentry.io/welcome/
|
||||
.. _docker-compose: https://github.com/docker/compose
|
||||
.. _PythonAnywhere: https://www.pythonanywhere.com/
|
||||
.. _Traefik: https://traefik.io/
|
||||
.. _LetsEncrypt: https://letsencrypt.org/
|
||||
.. _pre-commit: https://github.com/pre-commit/pre-commit
|
||||
|
||||
Constraints
|
||||
-----------
|
||||
|
||||
* Only maintained 3rd party libraries are used.
|
||||
* Uses PostgreSQL everywhere (10.16 - 13.2)
|
||||
* Environment variables for configuration (This won't work with Apache/mod_wsgi).
|
||||
|
||||
Support this Project!
|
||||
----------------------
|
||||
|
||||
This project is run by volunteers. Please support them in their efforts to maintain and improve Cookiecutter Django:
|
||||
|
||||
* Daniel Roy Greenfeld, Project Lead (`GitHub <https://github.com/pydanny>`_, `Patreon <https://www.patreon.com/danielroygreenfeld>`_): expertise in Django and AWS ELB.
|
||||
|
||||
* Nikita Shupeyko, Core Developer (`GitHub <https://github.com/webyneter>`_): expertise in Python/Django, hands-on DevOps and frontend experience.
|
||||
|
||||
Projects that provide financial support to the maintainers:
|
||||
|
||||
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. image:: https://cdn.shopify.com/s/files/1/0304/6901/products/Two-Scoops-of-Django-3-Alpha-Cover_540x_26507b15-e489-470b-8a97-02773dd498d1_1080x.jpg
|
||||
:name: Two Scoops of Django 3.x
|
||||
:align: center
|
||||
:alt: Two Scoops of Django
|
||||
:target: https://www.feldroy.com/products//two-scoops-of-django-3-x
|
||||
|
||||
Two Scoops of Django 3.x is the best ice cream-themed Django reference in the universe!
|
||||
|
||||
pyup
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. image:: https://pyup.io/static/images/logo.png
|
||||
:name: pyup
|
||||
:align: center
|
||||
:alt: pyup
|
||||
:target: https://pyup.io/
|
||||
|
||||
Pyup brings you automated security and dependency updates used by Google and other organizations. Free for open source projects!
|
||||
|
||||
Usage
|
||||
------
|
||||
|
||||
Let's pretend you want to create a Django project called "redditclone". Rather than using ``startproject``
|
||||
and then editing the results to include your name, email, and various configuration issues that always get forgotten until the worst possible moment, get cookiecutter_ to do all the work.
|
||||
|
||||
First, get Cookiecutter. Trust me, it's awesome::
|
||||
|
||||
$ pip install "cookiecutter>=1.7.0"
|
||||
|
||||
Now run it against this repo::
|
||||
|
||||
$ cookiecutter https://github.com/pydanny/cookiecutter-django
|
||||
|
||||
You'll be prompted for some values. Provide them, then a Django project will be created for you.
|
||||
|
||||
**Warning**: After this point, change 'Daniel Greenfeld', 'pydanny', etc to your own information.
|
||||
|
||||
Answer the prompts with your own desired options_. For example::
|
||||
|
||||
Cloning into 'cookiecutter-django'...
|
||||
remote: Counting objects: 550, done.
|
||||
remote: Compressing objects: 100% (310/310), done.
|
||||
remote: Total 550 (delta 283), reused 479 (delta 222)
|
||||
Receiving objects: 100% (550/550), 127.66 KiB | 58 KiB/s, done.
|
||||
Resolving deltas: 100% (283/283), done.
|
||||
project_name [Project Name]: Reddit Clone
|
||||
project_slug [reddit_clone]: reddit
|
||||
author_name [Daniel Roy Greenfeld]: Daniel Greenfeld
|
||||
email [you@example.com]: pydanny@gmail.com
|
||||
description [Behold My Awesome Project!]: A reddit clone.
|
||||
domain_name [example.com]: myreddit.com
|
||||
version [0.1.0]: 0.0.1
|
||||
timezone [UTC]: America/Los_Angeles
|
||||
use_whitenoise [n]: n
|
||||
use_celery [n]: y
|
||||
use_mailhog [n]: n
|
||||
use_sentry [n]: y
|
||||
use_pycharm [n]: y
|
||||
windows [n]: n
|
||||
use_docker [n]: n
|
||||
use_heroku [n]: y
|
||||
use_compressor [n]: y
|
||||
Select postgresql_version:
|
||||
1 - 13.2
|
||||
2 - 12.6
|
||||
3 - 11.11
|
||||
4 - 10.16
|
||||
Choose from 1, 2, 3, 4, 5 [1]: 1
|
||||
Select js_task_runner:
|
||||
1 - None
|
||||
2 - Gulp
|
||||
Choose from 1, 2 [1]: 1
|
||||
Select cloud_provider:
|
||||
1 - AWS
|
||||
2 - GCP
|
||||
3 - nginx
|
||||
4 - None
|
||||
Choose from 1, 2, 3, 4 [1]: 1
|
||||
use_nginx_for_serve_media_files[n]: n
|
||||
custom_bootstrap_compilation [n]: n
|
||||
Select open_source_license:
|
||||
1 - MIT
|
||||
2 - BSD
|
||||
3 - GPLv3
|
||||
4 - Apache Software License 2.0
|
||||
5 - Not open source
|
||||
Choose from 1, 2, 3, 4, 5 [1]: 1
|
||||
keep_local_envs_in_vcs [y]: y
|
||||
debug[n]: n
|
||||
|
||||
Enter the project and take a look around::
|
||||
|
||||
$ cd reddit/
|
||||
$ ls
|
||||
|
||||
Create a git repo and push it there::
|
||||
|
||||
$ git init
|
||||
$ git add .
|
||||
$ git commit -m "first awesome commit"
|
||||
$ git remote add origin git@github.com:pydanny/redditclone.git
|
||||
$ git push -u origin master
|
||||
|
||||
Now take a look at your repo. Don't forget to carefully look at the generated README. Awesome, right?
|
||||
|
||||
For local development, see the following:
|
||||
|
||||
* `Developing locally`_
|
||||
* `Developing locally using docker`_
|
||||
|
||||
.. _options: http://cookiecutter-django.readthedocs.io/en/latest/project-generation-options.html
|
||||
.. _`Developing locally`: http://cookiecutter-django.readthedocs.io/en/latest/developing-locally.html
|
||||
.. _`Developing locally using docker`: http://cookiecutter-django.readthedocs.io/en/latest/developing-locally-docker.html
|
||||
|
||||
Community
|
||||
-----------
|
||||
|
||||
* Have questions? **Before you ask questions anywhere else**, please post your question on `Stack Overflow`_ under the *cookiecutter-django* tag. We check there periodically for questions.
|
||||
* If you think you found a bug or want to request a feature, please open an issue_.
|
||||
* For anything else, you can chat with us on `Slack`_.
|
||||
|
||||
.. _`Stack Overflow`: http://stackoverflow.com/questions/tagged/cookiecutter-django
|
||||
.. _`issue`: https://github.com/pydanny/cookiecutter-django/issues
|
||||
.. _`Slack`: https://join.slack.com/t/cookie-cutter/shared_invite/enQtNzI0Mzg5NjE5Nzk5LTRlYWI2YTZhYmQ4YmU1Y2Q2NmE1ZjkwOGM0NDQyNTIwY2M4ZTgyNDVkNjMxMDdhZGI5ZGE5YmJjM2M3ODJlY2U
|
||||
|
||||
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.
|
||||
|
||||
For pyup.io Users
|
||||
-----------------
|
||||
|
||||
If you are using `pyup.io`_ to keep your dependencies updated and secure, use the code *cookiecutter* during checkout to get 15% off every month.
|
||||
|
||||
.. _`pyup.io`: https://pyup.io
|
||||
|
||||
"Your Stuff"
|
||||
-------------
|
||||
|
||||
Scattered throughout the Python and HTML of this project are places marked with "your stuff". This is where third-party libraries are to be integrated with your project.
|
||||
|
||||
Releases
|
||||
--------
|
||||
|
||||
Need a stable release? You can find them at https://github.com/pydanny/cookiecutter-django/releases
|
||||
|
||||
|
||||
Not Exactly What You Want?
|
||||
---------------------------
|
||||
|
||||
This is what I want. *It might not be what you want.* Don't worry, you have options:
|
||||
|
||||
Fork This
|
||||
~~~~~~~~~~
|
||||
|
||||
If you have differences in your preferred setup, I encourage you to fork this to create your own version.
|
||||
Once you have your fork working, let me know and I'll add it to a '*Similar Cookiecutter Templates*' list here.
|
||||
It's up to you whether or not to rename your fork.
|
||||
|
||||
If you do rename your fork, I encourage you to submit it to the following places:
|
||||
|
||||
* cookiecutter_ so it gets listed in the README as a template.
|
||||
* The cookiecutter grid_ on Django Packages.
|
||||
|
||||
.. _cookiecutter: https://github.com/cookiecutter/cookiecutter
|
||||
.. _grid: https://www.djangopackages.com/grids/g/cookiecutters/
|
||||
|
||||
Submit a Pull Request
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
We accept pull requests if they're small, atomic, and make our own project development
|
||||
experience better.
|
||||
|
||||
Articles
|
||||
---------
|
||||
|
||||
* `Using cookiecutter-django with Google Cloud Storage`_ - Mar. 12, 2019
|
||||
* `cookiecutter-django with Nginx, Route 53 and ELB`_ - Feb. 12, 2018
|
||||
* `cookiecutter-django and Amazon RDS`_ - Feb. 7, 2018
|
||||
* `Using Cookiecutter to Jumpstart a Django Project on Windows with PyCharm`_ - May 19, 2017
|
||||
* `Exploring with Cookiecutter`_ - Dec. 3, 2016
|
||||
* `Introduction to Cookiecutter-Django`_ - Feb. 19, 2016
|
||||
* `Django and GitLab - Running Continuous Integration and tests with your FREE account`_ - May. 11, 2016
|
||||
* `Development and Deployment of Cookiecutter-Django on Fedora`_ - Jan. 18, 2016
|
||||
* `Development and Deployment of Cookiecutter-Django via Docker`_ - Dec. 29, 2015
|
||||
* `How to create a Django Application using Cookiecutter and Django 1.8`_ - Sept. 12, 2015
|
||||
|
||||
Have a blog or online publication? Write about your cookiecutter-django tips and tricks, then send us a pull request with the link.
|
||||
|
||||
.. _`Using cookiecutter-django with Google Cloud Storage`: https://ahhda.github.io/cloud/gce/django/2019/03/12/using-django-cookiecutter-cloud-storage.html
|
||||
.. _`cookiecutter-django with Nginx, Route 53 and ELB`: https://msaizar.com/blog/cookiecutter-django-nginx-route-53-and-elb/
|
||||
.. _`cookiecutter-django and Amazon RDS`: https://msaizar.com/blog/cookiecutter-django-and-amazon-rds/
|
||||
.. _`Exploring with Cookiecutter`: http://www.snowboardingcoder.com/django/2016/12/03/exploring-with-cookiecutter/
|
||||
.. _`Using Cookiecutter to Jumpstart a Django Project on Windows with PyCharm`: https://joshuahunter.com/posts/using-cookiecutter-to-jumpstart-a-django-project-on-windows-with-pycharm/
|
||||
|
||||
.. _`Development and Deployment of Cookiecutter-Django via Docker`: https://realpython.com/blog/python/development-and-deployment-of-cookiecutter-django-via-docker/
|
||||
.. _`Development and Deployment of Cookiecutter-Django on Fedora`: https://realpython.com/blog/python/development-and-deployment-of-cookiecutter-django-on-fedora/
|
||||
.. _`How to create a Django Application using Cookiecutter and Django 1.8`: https://www.swapps.io/blog/how-to-create-a-django-application-using-cookiecutter-and-django-1-8/
|
||||
.. _`Introduction to Cookiecutter-Django`: http://krzysztofzuraw.com/blog/2016/django-cookiecutter.html
|
||||
.. _`Django and GitLab - Running Continuous Integration and tests with your FREE account`: http://dezoito.github.io/2016/05/11/django-gitlab-continuous-integration-phantomjs.html
|
||||
|
||||
Code of Conduct
|
||||
---------------
|
||||
|
||||
Everyone interacting in the Cookiecutter project's codebases, issue trackers, chat
|
||||
rooms, and mailing lists is expected to follow the `PyPA Code of Conduct`_.
|
||||
|
||||
|
||||
.. _`PyPA Code of Conduct`: https://www.pypa.io/en/latest/code-of-conduct/
|
|
@ -18,10 +18,11 @@
|
|||
"use_pycharm": "n",
|
||||
"use_docker": "n",
|
||||
"postgresql_version": [
|
||||
"13.2",
|
||||
"12.6",
|
||||
"11.11",
|
||||
"10.16"
|
||||
"14.1",
|
||||
"13.5",
|
||||
"12.9",
|
||||
"11.14",
|
||||
"10.19"
|
||||
],
|
||||
"js_task_runner": [
|
||||
"None",
|
||||
|
|
|
@ -7,10 +7,7 @@
|
|||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
from datetime import datetime
|
||||
import os
|
||||
import sys
|
||||
|
||||
now = datetime.now()
|
||||
|
||||
|
@ -92,7 +89,7 @@ pygments_style = "sphinx"
|
|||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
html_theme = "default"
|
||||
html_theme = "sphinx_rtd_theme"
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
|
@ -242,7 +239,8 @@ texinfo_documents = [
|
|||
"Cookiecutter Django documentation",
|
||||
"Daniel Roy Greenfeld",
|
||||
"Cookiecutter Django",
|
||||
"A Cookiecutter template for creating production-ready Django projects quickly.",
|
||||
"A Cookiecutter template for creating production-ready "
|
||||
"Django projects quickly.",
|
||||
"Miscellaneous",
|
||||
)
|
||||
]
|
||||
|
|
|
@ -3,8 +3,8 @@ Deployment on Heroku
|
|||
|
||||
.. index:: Heroku
|
||||
|
||||
Commands to run
|
||||
---------------
|
||||
Script
|
||||
------
|
||||
|
||||
Run these commands to deploy the project to Heroku:
|
||||
|
||||
|
@ -20,6 +20,7 @@ Run these commands to deploy the project to Heroku:
|
|||
|
||||
heroku addons:create heroku-redis:hobby-dev
|
||||
|
||||
# Assuming you chose Mailgun as mail service (see below for others)
|
||||
heroku addons:create mailgun:starter
|
||||
|
||||
heroku config:set PYTHONHASHSEED=random
|
||||
|
@ -53,11 +54,25 @@ Run these commands to deploy the project to Heroku:
|
|||
|
||||
heroku open
|
||||
|
||||
Notes
|
||||
-----
|
||||
|
||||
Email Service
|
||||
+++++++++++++
|
||||
|
||||
The script above assumes that you've chose Mailgun as email service. If you want to use another one, check the `documentation for django-anymail <https://anymail.readthedocs.io>`_ to know which environment variables to set. Heroku provides other `add-ons for emails <https://elements.heroku.com/addons#email-sms>`_ (e.g. Sendgrid) which can be configured with a similar one line command.
|
||||
|
||||
.. warning::
|
||||
|
||||
.. include:: mailgun.rst
|
||||
|
||||
Heroku & Docker
|
||||
+++++++++++++++
|
||||
|
||||
Although Heroku has some sort of `Docker support`_, it's not supported by cookiecutter-django.
|
||||
We invite you to follow Heroku documentation about it.
|
||||
|
||||
.. _Docker support: https://devcenter.heroku.com/articles/build-docker-images-heroku-yml
|
||||
|
||||
Optional actions
|
||||
----------------
|
||||
|
@ -111,11 +126,3 @@ which runs Gulp in cookiecutter-django.
|
|||
If things don't work, please refer to the Heroku docs.
|
||||
|
||||
.. _multiple buildpacks: https://devcenter.heroku.com/articles/using-multiple-buildpacks-for-an-app
|
||||
|
||||
About Heroku & Docker
|
||||
---------------------
|
||||
|
||||
Although Heroku has some sort of `Docker support`_, it's not supported by cookiecutter-django.
|
||||
We invite you to follow Heroku documentation about it.
|
||||
|
||||
.. _Docker support: https://devcenter.heroku.com/articles/build-docker-images-heroku-yml
|
||||
|
|
|
@ -15,7 +15,7 @@ Full instructions follow, but here's a high-level view.
|
|||
|
||||
2. Set your config variables in the *postactivate* script
|
||||
|
||||
3. Run the *manage.py* ``migrate`` and ``collectstatic`` {%- if cookiecutter.use_compressor == "y" %}and ``compress`` {%- endif %}commands
|
||||
3. Run the *manage.py* ``migrate`` and ``collectstatic`` commands. If you've opted for django-compressor, also run ``compress``
|
||||
|
||||
4. Add an entry to the PythonAnywhere *Web tab*
|
||||
|
||||
|
@ -25,7 +25,6 @@ Full instructions follow, but here's a high-level view.
|
|||
Once you've been through this one-off config, future deployments are much simpler: just ``git pull`` and then hit the "Reload" button :)
|
||||
|
||||
|
||||
|
||||
Getting your code and dependencies installed on PythonAnywhere
|
||||
--------------------------------------------------------------
|
||||
|
||||
|
@ -39,7 +38,6 @@ Make sure your project is fully committed and pushed up to Bitbucket or Github o
|
|||
pip install -r requirements/production.txt # may take a few minutes
|
||||
|
||||
|
||||
|
||||
Setting environment variables in the console
|
||||
--------------------------------------------
|
||||
|
||||
|
@ -57,7 +55,7 @@ Set environment variables via the virtualenv "postactivate" script (this will se
|
|||
|
||||
vi $VIRTUAL_ENV/bin/postactivate
|
||||
|
||||
**TIP:** *If you don't like vi, you can also edit this file via the PythonAnywhere "Files" menu; look in the ".virtualenvs" folder*.
|
||||
.. note:: If you don't like vi, you can also edit this file via the PythonAnywhere "Files" menu; look in the ".virtualenvs" folder.
|
||||
|
||||
Add these exports
|
||||
|
||||
|
@ -73,13 +71,14 @@ Add these exports
|
|||
export DJANGO_AWS_ACCESS_KEY_ID=
|
||||
export DJANGO_AWS_SECRET_ACCESS_KEY=
|
||||
export DJANGO_AWS_STORAGE_BUCKET_NAME=
|
||||
export DATABASE_URL='<see below>'
|
||||
export DATABASE_URL='<see Database setup section below>'
|
||||
export REDIS_URL='<see Redis section below>'
|
||||
|
||||
**NOTE:** *The AWS details are not required if you're using whitenoise or the built-in pythonanywhere static files service, but you do need to set them to blank, as above.*
|
||||
.. note:: The AWS details are not required if you're using whitenoise or the built-in pythonanywhere static files service, but you do need to set them to blank, as above.
|
||||
|
||||
|
||||
Database setup:
|
||||
---------------
|
||||
Database setup
|
||||
--------------
|
||||
|
||||
Go to the PythonAnywhere **Databases tab** and configure your database.
|
||||
|
||||
|
@ -109,18 +108,26 @@ Now run the migration, and collectstatic:
|
|||
source $VIRTUAL_ENV/bin/postactivate
|
||||
python manage.py migrate
|
||||
python manage.py collectstatic
|
||||
{%- if cookiecutter.use_compressor == "y" %}python manage.py compress {%- endif %}
|
||||
# if using django-compressor:
|
||||
python manage.py compress
|
||||
# and, optionally
|
||||
python manage.py createsuperuser
|
||||
|
||||
|
||||
Redis
|
||||
-----
|
||||
|
||||
PythonAnywhere does NOT `offer a built-in solution <https://www.pythonanywhere.com/forums/topic/1666/>`_ for Redis, however the production setup from Cookiecutter Django uses Redis as cache and requires one.
|
||||
|
||||
We recommend to signup to a separate service offering hosted Redis (e.g. `Redislab <https://redis.com/>`_) and use the URL they provide.
|
||||
|
||||
|
||||
Configure the PythonAnywhere Web Tab
|
||||
------------------------------------
|
||||
|
||||
Go to the PythonAnywhere **Web tab**, hit **Add new web app**, and choose **Manual Config**, and then the version of Python you used for your virtualenv.
|
||||
|
||||
**NOTE:** *If you're using a custom domain (not on \*.pythonanywhere.com), then you'll need to set up a CNAME with your domain registrar.*
|
||||
.. note:: If you're using a custom domain (not on \*.pythonanywhere.com), then you'll need to set up a CNAME with your domain registrar.
|
||||
|
||||
When you're redirected back to the web app config screen, set the **path to your virtualenv**. If you used virtualenvwrapper as above, you can just enter its name.
|
||||
|
||||
|
@ -153,15 +160,14 @@ Click through to the **WSGI configuration file** link (near the top) and edit th
|
|||
Back on the Web tab, hit **Reload**, and your app should be live!
|
||||
|
||||
|
||||
**NOTE:** *you may see security warnings until you set up your SSL certificates. If you
|
||||
want to suppress them temporarily, set DJANGO_SECURE_SSL_REDIRECT to blank. Follow
|
||||
the instructions here to get SSL set up: https://help.pythonanywhere.com/pages/SSLOwnDomains/*
|
||||
.. note:: You may see security warnings until you set up your SSL certificates. If you want to suppress them temporarily, set ``DJANGO_SECURE_SSL_REDIRECT`` to blank. Follow `these instructions <https://help.pythonanywhere.com/pages/HTTPSSetup>`_ to get SSL set up.
|
||||
|
||||
|
||||
|
||||
Optional: static files
|
||||
----------------------
|
||||
|
||||
If you want to use the PythonAnywhere static files service instead of using whitenoise or S3, you'll find its configuration section on the Web tab. Essentially you'll need an entry to match your ``STATIC_URL`` and ``STATIC_ROOT`` settings. There's more info here: https://help.pythonanywhere.com/pages/DjangoStaticFiles
|
||||
If you want to use the PythonAnywhere static files service instead of using whitenoise or S3, you'll find its configuration section on the Web tab. Essentially you'll need an entry to match your ``STATIC_URL`` and ``STATIC_ROOT`` settings. There's more info `in this article <https://help.pythonanywhere.com/pages/DjangoStaticFiles>`_.
|
||||
|
||||
|
||||
Future deployments
|
||||
|
@ -176,8 +182,9 @@ For subsequent deployments, the procedure is much simpler. In a Bash console:
|
|||
git pull
|
||||
python manage.py migrate
|
||||
python manage.py collectstatic
|
||||
{%- if cookiecutter.use_compressor == "y" %}python manage.py compress {%- endif %}
|
||||
# if using django-compressor:
|
||||
python manage.py compress
|
||||
|
||||
And then go to the Web tab and hit **Reload**
|
||||
|
||||
**TIP:** *if you're really keen, you can set up git-push based deployments: https://blog.pythonanywhere.com/87/*
|
||||
.. note:: If you're really keen, you can set up git-push based deployments: https://blog.pythonanywhere.com/87/
|
||||
|
|
|
@ -18,7 +18,7 @@ Prerequisites
|
|||
|
||||
* Docker; if you don't have it yet, follow the `installation instructions`_;
|
||||
* Docker Compose; refer to the official documentation for the `installation guide`_.
|
||||
* Pre-commit; refer to the official documentation for the `installation guide`_.
|
||||
* Pre-commit; refer to the official documentation for the [pre-commit](https://pre-commit.com/#install).
|
||||
|
||||
.. _`installation instructions`: https://docs.docker.com/install/#supported-platforms
|
||||
.. _`installation guide`: https://docs.docker.com/compose/install/
|
||||
|
@ -167,16 +167,18 @@ docker
|
|||
|
||||
The ``container_name`` from the yml file can be used to check on containers with docker commands, for example: ::
|
||||
|
||||
$ docker logs worker
|
||||
$ docker top worker
|
||||
$ docker logs <project_slug>_local_celeryworker
|
||||
$ docker top <project_slug>_local_celeryworker
|
||||
|
||||
|
||||
Notice that the ``container_name`` is generated dynamically using your project slug as a prefix
|
||||
|
||||
Mailhog
|
||||
~~~~~~~
|
||||
|
||||
When developing locally you can go with MailHog_ for email testing provided ``use_mailhog`` was set to ``y`` on setup. To proceed,
|
||||
|
||||
#. make sure ``mailhog`` container is up and running;
|
||||
#. make sure ``<project_slug>_local_mailhog`` container is up and running;
|
||||
|
||||
#. open up ``http://127.0.0.1:8025``.
|
||||
|
||||
|
@ -213,7 +215,7 @@ Developing locally with HTTPS
|
|||
|
||||
Increasingly it is becoming necessary to develop software in a secure environment in order that there are very few changes when deploying to production. Recently Facebook changed their policies for apps/sites that use Facebook login which requires the use of an HTTPS URL for the OAuth redirect URL. So if you want to use the ``users`` application with a OAuth provider such as Facebook, securing your communication to the local development environment will be necessary.
|
||||
|
||||
On order to create a secure environment, we need to have a trusted SSL certficate installed in our Docker application.
|
||||
In order to create a secure environment, we need to have a trusted SSL certficate installed in our Docker application.
|
||||
|
||||
#. **Let's Encrypt**
|
||||
|
||||
|
@ -233,14 +235,14 @@ On order to create a secure environment, we need to have a trusted SSL certficat
|
|||
|
||||
.. _`mkcert`: https://github.com/FiloSottile/mkcert/blob/master/README.md#supported-root-stores
|
||||
|
||||
After installing a trusted TLS certificate, configure your docker installation. We are going to configure an ``nginx`` reverse-proxy server. This makes sure that it does not interfere with our ``traefik`` configuration that is reserved for production environements.
|
||||
After installing a trusted TLS certificate, configure your docker installation. We are going to configure an ``nginx`` reverse-proxy server. This makes sure that it does not interfere with our ``traefik`` configuration that is reserved for production environments.
|
||||
|
||||
These are the places that you should configure to secure your local environment.
|
||||
|
||||
certs
|
||||
~~~~~
|
||||
|
||||
Take the certificates that you generated and place them in a folder called ``certs`` on the projects root folder. Assuming that you registered your local hostname as ``my-dev-env.local``, the certificates you will put in the folder should have the names ``my-dev-env.local.crt`` and ``my-dev-env.local.key``.
|
||||
Take the certificates that you generated and place them in a folder called ``certs`` in the project's root folder. Assuming that you registered your local hostname as ``my-dev-env.local``, the certificates you will put in the folder should have the names ``my-dev-env.local.crt`` and ``my-dev-env.local.key``.
|
||||
|
||||
local.yml
|
||||
~~~~~~~~~
|
||||
|
@ -264,7 +266,7 @@ local.yml
|
|||
|
||||
...
|
||||
|
||||
#. Link the ``nginx-proxy`` to ``django`` through environmental variables.
|
||||
#. Link the ``nginx-proxy`` to ``django`` through environment variables.
|
||||
|
||||
``django`` already has an ``.env`` file connected to it. Add the following variables. You should do this especially if you are working with a team and you want to keep your local environment details to yourself.
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ First things first.
|
|||
|
||||
#. Install cookiecutter-django: ::
|
||||
|
||||
$ cookiecutter gh:pydanny/cookiecutter-django
|
||||
$ cookiecutter gh:cookiecutter/cookiecutter-django
|
||||
|
||||
#. Install development requirements: ::
|
||||
|
||||
|
@ -87,7 +87,7 @@ or if you're running asynchronously: ::
|
|||
.. _Redis: https://redis.io/download
|
||||
.. _CookieCutter: https://github.com/cookiecutter/cookiecutter
|
||||
.. _createdb: https://www.postgresql.org/docs/current/static/app-createdb.html
|
||||
.. _initial PostgreSQL set up: http://suite.opengeo.org/docs/latest/dataadmin/pgGettingStarted/firstconnect.html
|
||||
.. _initial PostgreSQL set up: https://web.archive.org/web/20190303010033/http://suite.opengeo.org/docs/latest/dataadmin/pgGettingStarted/firstconnect.html
|
||||
.. _postgres documentation: https://www.postgresql.org/docs/current/static/auth-pg-hba-conf.html
|
||||
.. _pre-commit: https://pre-commit.com/
|
||||
.. _direnv: https://direnv.net/
|
||||
|
@ -154,8 +154,24 @@ To run Celery locally, make sure redis-server is installed (instructions are ava
|
|||
Sass Compilation & Live Reloading
|
||||
---------------------------------
|
||||
|
||||
If you’d like to take advantage of live reloading and Sass compilation you can do so with a little
|
||||
bit of preparation, see :ref:`sass-compilation-live-reload`.
|
||||
If you've opted for Gulp as JS task runner, the project comes configured with `Sass`_ compilation and `live reloading`_. As you change you Sass/JS source files, the task runner will automatically rebuild the corresponding CSS and JS assets and reload them in your browser without refreshing the page.
|
||||
|
||||
#. Make sure that `Node.js`_ v16 is installed on your machine.
|
||||
#. In the project root, install the JS dependencies with::
|
||||
|
||||
$ npm install
|
||||
|
||||
#. Now - with your virtualenv activated - start the application by running::
|
||||
|
||||
$ npm run dev
|
||||
|
||||
The app will now run with live reloading enabled, applying front-end changes dynamically.
|
||||
|
||||
.. 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 don NOT need to run Django as your would normally with ``manage.py runserver``.
|
||||
|
||||
.. _Node.js: http://nodejs.org/download/
|
||||
.. _Sass: https://sass-lang.com/
|
||||
.. _live reloading: https://browsersync.io
|
||||
|
||||
Summary
|
||||
-------
|
||||
|
|
|
@ -10,7 +10,7 @@ It is there to add a migration so you don't have to manually change the ``sites.
|
|||
|
||||
See `0003_set_site_domain_and_name.py`_.
|
||||
|
||||
.. _`0003_set_site_domain_and_name.py`: https://github.com/pydanny/cookiecutter-django/blob/master/%7B%7Bcookiecutter.project_slug%7D%7D/%7B%7Bcookiecutter.project_slug%7D%7D/contrib/sites/migrations/0003_set_site_domain_and_name.py
|
||||
.. _`0003_set_site_domain_and_name.py`: https://github.com/cookiecutter/cookiecutter-django/blob/master/%7B%7Bcookiecutter.project_slug%7D%7D/%7B%7Bcookiecutter.project_slug%7D%7D/contrib/sites/migrations/0003_set_site_domain_and_name.py
|
||||
|
||||
|
||||
Why aren't you using just one configuration file (12-Factor App)
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
.. cookiecutter-django documentation master file.
|
||||
|
||||
Welcome to Cookiecutter Django's documentation!
|
||||
====================================================================
|
||||
===============================================
|
||||
|
||||
A Cookiecutter_ template for Django.
|
||||
Powered by Cookiecutter_, Cookiecutter Django is a project template for jumpstarting production-ready Django projects. The template offers a number of generation options, we invite you to check the :ref:`dedicated page <template-options>` to learn more about each of them.
|
||||
|
||||
.. _cookiecutter: https://github.com/cookiecutter/cookiecutter
|
||||
|
||||
Contents:
|
||||
Contents
|
||||
--------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
@ -28,7 +29,7 @@ Contents:
|
|||
troubleshooting
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
------------------
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`search`
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
.. _sass-compilation-live-reload:
|
||||
|
||||
Sass Compilation & Live Reloading
|
||||
=================================
|
||||
|
||||
If you'd like to take advantage of `live reload`_ and Sass compilation:
|
||||
|
||||
- Make sure that nodejs_ is installed. Then in the project root run::
|
||||
|
||||
$ npm install
|
||||
|
||||
.. _nodejs: http://nodejs.org/download/
|
||||
|
||||
- Now you just need::
|
||||
|
||||
$ npm run dev
|
||||
|
||||
The base app will now run as it would with the usual ``manage.py runserver`` but with live reloading and Sass compilation enabled.
|
||||
When changing your Sass files, they will be automatically recompiled and change will be reflected in your browser without refreshing.
|
||||
|
||||
To get live reloading to work you'll probably need to install an `appropriate browser extension`_
|
||||
|
||||
.. _live reload: http://livereload.com/
|
||||
.. _appropriate browser extension: http://livereload.com/extensions/
|
|
@ -1,7 +1,7 @@
|
|||
If your email server used to send email isn't configured properly (Mailgun by default),
|
||||
attempting to send an email will cause an Internal Server Error.
|
||||
|
||||
By default, django-allauth is setup to `have emails verifications mandatory`_,
|
||||
By default, ``django-allauth`` is setup to `have emails verifications mandatory`_,
|
||||
which means it'll send a verification email when an unverified user tries to
|
||||
log-in or when someone tries to sign-up.
|
||||
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
.. _template-options:
|
||||
|
||||
Project Generation Options
|
||||
==========================
|
||||
|
||||
This page describes all the template options that will be prompted by the `cookiecutter CLI`_ prior to generating your project.
|
||||
|
||||
.. _cookiecutter CLI: https://github.com/cookiecutter/cookiecutter
|
||||
|
||||
project_name:
|
||||
Your project's human-readable name, capitals and spaces allowed.
|
||||
|
||||
|
@ -49,11 +55,11 @@ use_docker:
|
|||
postgresql_version:
|
||||
Select a PostgreSQL_ version to use. The choices are:
|
||||
|
||||
1. 12.3
|
||||
2. 11.8
|
||||
3. 10.8
|
||||
4. 9.6
|
||||
5. 9.5
|
||||
1. 14.1
|
||||
2. 13.5
|
||||
3. 12.9
|
||||
4. 11.14
|
||||
5. 10.19
|
||||
|
||||
js_task_runner:
|
||||
Select a JavaScript task runner. The choices are:
|
||||
|
|
2
docs/requirements.txt
Normal file
2
docs/requirements.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
sphinx==4.4.0
|
||||
sphinx-rtd-theme==1.0.0
|
|
@ -47,5 +47,5 @@ Others
|
|||
|
||||
#. New apps not getting created in project root: This is the expected behavior, because cookiecutter-django does not change the way that django startapp works, you'll have to fix this manually (see `#1725`_)
|
||||
|
||||
.. _#528: https://github.com/pydanny/cookiecutter-django/issues/528#issuecomment-212650373
|
||||
.. _#1725: https://github.com/pydanny/cookiecutter-django/issues/1725#issuecomment-407493176
|
||||
.. _#528: https://github.com/cookiecutter/cookiecutter-django/issues/528#issuecomment-212650373
|
||||
.. _#1725: https://github.com/cookiecutter/cookiecutter-django/issues/1725#issuecomment-407493176
|
||||
|
|
|
@ -5,10 +5,12 @@ NOTE:
|
|||
can potentially be run in Python 2.x environment
|
||||
(at least so we presume in `pre_gen_project.py`).
|
||||
|
||||
TODO: ? restrict Cookiecutter Django project initialization to Python 3.x environments only
|
||||
TODO: restrict Cookiecutter Django project initialization to
|
||||
Python 3.x environments only
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
import json
|
||||
import os
|
||||
import random
|
||||
import shutil
|
||||
|
@ -59,6 +61,10 @@ def remove_docker_files():
|
|||
file_names = ["local.yml", "production.yml", ".dockerignore"]
|
||||
for file_name in file_names:
|
||||
os.remove(file_name)
|
||||
if "{{ cookiecutter.use_pycharm }}".lower() == "y":
|
||||
file_names = ["docker_compose_up_django.xml", "docker_compose_up_docs.xml"]
|
||||
for file_name in file_names:
|
||||
os.remove(os.path.join(".idea", "runConfigurations", file_name))
|
||||
|
||||
|
||||
def remove_utility_files():
|
||||
|
@ -94,6 +100,16 @@ def remove_packagejson_file():
|
|||
os.remove(file_name)
|
||||
|
||||
|
||||
def remove_bootstrap_packages():
|
||||
with open("package.json", mode="r") as fd:
|
||||
content = json.load(fd)
|
||||
for package_name in ["bootstrap", "gulp-concat", "@popperjs/core"]:
|
||||
content["devDependencies"].pop(package_name)
|
||||
with open("package.json", mode="w") as fd:
|
||||
json.dump(content, fd, ensure_ascii=False, indent=2)
|
||||
fd.write("\n")
|
||||
|
||||
|
||||
def remove_celery_files():
|
||||
file_names = [
|
||||
os.path.join("config", "celery_app.py"),
|
||||
|
@ -127,13 +143,6 @@ def remove_dotgithub_folder():
|
|||
shutil.rmtree(".github")
|
||||
|
||||
|
||||
def append_to_project_gitignore(path):
|
||||
gitignore_file_path = ".gitignore"
|
||||
with open(gitignore_file_path, "a") as gitignore_file:
|
||||
gitignore_file.write(path)
|
||||
gitignore_file.write(os.linesep)
|
||||
|
||||
|
||||
def generate_random_string(
|
||||
length, using_digits=False, using_ascii_letters=False, using_punctuation=False
|
||||
):
|
||||
|
@ -164,8 +173,8 @@ def set_flag(file_path, flag, value=None, formatted=None, *args, **kwargs):
|
|||
random_string = generate_random_string(*args, **kwargs)
|
||||
if random_string is None:
|
||||
print(
|
||||
"We couldn't find a secure pseudo-random number generator on your system. "
|
||||
"Please, make sure to manually {} later.".format(flag)
|
||||
"We couldn't find a secure pseudo-random number generator on your "
|
||||
"system. Please, make sure to manually {} later.".format(flag)
|
||||
)
|
||||
random_string = flag
|
||||
if formatted is not None:
|
||||
|
@ -248,10 +257,10 @@ def set_celery_flower_password(file_path, value=None):
|
|||
return celery_flower_password
|
||||
|
||||
|
||||
def append_to_gitignore_file(s):
|
||||
def append_to_gitignore_file(ignored_line):
|
||||
with open(".gitignore", "a") as gitignore_file:
|
||||
gitignore_file.write(s)
|
||||
gitignore_file.write(os.linesep)
|
||||
gitignore_file.write(ignored_line)
|
||||
gitignore_file.write("\n")
|
||||
|
||||
|
||||
def set_flags_in_envs(postgres_user, celery_flower_user, debug=False):
|
||||
|
@ -318,6 +327,11 @@ def remove_drf_starter_files():
|
|||
"{{cookiecutter.project_slug}}", "users", "tests", "test_drf_views.py"
|
||||
)
|
||||
)
|
||||
os.remove(
|
||||
os.path.join(
|
||||
"{{cookiecutter.project_slug}}", "users", "tests", "test_swagger_ui.py"
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def remove_storages_module():
|
||||
|
@ -385,6 +399,8 @@ def main():
|
|||
remove_packagejson_file()
|
||||
if "{{ cookiecutter.use_docker }}".lower() == "y":
|
||||
remove_node_dockerfile()
|
||||
elif "{{ cookiecutter.custom_bootstrap_compilation }}" == "n":
|
||||
remove_bootstrap_packages()
|
||||
|
||||
if ("{{ cookiecutter.cloud_provider}}".lower() == "none") and (
|
||||
"{{ cookiecutter.use_nginx_for_serve_media_files}}".lower() == "n"
|
||||
|
|
|
@ -4,7 +4,8 @@ NOTE:
|
|||
as the whole Cookiecutter Django project initialization
|
||||
can potentially be run in Python 2.x environment.
|
||||
|
||||
TODO: ? restrict Cookiecutter Django project initialization to Python 3.x environments only
|
||||
TODO: restrict Cookiecutter Django project initialization
|
||||
to Python 3.x environments only
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
|
@ -45,7 +46,7 @@ if "{{ cookiecutter.use_docker }}".lower() == "n":
|
|||
)
|
||||
yes_options, no_options = frozenset(["y"]), frozenset(["n"])
|
||||
while True:
|
||||
choice = raw_input().lower()
|
||||
choice = raw_input().lower() # noqa: F821
|
||||
if choice in yes_options:
|
||||
break
|
||||
|
||||
|
@ -71,7 +72,8 @@ if (
|
|||
and "{{ cookiecutter.cloud_provider }}" == "None"
|
||||
):
|
||||
print(
|
||||
"You should either use Whitenoise or select a Cloud Provider to serve static files"
|
||||
"You should either use Whitenoise or select a "
|
||||
"Cloud Provider to serve static files"
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
|
@ -92,6 +94,7 @@ if (
|
|||
and "{{ cookiecutter.mail_service }}" == "Amazon SES"
|
||||
):
|
||||
print(
|
||||
"You should either use AWS or select a different Mail Service for sending emails."
|
||||
"You should either use AWS or select a different "
|
||||
"Mail Service for sending emails."
|
||||
)
|
||||
sys.exit(1)
|
||||
|
|
|
@ -4,21 +4,23 @@ binaryornot==0.4.4
|
|||
|
||||
# Code quality
|
||||
# ------------------------------------------------------------------------------
|
||||
black==21.7b0
|
||||
isort==5.9.3
|
||||
flake8==3.9.2
|
||||
flake8-isort==4.0.0
|
||||
pre-commit==2.14.0
|
||||
black==21.12b0
|
||||
isort==5.10.1
|
||||
flake8==4.0.1
|
||||
flake8-isort==4.1.1
|
||||
pre-commit==2.17.0
|
||||
|
||||
# Testing
|
||||
# ------------------------------------------------------------------------------
|
||||
tox==3.24.1
|
||||
pytest==6.2.4
|
||||
tox==3.24.5
|
||||
pytest==6.2.5
|
||||
pytest-cookies==0.6.1
|
||||
pytest-instafail==0.4.2
|
||||
pyyaml==5.4.1
|
||||
pyyaml==6.0
|
||||
|
||||
# Scripting
|
||||
# ------------------------------------------------------------------------------
|
||||
PyGithub==1.55
|
||||
jinja2==3.0.1
|
||||
gitpython==3.1.26
|
||||
jinja2==3.0.3
|
||||
requests==2.27.1
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
|
295
scripts/create_django_issue.py
Normal file
295
scripts/create_django_issue.py
Normal file
|
@ -0,0 +1,295 @@
|
|||
"""
|
||||
Creates an issue that generates a table for dependency checking whether
|
||||
all packages support the latest Django version. "Latest" does not include
|
||||
patches, only comparing major and minor version numbers.
|
||||
|
||||
This script handles when there are multiple Django versions that need
|
||||
to keep up to date.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING, Any, Iterable, NamedTuple
|
||||
|
||||
import requests
|
||||
from github import Github
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from github.Issue import Issue
|
||||
|
||||
CURRENT_FILE = Path(__file__)
|
||||
ROOT = CURRENT_FILE.parents[1]
|
||||
REQUIREMENTS_DIR = ROOT / "{{cookiecutter.project_slug}}" / "requirements"
|
||||
GITHUB_TOKEN = os.getenv("GITHUB_TOKEN", None)
|
||||
GITHUB_REPO = os.getenv("GITHUB_REPOSITORY", None)
|
||||
|
||||
|
||||
class DjVersion(NamedTuple):
|
||||
"""
|
||||
Wrapper to parse, compare and render Django versions.
|
||||
|
||||
Only keeps track on (major, minor) versions, excluding patches and pre-releases.
|
||||
"""
|
||||
|
||||
major: int
|
||||
minor: int
|
||||
|
||||
def __str__(self) -> str:
|
||||
"""To render as string."""
|
||||
return f"{self.major}.{self.minor}"
|
||||
|
||||
@classmethod
|
||||
def parse(cls, version_str: str) -> DjVersion:
|
||||
"""Parse interesting values from the version string."""
|
||||
major, minor, *_ = version_str.split(".")
|
||||
return cls(major=int(major), minor=int(minor))
|
||||
|
||||
|
||||
def get_package_info(package: str) -> dict:
|
||||
"""Get package metadata using PyPI API."""
|
||||
# "django" converts to "Django" on redirect
|
||||
r = requests.get(f"https://pypi.org/pypi/{package}/json", allow_redirects=True)
|
||||
if not r.ok:
|
||||
print(f"Couldn't find package: {package}")
|
||||
sys.exit(1)
|
||||
return r.json()
|
||||
|
||||
|
||||
def get_django_versions() -> Iterable[DjVersion]:
|
||||
"""List all django versions."""
|
||||
django_package_info: dict[str, Any] = get_package_info("django")
|
||||
releases = django_package_info["releases"].keys()
|
||||
for release_str in releases:
|
||||
if release_str.replace(".", "").isdigit():
|
||||
# Exclude pre-releases with non-numeric characters in version
|
||||
yield DjVersion.parse(release_str)
|
||||
|
||||
|
||||
def get_name_and_version(requirements_line: str) -> tuple[str, ...]:
|
||||
"""Get the name a version of a package from a line in the requirement file."""
|
||||
full_name, version = requirements_line.split(" ", 1)[0].split("==")
|
||||
name_without_extras = full_name.split("[", 1)[0]
|
||||
return name_without_extras, version
|
||||
|
||||
|
||||
def get_all_latest_django_versions() -> tuple[DjVersion, list[DjVersion]]:
|
||||
"""
|
||||
Grabs all Django versions that are worthy of a GitHub issue.
|
||||
|
||||
Depends on Django versions having higher major version or minor version.
|
||||
"""
|
||||
print("Fetching all Django versions from PyPI")
|
||||
base_txt = REQUIREMENTS_DIR / "base.txt"
|
||||
with base_txt.open() as f:
|
||||
for line in f.readlines():
|
||||
if "django==" in line:
|
||||
break
|
||||
else:
|
||||
print(f"django not found in {base_txt}") # Huh...?
|
||||
sys.exit(1)
|
||||
|
||||
# Begin parsing and verification
|
||||
_, current_version_str = get_name_and_version(line)
|
||||
# Get a tuple of (major, minor) - ignoring patch version
|
||||
current_minor_version = DjVersion.parse(current_version_str)
|
||||
newer_versions: set[DjVersion] = set()
|
||||
for django_version in get_django_versions():
|
||||
if django_version > current_minor_version:
|
||||
newer_versions.add(django_version)
|
||||
|
||||
return current_minor_version, sorted(newer_versions, reverse=True)
|
||||
|
||||
|
||||
_TABLE_HEADER = """
|
||||
|
||||
## {file}.txt
|
||||
|
||||
| Name | Version in Master | {dj_version} Compatible Version | OK |
|
||||
| ---- | :---------------: | :-----------------------------: | :-: |
|
||||
"""
|
||||
VITAL_BUT_UNKNOWN = [
|
||||
"django-environ", # not updated often
|
||||
]
|
||||
|
||||
|
||||
class GitHubManager:
|
||||
def __init__(self, base_dj_version: DjVersion, needed_dj_versions: list[DjVersion]):
|
||||
self.github = Github(GITHUB_TOKEN)
|
||||
self.repo = self.github.get_repo(GITHUB_REPO)
|
||||
|
||||
self.base_dj_version = base_dj_version
|
||||
self.needed_dj_versions = needed_dj_versions
|
||||
# (major+minor) Version and description
|
||||
self.existing_issues: dict[DjVersion, Issue] = {}
|
||||
|
||||
# Load all requirements from our requirements files and preload their
|
||||
# package information like a cache:
|
||||
self.requirements_files = ["base", "local", "production"]
|
||||
# Format:
|
||||
# requirement file name: {package name: (master_version, package_info)}
|
||||
self.requirements: dict[str, dict[str, tuple[str, dict]]] = {
|
||||
x: {} for x in self.requirements_files
|
||||
}
|
||||
|
||||
def setup(self) -> None:
|
||||
self.load_requirements()
|
||||
self.load_existing_issues()
|
||||
|
||||
def load_requirements(self):
|
||||
print("Reading requirements")
|
||||
for requirements_file in self.requirements_files:
|
||||
with (REQUIREMENTS_DIR / f"{requirements_file}.txt").open() as f:
|
||||
for line in f.readlines():
|
||||
if "==" in line and not line.startswith("{%"):
|
||||
name, version = get_name_and_version(line)
|
||||
self.requirements[requirements_file][name] = (
|
||||
version,
|
||||
get_package_info(name),
|
||||
)
|
||||
|
||||
def load_existing_issues(self):
|
||||
"""Closes the issue if the base Django version is greater than needed"""
|
||||
print("Load existing issues from GitHub")
|
||||
qualifiers = {
|
||||
"repo": GITHUB_REPO,
|
||||
"author": "app/github-actions",
|
||||
"state": "open",
|
||||
"is": "issue",
|
||||
"in": "title",
|
||||
}
|
||||
issues = list(
|
||||
self.github.search_issues(
|
||||
"[Django Update]", "created", "desc", **qualifiers
|
||||
)
|
||||
)
|
||||
print(f"Found {len(issues)} issues matching search")
|
||||
for issue in issues:
|
||||
matches = re.match(r"\[Update Django] Django (\d+.\d+)$", issue.title)
|
||||
if not matches:
|
||||
continue
|
||||
issue_version = DjVersion.parse(matches.group(1))
|
||||
if self.base_dj_version > issue_version:
|
||||
issue.edit(state="closed")
|
||||
print(f"Closed issue {issue.title} (ID: [{issue.id}]({issue.url}))")
|
||||
else:
|
||||
self.existing_issues[issue_version] = issue
|
||||
|
||||
def get_compatibility(
|
||||
self, package_name: str, package_info: dict, needed_dj_version: DjVersion
|
||||
):
|
||||
"""
|
||||
Verify compatibility via setup.py classifiers. If Django is not in the
|
||||
classifiers, then default compatibility is n/a and OK is ✅.
|
||||
|
||||
If it's a package that's vital but known to not be updated often, we give it
|
||||
a ❓. If a package has ❓ or 🕒, then we allow manual update. Automatic updates
|
||||
only include ❌ and ✅.
|
||||
"""
|
||||
# If issue previously existed, find package and skip any gtg, manually
|
||||
# updated packages, or known releases that will happen but haven't yet
|
||||
if issue := self.existing_issues.get(needed_dj_version):
|
||||
if index := issue.body.find(package_name):
|
||||
name, _current, prev_compat, ok = [
|
||||
s.strip() for s in issue.body[index:].split("|", 4)[:4]
|
||||
]
|
||||
if ok in ("✅", "❓", "🕒"):
|
||||
return prev_compat, ok
|
||||
|
||||
if package_name in VITAL_BUT_UNKNOWN:
|
||||
return "", "❓"
|
||||
|
||||
# Check classifiers if it includes Django
|
||||
supported_dj_versions: list[DjVersion] = []
|
||||
for classifier in package_info["info"]["classifiers"]:
|
||||
# Usually in the form of "Framework :: Django :: 3.2"
|
||||
tokens = classifier.split(" ")
|
||||
if len(tokens) >= 5 and tokens[2].lower() == "django":
|
||||
version = DjVersion.parse(tokens[4])
|
||||
if len(version) == 2:
|
||||
supported_dj_versions.append(version)
|
||||
|
||||
if supported_dj_versions:
|
||||
if any(v >= needed_dj_version for v in supported_dj_versions):
|
||||
return package_info["info"]["version"], "✅"
|
||||
else:
|
||||
return "", "❌"
|
||||
|
||||
# Django classifier DNE; assume it isn't a Django lib
|
||||
# Great exceptions include pylint-django, where we need to do this manually...
|
||||
return "n/a", "✅"
|
||||
|
||||
HOME_PAGE_URL_KEYS = [
|
||||
"home_page",
|
||||
"project_url",
|
||||
"docs_url",
|
||||
"package_url",
|
||||
"release_url",
|
||||
"bugtrack_url",
|
||||
]
|
||||
|
||||
def _get_md_home_page_url(self, package_info: dict):
|
||||
urls = [
|
||||
package_info["info"].get(url_key) for url_key in self.HOME_PAGE_URL_KEYS
|
||||
]
|
||||
try:
|
||||
return f"[{{}}]({next(item for item in urls if item)})"
|
||||
except StopIteration:
|
||||
return "{}"
|
||||
|
||||
def generate_markdown(self, needed_dj_version: DjVersion):
|
||||
requirements = f"{needed_dj_version} requirements tables\n\n"
|
||||
for _file in self.requirements_files:
|
||||
requirements += _TABLE_HEADER.format_map(
|
||||
{"file": _file, "dj_version": needed_dj_version}
|
||||
)
|
||||
for package_name, (version, info) in self.requirements[_file].items():
|
||||
compat_version, icon = self.get_compatibility(
|
||||
package_name, info, needed_dj_version
|
||||
)
|
||||
requirements += (
|
||||
f"| {self._get_md_home_page_url(info).format(package_name)} "
|
||||
f"| {version} "
|
||||
f"| {compat_version} "
|
||||
f"| {icon} "
|
||||
f"|\n"
|
||||
)
|
||||
return requirements
|
||||
|
||||
def create_or_edit_issue(self, needed_dj_version: DjVersion, description: str):
|
||||
if issue := self.existing_issues.get(needed_dj_version):
|
||||
print(f"Editing issue #{issue.number} for Django {needed_dj_version}")
|
||||
issue.edit(body=description)
|
||||
else:
|
||||
print(f"Creating new issue for Django {needed_dj_version}")
|
||||
issue = self.repo.create_issue(
|
||||
f"[Update Django] Django {needed_dj_version}", description
|
||||
)
|
||||
issue.add_to_labels(f"django{needed_dj_version}")
|
||||
|
||||
def generate(self):
|
||||
for version in self.needed_dj_versions:
|
||||
print(f"Handling GitHub issue for Django {version}")
|
||||
md_content = self.generate_markdown(version)
|
||||
print(f"Generated markdown:\n\n{md_content}")
|
||||
self.create_or_edit_issue(version, md_content)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
# Check if there are any djs
|
||||
current_dj, latest_djs = get_all_latest_django_versions()
|
||||
if not latest_djs:
|
||||
sys.exit(0)
|
||||
manager = GitHubManager(current_dj, latest_djs)
|
||||
manager.setup()
|
||||
manager.generate()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if GITHUB_REPO is None:
|
||||
raise RuntimeError(
|
||||
"No github repo, please set the environment variable GITHUB_REPOSITORY"
|
||||
)
|
||||
main()
|
|
@ -1,22 +1,31 @@
|
|||
import datetime as dt
|
||||
import os
|
||||
import re
|
||||
from pathlib import Path
|
||||
from typing import Iterable
|
||||
|
||||
import git
|
||||
import github.PullRequest
|
||||
import github.Repository
|
||||
from github import Github
|
||||
from jinja2 import Template
|
||||
import datetime as dt
|
||||
|
||||
CURRENT_FILE = Path(__file__)
|
||||
ROOT = CURRENT_FILE.parents[1]
|
||||
GITHUB_TOKEN = os.getenv("GITHUB_TOKEN", None)
|
||||
|
||||
# Generate changelog for PRs merged yesterday
|
||||
MERGED_DATE = dt.date.today() - dt.timedelta(days=1)
|
||||
GITHUB_TOKEN = os.getenv("GITHUB_TOKEN")
|
||||
GITHUB_REPO = os.getenv("GITHUB_REPOSITORY")
|
||||
GIT_BRANCH = os.getenv("GITHUB_REF_NAME")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
"""
|
||||
Script entry point.
|
||||
"""
|
||||
merged_pulls = list(iter_pulls())
|
||||
# Generate changelog for PRs merged yesterday
|
||||
merged_date = dt.date.today() - dt.timedelta(days=1)
|
||||
repo = Github(login_or_token=GITHUB_TOKEN).get_repo(GITHUB_REPO)
|
||||
merged_pulls = list(iter_pulls(repo, merged_date))
|
||||
print(f"Merged pull requests: {merged_pulls}")
|
||||
if not merged_pulls:
|
||||
print("Nothing was merged, existing.")
|
||||
return
|
||||
|
@ -25,30 +34,50 @@ def main() -> None:
|
|||
grouped_pulls = group_pulls_by_change_type(merged_pulls)
|
||||
|
||||
# Generate portion of markdown
|
||||
rendered_content = generate_md(grouped_pulls)
|
||||
release_changes_summary = generate_md(grouped_pulls)
|
||||
print(f"Summary of changes: {release_changes_summary}")
|
||||
|
||||
# Update CHANGELOG.md file
|
||||
file_path = ROOT / "CHANGELOG.md"
|
||||
old_content = file_path.read_text()
|
||||
updated_content = old_content.replace(
|
||||
"<!-- GENERATOR_PLACEHOLDER -->",
|
||||
f"<!-- GENERATOR_PLACEHOLDER -->\n\n{rendered_content}",
|
||||
release = f"{merged_date:%Y.%m.%d}"
|
||||
changelog_path = ROOT / "CHANGELOG.md"
|
||||
write_changelog(changelog_path, release, release_changes_summary)
|
||||
print(f"Wrote {changelog_path}")
|
||||
|
||||
# Update version
|
||||
setup_py_path = ROOT / "setup.py"
|
||||
update_version(setup_py_path, release)
|
||||
print(f"Updated version in {setup_py_path}")
|
||||
|
||||
# Commit changes, create tag and push
|
||||
update_git_repo([changelog_path, setup_py_path], release)
|
||||
|
||||
# Create GitHub release
|
||||
github_release = repo.create_git_release(
|
||||
tag=release,
|
||||
name=release,
|
||||
message=release_changes_summary,
|
||||
)
|
||||
file_path.write_text(updated_content)
|
||||
print(f"Created release on GitHub {github_release}")
|
||||
|
||||
|
||||
def iter_pulls():
|
||||
def iter_pulls(
|
||||
repo: github.Repository.Repository,
|
||||
merged_date: dt.date,
|
||||
) -> Iterable[github.PullRequest.PullRequest]:
|
||||
"""Fetch merged pull requests at the date we're interested in."""
|
||||
repo = Github(login_or_token=GITHUB_TOKEN).get_repo("pydanny/cookiecutter-django")
|
||||
recent_pulls = repo.get_pulls(
|
||||
state="closed", sort="updated", direction="desc"
|
||||
state="closed",
|
||||
sort="updated",
|
||||
direction="desc",
|
||||
).get_page(0)
|
||||
for pull in recent_pulls:
|
||||
if pull.merged and pull.merged_at.date() == MERGED_DATE:
|
||||
if pull.merged and pull.merged_at.date() == merged_date:
|
||||
yield pull
|
||||
|
||||
|
||||
def group_pulls_by_change_type(pull_requests_list):
|
||||
def group_pulls_by_change_type(
|
||||
pull_requests_list: list[github.PullRequest.PullRequest],
|
||||
) -> dict[str, list[github.PullRequest.PullRequest]]:
|
||||
"""Group pull request by change type."""
|
||||
grouped_pulls = {
|
||||
"Changed": [],
|
||||
|
@ -56,7 +85,7 @@ def group_pulls_by_change_type(pull_requests_list):
|
|||
"Updated": [],
|
||||
}
|
||||
for pull in pull_requests_list:
|
||||
label_names = {l.name for l in pull.labels}
|
||||
label_names = {label.name for label in pull.labels}
|
||||
if "update" in label_names:
|
||||
group_name = "Updated"
|
||||
elif "bug" in label_names:
|
||||
|
@ -67,12 +96,63 @@ def group_pulls_by_change_type(pull_requests_list):
|
|||
return grouped_pulls
|
||||
|
||||
|
||||
def generate_md(grouped_pulls):
|
||||
def generate_md(grouped_pulls: dict[str, list[github.PullRequest.PullRequest]]) -> str:
|
||||
"""Generate markdown file from Jinja template."""
|
||||
changelog_template = ROOT / ".github" / "changelog-template.md"
|
||||
template = Template(changelog_template.read_text(), autoescape=True)
|
||||
return template.render(merge_date=MERGED_DATE, grouped_pulls=grouped_pulls)
|
||||
return template.render(grouped_pulls=grouped_pulls)
|
||||
|
||||
|
||||
def write_changelog(file_path: Path, release: str, content: str) -> None:
|
||||
"""Write Release details to the changelog file."""
|
||||
content = f"## {release}\n{content}"
|
||||
old_content = file_path.read_text()
|
||||
updated_content = old_content.replace(
|
||||
"<!-- GENERATOR_PLACEHOLDER -->",
|
||||
f"<!-- GENERATOR_PLACEHOLDER -->\n\n{content}",
|
||||
)
|
||||
file_path.write_text(updated_content)
|
||||
|
||||
|
||||
def update_version(file_path: Path, release: str) -> None:
|
||||
"""Update template version in setup.py."""
|
||||
old_content = file_path.read_text()
|
||||
updated_content = re.sub(
|
||||
r'\nversion = "\d+\.\d+\.\d+"\n',
|
||||
f'\nversion = "{release}"\n',
|
||||
old_content,
|
||||
)
|
||||
file_path.write_text(updated_content)
|
||||
|
||||
|
||||
def update_git_repo(paths: list[Path], release: str) -> None:
|
||||
"""Commit, tag changes in git repo and push to origin."""
|
||||
repo = git.Repo(ROOT)
|
||||
for path in paths:
|
||||
repo.git.add(path)
|
||||
message = f"Release {release}"
|
||||
|
||||
user = repo.git.config("--get", "user.name")
|
||||
email = repo.git.config("--get", "user.email")
|
||||
|
||||
repo.git.commit(
|
||||
m=message,
|
||||
author=f"{user} <{email}>",
|
||||
)
|
||||
repo.git.tag("-a", release, m=message)
|
||||
server = f"https://{GITHUB_TOKEN}@github.com/{GITHUB_REPO}.git"
|
||||
print(f"Pushing changes to {GIT_BRANCH} branch of {GITHUB_REPO}")
|
||||
repo.git.push(server, GIT_BRANCH)
|
||||
repo.git.push("--tags", server, GIT_BRANCH)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if GITHUB_REPO is None:
|
||||
raise RuntimeError(
|
||||
"No github repo, please set the environment variable GITHUB_REPOSITORY"
|
||||
)
|
||||
if GIT_BRANCH is None:
|
||||
raise RuntimeError(
|
||||
"No git branch set, please set the GITHUB_REF_NAME environment variable"
|
||||
)
|
||||
main()
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from github import Github
|
||||
from github.NamedUser import NamedUser
|
||||
from jinja2 import Template
|
||||
|
@ -7,6 +9,8 @@ from jinja2 import Template
|
|||
CURRENT_FILE = Path(__file__)
|
||||
ROOT = CURRENT_FILE.parents[1]
|
||||
BOT_LOGINS = ["pyup-bot"]
|
||||
GITHUB_TOKEN = os.getenv("GITHUB_TOKEN", None)
|
||||
GITHUB_REPO = os.getenv("GITHUB_REPOSITORY", None)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
|
@ -39,7 +43,7 @@ def iter_recent_authors():
|
|||
Use Github API to fetch recent authors rather than
|
||||
git CLI to work with Github usernames.
|
||||
"""
|
||||
repo = Github(per_page=5).get_repo("pydanny/cookiecutter-django")
|
||||
repo = Github(login_or_token=GITHUB_TOKEN, per_page=5).get_repo(GITHUB_REPO)
|
||||
recent_pulls = repo.get_pulls(
|
||||
state="closed", sort="updated", direction="desc"
|
||||
).get_page(0)
|
||||
|
@ -101,4 +105,8 @@ def write_md_file(contributors):
|
|||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if GITHUB_REPO is None:
|
||||
raise RuntimeError(
|
||||
"No github repo, please set the environment variable GITHUB_REPOSITORY"
|
||||
)
|
||||
main()
|
||||
|
|
7
setup.cfg
Normal file
7
setup.cfg
Normal file
|
@ -0,0 +1,7 @@
|
|||
[flake8]
|
||||
exclude = docs
|
||||
max-line-length = 88
|
||||
|
||||
[isort]
|
||||
profile = black
|
||||
known_first_party = tests,scripts,hooks
|
23
setup.py
23
setup.py
|
@ -1,21 +1,11 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
try:
|
||||
from setuptools import setup
|
||||
except ImportError:
|
||||
from distutils.core import setup
|
||||
|
||||
# Our version ALWAYS matches the version of Django we support
|
||||
# If Django has a new release, we branch, tag, then update this setting after the tag.
|
||||
version = "3.1.13"
|
||||
|
||||
if sys.argv[-1] == "tag":
|
||||
os.system(f'git tag -a {version} -m "version {version}"')
|
||||
os.system("git push --tags")
|
||||
sys.exit()
|
||||
# We use calendar versioning
|
||||
version = "2022.01.27"
|
||||
|
||||
with open("README.rst") as readme_file:
|
||||
long_description = readme_file.read()
|
||||
|
@ -23,18 +13,21 @@ with open("README.rst") as readme_file:
|
|||
setup(
|
||||
name="cookiecutter-django",
|
||||
version=version,
|
||||
description="A Cookiecutter template for creating production-ready Django projects quickly.",
|
||||
description=(
|
||||
"A Cookiecutter template for creating production-ready "
|
||||
"Django projects quickly."
|
||||
),
|
||||
long_description=long_description,
|
||||
author="Daniel Roy Greenfeld",
|
||||
author_email="pydanny@gmail.com",
|
||||
url="https://github.com/pydanny/cookiecutter-django",
|
||||
url="https://github.com/cookiecutter/cookiecutter-django",
|
||||
packages=[],
|
||||
license="BSD",
|
||||
zip_safe=False,
|
||||
classifiers=[
|
||||
"Development Status :: 4 - Beta",
|
||||
"Environment :: Console",
|
||||
"Framework :: Django :: 3.0",
|
||||
"Framework :: Django :: 3.2",
|
||||
"Intended Audience :: Developers",
|
||||
"Natural Language :: English",
|
||||
"License :: OSI Approved :: BSD License",
|
||||
|
|
0
tests/__init__.py
Normal file
0
tests/__init__.py
Normal file
|
@ -6,19 +6,12 @@
|
|||
set -o errexit
|
||||
set -x
|
||||
|
||||
# Install modern pip with new resolver:
|
||||
# https://blog.python.org/2020/11/pip-20-3-release-new-resolver.html
|
||||
pip install 'pip>=20.3'
|
||||
|
||||
# install test requirements
|
||||
pip install -r requirements.txt
|
||||
|
||||
# create a cache directory
|
||||
mkdir -p .cache/bare
|
||||
cd .cache/bare
|
||||
|
||||
# create the project using the default settings in cookiecutter.json
|
||||
cookiecutter ../../ --no-input --overwrite-if-exists use_docker=n $@
|
||||
cookiecutter ../../ --no-input --overwrite-if-exists use_docker=n "$@"
|
||||
cd my_awesome_project
|
||||
|
||||
# Install OS deps
|
||||
|
@ -35,3 +28,18 @@ pre-commit run --show-diff-on-failure -a
|
|||
|
||||
# run the project's tests
|
||||
pytest
|
||||
|
||||
# Make sure the check doesn't raise any warnings
|
||||
python manage.py check --fail-level WARNING
|
||||
|
||||
if [ -f "package.json" ]
|
||||
then
|
||||
npm install
|
||||
if [ -f "gulpfile.js" ]
|
||||
then
|
||||
npm run build
|
||||
fi
|
||||
fi
|
||||
|
||||
# Generate the HTML for the documentation
|
||||
cd docs && make html
|
||||
|
|
|
@ -1,15 +1,25 @@
|
|||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
from cookiecutter.exceptions import FailedHookException
|
||||
import sh
|
||||
|
||||
try:
|
||||
import sh
|
||||
except (ImportError, ModuleNotFoundError):
|
||||
sh = None # sh doesn't support Windows
|
||||
import yaml
|
||||
from binaryornot.check import is_binary
|
||||
from cookiecutter.exceptions import FailedHookException
|
||||
|
||||
PATTERN = r"{{(\s?cookiecutter)[.](.*?)}}"
|
||||
RE_OBJ = re.compile(PATTERN)
|
||||
|
||||
if sys.platform.startswith("win"):
|
||||
pytest.skip("sh doesn't support windows", allow_module_level=True)
|
||||
elif sys.platform.startswith("darwin") and os.getenv("CI"):
|
||||
pytest.skip("skipping slow macOS tests on CI", allow_module_level=True)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def context():
|
||||
|
@ -37,10 +47,11 @@ SUPPORTED_COMBINATIONS = [
|
|||
{"use_pycharm": "n"},
|
||||
{"use_docker": "y"},
|
||||
{"use_docker": "n"},
|
||||
{"postgresql_version": "13.2"},
|
||||
{"postgresql_version": "12.6"},
|
||||
{"postgresql_version": "11.11"},
|
||||
{"postgresql_version": "10.16"},
|
||||
{"postgresql_version": "14.1"},
|
||||
{"postgresql_version": "13.5"},
|
||||
{"postgresql_version": "12.9"},
|
||||
{"postgresql_version": "11.14"},
|
||||
{"postgresql_version": "10.19"},
|
||||
{"cloud_provider": "AWS", "use_whitenoise": "y"},
|
||||
{"cloud_provider": "AWS", "use_whitenoise": "n"},
|
||||
{"cloud_provider": "GCP", "use_whitenoise": "y"},
|
||||
|
@ -110,7 +121,7 @@ UNSUPPORTED_COMBINATIONS = [
|
|||
|
||||
|
||||
def _fixture_id(ctx):
|
||||
"""Helper to get a user friendly test name from the parametrized context."""
|
||||
"""Helper to get a user-friendly test name from the parametrized context."""
|
||||
return "-".join(f"{key}:{value}" for key, value in ctx.items())
|
||||
|
||||
|
||||
|
@ -264,7 +275,7 @@ def test_github_invokes_linter_and_pytest(
|
|||
|
||||
@pytest.mark.parametrize("slug", ["project slug", "Project_Slug"])
|
||||
def test_invalid_slug(cookies, context, slug):
|
||||
"""Invalid slug should failed pre-generation hook."""
|
||||
"""Invalid slug should fail pre-generation hook."""
|
||||
context.update({"project_slug": slug})
|
||||
|
||||
result = cookies.bake(extra_context=context)
|
||||
|
@ -281,3 +292,20 @@ def test_error_if_incompatible(cookies, context, invalid_context):
|
|||
|
||||
assert result.exit_code != 0
|
||||
assert isinstance(result.exception, FailedHookException)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
["use_pycharm", "pycharm_docs_exist"],
|
||||
[
|
||||
("n", False),
|
||||
("y", True),
|
||||
],
|
||||
)
|
||||
def test_pycharm_docs_removed(cookies, context, use_pycharm, pycharm_docs_exist):
|
||||
"""."""
|
||||
context.update({"use_pycharm": use_pycharm})
|
||||
result = cookies.bake(extra_context=context)
|
||||
|
||||
with open(f"{result.project}/docs/index.rst", "r") as f:
|
||||
has_pycharm_docs = "pycharm/configuration" in f.read()
|
||||
assert has_pycharm_docs is pycharm_docs_exist
|
||||
|
|
|
@ -6,15 +6,12 @@
|
|||
set -o errexit
|
||||
set -x
|
||||
|
||||
# install test requirements
|
||||
pip install -r requirements.txt
|
||||
|
||||
# create a cache directory
|
||||
mkdir -p .cache/docker
|
||||
cd .cache/docker
|
||||
|
||||
# create the project using the default settings in cookiecutter.json
|
||||
cookiecutter ../../ --no-input --overwrite-if-exists use_docker=y $@
|
||||
cookiecutter ../../ --no-input --overwrite-if-exists use_docker=y "$@"
|
||||
cd my_awesome_project
|
||||
|
||||
# Lint by running pre-commit on all files
|
||||
|
@ -24,6 +21,9 @@ git init
|
|||
git add .
|
||||
pre-commit run --show-diff-on-failure -a
|
||||
|
||||
# make sure all images build
|
||||
docker-compose -f local.yml build
|
||||
|
||||
# run the project's type checks
|
||||
docker-compose -f local.yml run django mypy my_awesome_project
|
||||
|
||||
|
@ -35,3 +35,9 @@ docker-compose -f local.yml run django python manage.py makemigrations --dry-run
|
|||
|
||||
# Test support for translations
|
||||
docker-compose -f local.yml run django python manage.py makemessages --all
|
||||
|
||||
# Make sure the check doesn't raise any warnings
|
||||
docker-compose -f local.yml run django python manage.py check --fail-level WARNING
|
||||
|
||||
# Generate the HTML for the documentation
|
||||
docker-compose -f local.yml run docs make html
|
||||
|
|
28
tests/test_hooks.py
Normal file
28
tests/test_hooks.py
Normal file
|
@ -0,0 +1,28 @@
|
|||
"""Unit tests for the hooks"""
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from hooks.post_gen_project import append_to_gitignore_file
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def working_directory(tmp_path):
|
||||
prev_cwd = Path.cwd()
|
||||
os.chdir(tmp_path)
|
||||
try:
|
||||
yield tmp_path
|
||||
finally:
|
||||
os.chdir(prev_cwd)
|
||||
|
||||
|
||||
def test_append_to_gitignore_file(working_directory):
|
||||
gitignore_file = working_directory / ".gitignore"
|
||||
gitignore_file.write_text("node_modules/\n")
|
||||
append_to_gitignore_file(".envs/*")
|
||||
linesep = os.linesep.encode()
|
||||
assert (
|
||||
gitignore_file.read_bytes() == b"node_modules/" + linesep + b".envs/*" + linesep
|
||||
)
|
||||
assert gitignore_file.read_text() == "node_modules/\n.envs/*\n"
|
|
@ -12,7 +12,7 @@ trim_trailing_whitespace = true
|
|||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
[*.{html,css,scss,json,yml}]
|
||||
[*.{html,css,scss,json,yml,xml}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
|
|
|
@ -1,7 +1,95 @@
|
|||
# Config for Dependabot updates. See Documentation here:
|
||||
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
# Update Github actions in workflows
|
||||
# Update GitHub actions in workflows
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
# Check for updates to GitHub Actions every weekday
|
||||
schedule:
|
||||
interval: "daily"
|
||||
|
||||
{%- if cookiecutter.use_docker == 'y' %}
|
||||
|
||||
# Enable version updates for Docker
|
||||
# We need to specify each Dockerfile in a separate entry because Dependabot doesn't
|
||||
# support wildcards or recursively checking subdirectories. Check this issue for updates:
|
||||
# https://github.com/dependabot/dependabot-core/issues/2178
|
||||
- package-ecosystem: "docker"
|
||||
# Look for a `Dockerfile` in the `compose/local/django` directory
|
||||
directory: "compose/local/django/"
|
||||
# Check for updates to GitHub Actions every weekday
|
||||
schedule:
|
||||
interval: "daily"
|
||||
|
||||
# Enable version updates for Docker
|
||||
- package-ecosystem: "docker"
|
||||
# Look for a `Dockerfile` in the `compose/local/docs` directory
|
||||
directory: "compose/local/docs/"
|
||||
# Check for updates to GitHub Actions every weekday
|
||||
schedule:
|
||||
interval: "daily"
|
||||
|
||||
# Enable version updates for Docker
|
||||
- package-ecosystem: "docker"
|
||||
# Look for a `Dockerfile` in the `compose/local/node` directory
|
||||
directory: "compose/local/node/"
|
||||
# Check for updates to GitHub Actions every weekday
|
||||
schedule:
|
||||
interval: "daily"
|
||||
|
||||
# Enable version updates for Docker
|
||||
- package-ecosystem: "docker"
|
||||
# Look for a `Dockerfile` in the `compose/production/aws` directory
|
||||
directory: "compose/production/aws/"
|
||||
# Check for updates to GitHub Actions every weekday
|
||||
schedule:
|
||||
interval: "daily"
|
||||
|
||||
# Enable version updates for Docker
|
||||
- package-ecosystem: "docker"
|
||||
# Look for a `Dockerfile` in the `compose/production/django` directory
|
||||
directory: "compose/production/django/"
|
||||
# Check for updates to GitHub Actions every weekday
|
||||
schedule:
|
||||
interval: "daily"
|
||||
|
||||
# Enable version updates for Docker
|
||||
- package-ecosystem: "docker"
|
||||
# Look for a `Dockerfile` in the `compose/production/postgres` directory
|
||||
directory: "compose/production/postgres/"
|
||||
# Check for updates to GitHub Actions every weekday
|
||||
schedule:
|
||||
interval: "daily"
|
||||
|
||||
# Enable version updates for Docker
|
||||
- package-ecosystem: "docker"
|
||||
# Look for a `Dockerfile` in the `compose/production/traefik` directory
|
||||
directory: "compose/production/traefik/"
|
||||
# Check for updates to GitHub Actions every weekday
|
||||
schedule:
|
||||
interval: "daily"
|
||||
|
||||
{%- endif %}
|
||||
|
||||
# Enable version updates for Python/Pip - Production
|
||||
- package-ecosystem: "pip"
|
||||
# Look for a `requirements.txt` in the `root` directory
|
||||
# also 'setup.cfg', 'runtime.txt' and 'requirements/*.txt'
|
||||
directory: "/"
|
||||
# Check for updates to GitHub Actions every weekday
|
||||
schedule:
|
||||
interval: "daily"
|
||||
|
||||
{%- if cookiecutter.js_task_runner != "None" %}
|
||||
|
||||
# Enable version updates for javascript/npm
|
||||
- package-ecosystem: "npm"
|
||||
# Look for a `packages.json' in the `root` directory
|
||||
directory: "/"
|
||||
# Check for updates to GitHub Actions every weekday
|
||||
schedule:
|
||||
interval: "daily"
|
||||
|
||||
{%- endif %}
|
||||
|
|
|
@ -23,16 +23,17 @@ jobs:
|
|||
- name: Checkout Code Repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Set up Python 3.9
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.9
|
||||
python-version: "3.9"
|
||||
cache: pip
|
||||
cache-dependency-path: |
|
||||
requirements/base.txt
|
||||
requirements/local.txt
|
||||
|
||||
# Run all pre-commit hooks on all the files.
|
||||
# Getting only staged files can be tricky in case a new PR is opened
|
||||
# since the action is run on a branch in detached head state
|
||||
- name: Install and Run Pre-commit
|
||||
uses: pre-commit/action@v2.0.0
|
||||
- name: Run pre-commit
|
||||
uses: pre-commit/action@v2.0.3
|
||||
|
||||
# With no caching at all the entire ci process takes 4m 30s to complete!
|
||||
pytest:
|
||||
|
@ -80,27 +81,14 @@ jobs:
|
|||
run: docker-compose -f local.yml down
|
||||
{%- else %}
|
||||
|
||||
- name: Set up Python 3.9
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.9
|
||||
|
||||
- name: Get pip cache dir
|
||||
id: pip-cache-location
|
||||
run: |
|
||||
echo "::set-output name=dir::$(pip cache dir)"
|
||||
{%- raw %}
|
||||
|
||||
- name: Cache pip Project Dependencies
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
# Get the location of pip cache dir
|
||||
path: ${{ steps.pip-cache-location.outputs.dir }}
|
||||
# Look to see if there is a cache hit for the corresponding requirements file
|
||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/local.txt') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pip-
|
||||
{%- endraw %}
|
||||
python-version: "3.9"
|
||||
cache: pip
|
||||
cache-dependency-path: |
|
||||
requirements/base.txt
|
||||
requirements/local.txt
|
||||
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
|
|
11
{{cookiecutter.project_slug}}/.gitignore
vendored
11
{{cookiecutter.project_slug}}/.gitignore
vendored
|
@ -327,13 +327,20 @@ Session.vim
|
|||
tags
|
||||
|
||||
### Project template
|
||||
{% if cookiecutter.use_mailhog == 'y' and cookiecutter.use_docker == 'n' %}
|
||||
{%- if cookiecutter.use_mailhog == 'y' and cookiecutter.use_docker == 'n' %}
|
||||
MailHog
|
||||
{%- endif %}
|
||||
{{ cookiecutter.project_slug }}/media/
|
||||
|
||||
.pytest_cache/
|
||||
|
||||
{% if cookiecutter.use_docker == 'y' %}
|
||||
{%- if cookiecutter.use_docker == 'y' %}
|
||||
.ipython/
|
||||
{%- endif %}
|
||||
|
||||
{%- if cookiecutter.js_task_runner == 'Gulp' %}
|
||||
project.css
|
||||
project.min.css
|
||||
vendors.js
|
||||
*.min.js
|
||||
{%- endif %}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration name="docker-compose up django" type="docker-deploy" factoryName="docker-compose.yml" server-name="Docker">
|
||||
<deployment type="docker-compose.yml">
|
||||
<settings>
|
||||
<option name="envFilePath" value=""/>
|
||||
<option name="services">
|
||||
<list>
|
||||
<option value="django"/>
|
||||
{%- if cookiecutter.use_celery == 'y' %}
|
||||
<option value="celeryworker"/>
|
||||
<option value="celerybeat"/>
|
||||
{%- endif %}
|
||||
{%- if cookiecutter.js_task_runner == 'Gulp' %}
|
||||
<option value="node"/>
|
||||
{%- endif %}
|
||||
</list>
|
||||
</option>
|
||||
<option name="sourceFilePath" value="local.yml"/>
|
||||
</settings>
|
||||
</deployment>
|
||||
<method v="2"/>
|
||||
</configuration>
|
||||
</component>
|
|
@ -0,0 +1,16 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration name="docker-compose up docs" type="docker-deploy" factoryName="docker-compose.yml" server-name="Docker">
|
||||
<deployment type="docker-compose.yml">
|
||||
<settings>
|
||||
<option name="envFilePath" value=""/>
|
||||
<option name="services">
|
||||
<list>
|
||||
<option value="docs"/>
|
||||
</list>
|
||||
</option>
|
||||
<option name="sourceFilePath" value="local.yml"/>
|
||||
</settings>
|
||||
</deployment>
|
||||
<method v="2"/>
|
||||
</configuration>
|
||||
</component>
|
|
@ -1,33 +1,31 @@
|
|||
exclude: 'docs|node_modules|migrations|.git|.tox'
|
||||
exclude: "^docs/|/migrations/"
|
||||
default_stages: [commit]
|
||||
fail_fast: true
|
||||
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.0.1
|
||||
rev: v4.1.0
|
||||
hooks:
|
||||
- id: trailing-whitespace
|
||||
- id: end-of-file-fixer
|
||||
- id: check-yaml
|
||||
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 21.7b0
|
||||
rev: 21.12b0
|
||||
hooks:
|
||||
- id: black
|
||||
|
||||
- repo: https://github.com/timothycrosley/isort
|
||||
rev: 5.9.3
|
||||
- repo: https://github.com/PyCQA/isort
|
||||
rev: 5.10.1
|
||||
hooks:
|
||||
- id: isort
|
||||
|
||||
- repo: https://gitlab.com/pycqa/flake8
|
||||
rev: 3.9.2
|
||||
- repo: https://github.com/PyCQA/flake8
|
||||
rev: 4.0.1
|
||||
hooks:
|
||||
- id: flake8
|
||||
args: ['--config=setup.cfg']
|
||||
args: ["--config=setup.cfg"]
|
||||
additional_dependencies: [flake8-isort]
|
||||
|
||||
|
||||
# sets up .pre-commit-ci.yaml to ensure pre-commit dependencies stay up to date
|
||||
ci:
|
||||
autoupdate_schedule: weekly
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[MASTER]
|
||||
load-plugins=pylint_django{% if cookiecutter.use_celery == "y" %}, pylint_celery{% endif %}
|
||||
|
||||
django-settings-module=config.settings.base
|
||||
[FORMAT]
|
||||
max-line-length=120
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
release: python manage.py migrate
|
||||
{%- if cookiecutter.use_async == "y" -%}
|
||||
{%- if cookiecutter.use_async == "y" %}
|
||||
web: gunicorn config.asgi:application -k uvicorn.workers.UvicornWorker
|
||||
{%- else %}
|
||||
web: gunicorn config.wsgi:application
|
||||
{%- endif %}
|
||||
{%- if cookiecutter.use_celery == "y" -%}
|
||||
worker: REMAP_SIGTERM=SIGQUIT celery worker --app=config.celery_app --loglevel=info
|
||||
beat: REMAP_SIGTERM=SIGQUIT celery beat --app=config.celery_app --loglevel=info
|
||||
{%- if cookiecutter.use_celery == "y" %}
|
||||
worker: REMAP_SIGTERM=SIGQUIT celery -A config.celery_app worker --loglevel=info
|
||||
beat: REMAP_SIGTERM=SIGQUIT celery -A config.celery_app beat --loglevel=info
|
||||
{%- endif %}
|
||||
|
|
143
{{cookiecutter.project_slug}}/README.md
Normal file
143
{{cookiecutter.project_slug}}/README.md
Normal file
|
@ -0,0 +1,143 @@
|
|||
# {{cookiecutter.project_name}}
|
||||
|
||||
{{ cookiecutter.description }}
|
||||
|
||||
[](https://github.com/cookiecutter/cookiecutter-django/)
|
||||
[](https://github.com/ambv/black)
|
||||
|
||||
{%- if cookiecutter.open_source_license != "Not open source" %}
|
||||
|
||||
License: {{cookiecutter.open_source_license}}
|
||||
{%- endif %}
|
||||
|
||||
## Settings
|
||||
|
||||
Moved to [settings](http://cookiecutter-django.readthedocs.io/en/latest/settings.html).
|
||||
|
||||
## Basic Commands
|
||||
|
||||
### Setting Up Your Users
|
||||
|
||||
- To create a **normal user account**, just go to Sign Up and fill out the form. Once you submit it, you'll see a "Verify Your E-mail Address" page. Go to your console to see a simulated email verification message. Copy the link into your browser. Now the user's email should be verified and ready to go.
|
||||
|
||||
- To create an **superuser account**, use this command:
|
||||
|
||||
$ python manage.py createsuperuser
|
||||
|
||||
For convenience, you can keep your normal user logged in on Chrome and your superuser logged in on Firefox (or similar), so that you can see how the site behaves for both kinds of users.
|
||||
|
||||
### Type checks
|
||||
|
||||
Running type checks with mypy:
|
||||
|
||||
$ mypy {{cookiecutter.project_slug}}
|
||||
|
||||
### Test coverage
|
||||
|
||||
To run the tests, check your test coverage, and generate an HTML coverage report:
|
||||
|
||||
$ coverage run -m pytest
|
||||
$ coverage html
|
||||
$ open htmlcov/index.html
|
||||
|
||||
#### Running tests with pytest
|
||||
|
||||
$ pytest
|
||||
|
||||
### Live reloading and Sass CSS compilation
|
||||
|
||||
Moved to [Live reloading and SASS compilation](http://cookiecutter-django.readthedocs.io/en/latest/live-reloading-and-sass-compilation.html).
|
||||
|
||||
{%- if cookiecutter.use_celery == "y" %}
|
||||
|
||||
### Celery
|
||||
|
||||
This app comes with Celery.
|
||||
|
||||
To run a celery worker:
|
||||
|
||||
``` bash
|
||||
cd {{cookiecutter.project_slug}}
|
||||
celery -A config.celery_app worker -l info
|
||||
```
|
||||
|
||||
Please note: For Celery's import magic to work, it is important *where* the celery commands are run. If you are in the same folder with *manage.py*, you should be right.
|
||||
|
||||
{%- endif %}
|
||||
{%- if cookiecutter.use_mailhog == "y" %}
|
||||
|
||||
### Email Server
|
||||
|
||||
{%- if cookiecutter.use_docker == "y" %}
|
||||
|
||||
In development, it is often nice to be able to see emails that are being sent from your application. For that reason local SMTP server [MailHog](https://github.com/mailhog/MailHog) with a web interface is available as docker container.
|
||||
|
||||
Container mailhog will start automatically when you will run all docker containers.
|
||||
Please check [cookiecutter-django Docker documentation](http://cookiecutter-django.readthedocs.io/en/latest/deployment-with-docker.html) for more details how to start all containers.
|
||||
|
||||
With MailHog running, to view messages that are sent by your application, open your browser and go to `http://127.0.0.1:8025`
|
||||
{%- 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.
|
||||
|
||||
1. [Download the latest MailHog release](https://github.com/mailhog/MailHog/releases) for your OS.
|
||||
|
||||
2. Rename the build to `MailHog`.
|
||||
|
||||
3. Copy the file to the project root.
|
||||
|
||||
4. Make it executable:
|
||||
|
||||
$ chmod +x MailHog
|
||||
|
||||
5. Spin up another terminal window and start it there:
|
||||
|
||||
./MailHog
|
||||
|
||||
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.
|
||||
|
||||
{%- endif %}
|
||||
|
||||
{%- endif %}
|
||||
{%- if cookiecutter.use_sentry == "y" %}
|
||||
|
||||
### Sentry
|
||||
|
||||
Sentry is an error logging aggregator service. You can sign up for a free account at <https://sentry.io/signup/?code=cookiecutter> or download and host it yourself.
|
||||
The system is set up with reasonable defaults, including 404 logging and integration with the WSGI application.
|
||||
|
||||
You must set the DSN url in production.
|
||||
{%- endif %}
|
||||
|
||||
## Deployment
|
||||
|
||||
The following details how to deploy this application.
|
||||
{%- if cookiecutter.use_heroku.lower() == "y" %}
|
||||
|
||||
### Heroku
|
||||
|
||||
See detailed [cookiecutter-django Heroku documentation](http://cookiecutter-django.readthedocs.io/en/latest/deployment-on-heroku.html).
|
||||
|
||||
{%- endif %}
|
||||
{%- if cookiecutter.use_docker.lower() == "y" %}
|
||||
|
||||
### Docker
|
||||
|
||||
See detailed [cookiecutter-django Docker documentation](http://cookiecutter-django.readthedocs.io/en/latest/deployment-with-docker.html).
|
||||
|
||||
{%- endif %}
|
||||
{%- if cookiecutter.custom_bootstrap_compilation == "y" %}
|
||||
### Custom Bootstrap Compilation
|
||||
|
||||
The generated CSS is set up with automatic Bootstrap recompilation with variables of your choice.
|
||||
Bootstrap v5 is installed using npm and customised by tweaking your variables in `static/sass/custom_bootstrap_vars`.
|
||||
|
||||
You can find a list of available variables [in the bootstrap source](https://github.com/twbs/bootstrap/blob/main/scss/_variables.scss), or get explanations on them in the [Bootstrap docs](https://getbootstrap.com/docs/5.1/customize/sass/).
|
||||
|
||||
{%- if cookiecutter.js_task_runner == "Gulp" %}
|
||||
Bootstrap's javascript as well as its dependencies is concatenated into a single file: `static/js/vendors.js`.
|
||||
{%- endif %}
|
||||
|
||||
{%- endif %}
|
|
@ -1,175 +0,0 @@
|
|||
{{cookiecutter.project_name}}
|
||||
{{ '=' * cookiecutter.project_name|length }}
|
||||
|
||||
{{cookiecutter.description}}
|
||||
|
||||
.. image:: https://img.shields.io/badge/built%20with-Cookiecutter%20Django-ff69b4.svg?logo=cookiecutter
|
||||
:target: https://github.com/pydanny/cookiecutter-django/
|
||||
:alt: Built with Cookiecutter Django
|
||||
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
|
||||
:target: https://github.com/ambv/black
|
||||
:alt: Black code style
|
||||
{%- if cookiecutter.open_source_license != "Not open source" %}
|
||||
|
||||
:License: {{cookiecutter.open_source_license}}
|
||||
{%- endif %}
|
||||
|
||||
Settings
|
||||
--------
|
||||
|
||||
Moved to settings_.
|
||||
|
||||
.. _settings: http://cookiecutter-django.readthedocs.io/en/latest/settings.html
|
||||
|
||||
Basic Commands
|
||||
--------------
|
||||
|
||||
Setting Up Your Users
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
* To create a **normal user account**, just go to Sign Up and fill out the form. Once you submit it, you'll see a "Verify Your E-mail Address" page. Go to your console to see a simulated email verification message. Copy the link into your browser. Now the user's email should be verified and ready to go.
|
||||
|
||||
* To create an **superuser account**, use this command::
|
||||
|
||||
$ python manage.py createsuperuser
|
||||
|
||||
For convenience, you can keep your normal user logged in on Chrome and your superuser logged in on Firefox (or similar), so that you can see how the site behaves for both kinds of users.
|
||||
|
||||
Type checks
|
||||
^^^^^^^^^^^
|
||||
|
||||
Running type checks with mypy:
|
||||
|
||||
::
|
||||
|
||||
$ mypy {{cookiecutter.project_slug}}
|
||||
|
||||
Test coverage
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
To run the tests, check your test coverage, and generate an HTML coverage report::
|
||||
|
||||
$ coverage run -m pytest
|
||||
$ coverage html
|
||||
$ open htmlcov/index.html
|
||||
|
||||
Running tests with py.test
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
$ pytest
|
||||
|
||||
Live reloading and Sass CSS compilation
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Moved to `Live reloading and SASS compilation`_.
|
||||
|
||||
.. _`Live reloading and SASS compilation`: http://cookiecutter-django.readthedocs.io/en/latest/live-reloading-and-sass-compilation.html
|
||||
|
||||
{%- if cookiecutter.use_celery == "y" %}
|
||||
|
||||
Celery
|
||||
^^^^^^
|
||||
|
||||
This app comes with Celery.
|
||||
|
||||
To run a celery worker:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd {{cookiecutter.project_slug}}
|
||||
celery -A config.celery_app worker -l info
|
||||
|
||||
Please note: For Celery's import magic to work, it is important *where* the celery commands are run. If you are in the same folder with *manage.py*, you should be right.
|
||||
|
||||
{%- endif %}
|
||||
{%- if cookiecutter.use_mailhog == "y" %}
|
||||
|
||||
Email Server
|
||||
^^^^^^^^^^^^
|
||||
{%- if cookiecutter.use_docker == 'y' %}
|
||||
|
||||
In development, it is often nice to be able to see emails that are being sent from your application. For that reason local SMTP server `MailHog`_ with a web interface is available as docker container.
|
||||
|
||||
Container mailhog will start automatically when you will run all docker containers.
|
||||
Please check `cookiecutter-django Docker documentation`_ 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``
|
||||
{%- 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`_ when generating the project a local SMTP server with a web interface will be available.
|
||||
|
||||
#. `Download the latest MailHog release`_ for your OS.
|
||||
|
||||
#. Rename the build to ``MailHog``.
|
||||
|
||||
#. Copy the file to the project root.
|
||||
|
||||
#. Make it executable: ::
|
||||
|
||||
$ chmod +x MailHog
|
||||
|
||||
#. Spin up another terminal window and start it there: ::
|
||||
|
||||
./MailHog
|
||||
|
||||
#. 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.
|
||||
|
||||
.. _`Download the latest MailHog release`: https://github.com/mailhog/MailHog/releases
|
||||
{%- endif %}
|
||||
|
||||
.. _mailhog: https://github.com/mailhog/MailHog
|
||||
{%- endif %}
|
||||
{%- if cookiecutter.use_sentry == "y" %}
|
||||
|
||||
Sentry
|
||||
^^^^^^
|
||||
|
||||
Sentry is an error logging aggregator service. You can sign up for a free account at https://sentry.io/signup/?code=cookiecutter or download and host it yourself.
|
||||
The system is setup with reasonable defaults, including 404 logging and integration with the WSGI application.
|
||||
|
||||
You must set the DSN url in production.
|
||||
{%- endif %}
|
||||
|
||||
Deployment
|
||||
----------
|
||||
|
||||
The following details how to deploy this application.
|
||||
{%- if cookiecutter.use_heroku.lower() == "y" %}
|
||||
|
||||
Heroku
|
||||
^^^^^^
|
||||
|
||||
See detailed `cookiecutter-django Heroku documentation`_.
|
||||
|
||||
.. _`cookiecutter-django Heroku documentation`: http://cookiecutter-django.readthedocs.io/en/latest/deployment-on-heroku.html
|
||||
{%- endif %}
|
||||
{%- if cookiecutter.use_docker.lower() == "y" %}
|
||||
|
||||
Docker
|
||||
^^^^^^
|
||||
|
||||
See detailed `cookiecutter-django Docker documentation`_.
|
||||
|
||||
.. _`cookiecutter-django Docker documentation`: http://cookiecutter-django.readthedocs.io/en/latest/deployment-with-docker.html
|
||||
{%- endif %}
|
||||
{%- if cookiecutter.custom_bootstrap_compilation == "y" %}
|
||||
Custom Bootstrap Compilation
|
||||
^^^^^^
|
||||
|
||||
The generated CSS is set up with automatic Bootstrap recompilation with variables of your choice.
|
||||
Bootstrap v4 is installed using npm and customised by tweaking your variables in ``static/sass/custom_bootstrap_vars``.
|
||||
|
||||
You can find a list of available variables `in the bootstrap source`_, or get explanations on them in the `Bootstrap docs`_.
|
||||
|
||||
{%- if cookiecutter.js_task_runner == 'Gulp' %}
|
||||
Bootstrap's javascript as well as its dependencies is concatenated into a single file: ``static/js/vendors.js``.
|
||||
{%- endif %}
|
||||
|
||||
.. _in the bootstrap source: https://github.com/twbs/bootstrap/blob/v4-dev/scss/_variables.scss
|
||||
.. _Bootstrap docs: https://getbootstrap.com/docs/4.1/getting-started/theming/
|
||||
|
||||
{%- endif %}
|
|
@ -1,4 +1,4 @@
|
|||
ARG PYTHON_VERSION=3.9-slim-buster
|
||||
ARG PYTHON_VERSION=3.9-slim-bullseye
|
||||
|
||||
# define an alias for the specfic python version used in this file.
|
||||
FROM python:${PYTHON_VERSION} as python
|
||||
|
|
|
@ -4,7 +4,8 @@ set -o errexit
|
|||
set -o nounset
|
||||
|
||||
|
||||
celery flower \
|
||||
--app=config.celery_app \
|
||||
--broker="${CELERY_BROKER_URL}" \
|
||||
celery \
|
||||
-A config.celery_app \
|
||||
-b "${CELERY_BROKER_URL}" \
|
||||
flower \
|
||||
--basic_auth="${CELERY_FLOWER_USER}:${CELERY_FLOWER_PASSWORD}"
|
||||
|
|
|
@ -1,28 +1,61 @@
|
|||
FROM python:3.9-slim-buster
|
||||
ARG PYTHON_VERSION=3.9-slim-bullseye
|
||||
|
||||
# define an alias for the specfic python version used in this file.
|
||||
FROM python:${PYTHON_VERSION} as python
|
||||
|
||||
|
||||
# Python build stage
|
||||
FROM python as python-build-stage
|
||||
|
||||
ENV PYTHONUNBUFFERED 1
|
||||
ENV PYTHONDONTWRITEBYTECODE 1
|
||||
|
||||
RUN apt-get update \
|
||||
RUN apt-get update && apt-get install --no-install-recommends -y \
|
||||
# dependencies for building Python packages
|
||||
&& apt-get install -y build-essential \
|
||||
build-essential \
|
||||
# psycopg2 dependencies
|
||||
&& apt-get install -y libpq-dev \
|
||||
# Translations dependencies
|
||||
&& apt-get install -y gettext \
|
||||
# Uncomment below lines to enable Sphinx output to latex and pdf
|
||||
# && apt-get install -y texlive-latex-recommended \
|
||||
# && apt-get install -y texlive-fonts-recommended \
|
||||
# && apt-get install -y texlive-latex-extra \
|
||||
# && apt-get install -y latexmk \
|
||||
libpq-dev \
|
||||
# cleaning up unused files
|
||||
&& apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Requirements are installed here to ensure they will be cached.
|
||||
COPY ./requirements /requirements
|
||||
# All imports needed for autodoc.
|
||||
RUN pip install -r /requirements/local.txt -r /requirements/production.txt
|
||||
|
||||
# create python dependency wheels
|
||||
RUN pip wheel --no-cache-dir --no-deps --wheel-dir /usr/src/app/wheels \
|
||||
-r /requirements/local.txt -r /requirements/production.txt \
|
||||
&& rm -rf /requirements
|
||||
|
||||
|
||||
# Python 'run' stage
|
||||
FROM python as python-run-stage
|
||||
|
||||
ARG BUILD_ENVIRONMENT
|
||||
ENV PYTHONUNBUFFERED 1
|
||||
ENV PYTHONDONTWRITEBYTECODE 1
|
||||
|
||||
RUN apt-get update && apt-get install --no-install-recommends -y \
|
||||
# To run the Makefile
|
||||
make \
|
||||
# psycopg2 dependencies
|
||||
libpq-dev \
|
||||
# Translations dependencies
|
||||
gettext \
|
||||
# Uncomment below lines to enable Sphinx output to latex and pdf
|
||||
# texlive-latex-recommended \
|
||||
# texlive-fonts-recommended \
|
||||
# texlive-latex-extra \
|
||||
# latexmk \
|
||||
# cleaning up unused files
|
||||
&& apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# copy python dependency wheels from python-build-stage
|
||||
COPY --from=python-build-stage /usr/src/app/wheels /wheels
|
||||
|
||||
# use wheels to install python dependencies
|
||||
RUN pip install --no-cache /wheels/* \
|
||||
&& rm -rf /wheels
|
||||
|
||||
COPY ./compose/local/docs/start /start-docs
|
||||
RUN sed -i 's/\r$//g' /start-docs
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
FROM node:10-stretch-slim
|
||||
FROM node:16-bullseye-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
ARG PYTHON_VERSION=3.9-slim-buster
|
||||
ARG PYTHON_VERSION=3.9-slim-bullseye
|
||||
|
||||
{% if cookiecutter.js_task_runner == 'Gulp' -%}
|
||||
FROM node:10-stretch-slim as client-builder
|
||||
FROM node:16-bullseye-slim as client-builder
|
||||
|
||||
ARG APP_HOME=/app
|
||||
WORKDIR ${APP_HOME}
|
||||
|
|
|
@ -5,4 +5,4 @@ set -o pipefail
|
|||
set -o nounset
|
||||
|
||||
|
||||
celery -A config.celery_app beat -l INFO
|
||||
exec celery -A config.celery_app beat -l INFO
|
||||
|
|
|
@ -4,7 +4,8 @@ set -o errexit
|
|||
set -o nounset
|
||||
|
||||
|
||||
celery flower \
|
||||
--app=config.celery_app \
|
||||
--broker="${CELERY_BROKER_URL}" \
|
||||
exec celery \
|
||||
-A config.celery_app \
|
||||
-b "${CELERY_BROKER_URL}" \
|
||||
flower \
|
||||
--basic_auth="${CELERY_FLOWER_USER}:${CELERY_FLOWER_PASSWORD}"
|
||||
|
|
|
@ -5,4 +5,4 @@ set -o pipefail
|
|||
set -o nounset
|
||||
|
||||
|
||||
celery -A config.celery_app worker -l INFO
|
||||
exec celery -A config.celery_app worker -l INFO
|
||||
|
|
|
@ -27,8 +27,8 @@ if compress_enabled; then
|
|||
python /app/manage.py compress
|
||||
fi
|
||||
{%- endif %}
|
||||
{% if cookiecutter.use_async == 'y' %}
|
||||
{%- if cookiecutter.use_async == 'y' %}
|
||||
/usr/local/bin/gunicorn config.asgi --bind 0.0.0.0:5000 --chdir=/app -k uvicorn.workers.UvicornWorker
|
||||
{% else %}
|
||||
{%- else %}
|
||||
/usr/local/bin/gunicorn config.wsgi --bind 0.0.0.0:5000 --chdir=/app
|
||||
{%- endif %}
|
||||
|
|
|
@ -48,6 +48,8 @@ DATABASES = {
|
|||
}
|
||||
{%- endif %}
|
||||
DATABASES["default"]["ATOMIC_REQUESTS"] = True
|
||||
# https://docs.djangoproject.com/en/stable/ref/settings/#std:setting-DEFAULT_AUTO_FIELD
|
||||
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
|
||||
|
||||
# URLS
|
||||
# ------------------------------------------------------------------------------
|
||||
|
@ -71,6 +73,7 @@ DJANGO_APPS = [
|
|||
]
|
||||
THIRD_PARTY_APPS = [
|
||||
"crispy_forms",
|
||||
"crispy_bootstrap5",
|
||||
"allauth",
|
||||
"allauth.account",
|
||||
"allauth.socialaccount",
|
||||
|
@ -81,11 +84,12 @@ THIRD_PARTY_APPS = [
|
|||
"rest_framework",
|
||||
"rest_framework.authtoken",
|
||||
"corsheaders",
|
||||
"drf_spectacular",
|
||||
{%- endif %}
|
||||
]
|
||||
|
||||
LOCAL_APPS = [
|
||||
"{{ cookiecutter.project_slug }}.users.apps.UsersConfig",
|
||||
"{{ cookiecutter.project_slug }}.users",
|
||||
# Your stuff: custom apps go here
|
||||
]
|
||||
# https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps
|
||||
|
@ -179,15 +183,11 @@ TEMPLATES = [
|
|||
{
|
||||
# https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-TEMPLATES-BACKEND
|
||||
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
||||
# https://docs.djangoproject.com/en/dev/ref/settings/#template-dirs
|
||||
# https://docs.djangoproject.com/en/dev/ref/settings/#dirs
|
||||
"DIRS": [str(APPS_DIR / "templates")],
|
||||
# https://docs.djangoproject.com/en/dev/ref/settings/#app-dirs
|
||||
"APP_DIRS": True,
|
||||
"OPTIONS": {
|
||||
# https://docs.djangoproject.com/en/dev/ref/settings/#template-loaders
|
||||
# https://docs.djangoproject.com/en/dev/ref/templates/api/#loader-types
|
||||
"loaders": [
|
||||
"django.template.loaders.filesystem.Loader",
|
||||
"django.template.loaders.app_directories.Loader",
|
||||
],
|
||||
# https://docs.djangoproject.com/en/dev/ref/settings/#template-context-processors
|
||||
"context_processors": [
|
||||
"django.template.context_processors.debug",
|
||||
|
@ -198,7 +198,7 @@ TEMPLATES = [
|
|||
"django.template.context_processors.static",
|
||||
"django.template.context_processors.tz",
|
||||
"django.contrib.messages.context_processors.messages",
|
||||
"{{ cookiecutter.project_slug }}.utils.context_processors.settings_context",
|
||||
"{{cookiecutter.project_slug}}.users.context_processors.allauth_settings",
|
||||
],
|
||||
},
|
||||
}
|
||||
|
@ -208,7 +208,8 @@ TEMPLATES = [
|
|||
FORM_RENDERER = "django.forms.renderers.TemplatesSetting"
|
||||
|
||||
# http://django-crispy-forms.readthedocs.io/en/latest/install.html#template-packs
|
||||
CRISPY_TEMPLATE_PACK = "bootstrap4"
|
||||
CRISPY_TEMPLATE_PACK = "bootstrap5"
|
||||
CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5"
|
||||
|
||||
# FIXTURES
|
||||
# ------------------------------------------------------------------------------
|
||||
|
@ -306,8 +307,12 @@ ACCOUNT_EMAIL_REQUIRED = True
|
|||
ACCOUNT_EMAIL_VERIFICATION = "mandatory"
|
||||
# https://django-allauth.readthedocs.io/en/latest/configuration.html
|
||||
ACCOUNT_ADAPTER = "{{cookiecutter.project_slug}}.users.adapters.AccountAdapter"
|
||||
# https://django-allauth.readthedocs.io/en/latest/forms.html
|
||||
ACCOUNT_FORMS = {"signup": "{{cookiecutter.project_slug}}.users.forms.UserSignupForm"}
|
||||
# https://django-allauth.readthedocs.io/en/latest/configuration.html
|
||||
SOCIALACCOUNT_ADAPTER = "{{cookiecutter.project_slug}}.users.adapters.SocialAccountAdapter"
|
||||
# https://django-allauth.readthedocs.io/en/latest/forms.html
|
||||
SOCIALACCOUNT_FORMS = {"signup": "{{cookiecutter.project_slug}}.users.forms.UserSocialSignupForm"}
|
||||
{% if cookiecutter.use_compressor == 'y' -%}
|
||||
# django-compressor
|
||||
# ------------------------------------------------------------------------------
|
||||
|
@ -330,6 +335,18 @@ REST_FRAMEWORK = {
|
|||
# django-cors-headers - https://github.com/adamchainz/django-cors-headers#setup
|
||||
CORS_URLS_REGEX = r"^/api/.*$"
|
||||
|
||||
# By Default swagger ui is available only to admin user. You can change permission classs to change that
|
||||
# See more configuration options at https://drf-spectacular.readthedocs.io/en/latest/settings.html#settings
|
||||
SPECTACULAR_SETTINGS = {
|
||||
"TITLE": "{{ cookiecutter.project_name }} API",
|
||||
"DESCRIPTION": "Documentation of API endpoiints of {{ cookiecutter.project_name }}",
|
||||
"VERSION": "1.0.0",
|
||||
"SERVE_PERMISSIONS": ["rest_framework.permissions.IsAdminUser"],
|
||||
"SERVERS": [
|
||||
{"url": "https://127.0.0.1:8000", "description": "Local Development server"},
|
||||
{"url": "https://{{ cookiecutter.domain_name }}", "description": "Production server"},
|
||||
],
|
||||
}
|
||||
{%- endif %}
|
||||
# Your stuff...
|
||||
# ------------------------------------------------------------------------------
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
import logging
|
||||
|
||||
import sentry_sdk
|
||||
from sentry_sdk.integrations.django import DjangoIntegration
|
||||
from sentry_sdk.integrations.logging import LoggingIntegration
|
||||
{%- if cookiecutter.use_celery == 'y' %}
|
||||
from sentry_sdk.integrations.celery import CeleryIntegration
|
||||
{% endif %}
|
||||
{%- endif %}
|
||||
from sentry_sdk.integrations.django import DjangoIntegration
|
||||
from sentry_sdk.integrations.logging import LoggingIntegration
|
||||
from sentry_sdk.integrations.redis import RedisIntegration
|
||||
|
||||
{% endif -%}
|
||||
|
@ -123,24 +123,12 @@ DEFAULT_FILE_STORAGE = "{{cookiecutter.project_slug}}.utils.storages.MediaRootGo
|
|||
MEDIA_URL = f"https://storage.googleapis.com/{GS_BUCKET_NAME}/media/"
|
||||
{%- endif %}
|
||||
|
||||
# TEMPLATES
|
||||
# ------------------------------------------------------------------------------
|
||||
# https://docs.djangoproject.com/en/dev/ref/settings/#templates
|
||||
TEMPLATES[-1]["OPTIONS"]["loaders"] = [ # type: ignore[index] # noqa F405
|
||||
(
|
||||
"django.template.loaders.cached.Loader",
|
||||
[
|
||||
"django.template.loaders.filesystem.Loader",
|
||||
"django.template.loaders.app_directories.Loader",
|
||||
],
|
||||
)
|
||||
]
|
||||
|
||||
# EMAIL
|
||||
# ------------------------------------------------------------------------------
|
||||
# https://docs.djangoproject.com/en/dev/ref/settings/#default-from-email
|
||||
DEFAULT_FROM_EMAIL = env(
|
||||
"DJANGO_DEFAULT_FROM_EMAIL", default="{{cookiecutter.project_name}} <noreply@{{cookiecutter.domain_name}}>"
|
||||
"DJANGO_DEFAULT_FROM_EMAIL",
|
||||
default="{{cookiecutter.project_name}} <noreply@{{cookiecutter.domain_name}}>",
|
||||
)
|
||||
# https://docs.djangoproject.com/en/dev/ref/settings/#server-email
|
||||
SERVER_EMAIL = env("DJANGO_SERVER_EMAIL", default=DEFAULT_FROM_EMAIL)
|
||||
|
|
|
@ -20,18 +20,6 @@ TEST_RUNNER = "django.test.runner.DiscoverRunner"
|
|||
# https://docs.djangoproject.com/en/dev/ref/settings/#password-hashers
|
||||
PASSWORD_HASHERS = ["django.contrib.auth.hashers.MD5PasswordHasher"]
|
||||
|
||||
# TEMPLATES
|
||||
# ------------------------------------------------------------------------------
|
||||
TEMPLATES[-1]["OPTIONS"]["loaders"] = [ # type: ignore[index] # noqa F405
|
||||
(
|
||||
"django.template.loaders.cached.Loader",
|
||||
[
|
||||
"django.template.loaders.filesystem.Loader",
|
||||
"django.template.loaders.app_directories.Loader",
|
||||
],
|
||||
)
|
||||
]
|
||||
|
||||
# EMAIL
|
||||
# ------------------------------------------------------------------------------
|
||||
# https://docs.djangoproject.com/en/dev/ref/settings/#email-backend
|
||||
|
|
|
@ -8,6 +8,7 @@ from django.urls import include, path
|
|||
from django.views import defaults as default_views
|
||||
from django.views.generic import TemplateView
|
||||
{%- if cookiecutter.use_drf == 'y' %}
|
||||
from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView
|
||||
from rest_framework.authtoken.views import obtain_auth_token
|
||||
{%- endif %}
|
||||
|
||||
|
@ -35,6 +36,12 @@ urlpatterns += [
|
|||
path("api/", include("config.api_router")),
|
||||
# DRF auth token
|
||||
path("auth-token/", obtain_auth_token),
|
||||
path("api/schema/", SpectacularAPIView.as_view(), name="api-schema"),
|
||||
path(
|
||||
"api/docs/",
|
||||
SpectacularSwaggerView.as_view(url_name="api-schema"),
|
||||
name="api-docs",
|
||||
),
|
||||
]
|
||||
{%- endif %}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
# You can set these variables from the command line, and also
|
||||
# from the environment for the first two.
|
||||
SPHINXOPTS ?=
|
||||
SPHINXBUILD ?= sphinx-build -c .
|
||||
SPHINXBUILD ?= sphinx-build
|
||||
SOURCEDIR = .
|
||||
BUILDDIR = ./_build
|
||||
{%- if cookiecutter.use_docker == 'y' %}
|
||||
|
@ -17,7 +17,7 @@ APP = ../{{cookiecutter.project_slug}}
|
|||
|
||||
# Put it first so that "make" without argument is like "make help".
|
||||
help:
|
||||
@$(SPHINXBUILD) help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -c .
|
||||
|
||||
# Build, watch and serve docs with live reload
|
||||
livehtml:
|
||||
|
@ -28,13 +28,9 @@ livehtml:
|
|||
|
||||
# Outputs rst files from django application code
|
||||
apidocs:
|
||||
{%- if cookiecutter.use_docker == 'y' %}
|
||||
sphinx-apidoc -o $(SOURCEDIR)/api /app
|
||||
{%- else %}
|
||||
sphinx-apidoc -o $(SOURCEDIR)/api ../{{cookiecutter.project_slug}}
|
||||
{%- endif %}
|
||||
sphinx-apidoc -o $(SOURCEDIR)/api $(APP)
|
||||
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: Makefile
|
||||
@$(SPHINXBUILD) -b $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -c .
|
||||
|
|
|
@ -10,8 +10,8 @@ Welcome to {{ cookiecutter.project_name }}'s documentation!
|
|||
:maxdepth: 2
|
||||
:caption: Contents:
|
||||
|
||||
howto
|
||||
pycharm/configuration
|
||||
howto{% if cookiecutter.use_pycharm == 'y' %}
|
||||
pycharm/configuration{% endif %}
|
||||
users
|
||||
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ const plumber = require('gulp-plumber')
|
|||
const postcss = require('gulp-postcss')
|
||||
const reload = browserSync.reload
|
||||
const rename = require('gulp-rename')
|
||||
const sass = require('gulp-sass')
|
||||
const sass = require('gulp-sass')(require('sass'))
|
||||
const spawn = require('child_process').spawn
|
||||
const uglify = require('gulp-uglify-es').default
|
||||
|
||||
|
@ -32,8 +32,7 @@ function pathsConfig(appName) {
|
|||
{%- if cookiecutter.custom_bootstrap_compilation == 'y' %}
|
||||
bootstrapSass: `${vendorsRoot}/bootstrap/scss`,
|
||||
vendorsJs: [
|
||||
`${vendorsRoot}/jquery/dist/jquery.slim.js`,
|
||||
`${vendorsRoot}/popper.js/dist/umd/popper.js`,
|
||||
`${vendorsRoot}/@popperjs/core/dist/umd/popper.js`,
|
||||
`${vendorsRoot}/bootstrap/dist/js/bootstrap.js`,
|
||||
],
|
||||
{%- endif %}
|
||||
|
@ -140,23 +139,25 @@ function initBrowserSync() {
|
|||
`${paths.js}/*.js`,
|
||||
`${paths.templates}/*.html`
|
||||
], {
|
||||
{%- if cookiecutter.use_docker == 'y' %}
|
||||
// https://www.browsersync.io/docs/options/#option-open
|
||||
// Disable as it doesn't work from inside a container
|
||||
open: false,
|
||||
{%- endif %}
|
||||
// https://www.browsersync.io/docs/options/#option-proxy
|
||||
{%- if cookiecutter.use_docker == 'n' %}
|
||||
proxy: 'localhost:8000'
|
||||
{%- else %}
|
||||
proxy: {
|
||||
{%- if cookiecutter.use_docker == 'n' %}
|
||||
target: '127.0.0.1:8000',
|
||||
{%- else %}
|
||||
target: 'django:8000',
|
||||
{%- endif %}
|
||||
proxyReq: [
|
||||
function(proxyReq, req) {
|
||||
// Assign proxy "host" header same as current request at Browsersync server
|
||||
proxyReq.setHeader('Host', req.headers.host)
|
||||
}
|
||||
]
|
||||
},
|
||||
// https://www.browsersync.io/docs/options/#option-open
|
||||
// Disable as it doesn't work from inside a container
|
||||
open: false
|
||||
{%- endif %}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
version: '3'
|
||||
|
||||
volumes:
|
||||
local_postgres_data: {}
|
||||
local_postgres_data_backups: {}
|
||||
{{ cookiecutter.project_slug }}_local_postgres_data: {}
|
||||
{{ cookiecutter.project_slug }}_local_postgres_data_backups: {}
|
||||
|
||||
services:
|
||||
django:{% if cookiecutter.use_celery == 'y' %} &django{% endif %}
|
||||
|
@ -10,9 +10,12 @@ services:
|
|||
context: .
|
||||
dockerfile: ./compose/local/django/Dockerfile
|
||||
image: {{ cookiecutter.project_slug }}_local_django
|
||||
container_name: django
|
||||
container_name: {{ cookiecutter.project_slug }}_local_django
|
||||
depends_on:
|
||||
- postgres
|
||||
{%- if cookiecutter.use_celery == 'y' %}
|
||||
- redis
|
||||
{%- endif %}
|
||||
{%- if cookiecutter.use_mailhog == 'y' %}
|
||||
- mailhog
|
||||
{%- endif %}
|
||||
|
@ -30,16 +33,16 @@ services:
|
|||
context: .
|
||||
dockerfile: ./compose/production/postgres/Dockerfile
|
||||
image: {{ cookiecutter.project_slug }}_production_postgres
|
||||
container_name: postgres
|
||||
container_name: {{ cookiecutter.project_slug }}_local_postgres
|
||||
volumes:
|
||||
- local_postgres_data:/var/lib/postgresql/data:Z
|
||||
- local_postgres_data_backups:/backups:z
|
||||
- {{ cookiecutter.project_slug }}_local_postgres_data:/var/lib/postgresql/data:Z
|
||||
- {{ cookiecutter.project_slug }}_local_postgres_data_backups:/backups:z
|
||||
env_file:
|
||||
- ./.envs/.local/.postgres
|
||||
|
||||
docs:
|
||||
image: {{ cookiecutter.project_slug }}_local_docs
|
||||
container_name: docs
|
||||
container_name: {{ cookiecutter.project_slug }}_local_docs
|
||||
build:
|
||||
context: .
|
||||
dockerfile: ./compose/local/docs/Dockerfile
|
||||
|
@ -56,7 +59,7 @@ services:
|
|||
|
||||
mailhog:
|
||||
image: mailhog/mailhog:v1.0.0
|
||||
container_name: mailhog
|
||||
container_name: {{ cookiecutter.project_slug }}_local_mailhog
|
||||
ports:
|
||||
- "8025:8025"
|
||||
|
||||
|
@ -65,12 +68,12 @@ services:
|
|||
|
||||
redis:
|
||||
image: redis:6
|
||||
container_name: redis
|
||||
container_name: {{ cookiecutter.project_slug }}_local_redis
|
||||
|
||||
celeryworker:
|
||||
<<: *django
|
||||
image: {{ cookiecutter.project_slug }}_local_celeryworker
|
||||
container_name: celeryworker
|
||||
container_name: {{ cookiecutter.project_slug }}_local_celeryworker
|
||||
depends_on:
|
||||
- redis
|
||||
- postgres
|
||||
|
@ -83,7 +86,7 @@ services:
|
|||
celerybeat:
|
||||
<<: *django
|
||||
image: {{ cookiecutter.project_slug }}_local_celerybeat
|
||||
container_name: celerybeat
|
||||
container_name: {{ cookiecutter.project_slug }}_local_celerybeat
|
||||
depends_on:
|
||||
- redis
|
||||
- postgres
|
||||
|
@ -96,7 +99,7 @@ services:
|
|||
flower:
|
||||
<<: *django
|
||||
image: {{ cookiecutter.project_slug }}_local_flower
|
||||
container_name: flower
|
||||
container_name: {{ cookiecutter.project_slug }}_local_flower
|
||||
ports:
|
||||
- "5555:5555"
|
||||
command: /start-flower
|
||||
|
@ -109,7 +112,7 @@ services:
|
|||
context: .
|
||||
dockerfile: ./compose/local/node/Dockerfile
|
||||
image: {{ cookiecutter.project_slug }}_local_node
|
||||
container_name: node
|
||||
container_name: {{ cookiecutter.project_slug }}_local_node
|
||||
depends_on:
|
||||
- django
|
||||
volumes:
|
||||
|
|
|
@ -3,36 +3,31 @@
|
|||
"version": "{{ cookiecutter.version }}",
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
{% if cookiecutter.js_task_runner == 'Gulp' -%}
|
||||
{% if cookiecutter.custom_bootstrap_compilation == 'y' -%}
|
||||
"bootstrap": "4.3.1",
|
||||
"bootstrap": "^5.1.3",
|
||||
"gulp-concat": "^2.6.1",
|
||||
"jquery": "3.3.1",
|
||||
"popper.js": "1.14.3",
|
||||
{% endif -%}
|
||||
"autoprefixer": "^9.4.7",
|
||||
"browser-sync": "^2.14.0",
|
||||
"cssnano": "^4.1.10",
|
||||
"gulp": "^4.0.0",
|
||||
"gulp-imagemin": "^5.0.3",
|
||||
"@popperjs/core": "^2.10.2",
|
||||
"autoprefixer": "^10.4.0",
|
||||
"browser-sync": "^2.27.7",
|
||||
"cssnano": "^5.0.11",
|
||||
"gulp": "^4.0.2",
|
||||
"gulp-imagemin": "^7.1.0",
|
||||
"gulp-plumber": "^1.2.1",
|
||||
"gulp-postcss": "^8.0.0",
|
||||
"gulp-rename": "^1.2.2",
|
||||
"gulp-sass": "^4.0.2",
|
||||
"gulp-uglify-es": "^1.0.4",
|
||||
"pixrem": "^5.0.0"
|
||||
{%- endif %}
|
||||
"gulp-postcss": "^9.0.1",
|
||||
"gulp-rename": "^2.0.0",
|
||||
"gulp-sass": "^5.0.0",
|
||||
"gulp-uglify-es": "^3.0.0",
|
||||
"pixrem": "^5.0.0",
|
||||
"postcss": "^8.3.11",
|
||||
"sass": "^1.43.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
"node": "16"
|
||||
},
|
||||
"browserslist": [
|
||||
"last 2 versions"
|
||||
],
|
||||
"scripts": {
|
||||
{% if cookiecutter.js_task_runner == 'Gulp' -%}
|
||||
"dev": "gulp",
|
||||
"build": "gulp generate-assets"
|
||||
{%- endif %}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,45 +1,48 @@
|
|||
pytz==2021.1 # https://github.com/stub42/pytz
|
||||
pytz==2021.3 # https://github.com/stub42/pytz
|
||||
python-slugify==5.0.2 # https://github.com/un33k/python-slugify
|
||||
Pillow==8.3.1 # https://github.com/python-pillow/Pillow
|
||||
Pillow==9.0.0 # https://github.com/python-pillow/Pillow
|
||||
{%- if cookiecutter.use_compressor == "y" %}
|
||||
{%- if cookiecutter.windows == 'y' and cookiecutter.use_docker == 'n' %}
|
||||
rcssmin==1.0.6 --install-option="--without-c-extensions" # https://github.com/ndparker/rcssmin
|
||||
rcssmin==1.1.0 --install-option="--without-c-extensions" # https://github.com/ndparker/rcssmin
|
||||
{%- else %}
|
||||
rcssmin==1.0.6 # https://github.com/ndparker/rcssmin
|
||||
rcssmin==1.1.0 # https://github.com/ndparker/rcssmin
|
||||
{%- endif %}
|
||||
{%- endif %}
|
||||
argon2-cffi==20.1.0 # https://github.com/hynek/argon2_cffi
|
||||
argon2-cffi==21.3.0 # https://github.com/hynek/argon2_cffi
|
||||
{%- if cookiecutter.use_whitenoise == 'y' %}
|
||||
whitenoise==5.3.0 # https://github.com/evansd/whitenoise
|
||||
{%- endif %}
|
||||
redis==3.5.3 # https://github.com/andymccurdy/redis-py
|
||||
redis==4.1.2 # https://github.com/redis/redis-py
|
||||
{%- if cookiecutter.use_docker == "y" or cookiecutter.windows == "n" %}
|
||||
hiredis==2.0.0 # https://github.com/redis/hiredis-py
|
||||
{%- endif %}
|
||||
{%- if cookiecutter.use_celery == "y" %}
|
||||
celery==4.4.6 # pyup: < 5.0,!=4.4.7 # https://github.com/celery/celery
|
||||
django-celery-beat==2.2.0 # https://github.com/celery/django-celery-beat
|
||||
celery==5.2.3 # pyup: < 6.0 # https://github.com/celery/celery
|
||||
django-celery-beat==2.2.1 # https://github.com/celery/django-celery-beat
|
||||
{%- if cookiecutter.use_docker == 'y' %}
|
||||
flower==0.9.7 # https://github.com/mher/flower
|
||||
flower==1.0.0 # https://github.com/mher/flower
|
||||
{%- endif %}
|
||||
{%- endif %}
|
||||
{%- if cookiecutter.use_async == 'y' %}
|
||||
uvicorn[standard]==0.14.0 # https://github.com/encode/uvicorn
|
||||
uvicorn[standard]==0.17.0.post1 # https://github.com/encode/uvicorn
|
||||
{%- endif %}
|
||||
|
||||
# Django
|
||||
# ------------------------------------------------------------------------------
|
||||
django==3.1.13 # pyup: < 3.2 # https://www.djangoproject.com/
|
||||
django-environ==0.4.5 # https://github.com/joke2k/django-environ
|
||||
django-model-utils==4.1.1 # https://github.com/jazzband/django-model-utils
|
||||
django-allauth==0.45.0 # https://github.com/pennersr/django-allauth
|
||||
django-crispy-forms==1.12.0 # https://github.com/django-crispy-forms/django-crispy-forms
|
||||
django==3.2.11 # pyup: < 4.0 # https://www.djangoproject.com/
|
||||
django-environ==0.8.1 # https://github.com/joke2k/django-environ
|
||||
django-model-utils==4.2.0 # https://github.com/jazzband/django-model-utils
|
||||
django-allauth==0.47.0 # https://github.com/pennersr/django-allauth
|
||||
django-crispy-forms==1.14.0 # https://github.com/django-crispy-forms/django-crispy-forms
|
||||
crispy-bootstrap5==0.6 # https://github.com/django-crispy-forms/crispy-bootstrap5
|
||||
{%- if cookiecutter.use_compressor == "y" %}
|
||||
django-compressor==2.4.1 # https://github.com/django-compressor/django-compressor
|
||||
django-compressor==3.1 # https://github.com/django-compressor/django-compressor
|
||||
{%- endif %}
|
||||
django-redis==5.0.0 # https://github.com/jazzband/django-redis
|
||||
django-redis==5.2.0 # https://github.com/jazzband/django-redis
|
||||
{%- if cookiecutter.use_drf == "y" %}
|
||||
# Django REST Framework
|
||||
djangorestframework==3.12.4 # https://github.com/encode/django-rest-framework
|
||||
django-cors-headers==3.7.0 # https://github.com/adamchainz/django-cors-headers
|
||||
djangorestframework==3.13.1 # https://github.com/encode/django-rest-framework
|
||||
django-cors-headers==3.11.0 # https://github.com/adamchainz/django-cors-headers
|
||||
# DRF-spectacular for api documentation
|
||||
drf-spectacular==0.21.1
|
||||
{%- endif %}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
-r base.txt
|
||||
|
||||
Werkzeug==1.0.1 # https://github.com/pallets/werkzeug
|
||||
Werkzeug[watchdog]==2.0.2 # https://github.com/pallets/werkzeug
|
||||
ipdb==0.13.9 # https://github.com/gotcha/ipdb
|
||||
{%- if cookiecutter.use_docker == 'y' %}
|
||||
psycopg2==2.9.1 # https://github.com/psycopg/psycopg2
|
||||
psycopg2==2.9.3 # https://github.com/psycopg/psycopg2
|
||||
{%- else %}
|
||||
psycopg2-binary==2.9.1 # https://github.com/psycopg/psycopg2
|
||||
psycopg2-binary==2.9.3 # https://github.com/psycopg/psycopg2
|
||||
{%- endif %}
|
||||
{%- if cookiecutter.use_async == 'y' or cookiecutter.use_celery == 'y' %}
|
||||
watchgod==0.7 # https://github.com/samuelcolvin/watchgod
|
||||
|
@ -13,33 +13,36 @@ watchgod==0.7 # https://github.com/samuelcolvin/watchgod
|
|||
|
||||
# Testing
|
||||
# ------------------------------------------------------------------------------
|
||||
mypy==0.910 # https://github.com/python/mypy
|
||||
django-stubs==1.8.0 # https://github.com/typeddjango/django-stubs
|
||||
pytest==6.2.4 # https://github.com/pytest-dev/pytest
|
||||
mypy==0.931 # https://github.com/python/mypy
|
||||
django-stubs==1.9.0 # https://github.com/typeddjango/django-stubs
|
||||
pytest==6.2.5 # https://github.com/pytest-dev/pytest
|
||||
pytest-sugar==0.9.4 # https://github.com/Frozenball/pytest-sugar
|
||||
{%- if cookiecutter.use_drf == "y" %}
|
||||
djangorestframework-stubs==1.4.0 # https://github.com/typeddjango/djangorestframework-stubs
|
||||
{%- endif %}
|
||||
|
||||
# Documentation
|
||||
# ------------------------------------------------------------------------------
|
||||
sphinx==4.1.2 # https://github.com/sphinx-doc/sphinx
|
||||
sphinx==4.4.0 # https://github.com/sphinx-doc/sphinx
|
||||
sphinx-autobuild==2021.3.14 # https://github.com/GaretJax/sphinx-autobuild
|
||||
|
||||
# Code quality
|
||||
# ------------------------------------------------------------------------------
|
||||
flake8==3.9.2 # https://github.com/PyCQA/flake8
|
||||
flake8-isort==4.0.0 # https://github.com/gforcada/flake8-isort
|
||||
coverage==5.5 # https://github.com/nedbat/coveragepy
|
||||
black==21.7b0 # https://github.com/psf/black
|
||||
pylint-django==2.4.4 # https://github.com/PyCQA/pylint-django
|
||||
flake8==4.0.1 # https://github.com/PyCQA/flake8
|
||||
flake8-isort==4.1.1 # https://github.com/gforcada/flake8-isort
|
||||
coverage==6.3 # https://github.com/nedbat/coveragepy
|
||||
black==21.12b0 # https://github.com/psf/black
|
||||
pylint-django==2.5.0 # https://github.com/PyCQA/pylint-django
|
||||
{%- if cookiecutter.use_celery == 'y' %}
|
||||
pylint-celery==0.3 # https://github.com/PyCQA/pylint-celery
|
||||
{%- endif %}
|
||||
pre-commit==2.14.0 # https://github.com/pre-commit/pre-commit
|
||||
pre-commit==2.17.0 # https://github.com/pre-commit/pre-commit
|
||||
|
||||
# Django
|
||||
# ------------------------------------------------------------------------------
|
||||
factory-boy==3.2.0 # https://github.com/FactoryBoy/factory_boy
|
||||
factory-boy==3.2.1 # https://github.com/FactoryBoy/factory_boy
|
||||
|
||||
django-debug-toolbar==3.2.1 # https://github.com/jazzband/django-debug-toolbar
|
||||
django-extensions==3.1.3 # https://github.com/django-extensions/django-extensions
|
||||
django-coverage-plugin==2.0.0 # https://github.com/nedbat/django_coverage_plugin
|
||||
pytest-django==4.4.0 # https://github.com/pytest-dev/pytest-django
|
||||
django-debug-toolbar==3.2.4 # https://github.com/jazzband/django-debug-toolbar
|
||||
django-extensions==3.1.5 # https://github.com/django-extensions/django-extensions
|
||||
django-coverage-plugin==2.0.2 # https://github.com/nedbat/django_coverage_plugin
|
||||
pytest-django==4.5.2 # https://github.com/pytest-dev/pytest-django
|
||||
|
|
|
@ -3,12 +3,12 @@
|
|||
-r base.txt
|
||||
|
||||
gunicorn==20.1.0 # https://github.com/benoitc/gunicorn
|
||||
psycopg2==2.9.1 # https://github.com/psycopg/psycopg2
|
||||
psycopg2==2.9.3 # https://github.com/psycopg/psycopg2
|
||||
{%- if cookiecutter.use_whitenoise == 'n' %}
|
||||
Collectfast==2.2.0 # https://github.com/antonagestam/collectfast
|
||||
{%- endif %}
|
||||
{%- if cookiecutter.use_sentry == "y" %}
|
||||
sentry-sdk==1.3.1 # https://github.com/getsentry/sentry-python
|
||||
sentry-sdk==1.5.4 # https://github.com/getsentry/sentry-python
|
||||
{%- endif %}
|
||||
{%- if cookiecutter.use_docker == "n" and cookiecutter.windows == "y" %}
|
||||
hiredis==2.0.0 # https://github.com/redis/hiredis-py
|
||||
|
@ -17,26 +17,26 @@ hiredis==2.0.0 # https://github.com/redis/hiredis-py
|
|||
# Django
|
||||
# ------------------------------------------------------------------------------
|
||||
{%- if cookiecutter.cloud_provider == 'AWS' %}
|
||||
django-storages[boto3]==1.11.1 # https://github.com/jschneier/django-storages
|
||||
django-storages[boto3]==1.12.3 # https://github.com/jschneier/django-storages
|
||||
{%- elif cookiecutter.cloud_provider == 'GCP' %}
|
||||
django-storages[google]==1.11.1 # https://github.com/jschneier/django-storages
|
||||
django-storages[google]==1.12.3 # https://github.com/jschneier/django-storages
|
||||
{%- endif %}
|
||||
{%- if cookiecutter.mail_service == 'Mailgun' %}
|
||||
django-anymail[mailgun]==8.4 # https://github.com/anymail/django-anymail
|
||||
django-anymail[mailgun]==8.5 # https://github.com/anymail/django-anymail
|
||||
{%- elif cookiecutter.mail_service == 'Amazon SES' %}
|
||||
django-anymail[amazon_ses]==8.4 # https://github.com/anymail/django-anymail
|
||||
django-anymail[amazon_ses]==8.5 # https://github.com/anymail/django-anymail
|
||||
{%- elif cookiecutter.mail_service == 'Mailjet' %}
|
||||
django-anymail[mailjet]==8.4 # https://github.com/anymail/django-anymail
|
||||
django-anymail[mailjet]==8.5 # https://github.com/anymail/django-anymail
|
||||
{%- elif cookiecutter.mail_service == 'Mandrill' %}
|
||||
django-anymail[mandrill]==8.4 # https://github.com/anymail/django-anymail
|
||||
django-anymail[mandrill]==8.5 # https://github.com/anymail/django-anymail
|
||||
{%- elif cookiecutter.mail_service == 'Postmark' %}
|
||||
django-anymail[postmark]==8.4 # https://github.com/anymail/django-anymail
|
||||
django-anymail[postmark]==8.5 # https://github.com/anymail/django-anymail
|
||||
{%- elif cookiecutter.mail_service == 'Sendgrid' %}
|
||||
django-anymail[sendgrid]==8.4 # https://github.com/anymail/django-anymail
|
||||
django-anymail[sendgrid]==8.5 # https://github.com/anymail/django-anymail
|
||||
{%- elif cookiecutter.mail_service == 'SendinBlue' %}
|
||||
django-anymail[sendinblue]==8.4 # https://github.com/anymail/django-anymail
|
||||
django-anymail[sendinblue]==8.5 # https://github.com/anymail/django-anymail
|
||||
{%- elif cookiecutter.mail_service == 'SparkPost' %}
|
||||
django-anymail[sparkpost]==8.4 # https://github.com/anymail/django-anymail
|
||||
django-anymail[sparkpost]==8.5 # https://github.com/anymail/django-anymail
|
||||
{%- elif cookiecutter.mail_service == 'Other SMTP' %}
|
||||
django-anymail==8.4 # https://github.com/anymail/django-anymail
|
||||
django-anymail==8.5 # https://github.com/anymail/django-anymail
|
||||
{%- endif %}
|
||||
|
|
|
@ -1 +1 @@
|
|||
python-3.9.4
|
||||
python-3.9.9
|
||||
|
|
|
@ -24,7 +24,7 @@ ignore_missing_imports = True
|
|||
warn_unused_ignores = True
|
||||
warn_redundant_casts = True
|
||||
warn_unused_configs = True
|
||||
plugins = mypy_django_plugin.main
|
||||
plugins = mypy_django_plugin.main{% if cookiecutter.use_drf == "y" %}, mypy_drf_plugin.main{% endif %}
|
||||
|
||||
[mypy.plugins.django-stubs]
|
||||
django_settings_module = config.settings.test
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
##basic build dependencies of various Django apps for Debian Bullseye 11.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
|
|
@ -7,23 +7,52 @@ from django.conf import settings
|
|||
from django.db import migrations
|
||||
|
||||
|
||||
def _update_or_create_site_with_sequence(site_model, connection, domain, name):
|
||||
"""Update or create the site with default ID and keep the DB sequence in sync."""
|
||||
site, created = site_model.objects.update_or_create(
|
||||
id=settings.SITE_ID,
|
||||
defaults={
|
||||
"domain": domain,
|
||||
"name": name,
|
||||
},
|
||||
)
|
||||
if created:
|
||||
# We provided the ID explicitly when creating the Site entry, therefore the DB
|
||||
# sequence to auto-generate them wasn't used and is now out of sync. If we
|
||||
# don't do anything, we'll get a unique constraint violation the next time a
|
||||
# site is created.
|
||||
# To avoid this, we need to manually update DB sequence and make sure it's
|
||||
# greater than the maximum value.
|
||||
max_id = site_model.objects.order_by('-id').first().id
|
||||
with connection.cursor() as cursor:
|
||||
cursor.execute("SELECT last_value from django_site_id_seq")
|
||||
(current_id,) = cursor.fetchone()
|
||||
if current_id <= max_id:
|
||||
cursor.execute(
|
||||
"alter sequence django_site_id_seq restart with %s",
|
||||
[max_id + 1],
|
||||
)
|
||||
|
||||
|
||||
def update_site_forward(apps, schema_editor):
|
||||
"""Set site domain and name."""
|
||||
Site = apps.get_model("sites", "Site")
|
||||
Site.objects.update_or_create(
|
||||
id=settings.SITE_ID,
|
||||
defaults={
|
||||
"domain": "{{cookiecutter.domain_name}}",
|
||||
"name": "{{cookiecutter.project_name}}",
|
||||
},
|
||||
_update_or_create_site_with_sequence(
|
||||
Site,
|
||||
schema_editor.connection,
|
||||
"{{cookiecutter.domain_name}}",
|
||||
"{{cookiecutter.project_name}}",
|
||||
)
|
||||
|
||||
|
||||
def update_site_backward(apps, schema_editor):
|
||||
"""Revert site domain and name to default."""
|
||||
Site = apps.get_model("sites", "Site")
|
||||
Site.objects.update_or_create(
|
||||
id=settings.SITE_ID, defaults={"domain": "example.com", "name": "example.com"}
|
||||
_update_or_create_site_with_sequence(
|
||||
Site,
|
||||
schema_editor.connection,
|
||||
"example.com",
|
||||
"example.com",
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -6,12 +6,16 @@ from django.db import migrations
|
|||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('sites', '0003_set_site_domain_and_name'),
|
||||
("sites", "0003_set_site_domain_and_name"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='site',
|
||||
options={'ordering': ['domain'], 'verbose_name': 'site', 'verbose_name_plural': 'sites'},
|
||||
name="site",
|
||||
options={
|
||||
"ordering": ["domain"],
|
||||
"verbose_name": "site",
|
||||
"verbose_name_plural": "sites",
|
||||
},
|
||||
),
|
||||
]
|
||||
|
|
|
@ -66,17 +66,14 @@ window.addEventListener('DOMContentLoaded',function() {
|
|||
const message = "{% translate 'Do you really want to remove the selected e-mail address?' %}";
|
||||
const actions = document.getElementsByName('action_remove');
|
||||
if (actions.length) {
|
||||
actions[0].addEventListener("click", function(e) {
|
||||
actions[0].addEventListener("click",function(e) {
|
||||
if (!confirm(message)) {
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
}
|
||||
Array.from(document.getElementsByClassName('form-group')).forEach(x => x.classList.remove('row'));
|
||||
});
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
$('.form-group').removeClass('row');
|
||||
})
|
||||
</script>
|
||||
{% endblock %}
|
||||
{%- endraw %}
|
||||
|
|
|
@ -13,25 +13,37 @@
|
|||
{% get_providers as socialaccount_providers %}
|
||||
|
||||
{% if socialaccount_providers %}
|
||||
<p>{% blocktranslate with site.name as site_name %}Please sign in with one
|
||||
of your existing third party accounts. Or, <a href="{{ signup_url }}">sign up</a>
|
||||
for a {{ site_name }} account and sign in below:{% endblocktranslate %}</p>
|
||||
<p>
|
||||
{% translate "Please sign in with one of your existing third party accounts:" %}
|
||||
{% if ACCOUNT_ALLOW_REGISTRATION %}
|
||||
{% blocktranslate trimmed %}
|
||||
Or, <a href="{{ signup_url }}">sign up</a>
|
||||
for a {{ site_name }} account and sign in below:
|
||||
{% endblocktranslate %}
|
||||
{% endif %}
|
||||
</p>
|
||||
|
||||
<div class="socialaccount_ballot">
|
||||
<div class="socialaccount_ballot">
|
||||
|
||||
<ul class="socialaccount_providers">
|
||||
{% include "socialaccount/snippets/provider_list.html" with process="login" %}
|
||||
</ul>
|
||||
|
||||
<div class="login-or">{% translate 'or' %}</div>
|
||||
<div class="login-or">{% translate "or" %}</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% include "socialaccount/snippets/login_extra.html" %}
|
||||
{% include "socialaccount/snippets/login_extra.html" %}
|
||||
|
||||
{% else %}
|
||||
<p>{% blocktranslate %}If you have not created an account yet, then please
|
||||
<a href="{{ signup_url }}">sign up</a> first.{% endblocktranslate %}</p>
|
||||
{% if ACCOUNT_ALLOW_REGISTRATION %}
|
||||
<p>
|
||||
{% blocktranslate trimmed %}
|
||||
If you have not created an account yet, then please
|
||||
<a href="{{ signup_url }}">sign up</a> first.
|
||||
{% endblocktranslate %}
|
||||
</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
<form class="login" method="POST" action="{% url 'account_login' %}">
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
{% raw %}{% load static i18n {% endraw %}{% if cookiecutter.use_compressor == "y" %}compress{% endif %}{% raw %}%}<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
{% get_current_language as LANGUAGE_CODE %}
|
||||
<html lang="{{ LANGUAGE_CODE }}">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||
|
@ -8,17 +9,12 @@
|
|||
<meta name="description" content="{% endraw %}{{ cookiecutter.description }}{% raw %}">
|
||||
<meta name="author" content="{% endraw %}{{ cookiecutter.author_name }}{% raw %}">
|
||||
|
||||
<!-- HTML5 shim, for IE6-8 support of HTML5 elements -->
|
||||
<!--[if lt IE 9]>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.min.js"></script>
|
||||
<![endif]-->
|
||||
|
||||
<link rel="icon" href="{% static 'images/favicons/favicon.ico' %}">
|
||||
|
||||
{% block css %}
|
||||
{%- endraw %}{% if cookiecutter.custom_bootstrap_compilation == "n" %}{% raw %}
|
||||
<!-- Latest compiled and minified Bootstrap CSS -->
|
||||
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.3/css/bootstrap.min.css" integrity="sha512-GQGU0fMMi238uA+a/bdWJfpUGKUkBdgfFdgBm72SUQ6BeyWjoY/ton0tEjH+OSH9iP4Dfh+7HM0I9f5eR0L/4w==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
||||
{%- endraw %}{% endif %}{% raw %}
|
||||
|
||||
<!-- Your stuff: Third-party CSS libraries go here -->
|
||||
|
@ -41,11 +37,8 @@
|
|||
<script defer src="{% static 'js/vendors.js' %}"></script>
|
||||
{%- endraw %}{% if cookiecutter.use_compressor == "y" %}{% raw %}{% endcompress %}{% endraw %}{% endif %}{% raw %}
|
||||
{%- endraw %}{% else %}{% raw %}
|
||||
<!-- Bootstrap JS and its dependencies-->
|
||||
<script defer src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
|
||||
<script defer src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
|
||||
|
||||
<!-- Bootstrap JS -->
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.3/js/bootstrap.min.js" integrity="sha512-OvBgP9A2JBgiRad/mM36mkzXSXaJE9BEIENnVEmeZdITvwT09xnxLtT4twkCa8m/loMbPHsvPl0T8lRGVBwjlQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
<!-- Your stuff: Third-party javascript libraries go here -->
|
||||
{%- endraw %}{% endif %}{% raw %}
|
||||
|
||||
|
@ -62,7 +55,8 @@
|
|||
|
||||
<div class="mb-1">
|
||||
<nav class="navbar navbar-expand-md navbar-light bg-light">
|
||||
<button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<div class="container-fluid">
|
||||
<button class="navbar-toggler navbar-toggler-right" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="{% url 'home' %}">{% endraw %}{{ cookiecutter.project_name }}{% raw %}</a>
|
||||
|
@ -70,7 +64,7 @@
|
|||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||
<ul class="navbar-nav mr-auto">
|
||||
<li class="nav-item active">
|
||||
<a class="nav-link" href="{% url 'home' %}">Home <span class="sr-only">(current)</span></a>
|
||||
<a class="nav-link" href="{% url 'home' %}">Home <span class="visually-hidden">(current)</span></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{% url 'about' %}">About</a>
|
||||
|
@ -85,10 +79,12 @@
|
|||
<a class="nav-link" href="{% url 'account_logout' %}">{% translate "Sign Out" %}</a>
|
||||
</li>
|
||||
{% else %}
|
||||
{% if ACCOUNT_ALLOW_REGISTRATION %}
|
||||
<li class="nav-item">
|
||||
{# URL provided by django-allauth/account/urls.py #}
|
||||
<a id="sign-up-link" class="nav-link" href="{% url 'account_signup' %}">{% translate "Sign Up" %}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li class="nav-item">
|
||||
{# URL provided by django-allauth/account/urls.py #}
|
||||
<a id="log-in-link" class="nav-link" href="{% url 'account_login' %}">{% translate "Sign In" %}</a>
|
||||
|
@ -96,6 +92,7 @@
|
|||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
</div>
|
||||
|
@ -104,7 +101,10 @@
|
|||
|
||||
{% if messages %}
|
||||
{% for message in messages %}
|
||||
<div class="alert {% if message.tags %}alert-{{ message.tags }}{% endif %}">{{ message }}<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button></div>
|
||||
<div class="alert alert-dismissible {% if message.tags %}alert-{{ message.tags }}{% endif %}">
|
||||
{{ message }}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
|
@ -117,7 +117,13 @@
|
|||
{% block modal %}{% endblock modal %}
|
||||
|
||||
{% block inline_javascript %}
|
||||
{# Script tags with only code, no src (defer by default) #}
|
||||
{% comment %}
|
||||
Script tags with only code, no src (defer by default). To run
|
||||
with a "defer" so that you run inline code:
|
||||
<script>
|
||||
window.addEventListener('DOMContentLoaded', () => {/* Run whatever you want */});
|
||||
</script>
|
||||
{% endcomment %}
|
||||
{% endblock inline_javascript %}
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -3,7 +3,7 @@ from django.contrib.auth import admin as auth_admin
|
|||
from django.contrib.auth import get_user_model
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from {{ cookiecutter.project_slug }}.users.forms import UserChangeForm, UserCreationForm
|
||||
from {{ cookiecutter.project_slug }}.users.forms import UserAdminChangeForm, UserAdminCreationForm
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
@ -11,8 +11,8 @@ User = get_user_model()
|
|||
@admin.register(User)
|
||||
class UserAdmin(auth_admin.UserAdmin):
|
||||
|
||||
form = UserChangeForm
|
||||
add_form = UserCreationForm
|
||||
form = UserAdminChangeForm
|
||||
add_form = UserAdminCreationForm
|
||||
fieldsets = (
|
||||
(None, {"fields": ("username", "password")}),
|
||||
(_("Personal info"), {"fields": ("name", "email")}),
|
||||
|
|
|
@ -16,9 +16,10 @@ class UserViewSet(RetrieveModelMixin, ListModelMixin, UpdateModelMixin, GenericV
|
|||
lookup_field = "username"
|
||||
|
||||
def get_queryset(self, *args, **kwargs):
|
||||
assert isinstance(self.request.user.id, int)
|
||||
return self.queryset.filter(id=self.request.user.id)
|
||||
|
||||
@action(detail=False, methods=["GET"])
|
||||
@action(detail=False)
|
||||
def me(self, request):
|
||||
serializer = UserSerializer(request.user, context={"request": request})
|
||||
return Response(status=status.HTTP_200_OK, data=serializer.data)
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
from django.conf import settings
|
||||
|
||||
|
||||
def allauth_settings(request):
|
||||
"""Expose some settings from django-allauth in templates."""
|
||||
return {
|
||||
"ACCOUNT_ALLOW_REGISTRATION": settings.ACCOUNT_ALLOW_REGISTRATION,
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
from allauth.account.forms import SignupForm
|
||||
from allauth.socialaccount.forms import SignupForm as SocialSignupForm
|
||||
from django.contrib.auth import forms as admin_forms
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
@ -5,15 +7,36 @@ from django.utils.translation import gettext_lazy as _
|
|||
User = get_user_model()
|
||||
|
||||
|
||||
class UserChangeForm(admin_forms.UserChangeForm):
|
||||
class UserAdminChangeForm(admin_forms.UserChangeForm):
|
||||
class Meta(admin_forms.UserChangeForm.Meta):
|
||||
model = User
|
||||
|
||||
|
||||
class UserCreationForm(admin_forms.UserCreationForm):
|
||||
class UserAdminCreationForm(admin_forms.UserCreationForm):
|
||||
"""
|
||||
Form for User Creation in the Admin Area.
|
||||
To change user signup, see UserSignupForm and UserSocialSignupForm.
|
||||
"""
|
||||
|
||||
class Meta(admin_forms.UserCreationForm.Meta):
|
||||
model = User
|
||||
|
||||
error_messages = {
|
||||
"username": {"unique": _("This username has already been taken.")}
|
||||
}
|
||||
|
||||
|
||||
class UserSignupForm(SignupForm):
|
||||
"""
|
||||
Form that will be rendered on a user sign up section/screen.
|
||||
Default fields will be added automatically.
|
||||
Check UserSocialSignupForm for accounts created from social.
|
||||
"""
|
||||
|
||||
|
||||
class UserSocialSignupForm(SocialSignupForm):
|
||||
"""
|
||||
Renders the form when user has signed up using social accounts.
|
||||
Default fields will be added automatically.
|
||||
See UserSignupForm otherwise.
|
||||
"""
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
# Generated by Django 3.2.9 on 2021-11-20 11:23
|
||||
import django.contrib.auth.models
|
||||
import django.contrib.auth.validators
|
||||
from django.db import migrations, models
|
||||
|
@ -8,7 +9,9 @@ class Migration(migrations.Migration):
|
|||
|
||||
initial = True
|
||||
|
||||
dependencies = [("auth", "0008_alter_user_username_max_length")]
|
||||
dependencies = [
|
||||
("auth", "0012_alter_user_first_name_max_length"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
|
@ -16,7 +19,7 @@ class Migration(migrations.Migration):
|
|||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
|
@ -111,10 +114,12 @@ class Migration(migrations.Migration):
|
|||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name_plural": "users",
|
||||
"verbose_name": "user",
|
||||
"verbose_name_plural": "users",
|
||||
"abstract": False,
|
||||
},
|
||||
managers=[("objects", django.contrib.auth.models.UserManager())],
|
||||
)
|
||||
managers=[
|
||||
("objects", django.contrib.auth.models.UserManager()),
|
||||
],
|
||||
),
|
||||
]
|
||||
|
|
|
@ -5,7 +5,11 @@ from django.utils.translation import gettext_lazy as _
|
|||
|
||||
|
||||
class User(AbstractUser):
|
||||
"""Default user for {{cookiecutter.project_name}}."""
|
||||
"""
|
||||
Default custom user model for {{cookiecutter.project_name}}.
|
||||
If adding fields that need to be filled at user signup,
|
||||
check forms.SignupForm and forms.SocialSignupForms accordingly.
|
||||
"""
|
||||
|
||||
#: First and last name do not cover name patterns around the globe
|
||||
name = CharField(_("Name of User"), blank=True, max_length=255)
|
||||
|
|
|
@ -4,20 +4,20 @@ Module for all Form Tests.
|
|||
import pytest
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from {{ cookiecutter.project_slug }}.users.forms import UserCreationForm
|
||||
from {{ cookiecutter.project_slug }}.users.forms import UserAdminCreationForm
|
||||
from {{ cookiecutter.project_slug }}.users.models import User
|
||||
|
||||
pytestmark = pytest.mark.django_db
|
||||
|
||||
|
||||
class TestUserCreationForm:
|
||||
class TestUserAdminCreationForm:
|
||||
"""
|
||||
Test class for all tests related to the UserCreationForm
|
||||
Test class for all tests related to the UserAdminCreationForm
|
||||
"""
|
||||
|
||||
def test_username_validation_error_msg(self, user: User):
|
||||
"""
|
||||
Tests UserCreation Form's unique validator functions correctly by testing:
|
||||
Tests UserAdminCreation Form's unique validator functions correctly by testing:
|
||||
1) A new user with an existing username cannot be added.
|
||||
2) Only 1 error is raised by the UserCreation Form
|
||||
3) The desired error message is raised
|
||||
|
@ -25,7 +25,7 @@ class TestUserCreationForm:
|
|||
|
||||
# The user already exists,
|
||||
# hence cannot be created.
|
||||
form = UserCreationForm(
|
||||
form = UserAdminCreationForm(
|
||||
{
|
||||
"username": user.username,
|
||||
"password1": user.password,
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user