Repository: cookiecutter/cookiecutter-django Branch: main Commit: 1ef10a7c8b0b Files: 245 Total size: 882.3 KB Directory structure: gitextract_c7d8xipx/ ├── .editorconfig ├── .gitattributes ├── .github/ │ ├── CONTRIBUTORS-template.md │ ├── FUNDING.yml │ ├── ISSUE_TEMPLATE/ │ │ ├── bug.md │ │ ├── feature.md │ │ ├── paid-support.md │ │ └── question.md │ ├── PULL_REQUEST_TEMPLATE.md │ ├── changelog-template.md │ ├── contributors.json │ ├── dependabot.yml │ └── workflows/ │ ├── align-versions.yml │ ├── ci.yml │ ├── dependabot-uv-lock.yml │ ├── django-issue-checker.yml │ ├── issue-manager.yml │ ├── pre-commit-autoupdate.yml │ ├── update-changelog.yml │ └── update-contributors.yml ├── .gitignore ├── .pre-commit-config.yaml ├── .pyup.yml ├── .readthedocs.yaml ├── AGENTS.md ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── CONTRIBUTORS.md ├── LICENSE ├── README.md ├── cookiecutter.json ├── docs/ │ ├── 1-getting-started/ │ │ ├── project-generation-options.rst │ │ └── settings.rst │ ├── 2-local-development/ │ │ ├── developing-locally-docker.rst │ │ ├── developing-locally.rst │ │ └── generate-project-block.rst │ ├── 3-deployment/ │ │ ├── deployment-on-heroku.rst │ │ ├── deployment-on-pythonanywhere.rst │ │ └── deployment-with-docker.rst │ ├── 4-guides/ │ │ ├── docker-postgres-backups.rst │ │ ├── document.rst │ │ ├── linters.rst │ │ ├── testing.rst │ │ └── websocket.rst │ ├── 5-help/ │ │ ├── faq.rst │ │ └── troubleshooting.rst │ ├── 6-about/ │ │ ├── contributing.md │ │ ├── generative-ai.md │ │ └── maintainer-guide.md │ ├── Makefile │ ├── __init__.py │ ├── _static/ │ │ └── .gitkeep │ ├── conf.py │ ├── includes/ │ │ └── mailgun.rst │ ├── index.rst │ └── make.bat ├── hooks/ │ ├── __init__.py │ ├── post_gen_project.py │ └── pre_gen_project.py ├── pyproject.toml ├── scripts/ │ ├── __init__.py │ ├── create_django_issue.py │ ├── node_version.py │ ├── ruff_version.py │ ├── update_changelog.py │ └── update_contributors.py ├── tests/ │ ├── __init__.py │ ├── test_bare.sh │ ├── test_cookiecutter_generation.py │ ├── test_docker.sh │ └── test_hooks.py ├── tox.ini └── {{cookiecutter.project_slug}}/ ├── .devcontainer/ │ ├── bash_history │ ├── bashrc.override.sh │ └── devcontainer.json ├── .dockerignore ├── .drone.yml ├── .editorconfig ├── .envs/ │ ├── .local/ │ │ ├── .django │ │ └── .postgres │ └── .production/ │ ├── .django │ └── .postgres ├── .gitattributes ├── .github/ │ ├── dependabot.yml │ └── workflows/ │ └── ci.yml ├── .gitignore ├── .gitlab-ci.yml ├── .pre-commit-config.yaml ├── .readthedocs.yml ├── .travis.yml ├── CONTRIBUTORS.txt ├── COPYING ├── LICENSE ├── Procfile ├── README.md ├── bin/ │ └── post_compile ├── compose/ │ ├── local/ │ │ ├── django/ │ │ │ ├── Dockerfile │ │ │ ├── celery/ │ │ │ │ ├── beat/ │ │ │ │ │ └── start │ │ │ │ ├── flower/ │ │ │ │ │ └── start │ │ │ │ └── worker/ │ │ │ │ └── start │ │ │ └── start │ │ ├── docs/ │ │ │ ├── Dockerfile │ │ │ └── start │ │ ├── node/ │ │ │ └── Dockerfile │ │ └── uv/ │ │ └── Dockerfile │ └── production/ │ ├── aws/ │ │ ├── Dockerfile │ │ └── maintenance/ │ │ ├── download │ │ └── upload │ ├── django/ │ │ ├── Dockerfile │ │ ├── celery/ │ │ │ ├── beat/ │ │ │ │ └── start │ │ │ ├── flower/ │ │ │ │ └── start │ │ │ └── worker/ │ │ │ └── start │ │ ├── entrypoint │ │ └── start │ ├── nginx/ │ │ ├── Dockerfile │ │ └── default.conf │ ├── postgres/ │ │ ├── Dockerfile │ │ └── maintenance/ │ │ ├── _sourced/ │ │ │ ├── constants.sh │ │ │ ├── countdown.sh │ │ │ ├── messages.sh │ │ │ └── yes_no.sh │ │ ├── backup │ │ ├── backups │ │ ├── restore │ │ └── rmbackup │ └── traefik/ │ ├── Dockerfile │ └── traefik.yml ├── config/ │ ├── __init__.py │ ├── api.py │ ├── api_router.py │ ├── asgi.py │ ├── celery_app.py │ ├── settings/ │ │ ├── __init__.py │ │ ├── base.py │ │ ├── local.py │ │ ├── production.py │ │ └── test.py │ ├── urls.py │ ├── websocket.py │ └── wsgi.py ├── docker-compose.docs.yml ├── docker-compose.local.yml ├── docker-compose.production.yml ├── docs/ │ ├── Makefile │ ├── __init__.py │ ├── conf.py │ ├── howto.rst │ ├── index.rst │ ├── make.bat │ ├── pycharm/ │ │ └── configuration.rst │ └── users.rst ├── gulpfile.mjs ├── justfile ├── locale/ │ ├── README.md │ ├── en_US/ │ │ └── LC_MESSAGES/ │ │ └── django.po │ ├── fr_FR/ │ │ └── LC_MESSAGES/ │ │ └── django.po │ └── pt_BR/ │ └── LC_MESSAGES/ │ └── django.po ├── manage.py ├── merge_production_dotenvs_in_dotenv.py ├── package.json ├── pyproject.toml ├── requirements/ │ ├── base.txt │ ├── local.txt │ └── production.txt ├── tests/ │ ├── __init__.py │ └── test_merge_production_dotenvs_in_dotenv.py ├── utility/ │ ├── install_os_dependencies.sh │ ├── install_python_dependencies.sh │ ├── requirements-bionic.apt │ ├── requirements-bookworm.apt │ ├── requirements-bullseye.apt │ ├── requirements-buster.apt │ ├── requirements-focal.apt │ ├── requirements-jammy.apt │ ├── requirements-jessie.apt │ ├── requirements-noble.apt │ ├── requirements-stretch.apt │ ├── requirements-trusty.apt │ └── requirements-xenial.apt ├── webpack/ │ ├── common.config.js │ ├── dev.config.js │ └── prod.config.js └── {{cookiecutter.project_slug}}/ ├── __init__.py ├── conftest.py ├── contrib/ │ ├── __init__.py │ └── sites/ │ ├── __init__.py │ └── migrations/ │ ├── 0001_initial.py │ ├── 0002_alter_domain_unique.py │ ├── 0003_set_site_domain_and_name.py │ ├── 0004_alter_options_ordering_domain.py │ └── __init__.py ├── static/ │ ├── fonts/ │ │ └── .gitkeep │ ├── js/ │ │ └── project.js │ └── sass/ │ ├── custom_bootstrap_vars.scss │ └── project.scss ├── templates/ │ ├── 403.html │ ├── 403_csrf.html │ ├── 404.html │ ├── 500.html │ ├── account/ │ │ └── base_manage_password.html │ ├── allauth/ │ │ ├── elements/ │ │ │ ├── alert.html │ │ │ ├── badge.html │ │ │ ├── button.html │ │ │ ├── field.html │ │ │ ├── fields.html │ │ │ ├── panel.html │ │ │ └── table.html │ │ └── layouts/ │ │ ├── entrance.html │ │ └── manage.html │ ├── base.html │ ├── pages/ │ │ ├── about.html │ │ └── home.html │ └── users/ │ ├── user_detail.html │ └── user_form.html └── users/ ├── __init__.py ├── adapters.py ├── admin.py ├── api/ │ ├── __init__.py │ ├── schema.py │ ├── serializers.py │ └── views.py ├── apps.py ├── context_processors.py ├── forms.py ├── managers.py ├── migrations/ │ ├── 0001_initial.py │ └── __init__.py ├── models.py ├── tasks.py ├── tests/ │ ├── __init__.py │ ├── api/ │ │ ├── __init__.py │ │ ├── test_openapi.py │ │ ├── test_urls.py │ │ └── test_views.py │ ├── factories.py │ ├── test_admin.py │ ├── test_forms.py │ ├── test_managers.py │ ├── test_models.py │ ├── test_tasks.py │ ├── test_urls.py │ └── test_views.py ├── urls.py └── views.py ================================================ FILE CONTENTS ================================================ ================================================ FILE: .editorconfig ================================================ # http://editorconfig.org root = true [*] charset = utf-8 end_of_line = lf insert_final_newline = true trim_trailing_whitespace = true [*.{py,rst,ini}] indent_style = space indent_size = 4 [*.{html,css,scss,json,yml,xml,toml}] indent_style = space indent_size = 2 [*.md] trim_trailing_whitespace = false [Makefile] indent_style = tab [nginx.conf] indent_style = space indent_size = 2 ================================================ FILE: .gitattributes ================================================ * text=auto ================================================ FILE: .github/CONTRIBUTORS-template.md ================================================ # Contributors ## Core Developers These contributors have commit flags for the repository, and are able to accept and merge pull requests. {%- for contributor in core_contributors %} {%- endfor %}
Name Github Twitter
{{ contributor.name }} {{ contributor.github_login }} {{ contributor.twitter_username }}
_Audrey is also the creator of Cookiecutter. Audrey and Daniel are on the Cookiecutter core team._ ## Other Contributors Listed in alphabetical order. {%- for contributor in other_contributors %} {%- endfor %}
Name Github Twitter
{{ contributor.name }} {{ contributor.github_login }} {{ contributor.twitter_username }}
### Special Thanks The following haven't provided code directly, but have provided guidance and advice. - Jannis Leidel - Nate Aune - Barry Morrison ================================================ FILE: .github/FUNDING.yml ================================================ # These are supported funding model platforms github: [pydanny, browniebroke, luzfcb] patreon: feldroy open_collective: cookiecutter-django ================================================ FILE: .github/ISSUE_TEMPLATE/bug.md ================================================ --- name: Bug Report about: Report a bug labels: bug --- ## What happened? ## What should've happened instead? ## Additional details - Host system configuration: - Version of cookiecutter CLI (get it with `cookiecutter --version`): - OS name and version: On Linux, run ```bash lsb_release -a 2> /dev/null || cat /etc/redhat-release 2> /dev/null || cat /etc/*-release 2> /dev/null || cat /etc/issue 2> /dev/null ``` On MacOs, run ```bash sw_vers ``` On Windows, via CMD, run ``` systeminfo | findstr /B /C:"OS Name" /C:"OS Version" ``` ```bash # Insert here the OS name and version ``` - Python version, run `python3 -V`: - Docker version (if using Docker), run `docker --version`: - docker compose version (if using Docker), run `docker compose --version`: - ... - Options selected and/or [replay file](https://cookiecutter.readthedocs.io/en/latest/advanced/replay.html): On Linux and macOS: `cat ${HOME}/.cookiecutter_replay/cookiecutter-django.json` (Please, take care to remove sensitive information) ```json ``` Logs:
$ cookiecutter https://github.com/cookiecutter/cookiecutter-django
project_name [Project Name]: ...
================================================ FILE: .github/ISSUE_TEMPLATE/feature.md ================================================ --- name: New Feature Proposal about: Propose a new feature labels: enhancement --- ## Description What are you proposing? How should it be implemented? ## Rationale Why should this feature be implemented? ================================================ FILE: .github/ISSUE_TEMPLATE/paid-support.md ================================================ --- name: Paid Support Request about: Ask Core Team members to help you out --- 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. - Bruno Alla, Core Developer ([GitHub](https://github.com/sponsors/browniebroke)). - 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. ================================================ FILE: .github/ISSUE_TEMPLATE/question.md ================================================ --- name: Question 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/). If that doesn't help, we recommend one of these 3 main channels: - 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/uFXweDQc5a) and ask around. - Start [a discussion](https://github.com/cookiecutter/cookiecutter-django/discussions) on our project's GitHub. ================================================ FILE: .github/PULL_REQUEST_TEMPLATE.md ================================================ ## Description Checklist: - [ ] 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 ================================================ FILE: .github/changelog-template.md ================================================ {%- 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.html_url }})) {%- endfor -%} {% endif -%} {% endfor -%} ================================================ FILE: .github/contributors.json ================================================ [ { "name": "Daniel Roy Greenfeld", "github_login": "pydanny", "twitter_username": "pydanny", "is_core": true }, { "name": "Audrey Roy Greenfeld", "github_login": "audreyr", "twitter_username": "audreyr", "is_core": true }, { "name": "Fábio C. Barrionuevo da Luz", "github_login": "luzfcb", "twitter_username": "luzfcb", "is_core": true }, { "name": "Saurabh Kumar", "github_login": "theskumar", "twitter_username": "_theskumar", "is_core": true }, { "name": "Jannis Gebauer", "github_login": "jayfk", "twitter_username": "", "is_core": true }, { "name": "Burhan Khalid", "github_login": "burhan", "twitter_username": "burhan", "is_core": true }, { "name": "Shupeyko Nikita", "github_login": "webyneter", "twitter_username": "webyneter", "is_core": true }, { "name": "Bruno Alla", "github_login": "browniebroke", "twitter_username": "_BrunoAlla", "is_core": true }, { "name": "Wan Liuyang", "github_login": "sfdye", "twitter_username": "sfdye", "is_core": true }, { "name": "Jelmer Draaijer", "github_login": "foarsitter", "twitter_username": "", "is_core": true }, { "name": "18", "github_login": "dezoito", "twitter_username": "" }, { "name": "2O4", "github_login": "2O4", "twitter_username": "" }, { "name": "a7p", "github_login": "a7p", "twitter_username": "" }, { "name": "Aadith PM", "github_login": "aadithpm", "twitter_username": "" }, { "name": "Aaron Eikenberry", "github_login": "aeikenberry", "twitter_username": "" }, { "name": "Adam Bogdał", "github_login": "bogdal", "twitter_username": "" }, { "name": "Adam Dobrawy", "github_login": "ad-m", "twitter_username": "" }, { "name": "Adam Steele", "github_login": "adammsteele", "twitter_username": "" }, { "name": "Agam Dua", "github_login": "", "twitter_username": "" }, { "name": "Agustín Scaramuzza", "github_login": "scaramagus", "twitter_username": "scaramagus" }, { "name": "Alberto Sanchez", "github_login": "alb3rto", "twitter_username": "" }, { "name": "Alex Tsai", "github_login": "caffodian", "twitter_username": "" }, { "name": "Alvaro [Andor]", "github_login": "andor-pierdelacabeza", "twitter_username": "" }, { "name": "Amjith Ramanujam", "github_login": "amjith", "twitter_username": "" }, { "name": "Andreas Meistad", "github_login": "ameistad", "twitter_username": "" }, { "name": "Andres Gonzalez", "github_login": "andresgz", "twitter_username": "" }, { "name": "Andrew Mikhnevich", "github_login": "zcho", "twitter_username": "" }, { "name": "Andrew Chen Wang", "github_login": "Andrew-Chen-Wang", "twitter_username": "" }, { "name": "Andy Rose", "github_login": "", "twitter_username": "" }, { "name": "Anna Callahan", "github_login": "jazztpt", "twitter_username": "" }, { "name": "Anna Sidwell", "github_login": "takkaria", "twitter_username": "" }, { "name": "Antonia Blair", "github_login": "antoniablair", "twitter_username": "antoniablairart" }, { "name": "Anuj Bansal", "github_login": "ahhda", "twitter_username": "" }, { "name": "Arcuri Davide", "github_login": "dadokkio", "twitter_username": "" }, { "name": "Areski Belaid", "github_login": "areski", "twitter_username": "" }, { "name": "AsheKR", "github_login": "ashekr", "twitter_username": "" }, { "name": "Ashley Camba", "github_login": "", "twitter_username": "" }, { "name": "Barclay Gauld", "github_login": "yunti", "twitter_username": "" }, { "name": "Bartek", "github_login": "btknu", "twitter_username": "" }, { "name": "Ben Lopatin", "github_login": "", "twitter_username": "" }, { "name": "Ben Warren", "github_login": "bwarren2", "twitter_username": "" }, { "name": "Benjamin Abel", "github_login": "", "twitter_username": "" }, { "name": "Bert de Miranda", "github_login": "bertdemiranda", "twitter_username": "" }, { "name": "Bo Lopker", "github_login": "blopker", "twitter_username": "" }, { "name": "Bo Peng", "github_login": "BoPeng", "twitter_username": "" }, { "name": "Bouke Haarsma", "github_login": "", "twitter_username": "" }, { "name": "Brent Payne", "github_login": "brentpayne", "twitter_username": "brentpayne" }, { "name": "Bruce Olivier", "github_login": "bolivierjr", "twitter_username": "" }, { "name": "Caio Ariede", "github_login": "caioariede", "twitter_username": "caioariede" }, { "name": "Carl Johnson", "github_login": "carlmjohnson", "twitter_username": "carlmjohnson" }, { "name": "Catherine Devlin", "github_login": "catherinedevlin", "twitter_username": "" }, { "name": "Cédric Gaspoz", "github_login": "cgaspoz", "twitter_username": "" }, { "name": "Charlie Smith", "github_login": "chuckus", "twitter_username": "" }, { "name": "Chris Curvey", "github_login": "ccurvey", "twitter_username": "" }, { "name": "Chris Franklin", "github_login": "", "twitter_username": "" }, { "name": "Chris Franklin", "github_login": "hairychris", "twitter_username": "" }, { "name": "Chris Pappalardo", "github_login": "ChrisPappalardo", "twitter_username": "" }, { "name": "Christopher Clarke", "github_login": "chrisdev", "twitter_username": "" }, { "name": "Cole Mackenzie", "github_login": "cmackenzie1", "twitter_username": "" }, { "name": "Cole Maclean", "github_login": "cole", "twitter_username": "cole" }, { "name": "Collederas", "github_login": "Collederas", "twitter_username": "" }, { "name": "Craig Margieson", "github_login": "cmargieson", "twitter_username": "" }, { "name": "Cristian Vargas", "github_login": "cdvv7788", "twitter_username": "" }, { "name": "Cullen Rhodes", "github_login": "c-rhodes", "twitter_username": "" }, { "name": "Curtis St Pierre", "github_login": "curtisstpierre", "twitter_username": "cstpierre1388" }, { "name": "Dan Shultz", "github_login": "shultz", "twitter_username": "" }, { "name": "Dani Hodovic", "github_login": "danihodovic", "twitter_username": "" }, { "name": "Daniel Hepper", "github_login": "dhepper", "twitter_username": "danielhepper" }, { "name": "Daniel Hillier", "github_login": "danifus", "twitter_username": "" }, { "name": "Daniel Sears", "github_login": "highpost", "twitter_username": "highpost" }, { "name": "Daniele Tricoli", "github_login": "eriol", "twitter_username": "" }, { "name": "David Díaz", "github_login": "ddiazpinto", "twitter_username": "DavidDiazPinto" }, { "name": "Davit Tovmasyan", "github_login": "davitovmasyan", "twitter_username": "" }, { "name": "Davur Clementsen", "github_login": "dsclementsen", "twitter_username": "davur" }, { "name": "Delio Castillo", "github_login": "jangeador", "twitter_username": "jangeador" }, { "name": "Demetris Stavrou", "github_login": "demestav", "twitter_username": "" }, { "name": "Denis Bobrov", "github_login": "delneg", "twitter_username": "" }, { "name": "Denis Orehovsky", "github_login": "apirobot", "twitter_username": "" }, { "name": "Denis Savran", "github_login": "blaxpy", "twitter_username": "" }, { "name": "Diane Chen", "github_login": "purplediane", "twitter_username": "purplediane88" }, { "name": "Dónal Adams", "github_login": "epileptic-fish", "twitter_username": "" }, { "name": "Dong Huynh", "github_login": "trungdong", "twitter_username": "" }, { "name": "Duda Nogueira", "github_login": "dudanogueira", "twitter_username": "dudanogueira" }, { "name": "Emanuel Calso", "github_login": "bloodpet", "twitter_username": "bloodpet" }, { "name": "Eraldo Energy", "github_login": "eraldo", "twitter_username": "" }, { "name": "Eric Groom", "github_login": "ericgroom", "twitter_username": "" }, { "name": "Ernesto Cedeno", "github_login": "codnee", "twitter_username": "" }, { "name": "Eyad Al Sibai", "github_login": "eyadsibai", "twitter_username": "" }, { "name": "Felipe Arruda", "github_login": "arruda", "twitter_username": "" }, { "name": "Florian Idelberger", "github_login": "step21", "twitter_username": "windrush" }, { "name": "Gabriel Mejia", "github_login": "elgartoinf", "twitter_username": "elgartoinf" }, { "name": "Garry Cairns", "github_login": "garry-cairns", "twitter_username": "" }, { "name": "Garry Polley", "github_login": "garrypolley", "twitter_username": "" }, { "name": "Gilbishkosma", "github_login": "Gilbishkosma", "twitter_username": "" }, { "name": "Glenn Wiskur", "github_login": "gwiskur", "twitter_username": "" }, { "name": "Guilherme Guy", "github_login": "guilherme1guy", "twitter_username": "" }, { "name": "Hamish Durkin", "github_login": "durkode", "twitter_username": "" }, { "name": "Hana Quadara", "github_login": "hanaquadara", "twitter_username": "" }, { "name": "Hannah Lazarus", "github_login": "hanhanhan", "twitter_username": "" }, { "name": "Harry Moreno", "github_login": "morenoh149", "twitter_username": "morenoh149" }, { "name": "Harry Percival", "github_login": "hjwp", "twitter_username": "" }, { "name": "Hendrik Schneider", "github_login": "hendrikschneider", "twitter_username": "" }, { "name": "Henrique G. G. Pereira", "github_login": "ikkebr", "twitter_username": "" }, { "name": "Howie Zhao", "github_login": "howiezhao", "twitter_username": "" }, { "name": "Ian Lee", "github_login": "IanLee1521", "twitter_username": "" }, { "name": "Irfan Ahmad", "github_login": "erfaan", "twitter_username": "erfaan" }, { "name": "Isaac12x", "github_login": "Isaac12x", "twitter_username": "" }, { "name": "Ivan Khomutov", "github_login": "ikhomutov", "twitter_username": "" }, { "name": "James Williams", "github_login": "jameswilliams1", "twitter_username": "" }, { "name": "Jan Van Bruggen", "github_login": "jvanbrug", "twitter_username": "" }, { "name": "Jerome Caisip", "github_login": "jeromecaisip", "twitter_username": "" }, { "name": "Jens Nilsson", "github_login": "phiberjenz", "twitter_username": "" }, { "name": "Jerome Leclanche", "github_login": "jleclanche", "twitter_username": "Adys" }, { "name": "Jimmy Gitonga", "github_login": "Afrowave", "twitter_username": "afrowave" }, { "name": "John Cass", "github_login": "jcass77", "twitter_username": "cass_john" }, { "name": "Jonathan Thompson", "github_login": "nojanath", "twitter_username": "" }, { "name": "Jules Cheron", "github_login": "jules-ch", "twitter_username": "" }, { "name": "Julien Almarcha", "github_login": "sladinji", "twitter_username": "" }, { "name": "Julio Castillo", "github_login": "juliocc", "twitter_username": "" }, { "name": "Kaido Kert", "github_login": "kaidokert", "twitter_username": "" }, { "name": "kappataumu", "github_login": "kappataumu", "twitter_username": "kappataumu" }, { "name": "Kaveh", "github_login": "ka7eh", "twitter_username": "" }, { "name": "Keith Bailey", "github_login": "keithjeb", "twitter_username": "" }, { "name": "Keith Webber", "github_login": "townie", "twitter_username": "" }, { "name": "Kevin A. Stone", "github_login": "", "twitter_username": "" }, { "name": "Kevin Ndung'u", "github_login": "kevgathuku", "twitter_username": "" }, { "name": "Keyvan Mosharraf", "github_login": "keyvanm", "twitter_username": "" }, { "name": "Krzysztof Szumny", "github_login": "noisy", "twitter_username": "" }, { "name": "Krzysztof Żuraw", "github_login": "krzysztofzuraw", "twitter_username": "" }, { "name": "Leo won", "github_login": "leollon", "twitter_username": "" }, { "name": "Leo Zhou", "github_login": "glasslion", "twitter_username": "" }, { "name": "Leon Kim", "github_login": "PilhwanKim", "twitter_username": "" }, { "name": "Leonardo Jimenez", "github_login": "xpostudio4", "twitter_username": "" }, { "name": "Lin Xianyi", "github_login": "iynaix", "twitter_username": "" }, { "name": "Luis Nell", "github_login": "originell", "twitter_username": "" }, { "name": "Lukas Klein", "github_login": "", "twitter_username": "" }, { "name": "Lyla Fischer", "github_login": "", "twitter_username": "" }, { "name": "Malik Sulaimanov", "github_login": "flyudvik", "twitter_username": "flyudvik" }, { "name": "Martin Blech", "github_login": "", "twitter_username": "" }, { "name": "Martin Saizar", "github_login": "msaizar", "twitter_username": "" }, { "name": "Mateusz Ostaszewski", "github_login": "mostaszewski", "twitter_username": "" }, { "name": "Mathijs Hoogland", "github_login": "MathijsHoogland", "twitter_username": "" }, { "name": "Matt Braymer-Hayes", "github_login": "mattayes", "twitter_username": "mattayes" }, { "name": "Matt Knapper", "github_login": "mknapper1", "twitter_username": "" }, { "name": "Matt Linares", "github_login": "", "twitter_username": "" }, { "name": "Matt Menzenski", "github_login": "menzenski", "twitter_username": "" }, { "name": "Matt Warren", "github_login": "mfwarren", "twitter_username": "" }, { "name": "Matthew Sisley", "github_login": "mjsisley", "twitter_username": "" }, { "name": "Matthias Sieber", "github_login": "manonthemat", "twitter_username": "MatzeOne" }, { "name": "Meghan Heintz", "github_login": "dot2dotseurat", "twitter_username": "" }, { "name": "Mesut Yılmaz", "github_login": "myilmaz", "twitter_username": "" }, { "name": "Michael Gecht", "github_login": "mimischi", "twitter_username": "_mischi" }, { "name": "Michael Samoylov", "github_login": "msamoylov", "twitter_username": "" }, { "name": "Min ho Kim", "github_login": "minho42", "twitter_username": "" }, { "name": "mozillazg", "github_login": "mozillazg", "twitter_username": "" }, { "name": "Nico Stefani", "github_login": "nicolas471", "twitter_username": "moby_dick91" }, { "name": "Oleg Russkin", "github_login": "rolep", "twitter_username": "" }, { "name": "Pablo", "github_login": "oubiga", "twitter_username": "" }, { "name": "Parbhat Puri", "github_login": "parbhat", "twitter_username": "" }, { "name": "Pawan Chaurasia", "github_login": "rjsnh1522", "twitter_username": "" }, { "name": "Peter Bittner", "github_login": "bittner", "twitter_username": "" }, { "name": "Peter Coles", "github_login": "mrcoles", "twitter_username": "" }, { "name": "Philipp Matthies", "github_login": "canonnervio", "twitter_username": "" }, { "name": "Pierre Chiquet", "github_login": "pchiquet", "twitter_username": "" }, { "name": "Raony Guimarães Corrêa", "github_login": "raonyguimaraes", "twitter_username": "" }, { "name": "Raphael Pierzina", "github_login": "hackebrot", "twitter_username": "" }, { "name": "Reggie Riser", "github_login": "reggieriser", "twitter_username": "" }, { "name": "René Muhl", "github_login": "rm--", "twitter_username": "" }, { "name": "Richard Hajdu", "github_login": "Tusky", "twitter_username": "" }, { "name": "Roman Afanaskin", "github_login": "siauPatrick", "twitter_username": "" }, { "name": "Roman Osipenko", "github_login": "romanosipenko", "twitter_username": "" }, { "name": "Russell Davies", "github_login": "", "twitter_username": "" }, { "name": "Sam Collins", "github_login": "MightySCollins", "twitter_username": "" }, { "name": "Sascha", "github_login": "saschalalala", "twitter_username": "saschalalala" }, { "name": "Sławek Ehlert", "github_login": "slafs", "twitter_username": "" }, { "name": "Sorasful", "github_login": "sorasful", "twitter_username": "" }, { "name": "Srinivas Nyayapati", "github_login": "shireenrao", "twitter_username": "" }, { "name": "stepmr", "github_login": "stepmr", "twitter_username": "" }, { "name": "Steve Steiner", "github_login": "ssteinerX", "twitter_username": "" }, { "name": "Sudarshan Wadkar", "github_login": "wadkar", "twitter_username": "" }, { "name": "Sule Marshall", "github_login": "suledev", "twitter_username": "" }, { "name": "Tano Abeleyra", "github_login": "tanoabeleyra", "twitter_username": "" }, { "name": "Taylor Baldwin", "github_login": "", "twitter_username": "" }, { "name": "Théo Segonds", "github_login": "show0k", "twitter_username": "" }, { "name": "Tim Claessens", "github_login": "timclaessens", "twitter_username": "" }, { "name": "Tim Freund", "github_login": "timfreund", "twitter_username": "" }, { "name": "Tom Atkins", "github_login": "knitatoms", "twitter_username": "" }, { "name": "Tom Offermann", "github_login": "", "twitter_username": "" }, { "name": "Travis McNeill", "github_login": "Travistock", "twitter_username": "tavistock_esq" }, { "name": "Tubo Shi", "github_login": "Tubo", "twitter_username": "" }, { "name": "Umair Ashraf", "github_login": "umrashrf", "twitter_username": "fabumair" }, { "name": "Vadim Iskuchekov", "github_login": "Egregors", "twitter_username": "egregors" }, { "name": "Vicente G. Reyes", "github_login": "reyesvicente", "twitter_username": "highcenburg" }, { "name": "Vitaly Babiy", "github_login": "", "twitter_username": "" }, { "name": "Vivian Guillen", "github_login": "viviangb", "twitter_username": "" }, { "name": "Vlad Doster", "github_login": "vladdoster", "twitter_username": "" }, { "name": "Will Farley", "github_login": "goldhand", "twitter_username": "g01dhand" }, { "name": "William Archinal", "github_login": "archinal", "twitter_username": "" }, { "name": "Xaver Y.R. Chen", "github_login": "yrchen", "twitter_username": "yrchen" }, { "name": "Yaroslav Halchenko", "github_login": "", "twitter_username": "" }, { "name": "Yuchen Xie", "github_login": "mapx", "twitter_username": "" }, { "name": "enchance", "github_login": "enchance", "twitter_username": "" }, { "name": "Jan Fabry", "github_login": "janfabry", "twitter_username": "" }, { "name": "Corey Garvey", "github_login": "coreygarvey", "twitter_username": "" }, { "name": "Arnav Choudhury", "github_login": "arnav13081994", "twitter_username": "" }, { "name": "Wes Turner", "github_login": "westurner", "twitter_username": "westurner" }, { "name": "Jakub Musko", "github_login": "umgelurgel", "twitter_username": "" }, { "name": "Fabian Affolter", "github_login": "fabaff", "twitter_username": "fabaff" }, { "name": "Simon Rey", "github_login": "eqqe", "twitter_username": "" }, { "name": "Yotam Tal", "github_login": "yotamtal", "twitter_username": "" }, { "name": "John", "github_login": "thorrak", "twitter_username": "" }, { "name": "vascop", "github_login": "vascop", "twitter_username": "" }, { "name": "PJ Hoberman", "github_login": "pjhoberman", "twitter_username": "" }, { "name": "lcd1232", "github_login": "lcd1232", "twitter_username": "" }, { "name": "Tames McTigue", "github_login": "Tamerz", "twitter_username": "" }, { "name": "Ray Besiga", "github_login": "raybesiga", "twitter_username": "raybesiga" }, { "name": "Grant McLean", "github_login": "grantm", "twitter_username": "grantmnz" }, { "name": "Kuo Chao Cheng", "github_login": "wwwtony5488", "twitter_username": "" }, { "name": "LECbg", "github_login": "LECbg", "twitter_username": "" }, { "name": "Haseeb ur Rehman", "github_login": "professorhaseeb", "twitter_username": "professorhaseeb" }, { "name": "Abdul Qoyyuum", "github_login": "Qoyyuum", "twitter_username": "Qoyyuum" }, { "name": "Matthew Foster Walsh", "github_login": "mfosterw", "twitter_username": "" }, { "name": "Keith Callenberg", "github_login": "keithcallenberg", "twitter_username": "" }, { "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_" }, { "name": "Jorge Valdez", "github_login": "jorgeavaldez", "twitter_username": "" }, { "name": "Ryan Fitch", "github_login": "ryfi", "twitter_username": "" }, { "name": "ghazi-git", "github_login": "ghazi-git", "twitter_username": "" }, { "name": "Cebrail Yılmaz", "github_login": "b1sar", "twitter_username": "" }, { "name": "Artur Barseghyan", "github_login": "barseghyanartur", "twitter_username": "" }, { "name": "innicoder", "github_login": "innicoder", "twitter_username": "" }, { "name": "Naveen", "github_login": "naveensrinivasan", "twitter_username": "snaveen" }, { "name": "Nikita Sobolev", "github_login": "sobolevn", "twitter_username": "" }, { "name": "Sebastian Reyes Espinosa", "github_login": "sebastian-code", "twitter_username": "sebastianreyese" }, { "name": "jugglinmike", "github_login": "jugglinmike", "twitter_username": "" }, { "name": "monosans", "github_login": "monosans", "twitter_username": "" }, { "name": "Marcio Mazza", "github_login": "marciomazza", "twitter_username": "marciomazza" }, { "name": "Brandon Rumiser", "github_login": "brumiser1550", "twitter_username": "" }, { "name": "krati yadav", "github_login": "krati5", "twitter_username": "" }, { "name": "Abe Hanoka", "github_login": "abe-101", "twitter_username": "abe__101" }, { "name": "Adin Hodovic", "github_login": "adinhodovic", "twitter_username": "" }, { "name": "Leifur Halldor Asgeirsson", "github_login": "leifurhauks", "twitter_username": "" }, { "name": "David", "github_login": "buckldav", "twitter_username": "" }, { "name": "rguptar", "github_login": "rguptar", "twitter_username": "" }, { "name": "Omer-5", "github_login": "Omer-5", "twitter_username": "" }, { "name": "TAKAHASHI Shuuji", "github_login": "shuuji3", "twitter_username": "" }, { "name": "Thomas Booij", "github_login": "ThomasBooij95", "twitter_username": "" }, { "name": "Pamela Fox", "github_login": "pamelafox", "twitter_username": "pamelafox" }, { "name": "Robin", "github_login": "Kaffeetasse", "twitter_username": "" }, { "name": "Patrick Tran", "github_login": "theptrk", "twitter_username": "" }, { "name": "tildebox", "github_login": "tildebox", "twitter_username": "" }, { "name": "duffn", "github_login": "duffn", "twitter_username": "" }, { "name": "Delphine LEMIRE", "github_login": "DelphineLemire", "twitter_username": "" }, { "name": "Hoai-Thu Vuong", "github_login": "thuvh", "twitter_username": "" }, { "name": "Arkadiusz Michał Ryś", "github_login": "arrys", "twitter_username": "" }, { "name": "mpsantos", "github_login": "mpsantos", "twitter_username": "" }, { "name": "Morten Kaae", "github_login": "MortenKaae", "twitter_username": "" }, { "name": "Birtibu", "github_login": "Birtibu", "twitter_username": "" }, { "name": "Matheus Jardim Bernardes", "github_login": "matheusjardimb", "twitter_username": "" }, { "name": "masavini", "github_login": "masavini", "twitter_username": "" }, { "name": "Joseph Hanna", "github_login": "sanchimenea", "twitter_username": "" }, { "name": "tmajerech", "github_login": "tmajerech", "twitter_username": "" }, { "name": "villancikos", "github_login": "villancikos", "twitter_username": "" }, { "name": "Imran Rahman", "github_login": "infraredCoding", "twitter_username": "" }, { "name": "hleroy", "github_login": "hleroy", "twitter_username": "" }, { "name": "Shayan Karimi", "github_login": "shywn-mrk", "twitter_username": "shywn_mrk" }, { "name": "Sadra Yahyapour", "github_login": "lnxpy", "twitter_username": "lnxpylnxpy" }, { "name": "Tharushan", "github_login": "Tharushan", "twitter_username": "" }, { "name": "Fateme Fouladkar", "github_login": "FatemeFouladkar", "twitter_username": "" }, { "name": "zhaoruibing", "github_login": "zhaoruibing", "twitter_username": "" }, { "name": "MinWoo Sung", "github_login": "SungMinWoo", "twitter_username": "" }, { "name": "itisnotyourenv", "github_login": "itisnotyourenv", "twitter_username": "" }, { "name": "Vageeshan Mankala", "github_login": "vagi8", "twitter_username": "" }, { "name": "Jakub Boukal", "github_login": "SukiCZ", "twitter_username": "" }, { "name": "Christian Jauvin", "github_login": "cjauvin", "twitter_username": "" }, { "name": "Plurific", "github_login": "paulschwenn", "twitter_username": "" }, { "name": "GitBib", "github_login": "GitBib", "twitter_username": "" }, { "name": "Freddy", "github_login": "Hraesvelg", "twitter_username": "" }, { "name": "aiden", "github_login": "anyidea", "twitter_username": "" }, { "name": "Michael V. Battista", "github_login": "mvbattista", "twitter_username": "mvbattista" }, { "name": "Nix Siow", "github_login": "nixsiow", "twitter_username": "nixsiow" }, { "name": "Jens Kaeske", "github_login": "jkaeske", "twitter_username": "" }, { "name": "henningbra", "github_login": "henningbra", "twitter_username": "" }, { "name": "Paul Wulff", "github_login": "mtmpaulwulff", "twitter_username": "" }, { "name": "Mounir", "github_login": "mounirmesselmeni", "twitter_username": "" }, { "name": "JAEGYUN JUNG", "github_login": "TGoddessana", "twitter_username": "" }, { "name": "Simeon Emanuilov", "github_login": "s-emanuilov", "twitter_username": "s_emanuilov" }, { "name": "Patrick Zhang", "github_login": "PatDuJour", "twitter_username": "" }, { "name": "GvS", "github_login": "GvS666", "twitter_username": "" }, { "name": "David Păcioianu", "github_login": "DavidPacioianu", "twitter_username": "" }, { "name": "farwill", "github_login": "farwill", "twitter_username": "" }, { "name": "quroom", "github_login": "quroom", "twitter_username": "" }, { "name": "Marios Frixou", "github_login": "frixou89", "twitter_username": "" }, { "name": "Geo Maciolek", "github_login": "GeoMaciolek", "twitter_username": "" }, { "name": "Nadav Peretz", "github_login": "nadavperetz", "twitter_username": "" }, { "name": "Param Kapur", "github_login": "paramkpr", "twitter_username": "ParamKapur" }, { "name": "Jason Mok", "github_login": "jasonmokk", "twitter_username": "" }, { "name": "Manas Mallick", "github_login": "ManDun", "twitter_username": "" }, { "name": "Alexandr Artemyev", "github_login": "Mogost", "twitter_username": "MOGOST" }, { "name": "Ali Shamakhi", "github_login": "ali-shamakhi", "twitter_username": "" }, { "name": "Filipe Nascimento", "github_login": "FilipeNas", "twitter_username": "" }, { "name": "Kevin Mills", "github_login": "millsks", "twitter_username": "" }, { "name": "milvagox", "github_login": "milvagox", "twitter_username": "milvagox" }, { "name": "Johnny Metz", "github_login": "johnnymetz", "twitter_username": "" }, { "name": "Will", "github_login": "novucs", "twitter_username": "" }, { "name": "rxm7706", "github_login": "rxm7706", "twitter_username": "" }, { "name": "Marlon Castillo", "github_login": "mcastle", "twitter_username": "" }, { "name": "Alex Kanavos", "github_login": "alexkanavos", "twitter_username": "" }, { "name": "LJFP", "github_login": "ljfp", "twitter_username": "" }, { "name": "Francisco Navarro Morales ", "github_login": "spothound", "twitter_username": "" }, { "name": "Mariot Tsitoara", "github_login": "mariot", "twitter_username": "" }, { "name": "Christian Jensen", "github_login": "jensenbox", "twitter_username": "cjensen" }, { "name": "Denis Darii", "github_login": "DNX", "twitter_username": "" }, { "name": "qwerrrqw", "github_login": "qwerrrqw", "twitter_username": "" }, { "name": "Pulse-Mind", "github_login": "pulse-mind", "twitter_username": "" }, { "name": "Hana Belay", "github_login": "earthcomfy", "twitter_username": "" }, { "name": "Ed Morley", "github_login": "edmorley", "twitter_username": "" }, { "name": "Alan Cyment", "github_login": "acyment", "twitter_username": "" }, { "name": "Kawsar Alam Foysal", "github_login": "iamfoysal", "twitter_username": "" }, { "name": "Igor Jerosimić", "github_login": "igor-wl", "twitter_username": "" }, { "name": "Pepa", "github_login": "07pepa", "twitter_username": "" }, { "name": "Aidos Kanapyanov", "github_login": "aidoskanapyanov", "twitter_username": "" }, { "name": "Jeongseok Kang", "github_login": "rapsealk", "twitter_username": "" }, { "name": "Jeff Foster", "github_login": "jeffpfoster", "twitter_username": "" }, { "name": "Dominique Plante", "github_login": "dominiqueplante", "twitter_username": "" }, { "name": "Lucas Klasa", "github_login": "lucaskbr", "twitter_username": "" }, { "name": "DevForsure", "github_login": "DevForsure", "twitter_username": "" }, { "name": "Vincent Leduc", "github_login": "leducvin", "twitter_username": "" }, { "name": "Martín Blech", "github_login": "martinblech", "twitter_username": "" }, { "name": "jlitrell", "github_login": "jlitrell", "twitter_username": "" }, { "name": "Maurício Gioachini", "github_login": "MauGx3", "twitter_username": "" }, { "name": "Donghoon Nam", "github_login": "codenamenam", "twitter_username": "" }, { "name": "Tosinibikunle", "github_login": "Tosinibikunle", "twitter_username": "" }, { "name": "Josh596", "github_login": "Josh596", "twitter_username": "" }, { "name": "Harshit Ranjan", "github_login": "HarshitR2004", "twitter_username": "" }, { "name": "Mohamed Feddad", "github_login": "mrf345", "twitter_username": "" }, { "name": "Christian González", "github_login": "nerdoc", "twitter_username": "" }, { "name": "Soldatov Serhii", "github_login": "soldatov-ss", "twitter_username": "" }, { "name": "asmo", "github_login": "a5m0", "twitter_username": "" } ] ================================================ FILE: .github/dependabot.yml ================================================ # Config for Dependabot updates. See Documentation here: # https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file version: 2 enable-beta-ecosystems: true updates: # Update Python deps for the template (not the generated project) - package-ecosystem: "uv" directory: "/" schedule: interval: "daily" labels: - "project infrastructure" ignore: - dependency-name: "ruff" # updated via PyUp # Update GitHub actions in workflows - package-ecosystem: "github-actions" directory: "/" schedule: interval: "daily" labels: - "project infrastructure" # Update npm packages - package-ecosystem: "npm" directories: - "{{cookiecutter.project_slug}}/" schedule: interval: "daily" labels: - "update" # Enable version updates for Docker - package-ecosystem: "docker" directories: - "{{cookiecutter.project_slug}}/compose/local/django/" - "{{cookiecutter.project_slug}}/compose/local/docs/" - "{{cookiecutter.project_slug}}/compose/production/django/" - "{{cookiecutter.project_slug}}/compose/local/node/" - "{{cookiecutter.project_slug}}/compose/production/aws/" - "{{cookiecutter.project_slug}}/compose/production/postgres/" - "{{cookiecutter.project_slug}}/compose/production/nginx/" - "{{cookiecutter.project_slug}}/compose/production/traefik/" schedule: interval: "daily" labels: - "update" # NOTE: Package ecosystem "docker-compose" can't handle Jinja tags in yml files ================================================ FILE: .github/workflows/align-versions.yml ================================================ name: align versions on: pull_request: paths: - "{{cookiecutter.project_slug}}/requirements/local.txt" - "{{cookiecutter.project_slug}}/compose/local/node/Dockerfile" # Manual trigger workflow_dispatch: permissions: contents: write pull-requests: write jobs: run: if: ${{ github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request' && (github.event.pull_request.user.login == 'pyup-bot' || github.event.pull_request.user.login == 'dependabot[bot]') }} runs-on: ubuntu-latest env: GH_PAT: ${{ secrets.GH_PAT }} strategy: fail-fast: false matrix: job: - script: scripts/ruff_version.py name: Ruff - script: scripts/node_version.py name: Node name: "${{ matrix.job.name }} versions" steps: - name: Checkout with token uses: actions/checkout@v6 if: ${{ env.GH_PAT != '' }} with: token: ${{ env.GH_PAT }} ref: ${{ github.head_ref }} - name: Checkout without token uses: actions/checkout@v6 if: ${{ env.GH_PAT == '' }} with: ref: ${{ github.head_ref }} - uses: astral-sh/setup-uv@v7 - run: uv run ${{ matrix.job.script }} - uses: stefanzweifel/git-auto-commit-action@v7 with: commit_message: Align versions ================================================ FILE: .github/workflows/ci.yml ================================================ name: CI on: push: branches: ["main"] pull_request: concurrency: group: ${{ github.head_ref || github.run_id }} cancel-in-progress: true jobs: tests: strategy: fail-fast: false matrix: os: - ubuntu-latest - windows-latest - macOS-latest name: "pytest ${{ matrix.os }}" runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v6 - name: Install uv uses: astral-sh/setup-uv@v7 - name: Install dependencies run: uv sync --locked - name: Run tests run: uv run pytest -n auto tests docker: strategy: fail-fast: false matrix: script: - name: Basic args: "ci_tool=Gitlab" - name: Celery & DRF args: "use_celery=y rest_api=DRF" - name: Gulp args: "frontend_pipeline=Gulp" - name: Webpack args: "frontend_pipeline=Webpack" name: "Docker ${{ matrix.script.name }}" runs-on: ubuntu-latest env: DOCKER_BUILDKIT: 1 COMPOSE_DOCKER_CLI_BUILD: 1 steps: - uses: actions/checkout@v6 - name: Install uv uses: astral-sh/setup-uv@v7 - name: Install dependencies run: uv sync --locked - name: Docker ${{ matrix.script.name }} run: sh tests/test_docker.sh ${{ matrix.script.args }} bare: strategy: fail-fast: false matrix: script: - name: Celery args: "use_celery=y frontend_pipeline='Django Compressor'" - name: Gulp args: "frontend_pipeline=Gulp" - name: Webpack args: "frontend_pipeline=Webpack use_heroku=y" - name: Email Username args: "username_type=email ci_tool=Github project_name='Something superduper long - the great amazing project' project_slug=my_awesome_project" - name: Email username & DRF args: "username_type=email rest_api=DRF ci_tool=Gitlab" - name: Async & Django-Ninja args: "use_async=y rest_api='Django Ninja'" - name: Async, email username & Django-Ninja args: "use_async=y username_type=email rest_api='Django Ninja'" name: "Bare metal ${{ matrix.script.name }}" runs-on: ubuntu-latest services: redis: image: redis:7.2 ports: - 6379:6379 postgres: image: postgres:14 ports: - 5432:5432 env: POSTGRES_PASSWORD: postgres env: REDIS_URL: "redis://localhost:6379/0" # postgres://user:password@host:port/database DATABASE_URL: "postgres://postgres:postgres@localhost:5432/postgres" steps: - uses: actions/checkout@v6 - name: Install uv uses: astral-sh/setup-uv@v7 - name: Install dependencies run: uv sync --locked - uses: actions/setup-node@v6 with: node-version-file: "{{cookiecutter.project_slug}}/package.json" - name: Bare Metal ${{ matrix.script.name }} run: sh tests/test_bare.sh ${{ matrix.script.args }} ================================================ FILE: .github/workflows/dependabot-uv-lock.yml ================================================ name: uv on: pull_request: paths: - "pyproject.toml" # Manual trigger workflow_dispatch: permissions: contents: write pull-requests: write jobs: lock: if: ${{ github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request' && (github.event.pull_request.user.login == 'pyup-bot' || github.event.pull_request.user.login == 'dependabot[bot]') }} runs-on: ubuntu-latest env: GH_PAT: ${{ secrets.GH_PAT }} steps: - name: Checkout with token uses: actions/checkout@v6 if: ${{ env.GH_PAT != '' }} with: token: ${{ env.GH_PAT }} - name: Checkout without token uses: actions/checkout@v6 if: ${{ env.GH_PAT == '' }} - uses: astral-sh/setup-uv@v7 - run: uv lock - uses: stefanzweifel/git-auto-commit-action@v7 with: commit_message: Regenerate uv.lock ================================================ FILE: .github/workflows/django-issue-checker.yml ================================================ # 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@v6 - name: Install uv uses: astral-sh/setup-uv@v7 - name: Create Django Major Issue run: uv run --locked scripts/create_django_issue.py env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ================================================ FILE: .github/workflows/issue-manager.yml ================================================ # Automatically close issues or pull requests that have a label, after a custom delay, if no one replies. # https://github.com/tiangolo/issue-manager name: Issue Manager on: schedule: - 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.6.0 with: token: ${{ secrets.GITHUB_TOKEN }} config: > { "answered": { "delay": 864000, "message": "Assuming the question was answered, this will be automatically closed now." }, "solved": { "delay": 864000, "message": "Assuming the original issue was solved, it will be automatically closed now." }, "waiting": { "delay": 864000, "message": "Automatically closing after waiting for additional info. To re-open, please provide the additional information requested." }, "wontfix": { "delay": 864000, "message": "As discussed, we won't be implementing this. Automatically closing." } } ================================================ FILE: .github/workflows/pre-commit-autoupdate.yml ================================================ # Run pre-commit autoupdate every day at midnight # and create a pull request if any changes name: Pre-commit auto-update on: schedule: - cron: "15 2 * * *" workflow_dispatch: # to trigger manually permissions: contents: read 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' permissions: contents: write # for peter-evans/create-pull-request to create branch pull-requests: write # for peter-evans/create-pull-request to create a PR runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - name: Install uv uses: astral-sh/setup-uv@v7 - name: Autoupdate template run: uv tool run pre-commit autoupdate - name: Autoupdate generated projects working-directory: "{{cookiecutter.project_slug}}" run: uv tool run pre-commit autoupdate - name: Create Pull Request uses: peter-evans/create-pull-request@v8 with: token: ${{ secrets.GITHUB_TOKEN }} branch: update/pre-commit-autoupdate title: Auto-update pre-commit hooks commit-message: Auto-update pre-commit hooks body: Update versions of tools in pre-commit configs to latest version labels: update ================================================ FILE: .github/workflows/update-changelog.yml ================================================ name: Update Changelog on: # Every day at 2am schedule: - cron: "0 2 * * *" # Manual trigger workflow_dispatch: jobs: 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@v6 - name: Install uv uses: astral-sh/setup-uv@v7 - name: Set git details run: | git config --global user.name "github-actions" git config --global user.email "action@github.com" - name: Update changelog run: uv run --locked scripts/update_changelog.py env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ================================================ FILE: .github/workflows/update-contributors.yml ================================================ name: Update Contributors on: push: branches: - main permissions: contents: read jobs: build: # Disables this workflow from running in a repository that is not part of the indicated organization/user if: github.repository_owner == 'cookiecutter' permissions: contents: write # for stefanzweifel/git-auto-commit-action to push code in repo runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - name: Install uv uses: astral-sh/setup-uv@v7 - name: Update list run: uv run --locked scripts/update_contributors.py env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Commit changes uses: stefanzweifel/git-auto-commit-action@v7 with: commit_message: Update Contributors file_pattern: CONTRIBUTORS.md .github/contributors.json ================================================ FILE: .gitignore ================================================ ### Python template # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # C extensions *.so # Distribution / packaging .Python build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ *.egg-info/ .installed.cfg *.egg # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .coverage.* .cache/ nosetests.xml coverage.xml *.cover .hypothesis/ # Translations *.mo *.pot # Django stuff: *.log # Sphinx documentation docs/_build/ # PyBuilder target/ # pyenv .python-version # celery beat schedule file celerybeat-schedule # Environments .env .venv env/ venv/ ENV/ # Rope project settings .ropeproject # mkdocs documentation /site # mypy .mypy_cache/ ### Linux template *~ # temporary files which can be created if a process still has a handle open of a deleted file .fuse_hidden* # KDE directory preferences .directory # Linux trash folder which might appear on any partition or disk .Trash-* # .nfs files are created when an open file is removed but is still being accessed .nfs* ### VisualStudioCode template .vscode/* !.vscode/settings.json !.vscode/tasks.json !.vscode/launch.json !.vscode/extensions.json ### Windows template # Windows thumbnail cache files Thumbs.db ehthumbs.db ehthumbs_vista.db # Dump file *.stackdump # Folder config file Desktop.ini # Recycle Bin used on file shares $RECYCLE.BIN/ # Windows Installer files *.cab *.msi *.msm *.msp # Windows shortcuts *.lnk ### SublimeText template # Cache files for Sublime Text *.tmlanguage.cache *.tmPreferences.cache *.stTheme.cache # Workspace files are user-specific *.sublime-workspace # Project files should be checked into the repository, unless a significant # proportion of contributors will probably not be using Sublime Text # *.sublime-project # SFTP configuration file sftp-config.json # Package control specific files Package Control.last-run Package Control.ca-list Package Control.ca-bundle Package Control.system-ca-bundle Package Control.cache/ Package Control.ca-certs/ Package Control.merged-ca-bundle Package Control.user-ca-bundle oscrypto-ca-bundle.crt bh_unicode_properties.cache # Sublime-github package stores a github token in this file # https://packagecontrol.io/packages/sublime-github GitHub.sublime-settings ### macOS template # General *.DS_Store .AppleDouble .LSOverride # Icon must end with two \r Icon # Thumbnails ._* # Files that might appear in the root of a volume .DocumentRevisions-V100 .fseventsd .Spotlight-V100 .TemporaryItems .Trashes .VolumeIcon.icns .com.apple.timemachine.donotpresent # Directories potentially created on remote AFP share .AppleDB .AppleDesktop Network Trash Folder Temporary Items .apdisk ### Vim template # Swap [._]*.s[a-v][a-z] [._]*.sw[a-p] [._]s[a-v][a-z] [._]sw[a-p] # Session Session.vim # Temporary .netrwhist # Auto-generated tag files tags # Even though the project might be opened and edited # in any of the JetBrains IDEs, it makes no sence whatsoever # to 'run' anything within it since any particular cookiecutter # is declarative by nature. .idea/ .pytest_cache/ ================================================ FILE: .pre-commit-config.yaml ================================================ exclude: "{{cookiecutter.project_slug}}|.github/contributors.json|CHANGELOG.md|CONTRIBUTORS.md" default_stages: [pre-commit] minimum_pre_commit_version: "3.2.0" default_language_version: python: python3.13 repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v6.0.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer - id: check-json - id: check-toml - id: check-xml - id: check-yaml - id: debug-statements - id: check-builtin-literals - id: check-case-conflict - id: detect-private-key - repo: https://github.com/pre-commit/mirrors-prettier rev: v4.0.0-alpha.8 hooks: - id: prettier args: ["--tab-width", "2"] - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.15.7 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] - id: ruff-format - repo: https://github.com/tox-dev/pyproject-fmt rev: v2.20.0 hooks: - id: pyproject-fmt ci: autoupdate_schedule: weekly skip: [] submodules: false ================================================ FILE: .pyup.yml ================================================ # configure updates globally # default: all # allowed: all, insecure, False update: all # configure dependency pinning globally # default: True # allowed: True, False pin: True # add a label to pull requests, default is not set # requires private repo permissions, even on public repos # default: empty label_prs: update requirements: - "{{cookiecutter.project_slug}}/requirements/base.txt" - "{{cookiecutter.project_slug}}/requirements/local.txt" - "{{cookiecutter.project_slug}}/requirements/production.txt" ================================================ FILE: .readthedocs.yaml ================================================ # Read the Docs configuration file # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details version: 2 build: os: ubuntu-24.04 tools: python: "3.13" jobs: pre_create_environment: - asdf plugin add uv - asdf install uv latest - asdf global uv latest create_environment: - uv venv "${READTHEDOCS_VIRTUALENV_PATH}" install: - UV_PROJECT_ENVIRONMENT="${READTHEDOCS_VIRTUALENV_PATH}" uv sync --frozen --no-dev --only-group docs sphinx: configuration: docs/conf.py ================================================ FILE: AGENTS.md ================================================ # AGENTS.md This file provides guidance to AI coding agents when working with code in this repository. ## What This Project Is cookiecutter-django is a **Cookiecutter template** that generates production-ready Django projects. It is NOT a Django application itself — it's a Jinja2-templated project scaffold. The generated project lives inside `{{cookiecutter.project_slug}}/` and gets processed by Cookiecutter when users run the generator. ## Commands ### Install dependencies ```bash uv sync --locked ``` ### Run tests ```bash # Full test suite (parallel, via tox) uv run tox run -e py # Direct pytest (parallel) uv run pytest -n auto tests # Single test uv run pytest tests/test_cookiecutter_generation.py -k "test_name" # Run with auto-fixable style checks enabled AUTOFIXABLE_STYLES=1 uv run pytest -n auto tests ``` ### Linting and formatting ```bash # Run all pre-commit hooks uv run pre-commit run --all-files # Ruff only uv run ruff check --fix uv run ruff format ``` ### Integration tests (require Docker or PostgreSQL+Redis) ```bash # Docker-based sh tests/test_docker.sh # defaults sh tests/test_docker.sh use_celery=y use_drf=y # with options # Bare metal (needs PostgreSQL and Redis running) sh tests/test_bare.sh sh tests/test_bare.sh use_celery=y frontend_pipeline=Gulp ``` ### Generate a project locally for debugging ```bash uv run cookiecutter . --no-input --output-dir=/tmp/debug ``` ## Architecture ### Template Generation Flow 1. User runs `cookiecutter` — prompted with options from `cookiecutter.json` 2. `hooks/pre_gen_project.py` validates input (project_slug format, conflicting options) 3. Jinja2 renders all files under `{{cookiecutter.project_slug}}/` with user choices 4. `hooks/post_gen_project.py` (~550 lines) removes files not needed for the chosen options, generates random secrets, and adjusts config files ### Key Files - **`cookiecutter.json`** — All template variables and their choices (project name, Docker, Celery, cloud provider, frontend pipeline, etc.) - **`hooks/pre_gen_project.py`** — Pre-generation validation (uses Jinja2 syntax at the top for context manipulation) - **`hooks/post_gen_project.py`** — Post-generation cleanup: removes files based on user choices, generates Django secret key, sets DB credentials, modifies package.json and .pre-commit-config.yaml - **`{{cookiecutter.project_slug}}/`** — The template directory; files here use Jinja2 conditionals (`{% if cookiecutter.use_celery == 'y' %}`) to include/exclude content ### Test Structure - **`tests/test_cookiecutter_generation.py`** — Main test file. Uses `pytest-cookies` to bake the template with 50+ option combinations defined in `SUPPORTED_COMBINATIONS`. Verifies: no Jinja syntax left in output, generated code passes linting, correct files present/absent. Skips on Windows (sh module) and macOS CI (slow). - **`tests/test_hooks.py`** — Unit tests for hook helper functions - **`tests/test_bare.sh`** / **`tests/test_docker.sh`** — Integration tests that generate a project and run its full test suite ### Generated Project Layout The generated Django project uses: - `config/settings/{base,local,test,production}.py` — Split settings with django-environ - `config/urls.py` — URL routing - `/users/` — Custom user model (username or email-based auth via django-allauth) - `compose/` — Docker configs for local and production - `requirements/` — Not used; dependencies managed via `pyproject.toml` + `uv.lock` ## Conventions - **Python 3.13** required (`requires-python = "==3.13.*"`) - **Line length**: 119 characters (ruff and djlint) - **Ruff** for linting/formatting; config in `pyproject.toml` under `[tool.ruff]` - **djLint** for HTML template linting with `profile = "jinja"` - Template files under `{{cookiecutter.project_slug}}/` are excluded from ruff (not parseable Python) - **Calendar versioning**: `YYYY.MM.DD` ## Adding a New Template Option 1. Add the variable and choices to `cookiecutter.json` 2. Add validation in `hooks/pre_gen_project.py` if needed 3. Add file removal/modification logic in `hooks/post_gen_project.py` 4. Use Jinja2 conditionals in template files: `{% if cookiecutter.option == 'y' %}` 5. Add test combinations to `SUPPORTED_COMBINATIONS` in `tests/test_cookiecutter_generation.py` ================================================ FILE: CHANGELOG.md ================================================ # Change Log All enhancements and patches to Cookiecutter Django will be documented in this file. ## 2026.03.19 ### Updated - Update ruff to 0.15.7 ([#6451](https://github.com/cookiecutter/cookiecutter-django/pull/6451)) - Update pyproject-fmt pre-commit hook ([#6449](https://github.com/cookiecutter/cookiecutter-django/pull/6449)) ## 2026.03.18 ### Updated - Update django-ninja to 1.6.2 ([#6448](https://github.com/cookiecutter/cookiecutter-django/pull/6448)) - Update djangorestframework to 3.17.0 ([#6447](https://github.com/cookiecutter/cookiecutter-django/pull/6447)) - Update django-ninja to 1.6.1 ([#6446](https://github.com/cookiecutter/cookiecutter-django/pull/6446)) - Update django-stubs to 6.0.1 ([#6445](https://github.com/cookiecutter/cookiecutter-django/pull/6445)) ## 2026.03.17 ### Updated - Update sentry-sdk to 2.55.0 ([#6443](https://github.com/cookiecutter/cookiecutter-django/pull/6443)) - Update coverage to 7.13.5 ([#6442](https://github.com/cookiecutter/cookiecutter-django/pull/6442)) - Update pyproject-fmt from v2.18.1 to v2.19.0 ([#6441](https://github.com/cookiecutter/cookiecutter-django/pull/6441)) - Update django-stubs to 6.0.0 ([#6440](https://github.com/cookiecutter/cookiecutter-django/pull/6440)) ## 2026.03.16 ### Updated - Update hiredis to 3.3.1 ([#6438](https://github.com/cookiecutter/cookiecutter-django/pull/6438)) - Update uvicorn to 0.42.0 ([#6437](https://github.com/cookiecutter/cookiecutter-django/pull/6437)) ## 2026.03.13 ### Updated - Update ruff to 0.15.6 ([#6432](https://github.com/cookiecutter/cookiecutter-django/pull/6432)) ## 2026.03.12 ### Updated - Update django-ninja to 1.6.0 ([#6431](https://github.com/cookiecutter/cookiecutter-django/pull/6431)) - Update pyproject-fmt pre-commit hook from 2.16.2 to 2.18.1 ([#6428](https://github.com/cookiecutter/cookiecutter-django/pull/6428)) - Bump traefik from 3.6.9 to v3.6.10 ([#6423](https://github.com/cookiecutter/cookiecutter-django/pull/6423)) - Bump nginx from 1.29.5 to 1.29.6 ([#6427](https://github.com/cookiecutter/cookiecutter-django/pull/6427)) ## 2026.03.10 ### Changed - Upgrade to Django 6.0 ([#6411](https://github.com/cookiecutter/cookiecutter-django/pull/6411)) ## 2026.03.09 ### Changed - Upgrade factory-boy to 3.3.3 and fix mypy compatibility ([#6417](https://github.com/cookiecutter/cookiecutter-django/pull/6417)) ### Updated - Update django-allauth to 65.15.0 ([#6424](https://github.com/cookiecutter/cookiecutter-django/pull/6424)) - Update redis to 7.3.0 ([#6418](https://github.com/cookiecutter/cookiecutter-django/pull/6418)) ## 2026.03.06 ### Updated - Update ruff to 0.15.5 ([#6414](https://github.com/cookiecutter/cookiecutter-django/pull/6414)) ## 2026.03.03 ### Updated - Update django to 5.2.12 ([#6407](https://github.com/cookiecutter/cookiecutter-django/pull/6407)) ## 2026.03.02 ### Changed - Update dependabot.yml to remove Django 6.0 ignore rule ([#6402](https://github.com/cookiecutter/cookiecutter-django/pull/6402)) ### Updated - Update sentry-sdk to 2.54.0 ([#6403](https://github.com/cookiecutter/cookiecutter-django/pull/6403)) - Bump amazon/aws-cli from 2.33.0 to 2.34.0 ([#6400](https://github.com/cookiecutter/cookiecutter-django/pull/6400)) ## 2026.03.01 ### Changed - Add `django-ninja` as REST API option ([#6088](https://github.com/cookiecutter/cookiecutter-django/pull/6088)) ### Updated - Update crispy-bootstrap5 to 2026.3 ([#6399](https://github.com/cookiecutter/cookiecutter-django/pull/6399)) - Update django-crispy-forms to 2.6 ([#6398](https://github.com/cookiecutter/cookiecutter-django/pull/6398)) ## 2026.02.28 ### Updated - Update django-celery-beat to 2.9.0 ([#6397](https://github.com/cookiecutter/cookiecutter-django/pull/6397)) ## 2026.02.27 ### Updated - Update whitenoise to 6.12.0 ([#6396](https://github.com/cookiecutter/cookiecutter-django/pull/6396)) ## 2026.02.26 ### Changed - Add pyproject-fmt to the generated project ([#6074](https://github.com/cookiecutter/cookiecutter-django/pull/6074)) ### Updated - Update ruff to 0.15.4 ([#6395](https://github.com/cookiecutter/cookiecutter-django/pull/6395)) - Update redis to 7.2.1 ([#6391](https://github.com/cookiecutter/cookiecutter-django/pull/6391)) ## 2026.02.25 ### Updated - Bump node from 24.13 to 24.14 ([#6386](https://github.com/cookiecutter/cookiecutter-django/pull/6386)) - Update django-upgrade pre-commit hook ([#6385](https://github.com/cookiecutter/cookiecutter-django/pull/6385)) ## 2026.02.24 ### Changed - Add agents instructions ([#6208](https://github.com/cookiecutter/cookiecutter-django/pull/6208)) ### Updated - Bump traefik from 3.6.8 to 3.6.9 ([#6384](https://github.com/cookiecutter/cookiecutter-django/pull/6384)) ## 2026.02.20 ### Updated - Update ruff to 0.15.2 ([#6375](https://github.com/cookiecutter/cookiecutter-django/pull/6375)) ## 2026.02.19 ### Updated - Update werkzeug to 3.1.6 ([#6374](https://github.com/cookiecutter/cookiecutter-django/pull/6374)) - Update django-environ to 0.13.0 ([#6368](https://github.com/cookiecutter/cookiecutter-django/pull/6368)) - Update psycopg to 3.3.3 ([#6371](https://github.com/cookiecutter/cookiecutter-django/pull/6371)) - Update pyproject-fmt to 2.16.1 ([#6369](https://github.com/cookiecutter/cookiecutter-django/pull/6369)) ## 2026.02.17 ### Updated - Update uvicorn to 0.41.0 ([#6366](https://github.com/cookiecutter/cookiecutter-django/pull/6366)) ## 2026.02.16 ### Updated - Update redis to 7.2.0 ([#6365](https://github.com/cookiecutter/cookiecutter-django/pull/6365)) - Update sentry-sdk to 2.53.0 ([#6363](https://github.com/cookiecutter/cookiecutter-django/pull/6363)) - Update pytest-django to 4.12.0 ([#6361](https://github.com/cookiecutter/cookiecutter-django/pull/6361)) - Update django-environ to 0.12.1 ([#6360](https://github.com/cookiecutter/cookiecutter-django/pull/6360)) - Update django-allauth to 65.14.3 ([#6359](https://github.com/cookiecutter/cookiecutter-django/pull/6359)) ## 2026.02.13 ### Updated - Update django-allauth to 65.14.2 ([#6358](https://github.com/cookiecutter/cookiecutter-django/pull/6358)) - Update gunicorn to 25.1.0 ([#6357](https://github.com/cookiecutter/cookiecutter-django/pull/6357)) - Update ruff to 0.15.1 ([#6354](https://github.com/cookiecutter/cookiecutter-django/pull/6354)) ## 2026.02.12 ### Updated - Bump traefik from 3.6.7 to 3.6.8 ([#6353](https://github.com/cookiecutter/cookiecutter-django/pull/6353)) ## 2026.02.11 ### Updated - Update pillow to 12.1.1 ([#6351](https://github.com/cookiecutter/cookiecutter-django/pull/6351)) ## 2026.02.10 ### Updated - Update redis to 7.1.1 ([#6338](https://github.com/cookiecutter/cookiecutter-django/pull/6338)) - Update coverage to 7.13.4 ([#6336](https://github.com/cookiecutter/cookiecutter-django/pull/6336)) ## 2026.02.09 ### Updated - Update django-allauth to 65.14.1 ([#6324](https://github.com/cookiecutter/cookiecutter-django/pull/6324)) - Update gunicorn to 25.0.3 ([#6323](https://github.com/cookiecutter/cookiecutter-django/pull/6323)) ## 2026.02.06 ### Updated - Update gunicorn to 25.0.2 ([#6322](https://github.com/cookiecutter/cookiecutter-django/pull/6322)) ## 2026.02.05 ### Updated - Bump nginx from 1.29.4 to 1.29.5 ([#6321](https://github.com/cookiecutter/cookiecutter-django/pull/6321)) ## 2026.02.04 ### Updated - Update sentry-sdk to 2.52.0 ([#6320](https://github.com/cookiecutter/cookiecutter-django/pull/6320)) - Update ruff to 0.15.0 ([#6319](https://github.com/cookiecutter/cookiecutter-django/pull/6319)) - Update gunicorn to 25.0.1 ([#6313](https://github.com/cookiecutter/cookiecutter-django/pull/6313)) - Update djangorestframework-stubs to 3.16.8 ([#6317](https://github.com/cookiecutter/cookiecutter-django/pull/6317)) - Update coverage to 7.13.3 ([#6315](https://github.com/cookiecutter/cookiecutter-django/pull/6315)) - Update django to 5.2.11 ([#6314](https://github.com/cookiecutter/cookiecutter-django/pull/6314)) ## 2026.02.02 ### Updated - Auto-update pre-commit hooks ([#6311](https://github.com/cookiecutter/cookiecutter-django/pull/6311)) - Update gunicorn to 25.0.0 ([#6312](https://github.com/cookiecutter/cookiecutter-django/pull/6312)) - Update sentry-sdk to 2.51.0 ([#6309](https://github.com/cookiecutter/cookiecutter-django/pull/6309)) - Update coverage to 7.13.2 ([#6307](https://github.com/cookiecutter/cookiecutter-django/pull/6307)) ## 2026.01.24 ### Updated - Update gunicorn to 24.1.1 ([#6306](https://github.com/cookiecutter/cookiecutter-django/pull/6306)) ## 2026.01.23 ### Updated - Update gunicorn to 24.1.0 ([#6305](https://github.com/cookiecutter/cookiecutter-django/pull/6305)) - Update gunicorn to 24.0.0 ([#6303](https://github.com/cookiecutter/cookiecutter-django/pull/6303)) - Update ruff to 0.14.14 ([#6302](https://github.com/cookiecutter/cookiecutter-django/pull/6302)) ## 2026.01.22 ### Updated - Update django-stubs to 5.2.9 ([#6301](https://github.com/cookiecutter/cookiecutter-django/pull/6301)) ## 2026.01.20 ### Updated - Update sentry-sdk to 2.50.0 ([#6300](https://github.com/cookiecutter/cookiecutter-django/pull/6300)) - Update django-debug-toolbar to 6.2.0 ([#6299](https://github.com/cookiecutter/cookiecutter-django/pull/6299)) ## 2026.01.18 ### Updated - Update django-allauth to 65.14.0 ([#6298](https://github.com/cookiecutter/cookiecutter-django/pull/6298)) ## 2026.01.16 ### Updated - Update ruff to 0.14.13 ([#6293](https://github.com/cookiecutter/cookiecutter-django/pull/6293)) ## 2026.01.15 ### Updated - Bump traefik from 3.6.6 to 3.6.7 ([#6291](https://github.com/cookiecutter/cookiecutter-django/pull/6291)) - Bump node from 24.12 to 24.13 ([#6288](https://github.com/cookiecutter/cookiecutter-django/pull/6288)) - Bump amazon/aws-cli from 2.32.3 to 2.33.0 ([#6289](https://github.com/cookiecutter/cookiecutter-django/pull/6289)) ## 2026.01.13 ### Updated - Update djangorestframework-stubs to 3.16.7 ([#6285](https://github.com/cookiecutter/cookiecutter-django/pull/6285)) ## 2026.01.08 ### Updated - Update ruff to 0.14.11 ([#6280](https://github.com/cookiecutter/cookiecutter-django/pull/6280)) - Update werkzeug to 3.1.5 ([#6279](https://github.com/cookiecutter/cookiecutter-django/pull/6279)) - Update sentry-sdk to 2.49.0 ([#6278](https://github.com/cookiecutter/cookiecutter-django/pull/6278)) ## 2026.01.07 ### Fixed - Fix virtual environment setup to GitLab CI ([#6175](https://github.com/cookiecutter/cookiecutter-django/pull/6175)) ### Updated - Update django to 5.2.10 ([#6277](https://github.com/cookiecutter/cookiecutter-django/pull/6277)) ## 2026.01.04 ### Updated - Update celery to 5.6.2 ([#6275](https://github.com/cookiecutter/cookiecutter-django/pull/6275)) ## 2026.01.02 ### Updated - Update sphinx to 9.1.0 ([#6269](https://github.com/cookiecutter/cookiecutter-django/pull/6269)) - Update pillow to 12.1.0 ([#6271](https://github.com/cookiecutter/cookiecutter-django/pull/6271)) ## 2025.12.30 ### Updated - Update celery to 5.6.1 ([#6267](https://github.com/cookiecutter/cookiecutter-django/pull/6267)) - Bump traefik from 3.6.5 to 3.6.6 ([#6268](https://github.com/cookiecutter/cookiecutter-django/pull/6268)) ## 2025.12.29 ### Updated - Update coverage to 7.13.1 ([#6266](https://github.com/cookiecutter/cookiecutter-django/pull/6266)) - Update collectfasta to 3.3.3 ([#6265](https://github.com/cookiecutter/cookiecutter-django/pull/6265)) ## 2025.12.23 ### Fixed - Remove silent `ImportError` suppression in `UsersConfig.ready()` ([#6263](https://github.com/cookiecutter/cookiecutter-django/pull/6263)) - Switch Dependabot to uv ecosystem ([#6258](https://github.com/cookiecutter/cookiecutter-django/pull/6258)) ### Updated - Update collectfasta to 3.3.2 ([#6262](https://github.com/cookiecutter/cookiecutter-django/pull/6262)) ## 2025.12.22 ### Updated - Update uvicorn to 0.40.0 ([#6261](https://github.com/cookiecutter/cookiecutter-django/pull/6261)) ## 2025.12.19 ### Updated - Update ruff to 0.14.10 ([#6255](https://github.com/cookiecutter/cookiecutter-django/pull/6255)) ## 2025.12.18 ### Updated - Update django-anymail to 14.0 ([#6254](https://github.com/cookiecutter/cookiecutter-django/pull/6254)) ## 2025.12.17 ### Updated - Bump traefik from 3.6.4 to 3.6.5 ([#6253](https://github.com/cookiecutter/cookiecutter-django/pull/6253)) - Update pre-commit to 4.5.1 ([#6251](https://github.com/cookiecutter/cookiecutter-django/pull/6251)) ## 2025.12.16 ### Updated - Update sentry-sdk to 2.48.0 ([#6250](https://github.com/cookiecutter/cookiecutter-django/pull/6250)) ## 2025.12.15 ### Updated - Update mypy to 1.19.1 ([#6249](https://github.com/cookiecutter/cookiecutter-django/pull/6249)) ## 2025.12.12 ### Updated - Bump node from 24.11 to 24.12 ([#6247](https://github.com/cookiecutter/cookiecutter-django/pull/6247)) - Update ruff to 0.14.9 ([#6245](https://github.com/cookiecutter/cookiecutter-django/pull/6245)) ## 2025.12.10 ### Updated - Bump nginx from 1.29.3 to 1.29.4 ([#6244](https://github.com/cookiecutter/cookiecutter-django/pull/6244)) ## 2025.12.09 ### Updated - Update django-webpack-loader to 3.2.3 ([#6241](https://github.com/cookiecutter/cookiecutter-django/pull/6241)) - Update coverage to 7.13.0 ([#6240](https://github.com/cookiecutter/cookiecutter-django/pull/6240)) ## 2025.12.08 ### Updated - Bump traefik from 3.6.2 to 3.6.4 ([#6239](https://github.com/cookiecutter/cookiecutter-django/pull/6239)) - Update psycopg to 3.3.2 ([#6237](https://github.com/cookiecutter/cookiecutter-django/pull/6237)) - Update pytest to 9.0.2 ([#6236](https://github.com/cookiecutter/cookiecutter-django/pull/6236)) ## 2025.12.05 ### Updated - Update rcssmin to 1.2.2 ([#6232](https://github.com/cookiecutter/cookiecutter-django/pull/6232)) - Update django-compressor to 4.6.0 ([#6231](https://github.com/cookiecutter/cookiecutter-django/pull/6231)) - Update ruff to 0.14.8 ([#6229](https://github.com/cookiecutter/cookiecutter-django/pull/6229)) - Update sphinx to 9.0.4 ([#6228](https://github.com/cookiecutter/cookiecutter-django/pull/6228)) - Update djangorestframework-stubs to 3.16.6 ([#6224](https://github.com/cookiecutter/cookiecutter-django/pull/6224)) ## 2025.12.03 ### Changed - Add docker buildkit flag ([#6219](https://github.com/cookiecutter/cookiecutter-django/pull/6219)) ### Updated - Update sentry-sdk to 2.47.0 ([#6223](https://github.com/cookiecutter/cookiecutter-django/pull/6223)) - Update psycopg to 3.3.1 ([#6221](https://github.com/cookiecutter/cookiecutter-django/pull/6221)) ## 2025.12.02 ### Updated - Update django to 5.2.9 ([#6220](https://github.com/cookiecutter/cookiecutter-django/pull/6220)) - Update mypy to 1.19.0 ([#6218](https://github.com/cookiecutter/cookiecutter-django/pull/6218)) - Update django-stubs to 5.2.8 ([#6216](https://github.com/cookiecutter/cookiecutter-django/pull/6216)) - Update psycopg to 3.3.0 ([#6215](https://github.com/cookiecutter/cookiecutter-django/pull/6215)) - Update sphinx to 9.0.1 ([#6214](https://github.com/cookiecutter/cookiecutter-django/pull/6214)) - Update werkzeug to 3.1.4 ([#6212](https://github.com/cookiecutter/cookiecutter-django/pull/6212)) - Update celery to 5.6.0 ([#6211](https://github.com/cookiecutter/cookiecutter-django/pull/6211)) - Update ruff to 0.14.7 ([#6205](https://github.com/cookiecutter/cookiecutter-django/pull/6205)) ## 2025.11.25 ### Changed - Add optional args to "just build" ([#6196](https://github.com/cookiecutter/cookiecutter-django/pull/6196)) ### Documentation - Update PostgreSQL version range in README ([#6203](https://github.com/cookiecutter/cookiecutter-django/pull/6203)) ### Updated - Update sentry-sdk to 2.46.0 ([#6202](https://github.com/cookiecutter/cookiecutter-django/pull/6202)) ## 2025.11.24 ### Updated - Update coverage to 7.12.0 ([#6200](https://github.com/cookiecutter/cookiecutter-django/pull/6200)) - Update pre-commit to 4.5.0 ([#6199](https://github.com/cookiecutter/cookiecutter-django/pull/6199)) - Bump amazon/aws-cli from 2.31.0 to 2.32.3 ([#6197](https://github.com/cookiecutter/cookiecutter-django/pull/6197)) - Update psycopg to 3.2.13 ([#6194](https://github.com/cookiecutter/cookiecutter-django/pull/6194)) - Bump traefik from 3.5.4 to 3.6.2 ([#6192](https://github.com/cookiecutter/cookiecutter-django/pull/6192)) - Update django-allauth to 65.13.1 ([#6189](https://github.com/cookiecutter/cookiecutter-django/pull/6189)) - Update sentry-sdk to 2.45.0 ([#6185](https://github.com/cookiecutter/cookiecutter-django/pull/6185)) - Update pytest to 9.0.1 ([#6179](https://github.com/cookiecutter/cookiecutter-django/pull/6179)) - Update redis to 7.1.0 ([#6187](https://github.com/cookiecutter/cookiecutter-django/pull/6187)) - Update ruff to 0.14.6 ([#6193](https://github.com/cookiecutter/cookiecutter-django/pull/6193)) ## 2025.11.16 ### Changed - Add PostgreSQL 18 ([#6144](https://github.com/cookiecutter/cookiecutter-django/pull/6144)) ### Updated - Update ruff to 0.14.5 ([#6182](https://github.com/cookiecutter/cookiecutter-django/pull/6182)) ## 2025.11.07 ### Updated - Auto-update pre-commit hooks ([#6165](https://github.com/cookiecutter/cookiecutter-django/pull/6165)) - Update ruff to 0.14.4 ([#6164](https://github.com/cookiecutter/cookiecutter-django/pull/6164)) - Update django-crispy-forms to 2.5 ([#6163](https://github.com/cookiecutter/cookiecutter-django/pull/6163)) ## 2025.11.06 ### Updated - Update django-webpack-loader to 3.2.2 ([#6161](https://github.com/cookiecutter/cookiecutter-django/pull/6161)) - Update django to 5.2.8 ([#6160](https://github.com/cookiecutter/cookiecutter-django/pull/6160)) ## 2025.11.03 ### Updated - Update drf-spectacular to 0.29.0 ([#6158](https://github.com/cookiecutter/cookiecutter-django/pull/6158)) ## 2025.10.31 ### Updated - Update psycopg to 3.2.12 ([#6143](https://github.com/cookiecutter/cookiecutter-django/pull/6143)) - Update django-allauth to 65.13.0 ([#6157](https://github.com/cookiecutter/cookiecutter-django/pull/6157)) - Update ruff to 0.14.3 ([#6155](https://github.com/cookiecutter/cookiecutter-django/pull/6155)) - Update django-debug-toolbar to 6.1.0 ([#6154](https://github.com/cookiecutter/cookiecutter-django/pull/6154)) - Update sentry-sdk to 2.43.0 ([#6151](https://github.com/cookiecutter/cookiecutter-django/pull/6151)) - Update redis to 7.0.1 ([#6146](https://github.com/cookiecutter/cookiecutter-django/pull/6146)) - Bump traefik from 3.5.3 to 3.5.4 ([#6150](https://github.com/cookiecutter/cookiecutter-django/pull/6150)) - Bump nginx from 1.29.2 to 1.29.3 ([#6149](https://github.com/cookiecutter/cookiecutter-django/pull/6149)) - Bump node from 24.10 to 24.11 ([#6147](https://github.com/cookiecutter/cookiecutter-django/pull/6147)) ## 2025.10.27 ### Fixed - keep_local_envs_in_vcs user preference ([#6132](https://github.com/cookiecutter/cookiecutter-django/pull/6132)) ## 2025.10.24 ### Updated - Update django-upgrade pre-commit hook to 1.29.1 ([#6141](https://github.com/cookiecutter/cookiecutter-django/pull/6141)) ## 2025.10.23 ### Updated - Update ruff to 0.14.2 ([#6140](https://github.com/cookiecutter/cookiecutter-django/pull/6140)) ## 2025.10.22 ### Updated - Update djangorestframework-stubs to 3.16.5 ([#6137](https://github.com/cookiecutter/cookiecutter-django/pull/6137)) ## 2025.10.21 ### Updated - Update sentry-sdk to 2.42.1 ([#6136](https://github.com/cookiecutter/cookiecutter-django/pull/6136)) - Update psycopg to 3.2.11 ([#6135](https://github.com/cookiecutter/cookiecutter-django/pull/6135)) ## 2025.10.20 ### Changed - Update pre-commit GitLab image to python3.13-bookworm ([#6126](https://github.com/cookiecutter/cookiecutter-django/pull/6126)) ### Documentation - Fixed various broken URLs and typos in the documentation ([#6133](https://github.com/cookiecutter/cookiecutter-django/pull/6133)) ### Updated - Update uvicorn to 0.38.0 ([#6134](https://github.com/cookiecutter/cookiecutter-django/pull/6134)) ## 2025.10.17 ### Updated - Update ruff to 0.14.1 ([#6128](https://github.com/cookiecutter/cookiecutter-django/pull/6128)) ## 2025.10.16 ### Updated - Update django-allauth to 65.12.1 ([#6127](https://github.com/cookiecutter/cookiecutter-django/pull/6127)) - Update pillow to 12.0.0 ([#6122](https://github.com/cookiecutter/cookiecutter-django/pull/6122)) - Update sentry-sdk to 2.42.0 ([#6124](https://github.com/cookiecutter/cookiecutter-django/pull/6124)) - Update coverage to 7.11.0 ([#6123](https://github.com/cookiecutter/cookiecutter-django/pull/6123)) ## 2025.10.15 ### Updated - Bump redis from 6 to 7.2 ([#6118](https://github.com/cookiecutter/cookiecutter-django/pull/6118)) ## 2025.10.14 ### Updated - Update watchfiles to 1.1.1 ([#6120](https://github.com/cookiecutter/cookiecutter-django/pull/6120)) - Update hiredis to 3.3.0 ([#6119](https://github.com/cookiecutter/cookiecutter-django/pull/6119)) ## 2025.10.13 ### Changed - Enable version updates for Docker Compose files ([#6116](https://github.com/cookiecutter/cookiecutter-django/pull/6116)) ## 2025.10.10 ### Updated - Bump node from 24.9 to 24.10 ([#6107](https://github.com/cookiecutter/cookiecutter-django/pull/6107)) ## 2025.10.09 ### Updated - Update sentry-sdk to 2.41.0 ([#6106](https://github.com/cookiecutter/cookiecutter-django/pull/6106)) ## 2025.10.08 ### Updated - Update django-stubs to 5.2.7 ([#6104](https://github.com/cookiecutter/cookiecutter-django/pull/6104)) - Bump nginx from 1.29.1 to 1.29.2 ([#6103](https://github.com/cookiecutter/cookiecutter-django/pull/6103)) ## 2025.10.07 ### Updated - Update ruff to 0.14.0 ([#6100](https://github.com/cookiecutter/cookiecutter-django/pull/6100)) ## 2025.10.06 ### Changed - fix(project generation fails with docker --load flag) ([#6097](https://github.com/cookiecutter/cookiecutter-django/pull/6097)) ### Updated - Update sentry-sdk to 2.40.0 ([#6096](https://github.com/cookiecutter/cookiecutter-django/pull/6096)) - Update django-coverage-plugin to 3.2.0 ([#6095](https://github.com/cookiecutter/cookiecutter-django/pull/6095)) - Update django-stubs to 5.2.6 ([#6093](https://github.com/cookiecutter/cookiecutter-django/pull/6093)) - Update django-allauth to 65.12.0 ([#6092](https://github.com/cookiecutter/cookiecutter-django/pull/6092)) ## 2025.10.02 ### Updated - Update ruff to 0.13.3 ([#6089](https://github.com/cookiecutter/cookiecutter-django/pull/6089)) ## 2025.10.01 ### Fixed - Fix Docker error volume name is too short during project generation ([#6086](https://github.com/cookiecutter/cookiecutter-django/pull/6086)) ### Updated - Update django to 5.2.7 ([#6087](https://github.com/cookiecutter/cookiecutter-django/pull/6087)) ## 2025.09.30 ### Updated - Bump node from 24.8 to 24.9 ([#6081](https://github.com/cookiecutter/cookiecutter-django/pull/6081)) - Bump traefik from 3.5.2 to 3.5.3 ([#6083](https://github.com/cookiecutter/cookiecutter-django/pull/6083)) - Update djangorestframework-stubs to 3.16.4 ([#6080](https://github.com/cookiecutter/cookiecutter-django/pull/6080)) ## 2025.09.25 ### Updated - Update ruff to 0.13.2 ([#6078](https://github.com/cookiecutter/cookiecutter-django/pull/6078)) - Update sentry-sdk to 2.39.0 ([#6077](https://github.com/cookiecutter/cookiecutter-django/pull/6077)) ## 2025.09.24 ### Updated - Bump amazon/aws-cli from 2.30.1 to 2.31.0 ([#6075](https://github.com/cookiecutter/cookiecutter-django/pull/6075)) ## 2025.09.23 ### Changed - Added help command to sphinx Makefile ([#6024](https://github.com/cookiecutter/cookiecutter-django/pull/6024)) - Update RTD config to latest recommendation for uv ([#6072](https://github.com/cookiecutter/cookiecutter-django/pull/6072)) ### Updated - Update uvicorn to 0.37.0 ([#6073](https://github.com/cookiecutter/cookiecutter-django/pull/6073)) - Bump sass from 1.93.0 to 1.93.1 ([#6071](https://github.com/cookiecutter/cookiecutter-django/pull/6071)) ## 2025.09.22 ### Updated - Update coverage to 7.10.7 ([#6070](https://github.com/cookiecutter/cookiecutter-django/pull/6070)) - Upgrade to Python 3.13 ([#6067](https://github.com/cookiecutter/cookiecutter-django/pull/6067)) ## 2025.09.20 ### Updated - Update uvicorn-worker to 0.4.0 ([#6069](https://github.com/cookiecutter/cookiecutter-django/pull/6069)) - Update uvicorn to 0.36.0 ([#6068](https://github.com/cookiecutter/cookiecutter-django/pull/6068)) ## 2025.09.19 ### Updated - Bump sass from 1.92.1 to 1.93.0 ([#6066](https://github.com/cookiecutter/cookiecutter-django/pull/6066)) - Update ruff to 0.13.1 ([#6065](https://github.com/cookiecutter/cookiecutter-django/pull/6065)) - Update mypy to 1.18.2 ([#6062](https://github.com/cookiecutter/cookiecutter-django/pull/6062)) ## 2025.09.18 ### Updated - Update djangorestframework-stubs to 3.16.3 ([#6061](https://github.com/cookiecutter/cookiecutter-django/pull/6061)) - Update django-cors-headers to 4.9.0 ([#6060](https://github.com/cookiecutter/cookiecutter-django/pull/6060)) - Update whitenoise to 6.11.0 ([#6059](https://github.com/cookiecutter/cookiecutter-django/pull/6059)) ## 2025.09.15 ### Changed - Upgrade to Django 5.2 ([#5962](https://github.com/cookiecutter/cookiecutter-django/pull/5962)) ### Updated - Update sentry-sdk to 2.38.0 ([#6057](https://github.com/cookiecutter/cookiecutter-django/pull/6057)) - Bump sass from 1.77.6 to 1.92.1 ([#6021](https://github.com/cookiecutter/cookiecutter-django/pull/6021)) - Bump amazon/aws-cli from 2.30.0 to 2.30.1 ([#6056](https://github.com/cookiecutter/cookiecutter-django/pull/6056)) ## 2025.09.14 ### Documentation - Update documentation for deploying on PythonAnywhere with uv ([#6017](https://github.com/cookiecutter/cookiecutter-django/pull/6017)) ### Updated - Update django-stubs to 5.2.5 ([#6055](https://github.com/cookiecutter/cookiecutter-django/pull/6055)) ## 2025.09.12 ### Updated - Bump amazon/aws-cli Docker image from 2.29.0 to 2.30.0 ([#6054](https://github.com/cookiecutter/cookiecutter-django/pull/6054)) ## 2025.09.11 ### Changed - Enable collectfasta for Azure storage ([#6052](https://github.com/cookiecutter/cookiecutter-django/pull/6052)) ### Updated - Update ruff to 0.13.0 ([#6045](https://github.com/cookiecutter/cookiecutter-django/pull/6045)) - Bump ruff pre-commit hook from 0.12.12 to 0.13.0 ([#6046](https://github.com/cookiecutter/cookiecutter-django/pull/6046)) - Bump node from 24.7 to 24.8 ([#6047](https://github.com/cookiecutter/cookiecutter-django/pull/6047)) ## 2025.09.10 ### Updated - Bump traefik from 3.5.1 to 3.5.2 ([#6041](https://github.com/cookiecutter/cookiecutter-django/pull/6041)) ## 2025.09.09 ### Updated - Bump nginx from 1.17.8 to 1.29.1 ([#6036](https://github.com/cookiecutter/cookiecutter-django/pull/6036)) - Bump amazon/aws-cli image from 2.28.0 to 2.29.0 ([#6031](https://github.com/cookiecutter/cookiecutter-django/pull/6031)) - Update django-allauth to 65.11.2 ([#6030](https://github.com/cookiecutter/cookiecutter-django/pull/6030)) - Update sentry-sdk to 2.37.1 ([#6027](https://github.com/cookiecutter/cookiecutter-django/pull/6027)) - Update whitenoise to 6.10.0 ([#6026](https://github.com/cookiecutter/cookiecutter-django/pull/6026)) - Update django-upgrade pre-commit hook ([#6025](https://github.com/cookiecutter/cookiecutter-django/pull/6025)) ## 2025.09.08 ### Fixed - Use `--locked` instead of `--frozen` when running `uv sync` ([#6018](https://github.com/cookiecutter/cookiecutter-django/pull/6018)) - Remove mentions of `pip` and `virtualenv` in the `install_python_dependencies.sh` utility script ([#6019](https://github.com/cookiecutter/cookiecutter-django/pull/6019)) ### Updated - Update psycopg to 3.2.10 ([#6023](https://github.com/cookiecutter/cookiecutter-django/pull/6023)) - Update django-cors-headers to 4.8.0 ([#6022](https://github.com/cookiecutter/cookiecutter-django/pull/6022)) ## 2025.09.06 ### Changed - Migrate to `uv` as package manager for the generated project ([#5434](https://github.com/cookiecutter/cookiecutter-django/pull/5434)) ## 2025.09.05 ### Updated - Update sentry-sdk to 2.37.0 ([#6015](https://github.com/cookiecutter/cookiecutter-django/pull/6015)) - Upgrade actions/setup-python to v6 in template ([#6012](https://github.com/cookiecutter/cookiecutter-django/pull/6012)) - Update django to 5.1.12 ([#6009](https://github.com/cookiecutter/cookiecutter-django/pull/6009)) - Update ruff to 0.12.12 ([#6013](https://github.com/cookiecutter/cookiecutter-django/pull/6013)) - Update pytest to 8.4.2 ([#6011](https://github.com/cookiecutter/cookiecutter-django/pull/6011)) ## 2025.09.04 ### Updated - Update django-anymail to 13.1 ([#6007](https://github.com/cookiecutter/cookiecutter-django/pull/6007)) - Update sentry-sdk to 2.36.0 ([#6006](https://github.com/cookiecutter/cookiecutter-django/pull/6006)) ## 2025.09.03 ### Documentation - Update PythonAnywhere deployment page ([#6003](https://github.com/cookiecutter/cookiecutter-django/pull/6003)) ### Updated - Bump traefik from 3.5.0 to 3.5.1 ([#6004](https://github.com/cookiecutter/cookiecutter-django/pull/6004)) ## 2025.09.02 ### Updated - Update sentry-sdk to 2.35.2 ([#6002](https://github.com/cookiecutter/cookiecutter-django/pull/6002)) ## 2025.08.31 ### Updated - Update coverage to 7.10.6 ([#5999](https://github.com/cookiecutter/cookiecutter-django/pull/5999)) ## 2025.08.29 ### Updated - Bump node from 24.6-bookworm-slim to 24.7-bookworm-slim in /{{cookiecutter.project_slug}}/compose/local/node ([#5997](https://github.com/cookiecutter/cookiecutter-django/pull/5997)) - Update ruff to 0.12.11 ([#5998](https://github.com/cookiecutter/cookiecutter-django/pull/5998)) ## 2025.08.28 ### Updated - Update django-allauth to 65.11.1 ([#5992](https://github.com/cookiecutter/cookiecutter-django/pull/5992)) - Auto-update pre-commit hooks ([#5993](https://github.com/cookiecutter/cookiecutter-django/pull/5993)) ## 2025.08.27 ### Updated - Update django-upgrade pre-commit hook ([#5991](https://github.com/cookiecutter/cookiecutter-django/pull/5991)) ## 2025.08.26 ### Updated - Update sentry-sdk to 2.35.1 ([#5988](https://github.com/cookiecutter/cookiecutter-django/pull/5988)) - Update sphinx-autobuild to 2025.8.25 ([#5989](https://github.com/cookiecutter/cookiecutter-django/pull/5989)) ## 2025.08.25 ### Updated - Update collectfasta to 3.3.1 ([#5987](https://github.com/cookiecutter/cookiecutter-django/pull/5987)) - Update coverage to 7.10.5 ([#5986](https://github.com/cookiecutter/cookiecutter-django/pull/5986)) - Update pytest-sugar to 1.1.1 ([#5984](https://github.com/cookiecutter/cookiecutter-django/pull/5984)) ## 2025.08.21 ### Updated - Update ruff to 0.12.10 ([#5983](https://github.com/cookiecutter/cookiecutter-django/pull/5983)) ## 2025.08.18 ### Updated - Bump node from 24.5 to 24.6 ([#5981](https://github.com/cookiecutter/cookiecutter-django/pull/5981)) - Update coverage to 7.10.4 ([#5980](https://github.com/cookiecutter/cookiecutter-django/pull/5980)) - Update pytest-sugar to 1.1.0 ([#5979](https://github.com/cookiecutter/cookiecutter-django/pull/5979)) ## 2025.08.15 ### Updated - Update django-allauth to 65.11.0 ([#5977](https://github.com/cookiecutter/cookiecutter-django/pull/5977)) - Update sentry-sdk to 2.35.0 ([#5976](https://github.com/cookiecutter/cookiecutter-django/pull/5976)) ## 2025.08.14 ### Updated - Update ruff to 0.12.9 ([#5975](https://github.com/cookiecutter/cookiecutter-django/pull/5975)) ## 2025.08.13 ### Fixed - Fix imagemin corruption with Gulp ([#5974](https://github.com/cookiecutter/cookiecutter-django/pull/5974)) ## 2025.08.12 ### Updated - Update coverage to 7.10.3 ([#5972](https://github.com/cookiecutter/cookiecutter-django/pull/5972)) ## 2025.08.10 ### Updated - Update pre-commit to 4.3.0 ([#5971](https://github.com/cookiecutter/cookiecutter-django/pull/5971)) - Auto-update pre-commit hooks ([#5970](https://github.com/cookiecutter/cookiecutter-django/pull/5970)) ## 2025.08.08 ### Changed - Remove `project.css` when a bundler is used ([#5874](https://github.com/cookiecutter/cookiecutter-django/pull/5874)) ### Updated - Update redis to 6.4.0 ([#5968](https://github.com/cookiecutter/cookiecutter-django/pull/5968)) - Update ruff to 0.12.8 ([#5969](https://github.com/cookiecutter/cookiecutter-django/pull/5969)) ## 2025.08.07 ### Updated - Update djangorestframework to 3.16.1 ([#5966](https://github.com/cookiecutter/cookiecutter-django/pull/5966)) ## 2025.08.06 ### Updated - Update coverage to 7.10.2 ([#5964](https://github.com/cookiecutter/cookiecutter-django/pull/5964)) - Update redis to 6.3.0 ([#5963](https://github.com/cookiecutter/cookiecutter-django/pull/5963)) ## 2025.08.05 ### Changed - Rename `master` branch to `main` ([#5961](https://github.com/cookiecutter/cookiecutter-django/pull/5961)) ### Updated - Bump node from 22.14 to 24.5 in local Docker image ([#5960](https://github.com/cookiecutter/cookiecutter-django/pull/5960)) ## 2025.08.01 ### Updated - Update django-debug-toolbar to 6.0.0 ([#5945](https://github.com/cookiecutter/cookiecutter-django/pull/5945)) - Bump amazon/aws-cli from 2.27.12 to 2.28.0 ([#5957](https://github.com/cookiecutter/cookiecutter-django/pull/5957)) - Update mypy to 1.17.1 ([#5956](https://github.com/cookiecutter/cookiecutter-django/pull/5956)) ## 2025.07.30 ### Changed - docs: remove `$` from shell command examples for easier copy-pasting ([#5948](https://github.com/cookiecutter/cookiecutter-django/pull/5948)) ### Updated - Update sentry-sdk to 2.34.1 ([#5955](https://github.com/cookiecutter/cookiecutter-django/pull/5955)) - Update ruff to 0.12.7 ([#5952](https://github.com/cookiecutter/cookiecutter-django/pull/5952)) ## 2025.07.27 ### Updated - Update coverage to 7.10.1 ([#5947](https://github.com/cookiecutter/cookiecutter-django/pull/5947)) ## 2025.07.25 ### Updated - Update django-anymail to 13.0.1 ([#5946](https://github.com/cookiecutter/cookiecutter-django/pull/5946)) ## 2025.07.24 ### Updated - Update coverage to 7.10.0 ([#5944](https://github.com/cookiecutter/cookiecutter-django/pull/5944)) - Update ruff to 0.12.5 ([#5943](https://github.com/cookiecutter/cookiecutter-django/pull/5943)) - Bump traefik from 3.4.4 to 3.5.0 ([#5942](https://github.com/cookiecutter/cookiecutter-django/pull/5942)) ## 2025.07.22 ### Updated - Update sentry-sdk to 2.33.2 ([#5941](https://github.com/cookiecutter/cookiecutter-django/pull/5941)) ## 2025.07.21 ### Updated - Update sentry-sdk to 2.33.1 ([#5940](https://github.com/cookiecutter/cookiecutter-django/pull/5940)) ## 2025.07.18 ### Updated - Update mypy to 1.17.0 ([#5937](https://github.com/cookiecutter/cookiecutter-django/pull/5937)) - Update django-stubs to 5.2.2 ([#5936](https://github.com/cookiecutter/cookiecutter-django/pull/5936)) ## 2025.07.17 ### Updated - Update ruff to 0.12.4 ([#5935](https://github.com/cookiecutter/cookiecutter-django/pull/5935)) ## 2025.07.16 ### Updated - Update sentry-sdk to 2.33.0 ([#5933](https://github.com/cookiecutter/cookiecutter-django/pull/5933)) ## 2025.07.15 ### Updated - Update mypy to 1.16.1 ([#5901](https://github.com/cookiecutter/cookiecutter-django/pull/5901)) - Bump traefik from 3.4.3 to 3.4.4 ([#5930](https://github.com/cookiecutter/cookiecutter-django/pull/5930)) ## 2025.07.14 ### Changed - Fix howto docker command ([#5929](https://github.com/cookiecutter/cookiecutter-django/pull/5929)) ## 2025.07.11 ### Updated - Update ruff to 0.12.3 ([#5928](https://github.com/cookiecutter/cookiecutter-django/pull/5928)) - Update django-allauth to 65.10.0 ([#5927](https://github.com/cookiecutter/cookiecutter-django/pull/5927)) ## 2025.07.05 ### Updated - Update coverage to 7.9.2 ([#5925](https://github.com/cookiecutter/cookiecutter-django/pull/5925)) ## 2025.07.04 ### Updated - Update ruff to 0.12.2 ([#5923](https://github.com/cookiecutter/cookiecutter-django/pull/5923)) ## 2025.07.02 ### Updated - Update pillow to 11.3.0 ([#5921](https://github.com/cookiecutter/cookiecutter-django/pull/5921)) ## 2025.06.30 ### Updated - Bump traefik from 3.4.1 to 3.4.3 ([#5917](https://github.com/cookiecutter/cookiecutter-django/pull/5917)) - Update uvicorn to 0.35.0 ([#5919](https://github.com/cookiecutter/cookiecutter-django/pull/5919)) - Update sentry-sdk to 2.32.0 ([#5918](https://github.com/cookiecutter/cookiecutter-django/pull/5918)) ## 2025.06.26 ### Updated - Update ruff to 0.12.1 ([#5916](https://github.com/cookiecutter/cookiecutter-django/pull/5916)) ## 2025.06.24 ### Updated - Update sentry-sdk to 2.31.0 ([#5912](https://github.com/cookiecutter/cookiecutter-django/pull/5912)) ## 2025.06.19 ### Updated - Update pytest to 8.4.1 ([#5907](https://github.com/cookiecutter/cookiecutter-django/pull/5907)) ## 2025.06.18 ### Updated - Update ruff to 0.12.0 ([#5904](https://github.com/cookiecutter/cookiecutter-django/pull/5904)) - Update django-stubs to 5.2.1 ([#5905](https://github.com/cookiecutter/cookiecutter-django/pull/5905)) - Update django-redis to 6.0.0 ([#5903](https://github.com/cookiecutter/cookiecutter-django/pull/5903)) - Update django-webpack-loader to 3.2.1 ([#5902](https://github.com/cookiecutter/cookiecutter-django/pull/5902)) ## 2025.06.17 ### Updated - Update django-coverage-plugin to 3.1.1 ([#5900](https://github.com/cookiecutter/cookiecutter-django/pull/5900)) - Update watchfiles to 1.1.0 ([#5899](https://github.com/cookiecutter/cookiecutter-django/pull/5899)) ## 2025.06.15 ### Updated - Update coverage to 7.9.1 ([#5898](https://github.com/cookiecutter/cookiecutter-django/pull/5898)) ## 2025.06.13 ### Updated - Update coverage to 7.9.0 ([#5897](https://github.com/cookiecutter/cookiecutter-django/pull/5897)) - Update sentry-sdk to 2.30.0 ([#5896](https://github.com/cookiecutter/cookiecutter-django/pull/5896)) ## 2025.06.11 ### Updated - Update collectfasta to 3.3.0 ([#5892](https://github.com/cookiecutter/cookiecutter-django/pull/5892)) ## 2025.06.10 ### Updated - Update django to 5.1.11 ([#5891](https://github.com/cookiecutter/cookiecutter-django/pull/5891)) - Update crispy-bootstrap5 to 2025.6 ([#5888](https://github.com/cookiecutter/cookiecutter-django/pull/5888)) ## 2025.06.06 ### Updated - Update ruff to 0.11.13 ([#5887](https://github.com/cookiecutter/cookiecutter-django/pull/5887)) ## 2025.06.05 ### Updated - Bump python from 3.12.10 to 3.12.11 in docs Docker ([#5883](https://github.com/cookiecutter/cookiecutter-django/pull/5883)) - Bump python from 3.12.10 to 3.12.11 in production Docker ([#5884](https://github.com/cookiecutter/cookiecutter-django/pull/5884)) - Bump python from 3.12.10 3.12.11 in local Docker ([#5885](https://github.com/cookiecutter/cookiecutter-django/pull/5885)) - Update django to 5.1.10 ([#5882](https://github.com/cookiecutter/cookiecutter-django/pull/5882)) ## 2025.06.04 ### Updated - Update argon2-cffi to 25.1.0 ([#5880](https://github.com/cookiecutter/cookiecutter-django/pull/5880)) - Update pytest to 8.4.0 ([#5881](https://github.com/cookiecutter/cookiecutter-django/pull/5881)) ## 2025.06.02 ### Updated - Update django-allauth to 65.9.0 ([#5879](https://github.com/cookiecutter/cookiecutter-django/pull/5879)) - Update uvicorn to 0.34.3 ([#5878](https://github.com/cookiecutter/cookiecutter-django/pull/5878)) - Update celery to 5.5.3 ([#5877](https://github.com/cookiecutter/cookiecutter-django/pull/5877)) - Update ruff to 0.11.12 ([#5872](https://github.com/cookiecutter/cookiecutter-django/pull/5872)) ## 2025.05.28 ### Updated - Update redis to 6.2.0 ([#5871](https://github.com/cookiecutter/cookiecutter-django/pull/5871)) - Bump traefik from 3.4.0 to 3.4.1 ([#5870](https://github.com/cookiecutter/cookiecutter-django/pull/5870)) ## 2025.05.27 ### Updated - Update coverage to 7.8.2 ([#5868](https://github.com/cookiecutter/cookiecutter-django/pull/5868)) - Update hiredis to 3.2.1 ([#5867](https://github.com/cookiecutter/cookiecutter-django/pull/5867)) ## 2025.05.24 ### Updated - Auto-update pre-commit hooks ([#5866](https://github.com/cookiecutter/cookiecutter-django/pull/5866)) ## 2025.05.23 ### Updated - Update hiredis to 3.2.0 ([#5864](https://github.com/cookiecutter/cookiecutter-django/pull/5864)) - Update ruff to 0.11.11 ([#5865](https://github.com/cookiecutter/cookiecutter-django/pull/5865)) ## 2025.05.22 ### Changed - Remove pin for fido2 library ([#5861](https://github.com/cookiecutter/cookiecutter-django/pull/5861)) ### Updated - Update coverage to 7.8.1 ([#5860](https://github.com/cookiecutter/cookiecutter-django/pull/5860)) - Update django-allauth to 65.8.1 ([#5859](https://github.com/cookiecutter/cookiecutter-django/pull/5859)) ## 2025.05.21 ### Updated - Auto-update pre-commit hooks ([#5858](https://github.com/cookiecutter/cookiecutter-django/pull/5858)) ## 2025.05.20 ### Fixed - Pin fido2<2 ([#5854](https://github.com/cookiecutter/cookiecutter-django/pull/5854)) ### Updated - Update sentry-sdk to 2.29.1 ([#5853](https://github.com/cookiecutter/cookiecutter-django/pull/5853)) - Update django-webpack-loader to 3.2.0 ([#5852](https://github.com/cookiecutter/cookiecutter-django/pull/5852)) ## 2025.05.16 ### Updated - Update django-celery-beat to 2.8.1 ([#5841](https://github.com/cookiecutter/cookiecutter-django/pull/5841)) - Update ruff to 0.11.10 ([#5847](https://github.com/cookiecutter/cookiecutter-django/pull/5847)) ## 2025.05.14 ### Updated - Auto-update pre-commit hooks ([#5846](https://github.com/cookiecutter/cookiecutter-django/pull/5846)) ## 2025.05.13 ### Changed - Remove redundant `use_celery` condition in local compose file ([#5845](https://github.com/cookiecutter/cookiecutter-django/pull/5845)) ### Updated - Update psycopg to 3.2.9 ([#5844](https://github.com/cookiecutter/cookiecutter-django/pull/5844)) - Update redis to 6.1.0 ([#5842](https://github.com/cookiecutter/cookiecutter-django/pull/5842)) ## 2025.05.12 ### Changed - Remove extra spaces in Dockerfile `COPY` instruction paths ([#5822](https://github.com/cookiecutter/cookiecutter-django/pull/5822)) - Add support for PostgreSQL 17 ([#5805](https://github.com/cookiecutter/cookiecutter-django/pull/5805)) ### Fixed - Fix media folder permissions prod dockerfile ([#5831](https://github.com/cookiecutter/cookiecutter-django/pull/5831)) ### Updated - Update sentry-sdk to 2.28.0 ([#5839](https://github.com/cookiecutter/cookiecutter-django/pull/5839)) - Update djangorestframework-stubs to 3.16.0 ([#5806](https://github.com/cookiecutter/cookiecutter-django/pull/5806)) - Bump traefik from 3.3.5 to 3.4.0 ([#5824](https://github.com/cookiecutter/cookiecutter-django/pull/5824)) - Bump python from 3.12.9 to 3.12.10 in production Dockerfile ([#5774](https://github.com/cookiecutter/cookiecutter-django/pull/5774)) - Bump python from 3.12.9 to 3.12.10 in docs Dockerfile ([#5773](https://github.com/cookiecutter/cookiecutter-django/pull/5773)) - Bump python from 3.12.9 to 3.12.10 local Dockerfile ([#5772](https://github.com/cookiecutter/cookiecutter-django/pull/5772)) - Update redis to 6.0.0 ([#5814](https://github.com/cookiecutter/cookiecutter-django/pull/5814)) - Update psycopg to 3.2.8 ([#5836](https://github.com/cookiecutter/cookiecutter-django/pull/5836)) - Update django-stubs to 5.2.0 ([#5804](https://github.com/cookiecutter/cookiecutter-django/pull/5804)) - Bump amazon/aws-cli from 2.25.0 to 2.27.12 ([#5838](https://github.com/cookiecutter/cookiecutter-django/pull/5838)) - Update ruff to 0.11.9 ([#5834](https://github.com/cookiecutter/cookiecutter-django/pull/5834)) - Update hiredis to 3.1.1 ([#5833](https://github.com/cookiecutter/cookiecutter-django/pull/5833)) ## 2025.05.09 ### Updated - Update django-debug-toolbar to 5.2.0 ([#5816](https://github.com/cookiecutter/cookiecutter-django/pull/5816)) - Update django-allauth to 65.8.0 ([#5830](https://github.com/cookiecutter/cookiecutter-django/pull/5830)) - Update django to 5.1.9 ([#5828](https://github.com/cookiecutter/cookiecutter-django/pull/5828)) ## 2025.05.02 ### Updated - Update ruff to 0.11.8 ([#5819](https://github.com/cookiecutter/cookiecutter-django/pull/5819)) ## 2025.04.30 ### Updated - Update celery to 5.5.2 ([#5803](https://github.com/cookiecutter/cookiecutter-django/pull/5803)) - Update ruff to 0.11.7 ([#5815](https://github.com/cookiecutter/cookiecutter-django/pull/5815)) - Update sentry-sdk to 2.27.0 ([#5799](https://github.com/cookiecutter/cookiecutter-django/pull/5799)) - Update uvicorn to 0.34.2 ([#5791](https://github.com/cookiecutter/cookiecutter-django/pull/5791)) - Update django-crispy-forms to 2.4 ([#5780](https://github.com/cookiecutter/cookiecutter-django/pull/5780)) - Update pillow to 11.2.1 ([#5779](https://github.com/cookiecutter/cookiecutter-django/pull/5779)) - Update django-extensions to 4.1 ([#5776](https://github.com/cookiecutter/cookiecutter-django/pull/5776)) - Update watchfiles to 1.0.5 ([#5771](https://github.com/cookiecutter/cookiecutter-django/pull/5771)) - Update ruff to 0.11.6 ([#5789](https://github.com/cookiecutter/cookiecutter-django/pull/5789)) - Update psycopg to 3.2.7 ([#5811](https://github.com/cookiecutter/cookiecutter-django/pull/5811)) - Update redis to 5.3.0 ([#5813](https://github.com/cookiecutter/cookiecutter-django/pull/5813)) ## 2025.04.08 ### Updated - Update django-extensions to 4.0 ([#5770](https://github.com/cookiecutter/cookiecutter-django/pull/5770)) ## 2025.04.05 ### Changed - Add Docker build caching on GitHub Actions ([#5700](https://github.com/cookiecutter/cookiecutter-django/pull/5700)) - Pin Pillow and Sphinx to non yanked release ([#5765](https://github.com/cookiecutter/cookiecutter-django/pull/5765)) ### Updated - Update ruff to 0.11.4 ([#5767](https://github.com/cookiecutter/cookiecutter-django/pull/5767)) ## 2025.04.03 ### Updated - Update django-anymail to 13.0 ([#5763](https://github.com/cookiecutter/cookiecutter-django/pull/5763)) - Update pytest-django to 4.11.1 ([#5762](https://github.com/cookiecutter/cookiecutter-django/pull/5762)) - Update ruff to 0.11.3 ([#5761](https://github.com/cookiecutter/cookiecutter-django/pull/5761)) - Update django-allauth to 65.7.0 ([#5760](https://github.com/cookiecutter/cookiecutter-django/pull/5760)) ## 2025.04.02 ### Fixed - Fix line endings for dotenv merge script on Windows ([#5754](https://github.com/cookiecutter/cookiecutter-django/pull/5754)) ### Updated - Update crispy-bootstrap5 to 2025.4 ([#5756](https://github.com/cookiecutter/cookiecutter-django/pull/5756)) - Update Django from 5.0 to 5.1 ([#5740](https://github.com/cookiecutter/cookiecutter-django/pull/5740)) - Update sentry-sdk to 2.25.1 ([#5757](https://github.com/cookiecutter/cookiecutter-django/pull/5757)) - Update django-storages to 1.14.6 ([#5753](https://github.com/cookiecutter/cookiecutter-django/pull/5753)) - Update pytest-django to 4.11.0 ([#5752](https://github.com/cookiecutter/cookiecutter-django/pull/5752)) ## 2025.04.01 ### Updated - Update pillow to 11.2.0 ([#5751](https://github.com/cookiecutter/cookiecutter-django/pull/5751)) - Bump traefik from 3.3.4 to 3.3.5 ([#5750](https://github.com/cookiecutter/cookiecutter-django/pull/5750)) - Update celery to 5.5.0 ([#5748](https://github.com/cookiecutter/cookiecutter-django/pull/5748)) ## 2025.03.31 ### Updated - Update django-allauth to 65.6.0 ([#5741](https://github.com/cookiecutter/cookiecutter-django/pull/5741)) - Update sentry-sdk to 2.25.0 ([#5747](https://github.com/cookiecutter/cookiecutter-django/pull/5747)) - Update coverage to 7.8.0 ([#5745](https://github.com/cookiecutter/cookiecutter-django/pull/5745)) ## 2025.03.28 ### Updated - Update djangorestframework to 3.16.0 ([#5743](https://github.com/cookiecutter/cookiecutter-django/pull/5743)) - Update django-upgrade pre-commit hook to v1.24.0 ([#5742](https://github.com/cookiecutter/cookiecutter-django/pull/5742)) ## 2025.03.24 ### Updated - Update django-allauth to 65.5.0 ([#5723](https://github.com/cookiecutter/cookiecutter-django/pull/5723)) - Update sentry-sdk to 2.24.1 ([#5739](https://github.com/cookiecutter/cookiecutter-django/pull/5739)) ## 2025.03.22 ### Updated - Update coverage to 7.7.1 ([#5736](https://github.com/cookiecutter/cookiecutter-django/pull/5736)) ## 2025.03.21 ### Updated - Update sentry-sdk to 2.24.0 ([#5734](https://github.com/cookiecutter/cookiecutter-django/pull/5734)) - Update django-debug-toolbar to 5.1.0 ([#5732](https://github.com/cookiecutter/cookiecutter-django/pull/5732)) - Update ruff to 0.11.2 ([#5735](https://github.com/cookiecutter/cookiecutter-django/pull/5735)) - Bump amazon/aws-cli from 2.24.0 to 2.25.0 ([#5733](https://github.com/cookiecutter/cookiecutter-django/pull/5733)) - Auto-update pre-commit hooks ([#5657](https://github.com/cookiecutter/cookiecutter-django/pull/5657)) ## 2025.03.19 ### Updated - Update pre-commit to 4.2.0 ([#5730](https://github.com/cookiecutter/cookiecutter-django/pull/5730)) ## 2025.03.17 ### Updated - Update sentry-sdk to 2.23.1 ([#5727](https://github.com/cookiecutter/cookiecutter-django/pull/5727)) - Update coverage to 7.7.0 ([#5725](https://github.com/cookiecutter/cookiecutter-django/pull/5725)) ## 2025.03.15 ### Updated - Update psycopg to 3.2.6 ([#5721](https://github.com/cookiecutter/cookiecutter-django/pull/5721)) - Update ruff to 0.11.0 ([#5724](https://github.com/cookiecutter/cookiecutter-django/pull/5724)) ## 2025.03.08 ### Updated - Update ruff to 0.9.10 ([#5720](https://github.com/cookiecutter/cookiecutter-django/pull/5720)) ## 2025.03.06 ### Updated - Update django to 5.0.13 ([#5719](https://github.com/cookiecutter/cookiecutter-django/pull/5719)) ## 2025.03.04 ### Changed - Add groups for dependabot updates ([#5709](https://github.com/cookiecutter/cookiecutter-django/pull/5709)) ### Updated - Update sphinx to 8.3.0 ([#5714](https://github.com/cookiecutter/cookiecutter-django/pull/5714)) - Update pytest to 8.3.5 ([#5713](https://github.com/cookiecutter/cookiecutter-django/pull/5713)) ## 2025.03.01 ### Updated - Update ruff to 0.9.9 ([#5711](https://github.com/cookiecutter/cookiecutter-django/pull/5711)) ## 2025.02.28 ### Updated - Update ruff to 0.9.8 ([#5708](https://github.com/cookiecutter/cookiecutter-django/pull/5708)) - Bump babel-loader from 9.2.1 to 10.0.0 ([#5710](https://github.com/cookiecutter/cookiecutter-django/pull/5710)) ## 2025.02.26 ### Updated - Bump traefik from 3.3.3 to 3.3.4 ([#5705](https://github.com/cookiecutter/cookiecutter-django/pull/5705)) ## 2025.02.25 ### Documentation - Fix links to FAQ about `contrib.sites` directory ([#5704](https://github.com/cookiecutter/cookiecutter-django/pull/5704)) ## 2025.02.23 ### Changed - Group dependabot docker directories ([#5698](https://github.com/cookiecutter/cookiecutter-django/pull/5698)) ### Updated - Update sphinx to 8.2.1 ([#5696](https://github.com/cookiecutter/cookiecutter-django/pull/5696)) - Update psycopg to 3.2.5 ([#5697](https://github.com/cookiecutter/cookiecutter-django/pull/5697)) ## 2025.02.21 ### Updated - Update djangorestframework-stubs to 3.15.3 ([#5695](https://github.com/cookiecutter/cookiecutter-django/pull/5695)) - Update sphinx to 8.2.0 ([#5693](https://github.com/cookiecutter/cookiecutter-django/pull/5693)) - Update ruff to 0.9.7 ([#5694](https://github.com/cookiecutter/cookiecutter-django/pull/5694)) ## 2025.02.17 ### Updated - Update sentry-sdk to 2.22.0 ([#5692](https://github.com/cookiecutter/cookiecutter-django/pull/5692)) - Update django-storages to 1.14.5 ([#5690](https://github.com/cookiecutter/cookiecutter-django/pull/5690)) ## 2025.02.14 ### Updated - Bump node from 22.13 to 22.14 ([#5688](https://github.com/cookiecutter/cookiecutter-django/pull/5688)) ## 2025.02.13 ### Updated - Update sentry-sdk to 2.21.0 ([#5687](https://github.com/cookiecutter/cookiecutter-django/pull/5687)) ## 2025.02.11 ### Updated - Update coverage to 7.6.12 ([#5686](https://github.com/cookiecutter/cookiecutter-django/pull/5686)) ## 2025.02.10 ### Updated - Update pytest-django to 4.10.0 ([#5684](https://github.com/cookiecutter/cookiecutter-django/pull/5684)) - Update ruff to 0.9.6 ([#5683](https://github.com/cookiecutter/cookiecutter-django/pull/5683)) - Bump amazon/aws-cli from 2.23.0 to 2.24.0 ([#5682](https://github.com/cookiecutter/cookiecutter-django/pull/5682)) ## 2025.02.08 ### Updated - Update coverage to 7.6.11 ([#5681](https://github.com/cookiecutter/cookiecutter-django/pull/5681)) ## 2025.02.07 ### Updated - Update mypy to 1.15.0 ([#5664](https://github.com/cookiecutter/cookiecutter-django/pull/5664)) - Update django-stubs to 5.1.3 ([#5680](https://github.com/cookiecutter/cookiecutter-django/pull/5680)) - Bump python from 3.12.8 to 3.12.9 in local Docker image ([#5678](https://github.com/cookiecutter/cookiecutter-django/pull/5678)) - Bump python from 3.12.8 to 3.12.9 in production Docker image ([#5677](https://github.com/cookiecutter/cookiecutter-django/pull/5677)) - Bump python from 3.12.8 to 3.12.9 in docs Docker image ([#5676](https://github.com/cookiecutter/cookiecutter-django/pull/5676)) - Update django-allauth to 65.4.1 ([#5679](https://github.com/cookiecutter/cookiecutter-django/pull/5679)) - Update django-cors-headers to 4.7.0 ([#5675](https://github.com/cookiecutter/cookiecutter-django/pull/5675)) - Update whitenoise to 6.9.0 ([#5674](https://github.com/cookiecutter/cookiecutter-django/pull/5674)) ## 2025.02.06 ### Fixed - Bump node version in production Dockerfile from 20 to 22.13 ([#5672](https://github.com/cookiecutter/cookiecutter-django/pull/5672)) ### Updated - Update ruff to 0.9.5 ([#5673](https://github.com/cookiecutter/cookiecutter-django/pull/5673)) ## 2025.02.05 ### Changed - Add missing trailing slash in test `MEDIA_URL` ([#5666](https://github.com/cookiecutter/cookiecutter-django/pull/5666)) ### Updated - Update django to 5.0.12 ([#5667](https://github.com/cookiecutter/cookiecutter-django/pull/5667)) ## 2025.02.03 ### Updated - Bump traefik from 3.3.2 to 3.3.3 ([#5660](https://github.com/cookiecutter/cookiecutter-django/pull/5660)) - Update factory-boy to 3.3.2 ([#5661](https://github.com/cookiecutter/cookiecutter-django/pull/5661)) ## 2025.01.30 ### Updated - Update ruff to 0.9.4 ([#5659](https://github.com/cookiecutter/cookiecutter-django/pull/5659)) ## 2025.01.26 ### Changed - Migrate generated project from `runtime.txt` to `.python-version` ([#5652](https://github.com/cookiecutter/cookiecutter-django/pull/5652)) ### Documentation - Update Heroku deployment guide ([#5656](https://github.com/cookiecutter/cookiecutter-django/pull/5656)) ## 2025.01.24 ### Updated - Update ruff to 0.9.3 ([#5654](https://github.com/cookiecutter/cookiecutter-django/pull/5654)) ## 2025.01.21 ### Changed - Update linter error code from TCH to TC ([#5651](https://github.com/cookiecutter/cookiecutter-django/pull/5651)) ### Updated - Update pre-commit to 4.1.0 ([#5650](https://github.com/cookiecutter/cookiecutter-django/pull/5650)) ## 2025.01.20 ### Changed - Group all API tests under a `tests.api` namespace ([#5615](https://github.com/cookiecutter/cookiecutter-django/pull/5615)) - Migrate post-generation hook to pathlib ([#5648](https://github.com/cookiecutter/cookiecutter-django/pull/5648)) ## 2025.01.16 ### Updated - Update ruff to 0.9.2 ([#5646](https://github.com/cookiecutter/cookiecutter-django/pull/5646)) - Bump amazon/aws-cli from 2.22.1 to 2.23.0 ([#5645](https://github.com/cookiecutter/cookiecutter-django/pull/5645)) ## 2025.01.15 ### Fixed - Fix setting for to `CELERY_WORKER_HIJACK_ROOT_LOGGER` ([#5643](https://github.com/cookiecutter/cookiecutter-django/pull/5643)) ### Updated - Update psycopg to 3.2.4 ([#5644](https://github.com/cookiecutter/cookiecutter-django/pull/5644)) - Update django-stubs to 5.1.2 ([#5639](https://github.com/cookiecutter/cookiecutter-django/pull/5639)) - Bump traefik from 3.3.1 to 3.3.2 ([#5642](https://github.com/cookiecutter/cookiecutter-django/pull/5642)) ## 2025.01.14 ### Updated - Update django to 5.0.11 ([#5640](https://github.com/cookiecutter/cookiecutter-django/pull/5640)) - Update sentry-sdk to 2.20.0 ([#5638](https://github.com/cookiecutter/cookiecutter-django/pull/5638)) - Update django-debug-toolbar to 5.0.1 ([#5636](https://github.com/cookiecutter/cookiecutter-django/pull/5636)) ## 2025.01.13 ### Updated - Update django-environ to 0.12.0 ([#5635](https://github.com/cookiecutter/cookiecutter-django/pull/5635)) - Bump traefik from 3.3.0 to 3.3.1 ([#5634](https://github.com/cookiecutter/cookiecutter-django/pull/5634)) ## 2025.01.11 ### Updated - Update ruff to 0.9.1 ([#5633](https://github.com/cookiecutter/cookiecutter-django/pull/5633)) ## 2025.01.10 ### Updated - Update watchfiles to 1.0.4 ([#5631](https://github.com/cookiecutter/cookiecutter-django/pull/5631)) ## 2025.01.09 ### Changed - Drop support for Python 2 in template generation hooks ([#5614](https://github.com/cookiecutter/cookiecutter-django/pull/5614)) ### Updated - Bump node from 22.12 to 22.13 ([#5627](https://github.com/cookiecutter/cookiecutter-django/pull/5627)) ## 2025.01.07 ### Fixed - Set `minimum_pre_commit_version` in pre-commit config ([#5626](https://github.com/cookiecutter/cookiecutter-django/pull/5626)) ### Updated - Bump traefik from 3.2.3 to 3.3.0 ([#5625](https://github.com/cookiecutter/cookiecutter-django/pull/5625)) ## 2025.01.06 ### Changed - Add justfile for use with docker ([#5621](https://github.com/cookiecutter/cookiecutter-django/pull/5621)) ## 2025.01.04 ### Updated - Update ruff to 0.8.6 ([#5622](https://github.com/cookiecutter/cookiecutter-django/pull/5622)) ## 2025.01.02 ### Fixed - Fix logging configuration for Celery tasks ([#5563](https://github.com/cookiecutter/cookiecutter-django/pull/5563)) ### Updated - Update ruff to 0.8.5 ([#5619](https://github.com/cookiecutter/cookiecutter-django/pull/5619)) - Update pillow to 11.1.0 ([#5617](https://github.com/cookiecutter/cookiecutter-django/pull/5617)) ## 2024.12.27 ### Updated - Update coverage to 7.6.10 ([#5608](https://github.com/cookiecutter/cookiecutter-django/pull/5608)) - Update uvicorn-worker to 0.3.0 ([#5607](https://github.com/cookiecutter/cookiecutter-django/pull/5607)) ## 2024.12.26 ### Updated - Update collectfasta to 3.2.1 ([#5606](https://github.com/cookiecutter/cookiecutter-django/pull/5606)) - Update django-allauth to 65.3.1 ([#5605](https://github.com/cookiecutter/cookiecutter-django/pull/5605)) ## 2024.12.24 ### Updated - Update djlint to 1.36.4 ([#5603](https://github.com/cookiecutter/cookiecutter-django/pull/5603)) - Update uvicorn to 0.34.0 ([#5592](https://github.com/cookiecutter/cookiecutter-django/pull/5592)) ## 2024.12.23 ### Updated - Bump webpack-cli from 5.1.4 to 6.0.1 ([#5601](https://github.com/cookiecutter/cookiecutter-django/pull/5601)) ## 2024.12.20 ### Updated - Update ruff to 0.8.4 ([#5595](https://github.com/cookiecutter/cookiecutter-django/pull/5595)) ## 2024.12.17 ### Updated - Update djangorestframework-stubs to 3.15.2 ([#5591](https://github.com/cookiecutter/cookiecutter-django/pull/5591)) - Bump traefik from 3.2.2 to 3.2.3 ([#5594](https://github.com/cookiecutter/cookiecutter-django/pull/5594)) ## 2024.12.12 ### Updated - Update ruff to 0.8.3 ([#5587](https://github.com/cookiecutter/cookiecutter-django/pull/5587)) ## 2024.12.11 ### Updated - Bump traefik from 3.2.1 to 3.2.2 ([#5586](https://github.com/cookiecutter/cookiecutter-django/pull/5586)) ## 2024.12.10 ### Updated - Update watchfiles to 1.0.3 ([#5585](https://github.com/cookiecutter/cookiecutter-django/pull/5585)) - Bump node from 22.11 to 22.12 ([#5583](https://github.com/cookiecutter/cookiecutter-django/pull/5583)) ## 2024.12.08 ### Fixed - Pin node to version 22.11 ([#5582](https://github.com/cookiecutter/cookiecutter-django/pull/5582)) ### Updated - Update ruff to 0.8.2 ([#5576](https://github.com/cookiecutter/cookiecutter-django/pull/5576)) - Update coverage to 7.6.9 ([#5581](https://github.com/cookiecutter/cookiecutter-django/pull/5581)) - Update sentry-sdk to 2.19.2 ([#5579](https://github.com/cookiecutter/cookiecutter-django/pull/5579)) - Bump python from 3.12.7 to 3.12.8 in production Docker image ([#5575](https://github.com/cookiecutter/cookiecutter-django/pull/5575)) - Bump python from 3.12.7 to 3.12.8 in local Docker image ([#5574](https://github.com/cookiecutter/cookiecutter-django/pull/5574)) - Bump python from 3.12.7 to 3.12.8 in docs Docker image ([#5573](https://github.com/cookiecutter/cookiecutter-django/pull/5573)) - Update hiredis to 3.1.0 ([#5571](https://github.com/cookiecutter/cookiecutter-django/pull/5571)) - Update redis to 5.2.1 ([#5580](https://github.com/cookiecutter/cookiecutter-django/pull/5580)) - Update django to 5.0.10 ([#5572](https://github.com/cookiecutter/cookiecutter-django/pull/5572)) - Update drf-spectacular to 0.28.0 ([#5564](https://github.com/cookiecutter/cookiecutter-django/pull/5564)) ## 2024.12.03 ### Updated - Update django-upgrade to 1.22.2 ([#5567](https://github.com/cookiecutter/cookiecutter-django/pull/5567)) ## 2024.12.02 ### Updated - Update pytest to 8.3.4 ([#5566](https://github.com/cookiecutter/cookiecutter-django/pull/5566)) ## 2024.12.01 ### Updated - Update django-allauth to 65.3.0 ([#5565](https://github.com/cookiecutter/cookiecutter-django/pull/5565)) ## 2024.11.29 ### Updated - Update ruff to 0.8.1 ([#5557](https://github.com/cookiecutter/cookiecutter-django/pull/5557)) - Update djlint to 1.36.3 ([#5558](https://github.com/cookiecutter/cookiecutter-django/pull/5558)) ## 2024.11.28 ### Updated - Update djlint to 1.36.2 ([#5555](https://github.com/cookiecutter/cookiecutter-django/pull/5555)) ## 2024.11.27 ### Fixed - Pin dart-sass to 1.77.6 to avoid deprecation warnings ([#5552](https://github.com/cookiecutter/cookiecutter-django/pull/5552)) ### Updated - Bump gulp-imagemin from 7.1.0 to 9.1.0 ([#5052](https://github.com/cookiecutter/cookiecutter-django/pull/5052)) - Bump gulp from 4.0.2 to 5.0.0 ([#4949](https://github.com/cookiecutter/cookiecutter-django/pull/4949)) ## 2024.11.26 ### Updated - Update coverage to 7.6.8 ([#5547](https://github.com/cookiecutter/cookiecutter-django/pull/5547)) - Update watchfiles to 1.0.0 ([#5548](https://github.com/cookiecutter/cookiecutter-django/pull/5548)) ## 2024.11.22 ### Updated - Update ruff to 0.8.0 ([#5545](https://github.com/cookiecutter/cookiecutter-django/pull/5545)) ## 2024.11.21 ### Changed - Add support for secure Redis (TLS support) ([#5526](https://github.com/cookiecutter/cookiecutter-django/pull/5526)) ### Updated - Update sentry-sdk to 2.19.0 ([#5543](https://github.com/cookiecutter/cookiecutter-django/pull/5543)) - Update uvicorn to 0.32.1 ([#5539](https://github.com/cookiecutter/cookiecutter-django/pull/5539)) - Bump traefik from 3.2.0 to 3.2.1 ([#5541](https://github.com/cookiecutter/cookiecutter-django/pull/5541)) ## 2024.11.20 ### Fixed - Fix typos in translation instructions in README ([#5538](https://github.com/cookiecutter/cookiecutter-django/pull/5538)) ### Updated - Bump amazon/aws-cli from 2.21.0 to 2.22.1 ([#5537](https://github.com/cookiecutter/cookiecutter-django/pull/5537)) ## 2024.11.16 ### Updated - Update ruff to 0.7.4 ([#5531](https://github.com/cookiecutter/cookiecutter-django/pull/5531)) ## 2024.11.15 ### Updated - Update coverage to 7.6.5 ([#5529](https://github.com/cookiecutter/cookiecutter-django/pull/5529)) ## 2024.11.14 ### Updated - Bump amazon/aws-cli from 2.20.0 to 2.21.0 ([#5528](https://github.com/cookiecutter/cookiecutter-django/pull/5528)) ## 2024.11.13 ### Updated - Update werkzeug to 3.1.3 ([#5524](https://github.com/cookiecutter/cookiecutter-django/pull/5524)) - Update ruff to 0.7.3 ([#5521](https://github.com/cookiecutter/cookiecutter-django/pull/5521)) - Bump amazon/aws-cli from 2.19.0 to 2.20.0 ([#5527](https://github.com/cookiecutter/cookiecutter-django/pull/5527)) - Update django-allauth to 65.2.0 ([#5523](https://github.com/cookiecutter/cookiecutter-django/pull/5523)) ## 2024.11.08 ### Updated - Update ruff pre-commit hook to 0.7.3 ([#5522](https://github.com/cookiecutter/cookiecutter-django/pull/5522)) ## 2024.11.07 ### Updated - Update djlint to 1.36.1 ([#5519](https://github.com/cookiecutter/cookiecutter-django/pull/5519)) ## 2024.11.05 ### Updated - Update djlint to 1.36.0 ([#5517](https://github.com/cookiecutter/cookiecutter-django/pull/5517)) ## 2024.11.04 ### Updated - Update sentry-sdk to 2.18.0 ([#5515](https://github.com/cookiecutter/cookiecutter-django/pull/5515)) ## 2024.11.02 ### Updated - Update ruff to 0.7.2 ([#5510](https://github.com/cookiecutter/cookiecutter-django/pull/5510)) ## 2024.11.01 ### Updated - Update djlint to 1.35.4 ([#5508](https://github.com/cookiecutter/cookiecutter-django/pull/5508)) - Bump amazon/aws-cli from 2.18.1 to 2.19.0 ([#5507](https://github.com/cookiecutter/cookiecutter-django/pull/5507)) ## 2024.10.30 ### Documentation - Small spelling correction in comment ([#5502](https://github.com/cookiecutter/cookiecutter-django/pull/5502)) ### Updated - Update djlint to 1.35.3 ([#5503](https://github.com/cookiecutter/cookiecutter-django/pull/5503)) - Update whitenoise to 6.8.2 ([#5501](https://github.com/cookiecutter/cookiecutter-django/pull/5501)) ## 2024.10.29 ### Updated - Update django-cors-headers to 4.6.0 ([#5499](https://github.com/cookiecutter/cookiecutter-django/pull/5499)) - Update whitenoise to 6.8.1 ([#5497](https://github.com/cookiecutter/cookiecutter-django/pull/5497)) - Bump traefik from 3.1.6 to 3.2.0 ([#5498](https://github.com/cookiecutter/cookiecutter-django/pull/5498)) ## 2024.10.26 ### Updated - Update django-stubs to 5.1.1 ([#5495](https://github.com/cookiecutter/cookiecutter-django/pull/5495)) - Update mypy to 1.13.0 ([#5484](https://github.com/cookiecutter/cookiecutter-django/pull/5484)) - Update werkzeug to 3.0.6 ([#5492](https://github.com/cookiecutter/cookiecutter-django/pull/5492)) ## 2024.10.25 ### Updated - Update werkzeug to 3.0.5 and unpin watchdog<5 ([#5489](https://github.com/cookiecutter/cookiecutter-django/pull/5489)) ## 2024.10.24 ### Updated - Update ruff to 0.7.1 ([#5487](https://github.com/cookiecutter/cookiecutter-django/pull/5487)) - Update redis to 5.2.0 ([#5486](https://github.com/cookiecutter/cookiecutter-django/pull/5486)) - Update django-allauth to 65.1.0 ([#5485](https://github.com/cookiecutter/cookiecutter-django/pull/5485)) ## 2024.10.22 ### Changed - Fix broken links in generated README ([#5482](https://github.com/cookiecutter/cookiecutter-django/pull/5482)) ### Updated - Auto-update pre-commit hooks ([#5483](https://github.com/cookiecutter/cookiecutter-django/pull/5483)) ## 2024.10.21 ### Changed - Remove CELERY_BROKER_URL in favor of REDIS_URL ([#4861](https://github.com/cookiecutter/cookiecutter-django/pull/4861)) ### Fixed - Fix a number of issues with Azure storage ([#5476](https://github.com/cookiecutter/cookiecutter-django/pull/5476)) ### Updated - Update coverage to 7.6.4 ([#5480](https://github.com/cookiecutter/cookiecutter-django/pull/5480)) ## 2024.10.17 ### Updated - Update ruff to 0.7.0 ([#5474](https://github.com/cookiecutter/cookiecutter-django/pull/5474)) - Update uvicorn to 0.32.0 ([#5471](https://github.com/cookiecutter/cookiecutter-django/pull/5471)) - Update pillow to 11.0.0 ([#5470](https://github.com/cookiecutter/cookiecutter-django/pull/5470)) - Update sentry-sdk to 2.17.0 ([#5473](https://github.com/cookiecutter/cookiecutter-django/pull/5473)) ## 2024.10.15 ### Changed - [pre-commit.ci] pre-commit autoupdate ([#5468](https://github.com/cookiecutter/cookiecutter-django/pull/5468)) ## 2024.10.14 ### Changed - Add requirements for ubuntu 24.04 ([#5467](https://github.com/cookiecutter/cookiecutter-django/pull/5467)) ### Updated - Update sphinx to 8.1.3 ([#5463](https://github.com/cookiecutter/cookiecutter-django/pull/5463)) - Update coverage to 7.6.3 ([#5464](https://github.com/cookiecutter/cookiecutter-django/pull/5464)) ## 2024.10.12 ### Changed - Pin Python version to 3.12 ([#5456](https://github.com/cookiecutter/cookiecutter-django/pull/5456)) ### Updated - Update sphinx to 8.1.1 ([#5457](https://github.com/cookiecutter/cookiecutter-django/pull/5457)) - Auto-update pre-commit hooks ([#5458](https://github.com/cookiecutter/cookiecutter-django/pull/5458)) - Update django-cors-headers to 4.5.0 ([#5459](https://github.com/cookiecutter/cookiecutter-django/pull/5459)) ## 2024.10.11 ### Changed - Update README.md broken links ([#5454](https://github.com/cookiecutter/cookiecutter-django/pull/5454)) - wait-for-it as dependency in the run stage ([#5452](https://github.com/cookiecutter/cookiecutter-django/pull/5452)) ### Updated - Auto-update pre-commit hooks ([#5450](https://github.com/cookiecutter/cookiecutter-django/pull/5450)) ## 2024.10.10 ### Updated - Update sentry-sdk to 2.16.0 ([#5444](https://github.com/cookiecutter/cookiecutter-django/pull/5444)) - Bump traefik from 3.1.5 to 3.1.6 ([#5449](https://github.com/cookiecutter/cookiecutter-django/pull/5449)) ## 2024.10.09 ### Updated - Update coverage to 7.6.2 ([#5448](https://github.com/cookiecutter/cookiecutter-django/pull/5448)) ## 2024.10.08 ### Changed - [pre-commit.ci] pre-commit autoupdate ([#5441](https://github.com/cookiecutter/cookiecutter-django/pull/5441)) ### Updated - Update pre-commit to 4.0.1 ([#5445](https://github.com/cookiecutter/cookiecutter-django/pull/5445)) - Bump amazon/aws-cli from 2.18.0 to 2.18.1 in /{{cookiecutter.project_slug}}/compose/production/aws ([#5443](https://github.com/cookiecutter/cookiecutter-django/pull/5443)) - Auto-update pre-commit hooks ([#5442](https://github.com/cookiecutter/cookiecutter-django/pull/5442)) ## 2024.10.07 ### Documentation - Docs: fix Mailgun include in troubleshooting sections ([#5439](https://github.com/cookiecutter/cookiecutter-django/pull/5439)) ### Updated - Update sphinx to 8.0.2 ([#5263](https://github.com/cookiecutter/cookiecutter-django/pull/5263)) - Update pre-commit to 4.0.0 ([#5432](https://github.com/cookiecutter/cookiecutter-django/pull/5432)) - Auto-update pre-commit hooks ([#5433](https://github.com/cookiecutter/cookiecutter-django/pull/5433)) - Update sphinx-rtd-theme to 3.0.0 ([#5437](https://github.com/cookiecutter/cookiecutter-django/pull/5437)) - Bump amazon/aws-cli from 2.17.0 to 2.18.0 in /{{cookiecutter.project_slug}}/compose/production/aws ([#5436](https://github.com/cookiecutter/cookiecutter-django/pull/5436)) ## 2024.10.05 ### Changed - Replace pip with uv for the project files ([#5356](https://github.com/cookiecutter/cookiecutter-django/pull/5356)) - Use wait-for-it in favor of the custom python script when waiting for postgres ([#5327](https://github.com/cookiecutter/cookiecutter-django/pull/5327)) ### Documentation - Spit docs into sections ([#5426](https://github.com/cookiecutter/cookiecutter-django/pull/5426)) ### Updated - Update crispy-bootstrap5 to 2024.10 ([#5430](https://github.com/cookiecutter/cookiecutter-django/pull/5430)) ## 2024.10.04 ### Updated - Update ruff to 0.6.9 ([#5428](https://github.com/cookiecutter/cookiecutter-django/pull/5428)) - Update redis to 5.1.1 ([#5427](https://github.com/cookiecutter/cookiecutter-django/pull/5427)) ## 2024.10.03 ### Updated - Update sphinx-autobuild to 2024.10.3 ([#5420](https://github.com/cookiecutter/cookiecutter-django/pull/5420)) - Bump traefik from 3.1.4 to 3.1.5 ([#5423](https://github.com/cookiecutter/cookiecutter-django/pull/5423)) ## 2024.10.02 ### Updated - Bump python from 3.12.6 to 3.12.7 in docs Docker image ([#5416](https://github.com/cookiecutter/cookiecutter-django/pull/5416)) - Bump python from 3.12.6 to 3.12.7 in local Docker image ([#5415](https://github.com/cookiecutter/cookiecutter-django/pull/5415)) - Bump python from 3.12.6 to 3.12.7 production Docker ([#5414](https://github.com/cookiecutter/cookiecutter-django/pull/5414)) ## 2024.10.01 ### Updated - Update sentry-sdk to 2.15.0 ([#5413](https://github.com/cookiecutter/cookiecutter-django/pull/5413)) ## 2024.09.29 ### Updated - Update psycopg to 3.2.3 ([#5411](https://github.com/cookiecutter/cookiecutter-django/pull/5411)) ## 2024.09.28 ### Updated - Update uvicorn to 0.31.0 ([#5408](https://github.com/cookiecutter/cookiecutter-django/pull/5408)) ## 2024.09.27 ### Updated - Update redis to 5.1.0 ([#5406](https://github.com/cookiecutter/cookiecutter-django/pull/5406)) - Update django-allauth to 65.0.2 ([#5405](https://github.com/cookiecutter/cookiecutter-django/pull/5405)) ## 2024.09.26 ### Updated - Update ruff to 0.6.8 ([#5402](https://github.com/cookiecutter/cookiecutter-django/pull/5402)) ## 2024.09.24 ### Updated - Update django-stubs to 5.1.0 ([#5400](https://github.com/cookiecutter/cookiecutter-django/pull/5400)) ## 2024.09.23 ### Changed - Fix Makefile and make.bat files used for automatic generation of documentation. ([#5347](https://github.com/cookiecutter/cookiecutter-django/pull/5347)) ### Updated - Update django-allauth to 65.0.1 ([#5399](https://github.com/cookiecutter/cookiecutter-django/pull/5399)) - Auto-update pre-commit hooks ([#5392](https://github.com/cookiecutter/cookiecutter-django/pull/5392)) - Update django-allauth to 65.0.0 ([#5393](https://github.com/cookiecutter/cookiecutter-django/pull/5393)) - Update ruff to 0.6.7 ([#5394](https://github.com/cookiecutter/cookiecutter-django/pull/5394)) ## 2024.09.21 ### Updated - Auto-update pre-commit hooks ([#5391](https://github.com/cookiecutter/cookiecutter-django/pull/5391)) ## 2024.09.20 ### Updated - Update sphinx-autobuild to 2024.9.19 ([#5386](https://github.com/cookiecutter/cookiecutter-django/pull/5386)) - Bump traefik from 3.1.3 to 3.1.4 in /{{cookiecutter.project_slug}}/compose/production/traefik ([#5389](https://github.com/cookiecutter/cookiecutter-django/pull/5389)) - Update ruff to 0.6.6 ([#5388](https://github.com/cookiecutter/cookiecutter-django/pull/5388)) - Update tox to 4.20.0 ([#5387](https://github.com/cookiecutter/cookiecutter-django/pull/5387)) ## 2024.09.17 ### Fixed - Set allauth email subject prefix ([#5278](https://github.com/cookiecutter/cookiecutter-django/pull/5278)) ### Documentation - Update postgres plan in Heroku deployment docs ([#5383](https://github.com/cookiecutter/cookiecutter-django/pull/5383)) ### Updated - Update sphinx-autobuild to 2024.9.17 ([#5382](https://github.com/cookiecutter/cookiecutter-django/pull/5382)) - Bump traefik from 3.1.2 to 3.1.3 ([#5380](https://github.com/cookiecutter/cookiecutter-django/pull/5380)) ## 2024.09.16 ### Updated - Update psycopg to 3.2.2 ([#5378](https://github.com/cookiecutter/cookiecutter-django/pull/5378)) ## 2024.09.15 ### Updated - Update ruff to 0.6.5 ([#5373](https://github.com/cookiecutter/cookiecutter-django/pull/5373)) ## 2024.09.11 ### Updated - Update djangorestframework-stubs to 3.15.1 ([#5372](https://github.com/cookiecutter/cookiecutter-django/pull/5372)) - Update django-anymail to 12.0 ([#5366](https://github.com/cookiecutter/cookiecutter-django/pull/5366)) ## 2024.09.10 ### Changed - Add nginx container to dependabot automation ([#5345](https://github.com/cookiecutter/cookiecutter-django/pull/5345)) ### Updated - Update pytest to 8.3.3 ([#5371](https://github.com/cookiecutter/cookiecutter-django/pull/5371)) - Bump postcss-preset-env from 9.6.0 to 10.0.3 ([#5368](https://github.com/cookiecutter/cookiecutter-django/pull/5368)) - Bump concurrently from 8.2.2 to 9.0.0 ([#5363](https://github.com/cookiecutter/cookiecutter-django/pull/5363)) - Bump python to 3.12.6 in local Docker ([#5370](https://github.com/cookiecutter/cookiecutter-django/pull/5370)) - Bump python to 3.12.6 in production Docker ([#5367](https://github.com/cookiecutter/cookiecutter-django/pull/5367)) - Bump python to 3.12.6 in docs Docker image ([#5369](https://github.com/cookiecutter/cookiecutter-django/pull/5369)) ## 2024.09.09 ### Updated - Update sentry-sdk to 2.14.0 ([#5365](https://github.com/cookiecutter/cookiecutter-django/pull/5365)) ## 2024.09.08 ### Changed - Remove "storages" from `INSTALLED_APPS` ([#5361](https://github.com/cookiecutter/cookiecutter-django/pull/5361)) ## 2024.09.07 ### Changed - Fix Requires Python to allow minor versions ([#5360](https://github.com/cookiecutter/cookiecutter-django/pull/5360)) ## 2024.09.06 ### Updated - Update ruff to 0.6.4 ([#5354](https://github.com/cookiecutter/cookiecutter-django/pull/5354)) - Update django-allauth to 64.2.1 ([#5352](https://github.com/cookiecutter/cookiecutter-django/pull/5352)) - Auto-update pre-commit hooks ([#5353](https://github.com/cookiecutter/cookiecutter-django/pull/5353)) ## 2024.09.05 ### Updated - Update django-upgrade to 1.21.0 ([#5348](https://github.com/cookiecutter/cookiecutter-django/pull/5348)) ## 2024.09.04 ### Updated - Update django-model-utils to 5.0.0 ([#5343](https://github.com/cookiecutter/cookiecutter-django/pull/5343)) ## 2024.09.03 ### Fixed - Pin watchdog to 4.0.2 ([#5335](https://github.com/cookiecutter/cookiecutter-django/pull/5335)) ### Updated - Update django to 5.0.9 ([#5341](https://github.com/cookiecutter/cookiecutter-django/pull/5341)) - Update sphinx-autobuild to 2024.9.3 ([#5340](https://github.com/cookiecutter/cookiecutter-django/pull/5340)) ## 2024.09.02 ### Updated - Auto-update pre-commit hooks ([#5334](https://github.com/cookiecutter/cookiecutter-django/pull/5334)) - Update django-allauth to 64.2.0 ([#5337](https://github.com/cookiecutter/cookiecutter-django/pull/5337)) - Update pytest-django to 4.9.0 ([#5338](https://github.com/cookiecutter/cookiecutter-django/pull/5338)) ## 2024.08.30 ### Updated - Update django-webpack-loader to 3.1.1 ([#5336](https://github.com/cookiecutter/cookiecutter-django/pull/5336)) ## 2024.08.29 ### Updated - Update ruff to 0.6.3 ([#5333](https://github.com/cookiecutter/cookiecutter-django/pull/5333)) - Update djlint to 1.35.2 ([#5332](https://github.com/cookiecutter/cookiecutter-django/pull/5332)) - Update djlint pre-commit hook to v1.34.2 ([#5331](https://github.com/cookiecutter/cookiecutter-django/pull/5331)) ## 2024.08.28 ### Updated - Update watchfiles to 0.24.0 ([#5330](https://github.com/cookiecutter/cookiecutter-django/pull/5330)) - Update djlint to 1.34.2 ([#5329](https://github.com/cookiecutter/cookiecutter-django/pull/5329)) ## 2024.08.26 ### Changed - Check DB migrations in GitHub CI ([#5322](https://github.com/cookiecutter/cookiecutter-django/pull/5322)) ### Updated - Update mypy to 1.11.2 ([#5320](https://github.com/cookiecutter/cookiecutter-django/pull/5320)) ## 2024.08.23 ### Updated - Update werkzeug to 3.0.4 ([#5313](https://github.com/cookiecutter/cookiecutter-django/pull/5313)) - Update ruff to 0.6.2 ([#5316](https://github.com/cookiecutter/cookiecutter-django/pull/5316)) ## 2024.08.22 ### Updated - Update django-celery-beat to 2.7.0 ([#5315](https://github.com/cookiecutter/cookiecutter-django/pull/5315)) ## 2024.08.21 ### Changed - Add type hint for UserFactory ([#5312](https://github.com/cookiecutter/cookiecutter-django/pull/5312)) ## 2024.08.20 ### Fixed - Add missing extra_body block in allauth entrance.html ([#5308](https://github.com/cookiecutter/cookiecutter-django/pull/5308)) ### Updated - Bump sass-loader from 14.2.1 to 16.0.1 ([#5309](https://github.com/cookiecutter/cookiecutter-django/pull/5309)) - Bump node from 20 to 22 ([#5039](https://github.com/cookiecutter/cookiecutter-django/pull/5039)) - Bump webpack-merge from 5.10.0 to 6.0.1 ([#5187](https://github.com/cookiecutter/cookiecutter-django/pull/5187)) - Bump css-loader from 6.11.0 to 7.1.2 ([#5089](https://github.com/cookiecutter/cookiecutter-django/pull/5089)) - Bump traefik from 2.11.2 to 3.1.2 ([#5282](https://github.com/cookiecutter/cookiecutter-django/pull/5282)) ## 2024.08.19 ### Updated - Update factory-boy to 3.3.1 ([#5307](https://github.com/cookiecutter/cookiecutter-django/pull/5307)) ## 2024.08.17 ### Updated - Update ruff to 0.6.1 ([#5303](https://github.com/cookiecutter/cookiecutter-django/pull/5303)) ## 2024.08.16 ### Updated - Update django-allauth to 64.1.0 ([#5302](https://github.com/cookiecutter/cookiecutter-django/pull/5302)) ## 2024.08.15 ### Updated - Update ruff to 0.6.0 ([#5300](https://github.com/cookiecutter/cookiecutter-django/pull/5300)) ## 2024.08.13 ### Updated - Update tox to 4.18.0 ([#5299](https://github.com/cookiecutter/cookiecutter-django/pull/5299)) - Update sentry-sdk to 2.13.0 ([#5298](https://github.com/cookiecutter/cookiecutter-django/pull/5298)) - Update uvicorn to 0.30.6 ([#5295](https://github.com/cookiecutter/cookiecutter-django/pull/5295)) ## 2024.08.12 ### Updated - Update gunicorn to 23.0.0 ([#5294](https://github.com/cookiecutter/cookiecutter-django/pull/5294)) ## 2024.08.09 ### Updated - Update Ruff pre-commit hook to v0.5.7 ([#5293](https://github.com/cookiecutter/cookiecutter-django/pull/5293)) ## 2024.08.08 ### Updated - Update ruff to 0.5.7 ([#5291](https://github.com/cookiecutter/cookiecutter-django/pull/5291)) - Bump python from 3.12.4 to 3.12.5 in docs Docker image ([#5287](https://github.com/cookiecutter/cookiecutter-django/pull/5287)) - Bump python from 3.12.4 to 3.12.5 in local Docker image ([#5289](https://github.com/cookiecutter/cookiecutter-django/pull/5289)) - Bump python from 3.12.4 to 3.12.5 in production Docker image ([#5290](https://github.com/cookiecutter/cookiecutter-django/pull/5290)) ## 2024.08.07 ### Updated - Update tox to 4.17.1 ([#5285](https://github.com/cookiecutter/cookiecutter-django/pull/5285)) - Update django-anymail to 11.1 ([#5286](https://github.com/cookiecutter/cookiecutter-django/pull/5286)) ## 2024.08.06 ### Updated - Update django to 5.0.8 ([#5281](https://github.com/cookiecutter/cookiecutter-django/pull/5281)) ## 2024.08.05 ### Documentation - Simplify documentation for https in local development ([#5252](https://github.com/cookiecutter/cookiecutter-django/pull/5252)) - Add Medium story in the Articles section ([#5275](https://github.com/cookiecutter/cookiecutter-django/pull/5275)) ### Updated - Update coverage to 7.6.1 ([#5276](https://github.com/cookiecutter/cookiecutter-django/pull/5276)) - Auto-update pre-commit hooks ([#5277](https://github.com/cookiecutter/cookiecutter-django/pull/5277)) ## 2024.08.04 ### Updated - Update uvicorn to 0.30.5 ([#5272](https://github.com/cookiecutter/cookiecutter-django/pull/5272)) - Update ruff to 0.5.6 ([#5273](https://github.com/cookiecutter/cookiecutter-django/pull/5273)) - Auto-update pre-commit hooks ([#5274](https://github.com/cookiecutter/cookiecutter-django/pull/5274)) ## 2024.07.31 ### Updated - Update uvicorn to 0.30.4 ([#5271](https://github.com/cookiecutter/cookiecutter-django/pull/5271)) - Update mypy to 1.11.1 ([#5270](https://github.com/cookiecutter/cookiecutter-django/pull/5270)) - Update pre-commit to 3.8.0 ([#5257](https://github.com/cookiecutter/cookiecutter-django/pull/5257)) - Update pyupgrade pre-commit hook to v3.17.0 ([#5258](https://github.com/cookiecutter/cookiecutter-django/pull/5258)) - Update redis to 5.0.8 ([#5265](https://github.com/cookiecutter/cookiecutter-django/pull/5265)) - Update django-stubs to 5.0.4 ([#5256](https://github.com/cookiecutter/cookiecutter-django/pull/5256)) - Update mypy to 1.11.0 ([#5231](https://github.com/cookiecutter/cookiecutter-django/pull/5231)) - Update django-allauth to 64.0.0 ([#5269](https://github.com/cookiecutter/cookiecutter-django/pull/5269)) - Update sentry-sdk to 2.12.0 ([#5268](https://github.com/cookiecutter/cookiecutter-django/pull/5268)) ## 2024.07.26 ### Updated - Update ruff to 0.5.5 ([#5250](https://github.com/cookiecutter/cookiecutter-django/pull/5250)) ## 2024.07.25 ### Changed - Upgrade to Django 5.0 ([#5199](https://github.com/cookiecutter/cookiecutter-django/pull/5199)) ### Updated - Update pytest to 8.3.2 ([#5249](https://github.com/cookiecutter/cookiecutter-django/pull/5249)) - Update sentry-sdk to 2.11.0 ([#5247](https://github.com/cookiecutter/cookiecutter-django/pull/5247)) ## 2024.07.24 ### Changed - fix non existent of two scoops of django image ([#5248](https://github.com/cookiecutter/cookiecutter-django/pull/5248)) ## 2024.07.23 ### Changed - Ensure that awscli service has a CMD to fix #5241 ([#5245](https://github.com/cookiecutter/cookiecutter-django/pull/5245)) ### Fixed - Downgrade watchfiles ([#5243](https://github.com/cookiecutter/cookiecutter-django/pull/5243)) ## 2024.07.22 ### Updated - Update django-compressor to 4.5.1 ([#5240](https://github.com/cookiecutter/cookiecutter-django/pull/5240)) ## 2024.07.21 ### Updated - Update ruff to 0.5.4 ([#5237](https://github.com/cookiecutter/cookiecutter-django/pull/5237)) - Update pytest to 8.3.1 ([#5236](https://github.com/cookiecutter/cookiecutter-django/pull/5236)) - Update sphinx to 7.4.7 ([#5235](https://github.com/cookiecutter/cookiecutter-django/pull/5235)) ## 2024.07.20 ### Updated - Update hiredis to 3.0.0 ([#5228](https://github.com/cookiecutter/cookiecutter-django/pull/5228)) - Update uvicorn to 0.30.3 ([#5234](https://github.com/cookiecutter/cookiecutter-django/pull/5234)) - Update django-crispy-forms to 2.3 ([#5229](https://github.com/cookiecutter/cookiecutter-django/pull/5229)) - Auto-update pre-commit hooks ([#5232](https://github.com/cookiecutter/cookiecutter-django/pull/5232)) ## 2024.07.19 ### Changed - Use "ENV key=value" instead of "ENV key value" in Dockerfiles ([#5225](https://github.com/cookiecutter/cookiecutter-django/pull/5225)) ### Updated - Update django-upgrade to 1.20.0 ([#5227](https://github.com/cookiecutter/cookiecutter-django/pull/5227)) - Update ruff to 0.5.3 ([#5224](https://github.com/cookiecutter/cookiecutter-django/pull/5224)) ## 2024.07.18 ### Updated - Update sphinx to 7.4.6 ([#5223](https://github.com/cookiecutter/cookiecutter-django/pull/5223)) ## 2024.07.17 ### Updated - Update sphinx to 7.4.5 ([#5222](https://github.com/cookiecutter/cookiecutter-django/pull/5222)) ## 2024.07.16 ### Fixed - Clear `ENTRYPOINT` in `awscli` image to allow script execution ([#5221](https://github.com/cookiecutter/cookiecutter-django/pull/5221)) ### Updated - Update sphinx to 7.4.4 ([#5218](https://github.com/cookiecutter/cookiecutter-django/pull/5218)) ## 2024.07.15 ### Updated - Update sentry-sdk to 2.10.0 ([#5216](https://github.com/cookiecutter/cookiecutter-django/pull/5216)) - Update sphinx to 7.4.2 ([#5215](https://github.com/cookiecutter/cookiecutter-django/pull/5215)) - Update ruff to 0.5.2 ([#5211](https://github.com/cookiecutter/cookiecutter-django/pull/5211)) - Update sphinx to 7.4.0 ([#5214](https://github.com/cookiecutter/cookiecutter-django/pull/5214)) ## 2024.07.12 ### Updated - Update django-allauth to 0.63.6 ([#5210](https://github.com/cookiecutter/cookiecutter-django/pull/5210)) - Update django-allauth to 0.63.5 ([#5206](https://github.com/cookiecutter/cookiecutter-django/pull/5206)) - Update coverage to 7.6.0 ([#5207](https://github.com/cookiecutter/cookiecutter-django/pull/5207)) - Update django-anymail to 11.0.1 ([#5208](https://github.com/cookiecutter/cookiecutter-django/pull/5208)) ## 2024.07.10 ### Updated - Update django-allauth to 0.63.4 ([#5204](https://github.com/cookiecutter/cookiecutter-django/pull/5204)) - Update django to 4.2.14 ([#5200](https://github.com/cookiecutter/cookiecutter-django/pull/5200)) - Update collectfasta to 3.2.0 ([#5201](https://github.com/cookiecutter/cookiecutter-django/pull/5201)) - Update sentry-sdk to 2.9.0 ([#5202](https://github.com/cookiecutter/cookiecutter-django/pull/5202)) - Update django-debug-toolbar to 4.4.6 ([#5203](https://github.com/cookiecutter/cookiecutter-django/pull/5203)) ## 2024.07.09 ### Changed - Migrate from Collectfast to Collestfasta ([#5172](https://github.com/cookiecutter/cookiecutter-django/pull/5172)) ### Documentation - Fix a typo in the `--all` option of the `makemessages` command ([#5198](https://github.com/cookiecutter/cookiecutter-django/pull/5198)) ### Updated - Update django-storages to 1.14.4 ([#5197](https://github.com/cookiecutter/cookiecutter-django/pull/5197)) ## 2024.07.08 ### Updated - Update ruff to 0.5.1 ([#5190](https://github.com/cookiecutter/cookiecutter-django/pull/5190)) - Update django-debug-toolbar to 4.4.5 ([#5192](https://github.com/cookiecutter/cookiecutter-django/pull/5192)) - Update sentry-sdk to 2.8.0 ([#5195](https://github.com/cookiecutter/cookiecutter-django/pull/5195)) ## 2024.07.05 ### Updated - Update django-debug-toolbar to 4.4.3 ([#5189](https://github.com/cookiecutter/cookiecutter-django/pull/5189)) ## 2024.07.02 ### Updated - Update pillow to 10.4.0 ([#5182](https://github.com/cookiecutter/cookiecutter-django/pull/5182)) ## 2024.07.01 ### Updated - Update ruff to 0.5.0 ([#5181](https://github.com/cookiecutter/cookiecutter-django/pull/5181)) - Update sentry-sdk to 2.7.1 ([#5174](https://github.com/cookiecutter/cookiecutter-django/pull/5174)) - Auto-update pre-commit hooks ([#5175](https://github.com/cookiecutter/cookiecutter-django/pull/5175)) - Update psycopg to 3.2.1 ([#5180](https://github.com/cookiecutter/cookiecutter-django/pull/5180)) ## 2024.06.30 ### Updated - Update django-upgrade to 1.19.0 ([#5171](https://github.com/cookiecutter/cookiecutter-django/pull/5171)) ## 2024.06.26 ### Fixed - Fix keywords case warning in Dockerfile ([#5164](https://github.com/cookiecutter/cookiecutter-django/pull/5164)) ### Updated - Update redis to 5.0.7 ([#5170](https://github.com/cookiecutter/cookiecutter-django/pull/5170)) - Update sentry-sdk to 2.7.0 ([#5169](https://github.com/cookiecutter/cookiecutter-django/pull/5169)) ## 2024.06.24 ### Updated - Update django-anymail to 11.0 ([#5163](https://github.com/cookiecutter/cookiecutter-django/pull/5163)) - Update coverage to 7.5.4 ([#5162](https://github.com/cookiecutter/cookiecutter-django/pull/5162)) ## 2024.06.22 ### Updated - Bump amazon/aws-cli from 2.16.10 to 2.17.0 ([#5161](https://github.com/cookiecutter/cookiecutter-django/pull/5161)) - Auto-update pre-commit hooks ([#5160](https://github.com/cookiecutter/cookiecutter-django/pull/5160)) - Update ruff to 0.4.10 ([#5159](https://github.com/cookiecutter/cookiecutter-django/pull/5159)) ## 2024.06.20 ### Fixed - Remove deprecated docker and python tags from GitLab CI config ([#5158](https://github.com/cookiecutter/cookiecutter-django/pull/5158)) ## 2024.06.19 ### Updated - Update djangorestframework to 3.15.2 ([#5156](https://github.com/cookiecutter/cookiecutter-django/pull/5156)) - Update django-cors-headers to 4.4.0 ([#5154](https://github.com/cookiecutter/cookiecutter-django/pull/5154)) - Update sentry-sdk to 2.6.0 ([#5153](https://github.com/cookiecutter/cookiecutter-django/pull/5153)) - Update whitenoise to 6.7.0 ([#5155](https://github.com/cookiecutter/cookiecutter-django/pull/5155)) ## 2024.06.18 ### Updated - Bump amazon/aws-cli from 2.16.8 to 2.16.10 ([#5149](https://github.com/cookiecutter/cookiecutter-django/pull/5149)) ## 2024.06.17 ### Updated - Update django-compressor to 4.5 ([#5145](https://github.com/cookiecutter/cookiecutter-django/pull/5145)) - Update rcssmin to 1.1.2 ([#4614](https://github.com/cookiecutter/cookiecutter-django/pull/4614)) ## 2024.06.15 ### Changed - Update start-flower in flower to wait until all celery workers are online ([#5012](https://github.com/cookiecutter/cookiecutter-django/pull/5012)) - Enhancing the security of cookies ([#5102](https://github.com/cookiecutter/cookiecutter-django/pull/5102)) ### Updated - Update django-crispy-forms to 2.2 ([#5143](https://github.com/cookiecutter/cookiecutter-django/pull/5143)) - Update sentry-sdk to 2.5.1 ([#5142](https://github.com/cookiecutter/cookiecutter-django/pull/5142)) - Auto-update pre-commit hooks ([#5140](https://github.com/cookiecutter/cookiecutter-django/pull/5140)) - Update django-allauth to 0.63.3 ([#5111](https://github.com/cookiecutter/cookiecutter-django/pull/5111)) ## 2024.06.14 ### Updated - Bump python from 3.12.3-slim-bookworm to 3.12.4-slim-bookworm in /{{cookiecutter.project_slug}}/compose/local/docs ([#5129](https://github.com/cookiecutter/cookiecutter-django/pull/5129)) - Bump python from 3.12.3-slim-bookworm to 3.12.4-slim-bookworm in /{{cookiecutter.project_slug}}/compose/local/django ([#5130](https://github.com/cookiecutter/cookiecutter-django/pull/5130)) - Bump python from 3.12.3-slim-bookworm to 3.12.4-slim-bookworm in /{{cookiecutter.project_slug}}/compose/production/django ([#5132](https://github.com/cookiecutter/cookiecutter-django/pull/5132)) - Bump amazon/aws-cli from 2.16.6 to 2.16.8 in /{{cookiecutter.project_slug}}/compose/production/aws ([#5138](https://github.com/cookiecutter/cookiecutter-django/pull/5138)) - Update ruff to 0.4.9 ([#5139](https://github.com/cookiecutter/cookiecutter-django/pull/5139)) ## 2024.06.13 ### Updated - Update redis to 5.0.6 ([#5137](https://github.com/cookiecutter/cookiecutter-django/pull/5137)) ## 2024.06.12 ### Updated - Bump amazon/aws-cli Docker image from 2.15.58 to 2.16.6 ([#5135](https://github.com/cookiecutter/cookiecutter-django/pull/5135)) ## 2024.06.08 ### Changed - Replace deprecated `uvicorn.workers` with `uvicorn-worker` ([#5110](https://github.com/cookiecutter/cookiecutter-django/pull/5110)) - Change aws-cli docker image to use official amazon image ([#5116](https://github.com/cookiecutter/cookiecutter-django/pull/5116)) ## 2024.06.06 ### Updated - Update sentry-sdk to 2.5.0 ([#5126](https://github.com/cookiecutter/cookiecutter-django/pull/5126)) - Update ruff to 0.4.8 ([#5122](https://github.com/cookiecutter/cookiecutter-django/pull/5122)) - Update redis to 5.0.5 ([#5125](https://github.com/cookiecutter/cookiecutter-django/pull/5125)) ## 2024.06.04 ### Updated - Update pytest to 8.2.2 ([#5120](https://github.com/cookiecutter/cookiecutter-django/pull/5120)) - Update sh to 2.0.7 ([#5114](https://github.com/cookiecutter/cookiecutter-django/pull/5114)) - Update sentry-sdk to 2.4.0 ([#5119](https://github.com/cookiecutter/cookiecutter-django/pull/5119)) ## 2024.06.02 ### Updated - Update uvicorn to 0.30.1 ([#5115](https://github.com/cookiecutter/cookiecutter-django/pull/5115)) ## 2024.06.01 ### Updated - Update ruff to 0.4.7 ([#5112](https://github.com/cookiecutter/cookiecutter-django/pull/5112)) ## 2024.05.30 ### Updated - Update uvicorn to 0.30.0 ([#5101](https://github.com/cookiecutter/cookiecutter-django/pull/5101)) ## 2024.05.29 ### Updated - Update requests to 2.32.3 ([#5108](https://github.com/cookiecutter/cookiecutter-django/pull/5108)) - Update ruff to 0.4.6 ([#5107](https://github.com/cookiecutter/cookiecutter-django/pull/5107)) - Auto-update pre-commit hooks ([#5106](https://github.com/cookiecutter/cookiecutter-django/pull/5106)) - Update coverage to 7.5.3 ([#5104](https://github.com/cookiecutter/cookiecutter-django/pull/5104)) - Update django-upgrade to 1.18.0 ([#5105](https://github.com/cookiecutter/cookiecutter-django/pull/5105)) ## 2024.05.27 ### Changed - Rename SendInBlue ESP to Brevo ([#5094](https://github.com/cookiecutter/cookiecutter-django/pull/5094)) ### Updated - Update django-stubs to 5.0.2 ([#5100](https://github.com/cookiecutter/cookiecutter-django/pull/5100)) - Update watchfiles to 0.22.0 ([#5099](https://github.com/cookiecutter/cookiecutter-django/pull/5099)) - Update django-allauth to 0.63.2 ([#5092](https://github.com/cookiecutter/cookiecutter-django/pull/5092)) - Update coverage to 7.5.2 ([#5095](https://github.com/cookiecutter/cookiecutter-django/pull/5095)) - Update django-debug-toolbar to 4.4.2 ([#5098](https://github.com/cookiecutter/cookiecutter-django/pull/5098)) ## 2024.05.23 ### Updated - Update sentry-sdk to 2.3.1 ([#5091](https://github.com/cookiecutter/cookiecutter-django/pull/5091)) - Auto-update pre-commit hooks ([#5087](https://github.com/cookiecutter/cookiecutter-django/pull/5087)) - Update ruff to 0.4.5 ([#5086](https://github.com/cookiecutter/cookiecutter-django/pull/5086)) ## 2024.05.21 ### Updated - Update sentry-sdk to 2.2.1 ([#5083](https://github.com/cookiecutter/cookiecutter-django/pull/5083)) ## 2024.05.20 ### Fixed - Fix PyCharm Run Configurations After local.yml Rename ([#5080](https://github.com/cookiecutter/cookiecutter-django/pull/5080)) ### Updated - Update pytest to 8.2.1 ([#5079](https://github.com/cookiecutter/cookiecutter-django/pull/5079)) ## 2024.05.18 ### Fixed - Fix redirect error when forcing allauth login in admin site ([#5078](https://github.com/cookiecutter/cookiecutter-django/pull/5078)) ## 2024.05.17 ### Updated - Update django-allauth to 0.63.1 ([#5076](https://github.com/cookiecutter/cookiecutter-django/pull/5076)) ## 2024.05.16 ### Documentation - Update Two scoops of Django book link & image ([#5073](https://github.com/cookiecutter/cookiecutter-django/pull/5073)) ### Updated - Update sentry-sdk to 2.2.0 ([#5074](https://github.com/cookiecutter/cookiecutter-django/pull/5074)) - Update django-allauth to 0.63.0 ([#5070](https://github.com/cookiecutter/cookiecutter-django/pull/5070)) ## 2024.05.15 ### Fixed - Disable DDT profiling panel ([#5069](https://github.com/cookiecutter/cookiecutter-django/pull/5069)) ## 2024.05.13 ### Changed - Rename docker compose files to include 'docker-compose' ([#4995](https://github.com/cookiecutter/cookiecutter-django/pull/4995)) - Remove obsolete `version` element from docker compose files ([#5059](https://github.com/cookiecutter/cookiecutter-django/pull/5059)) - Add Redis persistent storage when using celery ([#5063](https://github.com/cookiecutter/cookiecutter-django/pull/5063)) ### Fixed - Add noqa to ignore ruff false positive ([#5068](https://github.com/cookiecutter/cookiecutter-django/pull/5068)) - Fix staticfile settings with cloud provider and whitenoise ([#5057](https://github.com/cookiecutter/cookiecutter-django/pull/5057)) ### Updated - Update djangorestframework-stubs to 3.15.0 ([#5041](https://github.com/cookiecutter/cookiecutter-django/pull/5041)) - Update django-stubs to 5.0.0 ([#5040](https://github.com/cookiecutter/cookiecutter-django/pull/5040)) - Update mypy to 1.10.0 ([#5022](https://github.com/cookiecutter/cookiecutter-django/pull/5022)) - Update werkzeug to 3.0.3 ([#5050](https://github.com/cookiecutter/cookiecutter-django/pull/5050)) ## 2024.05.11 ### Updated - Update pre-commit to 3.7.1 ([#5066](https://github.com/cookiecutter/cookiecutter-django/pull/5066)) - Auto-update pre-commit hooks ([#5067](https://github.com/cookiecutter/cookiecutter-django/pull/5067)) ## 2024.05.10 ### Updated - Update psycopg to 3.1.19 ([#5064](https://github.com/cookiecutter/cookiecutter-django/pull/5064)) - Update django-upgrade to 1.17.0 ([#5065](https://github.com/cookiecutter/cookiecutter-django/pull/5065)) - Auto-update pre-commit hooks ([#5062](https://github.com/cookiecutter/cookiecutter-django/pull/5062)) - Update ruff to 0.4.4 ([#5061](https://github.com/cookiecutter/cookiecutter-django/pull/5061)) ## 2024.05.07 ### Updated - Update django to 4.2.13 ([#5058](https://github.com/cookiecutter/cookiecutter-django/pull/5058)) ## 2024.05.06 ### Fixed - Fix nginx image name in production.yml ([#5053](https://github.com/cookiecutter/cookiecutter-django/pull/5053)) ### Updated - Update django-model-utils to 4.5.1 ([#5044](https://github.com/cookiecutter/cookiecutter-django/pull/5044)) - Update django to 4.2.12 ([#5056](https://github.com/cookiecutter/cookiecutter-django/pull/5056)) - Update sentry-sdk to 2.1.1 ([#5055](https://github.com/cookiecutter/cookiecutter-django/pull/5055)) - Update ruff to 0.4.3 ([#5049](https://github.com/cookiecutter/cookiecutter-django/pull/5049)) ## 2024.05.05 ### Updated - Auto-update pre-commit hooks ([#5046](https://github.com/cookiecutter/cookiecutter-django/pull/5046)) - Update django-storages to 1.14.3 ([#5047](https://github.com/cookiecutter/cookiecutter-django/pull/5047)) - Update coverage to 7.5.1 ([#5048](https://github.com/cookiecutter/cookiecutter-django/pull/5048)) ## 2024.04.28 ### Updated - Update pytest to 8.2.0 ([#5034](https://github.com/cookiecutter/cookiecutter-django/pull/5034)) ## 2024.04.27 ### Updated - Update sentry-sdk to 2.0.1 ([#5030](https://github.com/cookiecutter/cookiecutter-django/pull/5030)) ## 2024.04.26 ### Updated - Auto-update pre-commit hooks ([#5029](https://github.com/cookiecutter/cookiecutter-django/pull/5029)) - Update ruff to 0.4.2 ([#5028](https://github.com/cookiecutter/cookiecutter-django/pull/5028)) ## 2024.04.25 ### Updated - Update coverage to 7.5.0 ([#5025](https://github.com/cookiecutter/cookiecutter-django/pull/5025)) - Bump cssnano from 6.1.2 to 7.0.0 ([#5024](https://github.com/cookiecutter/cookiecutter-django/pull/5024)) - Auto-update pre-commit hooks ([#5023](https://github.com/cookiecutter/cookiecutter-django/pull/5023)) ## 2024.04.24 ### Changed - Disable UP038 Ruff rule to avoid introducing slower code ([#5020](https://github.com/cookiecutter/cookiecutter-django/pull/5020)) ### Updated - Update django-allauth to 0.62.1 ([#5021](https://github.com/cookiecutter/cookiecutter-django/pull/5021)) ## 2024.04.23 ### Changed - Update link to djlint on pyproject.toml ([#5019](https://github.com/cookiecutter/cookiecutter-django/pull/5019)) ### Updated - Update redis to 5.0.4 ([#5018](https://github.com/cookiecutter/cookiecutter-django/pull/5018)) - Update django-allauth to 0.62.0 ([#5016](https://github.com/cookiecutter/cookiecutter-django/pull/5016)) ## 2024.04.22 ### Fixed - Fix broken link for sphinx-doc in generated docs ([#5015](https://github.com/cookiecutter/cookiecutter-django/pull/5015)) ## 2024.04.20 ### Updated - Auto-update pre-commit hooks ([#5014](https://github.com/cookiecutter/cookiecutter-django/pull/5014)) - Update pytest-xdist to 3.6.0 ([#5013](https://github.com/cookiecutter/cookiecutter-django/pull/5013)) ## 2024.04.19 ### Updated - Update ruff to 0.4.1 ([#5011](https://github.com/cookiecutter/cookiecutter-django/pull/5011)) - Update ruff to 0.4.0 ([#5007](https://github.com/cookiecutter/cookiecutter-django/pull/5007)) - Auto-update pre-commit hooks ([#5008](https://github.com/cookiecutter/cookiecutter-django/pull/5008)) - Update sphinx to 7.3.7 ([#5010](https://github.com/cookiecutter/cookiecutter-django/pull/5010)) ## 2024.04.18 ### Updated - Update celery to 5.4.0 ([#5005](https://github.com/cookiecutter/cookiecutter-django/pull/5005)) - Update sphinx to 7.3.6 ([#5004](https://github.com/cookiecutter/cookiecutter-django/pull/5004)) ## 2024.04.17 ### Updated - Update sphinx to 7.3.5 ([#5003](https://github.com/cookiecutter/cookiecutter-django/pull/5003)) - Update gunicorn to 22.0.0 ([#5001](https://github.com/cookiecutter/cookiecutter-django/pull/5001)) - Update sphinx to 7.3.3 ([#5000](https://github.com/cookiecutter/cookiecutter-django/pull/5000)) ## 2024.04.16 ### Changed - Add a prefix setting so that swagger tags are generated in a readable way ([#4975](https://github.com/cookiecutter/cookiecutter-django/pull/4975)) ### Fixed - Fix `runserver_plus` hot-reload when under Windows + Docker ([#4971](https://github.com/cookiecutter/cookiecutter-django/pull/4971)) ### Documentation - Update docs for `test_bare.sh` ([#4996](https://github.com/cookiecutter/cookiecutter-django/pull/4996)) ### Updated - Bump traefik from 2.11.0 to 2.11.2 ([#4993](https://github.com/cookiecutter/cookiecutter-django/pull/4993)) - Update sphinx-autobuild to 2024.4.16 ([#4999](https://github.com/cookiecutter/cookiecutter-django/pull/4999)) - Update sphinx-autobuild to 2024.4.13 ([#4991](https://github.com/cookiecutter/cookiecutter-django/pull/4991)) - Update sentry-sdk to 1.45.0 ([#4982](https://github.com/cookiecutter/cookiecutter-django/pull/4982)) - Update ruff to 0.3.7 ([#4989](https://github.com/cookiecutter/cookiecutter-django/pull/4989)) - Auto-update pre-commit hooks ([#4988](https://github.com/cookiecutter/cookiecutter-django/pull/4988)) ## 2024.04.10 ### Updated - Bump python from 3.12.2 to 3.12.3 in docs ([#4979](https://github.com/cookiecutter/cookiecutter-django/pull/4979)) - Bump python from 3.12.2 to 3.12.3 in local ([#4981](https://github.com/cookiecutter/cookiecutter-django/pull/4981)) - Bump python from 3.12.2 to 3.12.3 in production ([#4980](https://github.com/cookiecutter/cookiecutter-django/pull/4980)) ## 2024.04.09 ### Documentation - Fix start command for docs ([#4978](https://github.com/cookiecutter/cookiecutter-django/pull/4978)) ## 2024.04.07 ### Updated - Auto-update pre-commit hooks ([#4974](https://github.com/cookiecutter/cookiecutter-django/pull/4974)) ## 2024.04.06 ### Fixed - Fix syntax error in GitHub CI workflow ([#4972](https://github.com/cookiecutter/cookiecutter-django/pull/4972)) ## 2024.04.05 ### Updated - Update django-webpack-loader to 3.1.0 ([#4965](https://github.com/cookiecutter/cookiecutter-django/pull/4965)) ## 2024.04.03 ### Changed - Update GH actions to resolve deprecation warnings ([#4964](https://github.com/cookiecutter/cookiecutter-django/pull/4964)) ### Updated - Update sentry-sdk to 1.44.1 ([#4963](https://github.com/cookiecutter/cookiecutter-django/pull/4963)) ## 2024.04.02 ### Changed - Change pytest import mode to importlib ([#4950](https://github.com/cookiecutter/cookiecutter-django/pull/4950)) - Use main over master for branch name in deployment-on-heroku instruction ([#4954](https://github.com/cookiecutter/cookiecutter-django/pull/4954)) - change obsolete docker image "docker/compose:1.29.2" to "docker:25.0" ([#4961](https://github.com/cookiecutter/cookiecutter-django/pull/4961)) ### Updated - Update sentry-sdk to 1.44.0 ([#4948](https://github.com/cookiecutter/cookiecutter-django/pull/4948)) - Update ruff to 0.3.5 ([#4955](https://github.com/cookiecutter/cookiecutter-django/pull/4955)) - Update gitpython to 3.1.43 ([#4951](https://github.com/cookiecutter/cookiecutter-django/pull/4951)) - Update pillow to 10.3.0 ([#4953](https://github.com/cookiecutter/cookiecutter-django/pull/4953)) - Update django-model-utils to 4.5.0 ([#4956](https://github.com/cookiecutter/cookiecutter-django/pull/4956)) - Update drf-spectacular to 0.27.2 ([#4957](https://github.com/cookiecutter/cookiecutter-django/pull/4957)) - Update werkzeug to 3.0.2 ([#4958](https://github.com/cookiecutter/cookiecutter-django/pull/4958)) - Auto-update pre-commit hooks ([#4959](https://github.com/cookiecutter/cookiecutter-django/pull/4959)) ## 2024.03.29 ### Documentation - Add instruction for adding a django app ([#4944](https://github.com/cookiecutter/cookiecutter-django/pull/4944)) ## 2024.03.27 ### Updated - Update pre-commit to 3.7.0 ([#4943](https://github.com/cookiecutter/cookiecutter-django/pull/4943)) - Update djangorestframework to 3.15.1 ([#4941](https://github.com/cookiecutter/cookiecutter-django/pull/4941)) - Update ruff to 0.3.4 ([#4936](https://github.com/cookiecutter/cookiecutter-django/pull/4936)) - Auto-update pre-commit hooks ([#4937](https://github.com/cookiecutter/cookiecutter-django/pull/4937)) ## 2024.03.26 ### Documentation - Update mentions of psycopg in comments ([#4947](https://github.com/cookiecutter/cookiecutter-django/pull/4947)) ## 2024.03.21 ### Changed - Add PostgreSQL 16, remove Postgres 10 and 11 ([#4935](https://github.com/cookiecutter/cookiecutter-django/pull/4935)) ### Updated - Update uvicorn to 0.29.0 ([#4933](https://github.com/cookiecutter/cookiecutter-django/pull/4933)) - Update sentry-sdk to 1.43.0 ([#4934](https://github.com/cookiecutter/cookiecutter-django/pull/4934)) ## 2024.03.19 ### Changed - Add documentation to upgrade Postgres in Docker environment. Fix: #461 ([#4898](https://github.com/cookiecutter/cookiecutter-django/pull/4898)) - Upgrade Python to version 3.12 ([#4930](https://github.com/cookiecutter/cookiecutter-django/pull/4930)) ## 2024.03.18 ### Changed - Split the docs from local.yml and build the service in CI ([#4909](https://github.com/cookiecutter/cookiecutter-django/pull/4909)) ### Updated - Update django-anymail to 10.3 ([#4919](https://github.com/cookiecutter/cookiecutter-django/pull/4919)) - Update sentry-sdk to 1.42.0 ([#4921](https://github.com/cookiecutter/cookiecutter-django/pull/4921)) - Update coverage to 7.4.4 ([#4926](https://github.com/cookiecutter/cookiecutter-django/pull/4926)) - Update ruff to 0.3.3 ([#4927](https://github.com/cookiecutter/cookiecutter-django/pull/4927)) - Auto-update pre-commit hooks ([#4928](https://github.com/cookiecutter/cookiecutter-django/pull/4928)) ## 2024.03.17 ### Updated - Update djangorestframework to 3.15.0 ([#4929](https://github.com/cookiecutter/cookiecutter-django/pull/4929)) ## 2024.03.10 ### Updated - Auto-update pre-commit hooks ([#4912](https://github.com/cookiecutter/cookiecutter-django/pull/4912)) - Update ruff to 0.3.2 ([#4911](https://github.com/cookiecutter/cookiecutter-django/pull/4911)) - Update uvicorn to 0.28.0 ([#4913](https://github.com/cookiecutter/cookiecutter-django/pull/4913)) - Update redis to 5.0.3 ([#4916](https://github.com/cookiecutter/cookiecutter-django/pull/4916)) - Update pytest to 8.1.1 ([#4914](https://github.com/cookiecutter/cookiecutter-django/pull/4914)) ## 2024.03.07 ### Updated - Auto-update pre-commit hooks ([#4907](https://github.com/cookiecutter/cookiecutter-django/pull/4907)) - Update sentry-sdk to 1.41.0 ([#4908](https://github.com/cookiecutter/cookiecutter-django/pull/4908)) ## 2024.03.06 ### Fixed - Fix fully qualified docker images ([#4905](https://github.com/cookiecutter/cookiecutter-django/pull/4905)) ## 2024.03.04 ### Updated - Update pytest to 8.1.0 ([#4900](https://github.com/cookiecutter/cookiecutter-django/pull/4900)) - Update django to 4.2.11 ([#4901](https://github.com/cookiecutter/cookiecutter-django/pull/4901)) ## 2024.03.03 ### Updated - Update django-celery-beat to 2.6.0 ([#4899](https://github.com/cookiecutter/cookiecutter-django/pull/4899)) ## 2024.03.01 ### Changed - Add a maintainer guide to the docs ([#4884](https://github.com/cookiecutter/cookiecutter-django/pull/4884)) ### Updated - Auto-update pre-commit hooks ([#4897](https://github.com/cookiecutter/cookiecutter-django/pull/4897)) - Update ruff to 0.3.0 ([#4896](https://github.com/cookiecutter/cookiecutter-django/pull/4896)) ## 2024.02.28 ### Fixed - Fix invalid HTML in django-allauth field element template ([#4894](https://github.com/cookiecutter/cookiecutter-django/pull/4894)) - Fix permissions for media files when served by nginx ([#4889](https://github.com/cookiecutter/cookiecutter-django/pull/4889)) ### Documentation - Fix broken "Two scoops of django" link in FAQ ([#4892](https://github.com/cookiecutter/cookiecutter-django/pull/4892)) ### Updated - Update redis to 5.0.2 ([#4895](https://github.com/cookiecutter/cookiecutter-django/pull/4895)) - Update sentry-sdk to 1.40.6 ([#4893](https://github.com/cookiecutter/cookiecutter-django/pull/4893)) ## 2024.02.26 ### Changed - Allauth elements & MFA ([#4843](https://github.com/cookiecutter/cookiecutter-django/pull/4843)) ### Updated - Update pytest to 8.0.2 ([#4890](https://github.com/cookiecutter/cookiecutter-django/pull/4890)) - Update crispy-bootstrap5 to 2024.2 ([#4891](https://github.com/cookiecutter/cookiecutter-django/pull/4891)) ## 2024.02.24 ### Updated - Update coverage to 7.4.3 ([#4888](https://github.com/cookiecutter/cookiecutter-django/pull/4888)) ## 2024.02.23 ### Changed - Switch to local imports within app ([#4883](https://github.com/cookiecutter/cookiecutter-django/pull/4883)) - Install ruff extension in `devcontainer.json` ([#4887](https://github.com/cookiecutter/cookiecutter-django/pull/4887)) ### Updated - Bump webpack-dev-server to 5.0.2 ([#4875](https://github.com/cookiecutter/cookiecutter-django/pull/4875)) ## 2024.02.21 ### Changed - Switch to `celery.shared_task` to define tasks ([#4881](https://github.com/cookiecutter/cookiecutter-django/pull/4881)) - Replace usages of `get_user_model` by importing model directly ([#4879](https://github.com/cookiecutter/cookiecutter-django/pull/4879)) ### Updated - Auto-update pre-commit hooks ([#4873](https://github.com/cookiecutter/cookiecutter-django/pull/4873)) - Update pre-commit to 3.6.2 ([#4874](https://github.com/cookiecutter/cookiecutter-django/pull/4874)) - Update ruff to 0.2.2 ([#4871](https://github.com/cookiecutter/cookiecutter-django/pull/4871)) ## 2024.02.19 ### Updated - Update sentry-sdk to 1.40.5 ([#4876](https://github.com/cookiecutter/cookiecutter-django/pull/4876)) ## 2024.02.17 ### Updated - Update pytest to 8.0.1 ([#4870](https://github.com/cookiecutter/cookiecutter-django/pull/4870)) ## 2024.02.16 ### Changed - Speed up GitHub CI for Docker setup ([#4863](https://github.com/cookiecutter/cookiecutter-django/pull/4863)) ### Documentation - Add link to the ruff repository in requirements ([#4866](https://github.com/cookiecutter/cookiecutter-django/pull/4866)) ## 2024.02.13 ### Changed - Ruff linting & formatting ([#4834](https://github.com/cookiecutter/cookiecutter-django/pull/4834)) ### Updated - Update uvicorn to 0.27.1 ([#4848](https://github.com/cookiecutter/cookiecutter-django/pull/4848)) - Update sentry-sdk to 1.40.4 ([#4858](https://github.com/cookiecutter/cookiecutter-django/pull/4858)) - Bump traefik to 2.11.0 ([#4857](https://github.com/cookiecutter/cookiecutter-django/pull/4857)) - Auto-update pre-commit hooks ([#4855](https://github.com/cookiecutter/cookiecutter-django/pull/4855)) - Update black to 24.2.0 ([#4853](https://github.com/cookiecutter/cookiecutter-django/pull/4853)) ## 2024.02.12 ### Updated - Update django-model-utils to 4.4.0 ([#4850](https://github.com/cookiecutter/cookiecutter-django/pull/4850)) - Update pre-commit to 3.6.1 ([#4849](https://github.com/cookiecutter/cookiecutter-django/pull/4849)) - Update django-upgrade to 1.16.0 ([#4851](https://github.com/cookiecutter/cookiecutter-django/pull/4851)) - Auto-update pre-commit hooks ([#4852](https://github.com/cookiecutter/cookiecutter-django/pull/4852)) ## 2024.02.09 ### Updated - Update sentry-sdk to 1.40.3 ([#4847](https://github.com/cookiecutter/cookiecutter-django/pull/4847)) - Update django-allauth to 0.61.1 ([#4846](https://github.com/cookiecutter/cookiecutter-django/pull/4846)) - Update python-slugify to 8.0.4 ([#4844](https://github.com/cookiecutter/cookiecutter-django/pull/4844)) ## 2024.02.08 ### Updated - Bump python to 3.11.8 in compose/local/docs ([#4840](https://github.com/cookiecutter/cookiecutter-django/pull/4840)) - Bump python to 3.11.8 in compose/local/django ([#4841](https://github.com/cookiecutter/cookiecutter-django/pull/4841)) - Bump python to 3.11.8 in compose/production/django ([#4842](https://github.com/cookiecutter/cookiecutter-django/pull/4842)) ## 2024.02.07 ### Changed - Extend docker test with deploy check ([#4838](https://github.com/cookiecutter/cookiecutter-django/pull/4838)) - Generic UserManager ([#4836](https://github.com/cookiecutter/cookiecutter-django/pull/4836)) ### Updated - Update django-allauth to 0.61.0 ([#4839](https://github.com/cookiecutter/cookiecutter-django/pull/4839)) - Bump gulp-postcss to 10.0.0 ([#4835](https://github.com/cookiecutter/cookiecutter-django/pull/4835)) - Update sentry-sdk to 1.40.2 ([#4837](https://github.com/cookiecutter/cookiecutter-django/pull/4837)) - Update django to 4.2.10 ([#4833](https://github.com/cookiecutter/cookiecutter-django/pull/4833)) ## 2024.02.05 ### Updated - Update pytest to 8.0.0 ([#4813](https://github.com/cookiecutter/cookiecutter-django/pull/4813)) - Update pytest-sugar to 1.0.0 ([#4828](https://github.com/cookiecutter/cookiecutter-django/pull/4828)) - Update sphinx-autobuild to 2024.2.4 ([#4830](https://github.com/cookiecutter/cookiecutter-django/pull/4830)) - Update django-debug-toolbar to 4.3.0 ([#4829](https://github.com/cookiecutter/cookiecutter-django/pull/4829)) - Update psycopg to 3.1.18 ([#4831](https://github.com/cookiecutter/cookiecutter-django/pull/4831)) ## 2024.01.31 ### Updated - Update python-slugify to 8.0.3 ([#4826](https://github.com/cookiecutter/cookiecutter-django/pull/4826)) ## 2024.01.30 ### Updated - Update pytest-django to 4.8.0 ([#4823](https://github.com/cookiecutter/cookiecutter-django/pull/4823)) - Update sentry-sdk to 1.40.0 ([#4822](https://github.com/cookiecutter/cookiecutter-django/pull/4822)) - Update uvicorn to 0.27.0.post1 ([#4818](https://github.com/cookiecutter/cookiecutter-django/pull/4818)) ## 2024.01.29 ### Changed - Fix deprecation warning about renaming of `webpack_loader.loader` to `webpack_loader.loaders` ([#4815](https://github.com/cookiecutter/cookiecutter-django/pull/4815)) ### Documentation - Update mention of coverage config file to `pyproject.toml` in documentation ([#4816](https://github.com/cookiecutter/cookiecutter-django/pull/4816)) ### Updated - Update black to 24.1.1 ([#4814](https://github.com/cookiecutter/cookiecutter-django/pull/4814)) - Auto-update pre-commit hooks ([#4817](https://github.com/cookiecutter/cookiecutter-django/pull/4817)) ## 2024.01.27 ### Changed - Do not show webpack devserver overlay for warnings ([#4809](https://github.com/cookiecutter/cookiecutter-django/pull/4809)) ### Updated - Update python-slugify to 8.0.2 ([#4805](https://github.com/cookiecutter/cookiecutter-django/pull/4805)) - Update coverage to 7.4.1 ([#4807](https://github.com/cookiecutter/cookiecutter-django/pull/4807)) ## 2024.01.26 ### Updated - Update black to 24.1.0 ([#4806](https://github.com/cookiecutter/cookiecutter-django/pull/4806)) ## 2024.01.25 ### Changed - Replace custom static & media storage classes by passing options in the `STORAGES` setting ([#4803](https://github.com/cookiecutter/cookiecutter-django/pull/4803)) - Add registry to Docker images names ([#4804](https://github.com/cookiecutter/cookiecutter-django/pull/4804)) ## 2024.01.24 ### Changed - Migrate to the unified `STORAGES` setting added in Django 4.2 ([#4477](https://github.com/cookiecutter/cookiecutter-django/pull/4477)) ### Updated - Update uvicorn to 0.27.0 ([#4800](https://github.com/cookiecutter/cookiecutter-django/pull/4800)) ## 2024.01.21 ### Documentation - Update traefik doc links ([#4798](https://github.com/cookiecutter/cookiecutter-django/pull/4798)) ### Updated - Bump browser-sync from 2.29.3 to 3.0.2 in /{{cookiecutter.project_slug}} ([#4765](https://github.com/cookiecutter/cookiecutter-django/pull/4765)) ## 2024.01.19 ### Updated - Update drf-spectacular to 0.27.1 ([#4797](https://github.com/cookiecutter/cookiecutter-django/pull/4797)) ## 2024.01.17 ### Changed - Add a test to cover `DJANGO_ADMIN_FORCE_ALLAUTH` ([#4790](https://github.com/cookiecutter/cookiecutter-django/pull/4790)) ### Updated - Bump webpack-bundle-tracker to 3.0.1 ([#4781](https://github.com/cookiecutter/cookiecutter-django/pull/4781)) - Update django-webpack-loader to 3.0.1 ([#4793](https://github.com/cookiecutter/cookiecutter-django/pull/4793)) - Bump postcss-loader to 8.0.0 ([#4795](https://github.com/cookiecutter/cookiecutter-django/pull/4795)) - Update uvicorn to 0.26.0 ([#4794](https://github.com/cookiecutter/cookiecutter-django/pull/4794)) ## 2024.01.16 ### Updated - Bump sass-loader from 13.3.3 to 14.0.0 in /{{cookiecutter.project_slug}} ([#4791](https://github.com/cookiecutter/cookiecutter-django/pull/4791)) ## 2024.01.15 ### Documentation - Update allauth documentation links ([#4786](https://github.com/cookiecutter/cookiecutter-django/pull/4786)) ### Updated - Update django-allauth to 0.60.1 ([#4787](https://github.com/cookiecutter/cookiecutter-django/pull/4787)) ## 2024.01.11 ### Updated - Update jinja2 to 3.1.3 ([#4784](https://github.com/cookiecutter/cookiecutter-django/pull/4784)) ## 2024.01.10 ### Updated - Update sentry-sdk to 1.39.2 ([#4782](https://github.com/cookiecutter/cookiecutter-django/pull/4782)) ## 2024.01.09 ### Documentation - Update allauth settings documentation links ([#4769](https://github.com/cookiecutter/cookiecutter-django/pull/4769)) ### Updated - Update django-allauth to 0.60.0 ([#4776](https://github.com/cookiecutter/cookiecutter-django/pull/4776)) - Update psycopg to 3.1.17 ([#4777](https://github.com/cookiecutter/cookiecutter-django/pull/4777)) ## 2024.01.05 ### Updated - Auto-update pre-commit hooks ([#4774](https://github.com/cookiecutter/cookiecutter-django/pull/4774)) - Update flake8 to 7.0.0 ([#4775](https://github.com/cookiecutter/cookiecutter-django/pull/4775)) ## 2024.01.02 ### Updated - Update psycopg to 3.1.16 ([#4753](https://github.com/cookiecutter/cookiecutter-django/pull/4753)) - Update djlint to 1.34.1 ([#4773](https://github.com/cookiecutter/cookiecutter-django/pull/4773)) - Update uvicorn to 0.25.0 ([#4760](https://github.com/cookiecutter/cookiecutter-django/pull/4760)) - Auto-update pre-commit hooks ([#4749](https://github.com/cookiecutter/cookiecutter-django/pull/4749)) - Update black to 23.12.1 ([#4772](https://github.com/cookiecutter/cookiecutter-django/pull/4772)) - Update pillow to 10.2.0 ([#4770](https://github.com/cookiecutter/cookiecutter-django/pull/4770)) - Update django to 4.2.9 ([#4771](https://github.com/cookiecutter/cookiecutter-django/pull/4771)) - Update pytest to 7.4.4 ([#4767](https://github.com/cookiecutter/cookiecutter-django/pull/4767)) - Update coverage to 7.4.0 ([#4764](https://github.com/cookiecutter/cookiecutter-django/pull/4764)) ## 2023.12.19 ### Changed - Upgrade debian to 12 bookworm ([#4745](https://github.com/cookiecutter/cookiecutter-django/pull/4745)) ### Updated - Update hiredis to 2.3.2 ([#4750](https://github.com/cookiecutter/cookiecutter-django/pull/4750)) ## 2023.12.15 ### Updated - Update coverage to 7.3.3 ([#4748](https://github.com/cookiecutter/cookiecutter-django/pull/4748)) - Update psycopg to 3.1.15 ([#4747](https://github.com/cookiecutter/cookiecutter-django/pull/4747)) - Update sentry-sdk to 1.39.1 ([#4746](https://github.com/cookiecutter/cookiecutter-django/pull/4746)) - Auto-update pre-commit hooks ([#4743](https://github.com/cookiecutter/cookiecutter-django/pull/4743)) ## 2023.12.13 ### Updated - Auto-update pre-commit hooks ([#4740](https://github.com/cookiecutter/cookiecutter-django/pull/4740)) ## 2023.12.12 ### Updated - Update django-allauth to 0.59.0 ([#4739](https://github.com/cookiecutter/cookiecutter-django/pull/4739)) - Update sentry-sdk to 1.39.0 ([#4738](https://github.com/cookiecutter/cookiecutter-django/pull/4738)) - Update black to 23.12.0 ([#4737](https://github.com/cookiecutter/cookiecutter-django/pull/4737)) - Auto-update pre-commit hooks ([#4736](https://github.com/cookiecutter/cookiecutter-django/pull/4736)) - Update drf-spectacular to 0.27.0 ([#4735](https://github.com/cookiecutter/cookiecutter-django/pull/4735)) ## 2023.12.11 ### Updated - Auto-update pre-commit hooks ([#4730](https://github.com/cookiecutter/cookiecutter-django/pull/4730)) ## 2023.12.10 ### Updated - Update pre-commit to 3.6.0 ([#4728](https://github.com/cookiecutter/cookiecutter-django/pull/4728)) - Auto-update pre-commit hooks ([#4729](https://github.com/cookiecutter/cookiecutter-django/pull/4729)) ## 2023.12.09 ### Changed - Add missing __init__.py file to api module ([#4726](https://github.com/cookiecutter/cookiecutter-django/pull/4726)) ## 2023.12.07 ### Updated - Bump actions/setup-python from 4 to 5 ([#4723](https://github.com/cookiecutter/cookiecutter-django/pull/4723)) - Auto-update pre-commit hooks ([#4709](https://github.com/cookiecutter/cookiecutter-django/pull/4709)) - Bump traefik from 2.10.6 to 2.10.7 ([#4722](https://github.com/cookiecutter/cookiecutter-django/pull/4722)) ## 2023.12.06 ### Updated - Bump python from 3.11.6 to 3.11.7 ([#4719](https://github.com/cookiecutter/cookiecutter-django/pull/4719)) - Update mypy to 1.7.1, django-stubs to 4.2.7 and djangorestframework-stubs to 3.14.5 ([#4694](https://github.com/cookiecutter/cookiecutter-django/pull/4694)) ## 2023.12.04 ### Updated - Update django to 4.2.8 ([#4713](https://github.com/cookiecutter/cookiecutter-django/pull/4713)) - Bump node from 18 to 20 ([#4283](https://github.com/cookiecutter/cookiecutter-django/pull/4283)) - Update psycopg to 3.1.14 ([#4711](https://github.com/cookiecutter/cookiecutter-django/pull/4711)) ## 2023.12.02 ### Updated - Update mailpit to latest ([#4710](https://github.com/cookiecutter/cookiecutter-django/pull/4710)) ## 2023.11.30 ### Fixed - Removed tmp mount in devcontainer.json. Fix #4686 ([#4708](https://github.com/cookiecutter/cookiecutter-django/pull/4708)) ### Updated - Bump traefik from 2.10.5 to 2.10.6 ([#4706](https://github.com/cookiecutter/cookiecutter-django/pull/4706)) ## 2023.11.29 ### Updated - Update sentry-sdk to 1.38.0 ([#4705](https://github.com/cookiecutter/cookiecutter-django/pull/4705)) ## 2023.11.28 ### Fixed - Excludes devcontainer.json from the pre-commit ([#4702](https://github.com/cookiecutter/cookiecutter-django/pull/4702)) ### Updated - Update sphinx-rtd-theme to 2.0.0 ([#4700](https://github.com/cookiecutter/cookiecutter-django/pull/4700)) ## 2023.11.24 ### Updated - Update sentry-sdk to 1.37.1 ([#4696](https://github.com/cookiecutter/cookiecutter-django/pull/4696)) - Update sentry-sdk to 1.37.0 ([#4695](https://github.com/cookiecutter/cookiecutter-django/pull/4695)) ## 2023.11.22 ### Updated - Update celery to 5.3.6 ([#4693](https://github.com/cookiecutter/cookiecutter-django/pull/4693)) ## 2023.11.21 ### Updated - Update sentry-sdk to 1.36.0 ([#4687](https://github.com/cookiecutter/cookiecutter-django/pull/4687)) ## 2023.11.20 ### Fixed - Fix bug with social account adapter name override, in very specific conditions ([#4650](https://github.com/cookiecutter/cookiecutter-django/pull/4650)) ### Updated - Update django-cors-headers to 4.3.1 ([#4684](https://github.com/cookiecutter/cookiecutter-django/pull/4684)) - Update psycopg to 3.1.13 ([#4685](https://github.com/cookiecutter/cookiecutter-django/pull/4685)) ## 2023.11.14 ### Updated - Update sentry-sdk to 1.35.0 ([#4681](https://github.com/cookiecutter/cookiecutter-django/pull/4681)) - Auto-update pre-commit hooks ([#4683](https://github.com/cookiecutter/cookiecutter-django/pull/4683)) ## 2023.11.11 ### Updated - Update celery to 5.3.5 ([#4678](https://github.com/cookiecutter/cookiecutter-django/pull/4678)) ## 2023.11.09 ### Updated - Auto-update pre-commit hooks ([#4673](https://github.com/cookiecutter/cookiecutter-django/pull/4673)) - Update black to 23.11.0 ([#4674](https://github.com/cookiecutter/cookiecutter-django/pull/4674)) ## 2023.11.08 ### Updated - Update pytest-django to 4.7.0 ([#4672](https://github.com/cookiecutter/cookiecutter-django/pull/4672)) ## 2023.11.06 ### Changed - Add `rmbackup` script to remove backups from `postgres/backups`. Fixes: #4663 ([#4664](https://github.com/cookiecutter/cookiecutter-django/pull/4664)) ### Updated - Update django-allauth to 0.58.2 ([#4667](https://github.com/cookiecutter/cookiecutter-django/pull/4667)) - Update uvicorn to 0.24.0.post1 ([#4666](https://github.com/cookiecutter/cookiecutter-django/pull/4666)) ## 2023.11.04 ### Updated - Update uvicorn to 0.24.0 ([#4665](https://github.com/cookiecutter/cookiecutter-django/pull/4665)) ## 2023.11.03 ### Updated - Update flake8-isort to 6.1.1 ([#4662](https://github.com/cookiecutter/cookiecutter-django/pull/4662)) ## 2023.11.02 ### Updated - Update sentry-sdk to 1.34.0 ([#4660](https://github.com/cookiecutter/cookiecutter-django/pull/4660)) ## 2023.11.01 ### Updated - Update django to 4.2.7 ([#4658](https://github.com/cookiecutter/cookiecutter-django/pull/4658)) - Update django-stubs to 4.2.6 ([#4657](https://github.com/cookiecutter/cookiecutter-django/pull/4657)) ## 2023.10.31 ### Updated - Update pytest-django to 4.6.0 ([#4656](https://github.com/cookiecutter/cookiecutter-django/pull/4656)) - Update pytest to 7.4.3 ([#4654](https://github.com/cookiecutter/cookiecutter-django/pull/4654)) - Update werkzeug to 3.0.1 ([#4655](https://github.com/cookiecutter/cookiecutter-django/pull/4655)) - Update sentry-sdk to 1.33.1 ([#4653](https://github.com/cookiecutter/cookiecutter-django/pull/4653)) - Update sentry-sdk to 1.33.0 ([#4652](https://github.com/cookiecutter/cookiecutter-django/pull/4652)) - Update crispy-bootstrap5 to 2023.10 ([#4651](https://github.com/cookiecutter/cookiecutter-django/pull/4651)) ## 2023.10.26 ### Updated - Update django-anymail to 10.2 ([#4645](https://github.com/cookiecutter/cookiecutter-django/pull/4645)) ## 2023.10.24 ### Updated - Update black to 23.10.1 ([#4639](https://github.com/cookiecutter/cookiecutter-django/pull/4639)) - Auto-update pre-commit hooks ([#4641](https://github.com/cookiecutter/cookiecutter-django/pull/4641)) ## 2023.10.23 ### Updated - Update pylint-django to 2.5.5 ([#4638](https://github.com/cookiecutter/cookiecutter-django/pull/4638)) ## 2023.10.19 ### Updated - Update mypy to 1.6.1 ([#4634](https://github.com/cookiecutter/cookiecutter-django/pull/4634)) - Update djangorestframework-stubs to 3.14.4 ([#4637](https://github.com/cookiecutter/cookiecutter-django/pull/4637)) - Update django-stubs to 4.2.5 ([#4636](https://github.com/cookiecutter/cookiecutter-django/pull/4636)) ## 2023.10.17 ### Updated - Auto-update pre-commit hooks ([#4633](https://github.com/cookiecutter/cookiecutter-django/pull/4633)) - Update black to 23.10.0 ([#4632](https://github.com/cookiecutter/cookiecutter-django/pull/4632)) - Update pillow to 10.1.0 ([#4630](https://github.com/cookiecutter/cookiecutter-django/pull/4630)) - Update django-crispy-forms to 2.1 ([#4629](https://github.com/cookiecutter/cookiecutter-django/pull/4629)) ## 2023.10.13 ### Updated - Update pre-commit to 3.5.0 ([#4628](https://github.com/cookiecutter/cookiecutter-django/pull/4628)) - Update watchfiles to 0.21.0 ([#4627](https://github.com/cookiecutter/cookiecutter-django/pull/4627)) ## 2023.10.12 ### Updated - Update django-cors-headers to 4.3.0 ([#4625](https://github.com/cookiecutter/cookiecutter-django/pull/4625)) - Update whitenoise to 6.6.0 ([#4624](https://github.com/cookiecutter/cookiecutter-django/pull/4624)) - Update sentry-sdk to 1.32.0 ([#4623](https://github.com/cookiecutter/cookiecutter-django/pull/4623)) - Bump traefik from 2.10.4 to 2.10.5 ([#4626](https://github.com/cookiecutter/cookiecutter-django/pull/4626)) ## 2023.10.09 ### Updated - Bump stefanzweifel/git-auto-commit-action from 4.16.0 to 5.0.0 ([#4621](https://github.com/cookiecutter/cookiecutter-django/pull/4621)) - Update django-storages to 1.14.2 ([#4620](https://github.com/cookiecutter/cookiecutter-django/pull/4620)) ## 2023.10.08 ### Updated - Auto-update pre-commit hooks ([#4619](https://github.com/cookiecutter/cookiecutter-django/pull/4619)) ## 2023.10.05 ### Updated - Update djangorestframework-stubs to 3.14.3 ([#4618](https://github.com/cookiecutter/cookiecutter-django/pull/4618)) - Update django-stubs to 4.2.4 ([#4566](https://github.com/cookiecutter/cookiecutter-django/pull/4566)) - Update mypy to 1.5.1 ([#4568](https://github.com/cookiecutter/cookiecutter-django/pull/4568)) ## 2023.10.04 ### Updated - Update django to 4.2.6 ([#4617](https://github.com/cookiecutter/cookiecutter-django/pull/4617)) - Update coverage to 7.3.2 ([#4616](https://github.com/cookiecutter/cookiecutter-django/pull/4616)) - Update werkzeug to 3.0.0 ([#4608](https://github.com/cookiecutter/cookiecutter-django/pull/4608)) - Update django-redis to 5.4.0 ([#4609](https://github.com/cookiecutter/cookiecutter-django/pull/4609)) - Bump docs Python docker image from 3.11.5 to 3.11.6 ([#4615](https://github.com/cookiecutter/cookiecutter-django/pull/4615)) ## 2023.10.03 ### Changed - [pre-commit.ci] pre-commit autoupdate ([#4613](https://github.com/cookiecutter/cookiecutter-django/pull/4613)) ### Updated - Bump prod Python docker image from 3.11.5 to 3.11.6 ([#4611](https://github.com/cookiecutter/cookiecutter-django/pull/4611)) - Bump local Python docker image from 3.11.5 to 3.11.6 ([#4612](https://github.com/cookiecutter/cookiecutter-django/pull/4612)) - Auto-update pre-commit hooks ([#4610](https://github.com/cookiecutter/cookiecutter-django/pull/4610)) ## 2023.09.29 ### Updated - Update django-storages to 1.14.1 ([#4604](https://github.com/cookiecutter/cookiecutter-django/pull/4604)) ## 2023.09.28 ### Updated - Update psycopg to 3.1.12 ([#4601](https://github.com/cookiecutter/cookiecutter-django/pull/4601)) ## 2023.09.27 ### Fixed - Fix ownership for /start-flower script in production Dockerfile ([#4603](https://github.com/cookiecutter/cookiecutter-django/pull/4603)) ## 2023.09.26 ### Updated - Update redis to 5.0.1 ([#4600](https://github.com/cookiecutter/cookiecutter-django/pull/4600)) ## 2023.09.25 ### Updated - Update django-upgrade to 1.15.0 ([#4598](https://github.com/cookiecutter/cookiecutter-django/pull/4598)) - Update django-allauth to 0.57.0 ([#4597](https://github.com/cookiecutter/cookiecutter-django/pull/4597)) - Auto-update pre-commit hooks ([#4596](https://github.com/cookiecutter/cookiecutter-django/pull/4596)) ## 2023.09.23 ### Updated - Update psycopg to 3.1.11 ([#4595](https://github.com/cookiecutter/cookiecutter-django/pull/4595)) - Auto-update pre-commit hooks ([#4591](https://github.com/cookiecutter/cookiecutter-django/pull/4591)) - Update drf-spectacular to 0.26.5 ([#4594](https://github.com/cookiecutter/cookiecutter-django/pull/4594)) ## 2023.09.21 ### Updated - Auto-update pre-commit hooks ([#4589](https://github.com/cookiecutter/cookiecutter-django/pull/4589)) - Update djlint to 1.34.0 ([#4590](https://github.com/cookiecutter/cookiecutter-django/pull/4590)) ## 2023.09.19 ### Updated - Auto-update pre-commit hooks ([#4588](https://github.com/cookiecutter/cookiecutter-django/pull/4588)) - Update djlint to 1.33.0 ([#4587](https://github.com/cookiecutter/cookiecutter-django/pull/4587)) ## 2023.09.16 ### Updated - Auto-update pre-commit hooks ([#4586](https://github.com/cookiecutter/cookiecutter-django/pull/4586)) ## 2023.09.15 ### Updated - Update flake8-isort to 6.1.0 ([#4585](https://github.com/cookiecutter/cookiecutter-django/pull/4585)) - Update pillow to 10.0.1 ([#4584](https://github.com/cookiecutter/cookiecutter-django/pull/4584)) ## 2023.09.14 ### Updated - Update sphinx to 7.2.6 ([#4583](https://github.com/cookiecutter/cookiecutter-django/pull/4583)) ## 2023.09.13 ### Updated - Update sentry-sdk to 1.31.0 ([#4582](https://github.com/cookiecutter/cookiecutter-django/pull/4582)) ## 2023.09.12 ### Updated - Update django-storages to 1.14 ([#4564](https://github.com/cookiecutter/cookiecutter-django/pull/4564)) ## 2023.09.11 ### Updated - Auto-update pre-commit hooks ([#4579](https://github.com/cookiecutter/cookiecutter-django/pull/4579)) - Update black to 23.9.1 ([#4580](https://github.com/cookiecutter/cookiecutter-django/pull/4580)) - Update django-allauth to 0.56.1 ([#4576](https://github.com/cookiecutter/cookiecutter-django/pull/4576)) ## 2023.09.08 ### Updated - Update pytest to 7.4.2 ([#4573](https://github.com/cookiecutter/cookiecutter-django/pull/4573)) ## 2023.09.07 ### Updated - Update django-allauth to 0.56.0 ([#4571](https://github.com/cookiecutter/cookiecutter-django/pull/4571)) ## 2023.09.06 ### Changed - Replace Mailhog with Mailpit ([#4551](https://github.com/cookiecutter/cookiecutter-django/pull/4551)) ### Updated - Update sphinx to 7.2.5 ([#4569](https://github.com/cookiecutter/cookiecutter-django/pull/4569)) - Bump actions/checkout from 3 to 4 ([#4565](https://github.com/cookiecutter/cookiecutter-django/pull/4565)) - Update coverage to 7.3.1 ([#4567](https://github.com/cookiecutter/cookiecutter-django/pull/4567)) ## 2023.09.04 ### Updated - Update django to 4.2.5 ([#4563](https://github.com/cookiecutter/cookiecutter-django/pull/4563)) ## 2023.09.03 ### Updated - Update celery to 5.3.4 ([#4562](https://github.com/cookiecutter/cookiecutter-django/pull/4562)) ## 2023.09.02 ### Updated - Update pytest to 7.4.1 ([#4561](https://github.com/cookiecutter/cookiecutter-django/pull/4561)) - Update pre-commit to 3.4.0 ([#4560](https://github.com/cookiecutter/cookiecutter-django/pull/4560)) - Update django-environ to 0.11.2 ([#4558](https://github.com/cookiecutter/cookiecutter-django/pull/4558)) ## 2023.09.01 ## 2023.08.31 ### Updated - Auto-update pre-commit hooks ([#4550](https://github.com/cookiecutter/cookiecutter-django/pull/4550)) - Update django-allauth to 0.55.2 ([#4549](https://github.com/cookiecutter/cookiecutter-django/pull/4549)) - Update celery to 5.3.3 ([#4553](https://github.com/cookiecutter/cookiecutter-django/pull/4553)) ## 2023.08.30 ### Updated - Update django-environ to 0.11.0 ([#4548](https://github.com/cookiecutter/cookiecutter-django/pull/4548)) ## 2023.08.29 ### Updated - Update sentry-sdk to 1.30.0 ([#4546](https://github.com/cookiecutter/cookiecutter-django/pull/4546)) ## 2023.08.28 ### Changed - Add French translations ([#4454](https://github.com/cookiecutter/cookiecutter-django/pull/4454)) - Change `MEDIA_URL` to an absolute URL in tests ([#4460](https://github.com/cookiecutter/cookiecutter-django/pull/4460)) ### Fixed - Fix a small compatibility issue between black and flake8 ([#4541](https://github.com/cookiecutter/cookiecutter-django/pull/4541)) ### Updated - Update django-allauth to 0.55.0 ([#4535](https://github.com/cookiecutter/cookiecutter-django/pull/4535)) - Update watchfiles to 0.20.0 ([#4537](https://github.com/cookiecutter/cookiecutter-django/pull/4537)) - Update Python version from 3.11.4 to 3.11.5 ([#4542](https://github.com/cookiecutter/cookiecutter-django/pull/4542)) ## 2023.08.19 ### Changed - Override `_after_postgeneration` to force save in `UserFactory` ([#4534](https://github.com/cookiecutter/cookiecutter-django/pull/4534)) ## 2023.08.17 ### Updated - Update argon2-cffi to 23.1.0 ([#4527](https://github.com/cookiecutter/cookiecutter-django/pull/4527)) - Auto-update pre-commit hooks ([#4530](https://github.com/cookiecutter/cookiecutter-django/pull/4530)) ## 2023.08.16 ### Updated - Update django-upgrade to 1.14.1 ([#4528](https://github.com/cookiecutter/cookiecutter-django/pull/4528)) ## 2023.08.15 ### Updated - Update redis to 5.0.0 ([#4526](https://github.com/cookiecutter/cookiecutter-django/pull/4526)) ## 2023.08.14 ### Changed - Install Django and DRF stubs with `compatible-mypy` extra (as per offical recommendation) ([#4361](https://github.com/cookiecutter/cookiecutter-django/pull/4361)) - Fix `overrideCommand` value in `devcontainer` so that the `django` container can run (#4517) ([#4517](https://github.com/cookiecutter/cookiecutter-django/pull/4517)) ### Fixed - Prevent error in data migration caused by long project name ([#4525](https://github.com/cookiecutter/cookiecutter-django/pull/4525)) - Remove unused gulp-concat when Webpack is selected ([#4520](https://github.com/cookiecutter/cookiecutter-django/pull/4520)) - Exclude env files from container image (add .envs/ to .dockerignore) ([#4476](https://github.com/cookiecutter/cookiecutter-django/pull/4476)) ### Updated - Update werkzeug to 2.3.7 ([#4521](https://github.com/cookiecutter/cookiecutter-django/pull/4521)) - Update coverage to 7.3.0 ([#4516](https://github.com/cookiecutter/cookiecutter-django/pull/4516)) - Update django-debug-toolbar to 4.2.0 ([#4511](https://github.com/cookiecutter/cookiecutter-django/pull/4511)) - Update flower to 2.0.1 ([#4518](https://github.com/cookiecutter/cookiecutter-django/pull/4518)) ## 2023.08.10 ### Fixed - Corrected 'or' translation to pt-br ([#4507](https://github.com/cookiecutter/cookiecutter-django/pull/4507)) ## 2023.08.04 ### Updated - Auto-update pre-commit hooks ([#4503](https://github.com/cookiecutter/cookiecutter-django/pull/4503)) ## 2023.08.01 ### Updated - Auto-update pre-commit hooks ([#4499](https://github.com/cookiecutter/cookiecutter-django/pull/4499)) - Update django-anymail to 10.1 ([#4497](https://github.com/cookiecutter/cookiecutter-django/pull/4497)) - Update sentry-sdk to 1.29.2 ([#4496](https://github.com/cookiecutter/cookiecutter-django/pull/4496)) - Update django to 4.2.4 ([#4495](https://github.com/cookiecutter/cookiecutter-django/pull/4495)) - Update flake8 to 6.1.0 ([#4489](https://github.com/cookiecutter/cookiecutter-django/pull/4489)) - Update uvicorn to 0.23.2 ([#4490](https://github.com/cookiecutter/cookiecutter-django/pull/4490)) - Update sentry-sdk to 1.29.1 ([#4494](https://github.com/cookiecutter/cookiecutter-django/pull/4494)) ## 2023.07.30 ### Fixed - Fix `README.md` file extension in `setup.py` ([#4488](https://github.com/cookiecutter/cookiecutter-django/pull/4488)) ## 2023.07.28 ### Changed - Add support for Drone CI ([#4382](https://github.com/cookiecutter/cookiecutter-django/pull/4382)) ## 2023.07.27 ### Documentation - Document that `docker exec` does not work for running management commands ([#4487](https://github.com/cookiecutter/cookiecutter-django/pull/4487)) - Add Webpack instructions for developping locally with HTTPS ([#4486](https://github.com/cookiecutter/cookiecutter-django/pull/4486)) ## 2023.07.25 ### Updated - Upgrade to traefik 2.10.4 ([#4483](https://github.com/cookiecutter/cookiecutter-django/pull/4483)) ## 2023.07.24 ### Fixed - Add missing custom CRSF error page in prod ([#4464](https://github.com/cookiecutter/cookiecutter-django/pull/4464)) ### Documentation - Replace `docker-compose` by `docker compose` in docs ([#4463](https://github.com/cookiecutter/cookiecutter-django/pull/4463)) ### Updated - Update drf-spectacular to 0.26.4 ([#4481](https://github.com/cookiecutter/cookiecutter-django/pull/4481)) ## 2023.07.20 ### Updated - Update djlint to 1.32.1 ([#4475](https://github.com/cookiecutter/cookiecutter-django/pull/4475)) ## 2023.07.19 ### Updated - Update factory-boy to 3.3.0 ([#4472](https://github.com/cookiecutter/cookiecutter-django/pull/4472)) - Update gunicorn to 21.2.0 ([#4473](https://github.com/cookiecutter/cookiecutter-django/pull/4473)) - Update djlint to 1.32.0 ([#4471](https://github.com/cookiecutter/cookiecutter-django/pull/4471)) ## 2023.07.18 ### Updated - Update gunicorn to 21.1.0 ([#4470](https://github.com/cookiecutter/cookiecutter-django/pull/4470)) - Update uvicorn to 0.23.1 ([#4468](https://github.com/cookiecutter/cookiecutter-django/pull/4468)) - Update gunicorn to 21.0.1 ([#4466](https://github.com/cookiecutter/cookiecutter-django/pull/4466)) ## 2023.07.13 ### Updated - Update sentry-sdk to 1.28.1 ([#4458](https://github.com/cookiecutter/cookiecutter-django/pull/4458)) ## 2023.07.11 ### Changed - Improve type hints for `UserSerializer` ([#4429](https://github.com/cookiecutter/cookiecutter-django/pull/4429)) - [pre-commit.ci] pre-commit autoupdate ([#4453](https://github.com/cookiecutter/cookiecutter-django/pull/4453)) ### Fixed - Fix `/tmp` bind mount in devcontainer config ([#4455](https://github.com/cookiecutter/cookiecutter-django/pull/4455)) ### Updated - Update black to 23.7.0 ([#4452](https://github.com/cookiecutter/cookiecutter-django/pull/4452)) ## 2023.07.10 ### Fixed - Prevent user's name being shown twice on user details page if username is set to email ([#4436](https://github.com/cookiecutter/cookiecutter-django/pull/4436)) - Add missing trailing space in `EMAIL_SUBJECT_PREFIX` setting ([#4434](https://github.com/cookiecutter/cookiecutter-django/pull/4434)) ### Documentation - Clarify documentation on which port to use to access the application when using Webpack or Gulp ([#4413](https://github.com/cookiecutter/cookiecutter-django/pull/4413)) ### Updated - Update django-coverage-plugin to 3.1.0 ([#4446](https://github.com/cookiecutter/cookiecutter-django/pull/4446)) - Update pillow to 10.0.0 ([#4432](https://github.com/cookiecutter/cookiecutter-django/pull/4432)) - Update django-cors-headers to 4.2.0 ([#4445](https://github.com/cookiecutter/cookiecutter-django/pull/4445)) - Update sentry-sdk to 1.28.0 ([#4444](https://github.com/cookiecutter/cookiecutter-django/pull/4444)) ## 2023.07.09 ### Fixed - Fix missing run configurations when PyCharm is selected ([#4441](https://github.com/cookiecutter/cookiecutter-django/pull/4441)) ## 2023.07.08 ### Updated - Update sentry-sdk to 1.27.1 ([#4440](https://github.com/cookiecutter/cookiecutter-django/pull/4440)) ## 2023.07.04 ### Changed - Add PostgreSQL 15 ([#4431](https://github.com/cookiecutter/cookiecutter-django/pull/4431)) - [pre-commit.ci] pre-commit autoupdate ([#4438](https://github.com/cookiecutter/cookiecutter-django/pull/4438)) ### Updated - Update sentry-sdk to 1.27.0 ([#4439](https://github.com/cookiecutter/cookiecutter-django/pull/4439)) - Update postcss-preset-env to 9.0.0 ([#4437](https://github.com/cookiecutter/cookiecutter-django/pull/4437)) ## 2023.07.03 ### Changed - Add a devcontainer configuration with Docker ([#4198](https://github.com/cookiecutter/cookiecutter-django/pull/4198)) ### Updated - Update django-stubs to 4.2.3 ([#4430](https://github.com/cookiecutter/cookiecutter-django/pull/4430)) - Update django to 4.2.3 ([#4435](https://github.com/cookiecutter/cookiecutter-django/pull/4435)) ## 2023.06.30 ### Changed - Add option to use django-allauth workflow in the admin ([#1921](https://github.com/cookiecutter/cookiecutter-django/pull/1921)) ## 2023.06.29 ### Changed - Replace psycopg2 by psycopg3 ([#4421](https://github.com/cookiecutter/cookiecutter-django/pull/4421)) ## 2023.06.28 ### Changed - Upgrade to django 4.2 ([#4393](https://github.com/cookiecutter/cookiecutter-django/pull/4393)) ### Fixed - Fix PostgreSQL version in GitHub workflow ([#4423](https://github.com/cookiecutter/cookiecutter-django/pull/4423)) ### Updated - Update werkzeug to 2.3.6 ([#4427](https://github.com/cookiecutter/cookiecutter-django/pull/4427)) - Update django-compressor to 4.4 ([#4422](https://github.com/cookiecutter/cookiecutter-django/pull/4422)) ## 2023.06.27 ### Changed - Populate User `name` field during social auth ([#3968](https://github.com/cookiecutter/cookiecutter-django/pull/3968)) - Add djLint for HTML formatting and linting ([#4389](https://github.com/cookiecutter/cookiecutter-django/pull/4389)) ### Fixed - Only include prettier pre-commit hook with node-based front-end pipeline ([#4418](https://github.com/cookiecutter/cookiecutter-django/pull/4418)) ### Updated - Update djangorestframework-stubs to 3.14.2 ([#4420](https://github.com/cookiecutter/cookiecutter-django/pull/4420)) - Update django-stubs to 4.2.2 ([#4419](https://github.com/cookiecutter/cookiecutter-django/pull/4419)) ## 2023.06.26 ### Updated - Update pytest to 7.4.0 ([#4412](https://github.com/cookiecutter/cookiecutter-django/pull/4412)) - Update redis to 4.6.0 ([#4415](https://github.com/cookiecutter/cookiecutter-django/pull/4415)) - Update mypy to 1.4.1 ([#4416](https://github.com/cookiecutter/cookiecutter-django/pull/4416)) ## 2023.06.22 ### Updated - Update pygithub to 1.59.0 ([#4410](https://github.com/cookiecutter/cookiecutter-django/pull/4410)) - Update drf-spectacular to 0.26.3 ([#4411](https://github.com/cookiecutter/cookiecutter-django/pull/4411)) - Update sentry-sdk to 1.26.0 ([#4409](https://github.com/cookiecutter/cookiecutter-django/pull/4409)) ## 2023.06.21 ### Updated - Upgrade traefik to 2.10.3 ([#4408](https://github.com/cookiecutter/cookiecutter-django/pull/4408)) ## 2023.06.19 ### Updated - Auto-update pre-commit hooks ([#4405](https://github.com/cookiecutter/cookiecutter-django/pull/4405)) - Update celery to 5.3.1 ([#4404](https://github.com/cookiecutter/cookiecutter-django/pull/4404)) ## 2023.06.18 ### Changed - Fix missing celery env variable when running compilemessages ([#4403](https://github.com/cookiecutter/cookiecutter-django/pull/4403)) ### Updated - Update flower to 2.0.0 ([#4402](https://github.com/cookiecutter/cookiecutter-django/pull/4402)) ## 2023.06.17 ## 2023.06.16 ### Updated - Update whitenoise to 6.5.0 ([#4400](https://github.com/cookiecutter/cookiecutter-django/pull/4400)) - Update django-redis to 5.3.0 ([#4399](https://github.com/cookiecutter/cookiecutter-django/pull/4399)) - Auto-update pre-commit hooks ([#4395](https://github.com/cookiecutter/cookiecutter-django/pull/4395)) ## 2023.06.14 ### Updated - Update django-cors-headers to 4.1.0 ([#4391](https://github.com/cookiecutter/cookiecutter-django/pull/4391)) - Update django-upgrade to 1.14.0 ([#4394](https://github.com/cookiecutter/cookiecutter-django/pull/4394)) - Update django-webpack-loader to 2.0.1 ([#4392](https://github.com/cookiecutter/cookiecutter-django/pull/4392)) - Update pre-commit to 3.3.3 ([#4390](https://github.com/cookiecutter/cookiecutter-django/pull/4390)) ## 2023.06.11 ### Updated - Update pytest to 7.3.2 ([#4384](https://github.com/cookiecutter/cookiecutter-django/pull/4384)) - Auto-update pre-commit hooks ([#4385](https://github.com/cookiecutter/cookiecutter-django/pull/4385)) ## 2023.06.09 ### Fixed - Fix missing `compilemessages` step before deploying to prod ([#4363](https://github.com/cookiecutter/cookiecutter-django/pull/4363)) ## 2023.06.08 ### Fixed - Fix failure in user view test caused by translations ([#4374](https://github.com/cookiecutter/cookiecutter-django/pull/4374)) ### Updated - Update to Python 3.11.4 in production Docker compose ([#4378](https://github.com/cookiecutter/cookiecutter-django/pull/4378)) - Update to Python 3.11.4 in docs Docker compose ([#4379](https://github.com/cookiecutter/cookiecutter-django/pull/4379)) - Update to Python 3.11.4 in local Docker compose ([#4380](https://github.com/cookiecutter/cookiecutter-django/pull/4380)) - Update celery to 5.3.0 ([#4369](https://github.com/cookiecutter/cookiecutter-django/pull/4369)) - Update werkzeug to 2.3.5 ([#4377](https://github.com/cookiecutter/cookiecutter-django/pull/4377)) ## 2023.06.07 ### Changed - Replace `runserver` with `runserver_plus` ([#4373](https://github.com/cookiecutter/cookiecutter-django/pull/4373)) - Add translations for Brazilian Portuguese ([#4367](https://github.com/cookiecutter/cookiecutter-django/pull/4367)) ### Updated - Update sentry-sdk to 1.25.1 ([#4376](https://github.com/cookiecutter/cookiecutter-django/pull/4376)) - Update django-extensions to 3.2.3 ([#4372](https://github.com/cookiecutter/cookiecutter-django/pull/4372)) - Update djangorestframework-stubs to 3.14.1 ([#4366](https://github.com/cookiecutter/cookiecutter-django/pull/4366)) - Update django-stubs to 4.2.1 ([#4365](https://github.com/cookiecutter/cookiecutter-django/pull/4365)) - Update mypy to 1.3.0 ([#4327](https://github.com/cookiecutter/cookiecutter-django/pull/4327)) ## 2023.06.02 ### Updated - Update sentry-sdk to 1.25.0 ([#4364](https://github.com/cookiecutter/cookiecutter-django/pull/4364)) ## 2023.05.30 ### Updated - Update hiredis to 2.2.3 ([#4360](https://github.com/cookiecutter/cookiecutter-django/pull/4360)) - Update django-debug-toolbar to 4.1.0 ([#4359](https://github.com/cookiecutter/cookiecutter-django/pull/4359)) - Update redis to 4.5.5 ([#4358](https://github.com/cookiecutter/cookiecutter-django/pull/4358)) - Update django-anymail to 10.0 ([#4357](https://github.com/cookiecutter/cookiecutter-django/pull/4357)) - Update coverage to 7.2.7 ([#4356](https://github.com/cookiecutter/cookiecutter-django/pull/4356)) ## 2023.05.28 ## 2023.05.24 ### Fixed - Prevent Celery restarts on media file changes ([#4352](https://github.com/cookiecutter/cookiecutter-django/pull/4352)) ### Updated - Update coverage to 7.2.6 ([#4351](https://github.com/cookiecutter/cookiecutter-django/pull/4351)) ## 2023.05.23 ### Changed - Fix compatibility webpack-bundle-tracker>=2.0.0 js library required after upgrade django-webpack-loader>=2.0.0 ([#4350](https://github.com/cookiecutter/cookiecutter-django/pull/4350)) ### Updated - Update sphinx-rtd-theme to 1.2.1 ([#4348](https://github.com/cookiecutter/cookiecutter-django/pull/4348)) - Update sentry-sdk to 1.24.0 ([#4349](https://github.com/cookiecutter/cookiecutter-django/pull/4349)) - Bump webpack-bundle-tracker from 1.8.1 to 2.0.0 in /{{cookiecutter.project_slug}} ([#4347](https://github.com/cookiecutter/cookiecutter-django/pull/4347)) - Update django-webpack-loader to 2.0.0 ([#4345](https://github.com/cookiecutter/cookiecutter-django/pull/4345)) - Update pytest-xdist to 3.3.1 ([#4344](https://github.com/cookiecutter/cookiecutter-django/pull/4344)) - Update requests to 2.31.0 ([#4346](https://github.com/cookiecutter/cookiecutter-django/pull/4346)) ## 2023.05.18 ### Updated - Update pre-commit to 3.3.2 ([#4342](https://github.com/cookiecutter/cookiecutter-django/pull/4342)) ## 2023.05.17 ### Updated - Update sentry-sdk to 1.23.1 ([#4341](https://github.com/cookiecutter/cookiecutter-django/pull/4341)) ## 2023.05.15 ### Updated - Update django-cors-headers to 4.0.0 ([#4329](https://github.com/cookiecutter/cookiecutter-django/pull/4329)) - Update sentry-sdk to 1.23.0 ([#4337](https://github.com/cookiecutter/cookiecutter-django/pull/4337)) ## 2023.05.09 ### Updated - Update werkzeug to 2.3.4 ([#4325](https://github.com/cookiecutter/cookiecutter-django/pull/4325)) ## 2023.05.08 ### Updated - Auto-update pre-commit hooks ([#4320](https://github.com/cookiecutter/cookiecutter-django/pull/4320)) - Update sentry-sdk to 1.22.2 ([#4321](https://github.com/cookiecutter/cookiecutter-django/pull/4321)) ## 2023.05.04 ### Changed - Remove pytz from dependencies ([#4309](https://github.com/cookiecutter/cookiecutter-django/pull/4309)) ### Updated - Update django-anymail to 9.2 ([#4316](https://github.com/cookiecutter/cookiecutter-django/pull/4316)) - Update pre-commit to 3.3.1 ([#4315](https://github.com/cookiecutter/cookiecutter-django/pull/4315)) - Update coverage to 7.2.5 ([#4314](https://github.com/cookiecutter/cookiecutter-django/pull/4314)) - Update django to 4.1.9 ([#4313](https://github.com/cookiecutter/cookiecutter-django/pull/4313)) - Update sentry-sdk to 1.21.1 ([#4312](https://github.com/cookiecutter/cookiecutter-django/pull/4312)) - Update requests to 2.30.0 ([#4311](https://github.com/cookiecutter/cookiecutter-django/pull/4311)) ## 2023.05.02 ### Updated - Upgrade traefik to 2.10.1 ([#4304](https://github.com/cookiecutter/cookiecutter-django/pull/4304)) - Update uvicorn to 0.22.0 ([#4305](https://github.com/cookiecutter/cookiecutter-django/pull/4305)) - Update werkzeug to 2.3.3 ([#4307](https://github.com/cookiecutter/cookiecutter-django/pull/4307)) ## 2023.04.28 ### Changed - Add django-upgrade to pre-commit hooks ([#4298](https://github.com/cookiecutter/cookiecutter-django/pull/4298)) ## 2023.04.27 ### Updated - Update djangorestframework-stubs to 3.14.0 ([#4303](https://github.com/cookiecutter/cookiecutter-django/pull/4303)) - Update werkzeug to 2.3.1 ([#4302](https://github.com/cookiecutter/cookiecutter-django/pull/4302)) - Update django-stubs to 4.2.0 ([#4301](https://github.com/cookiecutter/cookiecutter-django/pull/4301)) ## 2023.04.26 ### Updated - Upgrade cssnano to v6.0.0 ([#4233](https://github.com/cookiecutter/cookiecutter-django/pull/4233)) - Upgrade concurrently to 8.0.1 ([#4237](https://github.com/cookiecutter/cookiecutter-django/pull/4237)) - Upgrade to node v18 ([#4294](https://github.com/cookiecutter/cookiecutter-django/pull/4294)) - Update coverage to 7.2.3 ([#4297](https://github.com/cookiecutter/cookiecutter-django/pull/4297)) - Update mypy to 1.2.0 ([#4295](https://github.com/cookiecutter/cookiecutter-django/pull/4295)) - Update werkzeug to 2.3.0 ([#4296](https://github.com/cookiecutter/cookiecutter-django/pull/4296)) ## 2023.04.25 ### Updated - Update sentry-sdk to 1.21.0 ([#4293](https://github.com/cookiecutter/cookiecutter-django/pull/4293)) - Update sphinx to 6.2.1 ([#4292](https://github.com/cookiecutter/cookiecutter-django/pull/4292)) - Bump traefik from 2.9.10 to 2.10.0 ([#4290](https://github.com/cookiecutter/cookiecutter-django/pull/4290)) - Auto-update pre-commit hooks ([#4288](https://github.com/cookiecutter/cookiecutter-django/pull/4288)) ## 2023.04.24 ### Updated - Auto-update pre-commit hooks ([#4286](https://github.com/cookiecutter/cookiecutter-django/pull/4286)) - Update sphinx to 6.2.0 ([#4285](https://github.com/cookiecutter/cookiecutter-django/pull/4285)) ## 2023.04.19 ### Updated - Update sentry-sdk to 1.20.0 ([#4282](https://github.com/cookiecutter/cookiecutter-django/pull/4282)) ## 2023.04.18 ### Documentation - Document how to add 3rd party packages with Docker ([#4279](https://github.com/cookiecutter/cookiecutter-django/pull/4279)) ## 2023.04.15 ### Changed - Add username_type option ([#3958](https://github.com/cookiecutter/cookiecutter-django/pull/3958)) - Fix inconsistent line length and move configs to pyproject.toml ([#4276](https://github.com/cookiecutter/cookiecutter-django/pull/4276)) - Relax rules for linting of pull requests on this template ([#4273](https://github.com/cookiecutter/cookiecutter-django/pull/4273)) - Add more pre-commit hooks ([#4266](https://github.com/cookiecutter/cookiecutter-django/pull/4266)) - Upgrade Python to version 3.11 (Faster CPython) ([#4256](https://github.com/cookiecutter/cookiecutter-django/pull/4256)) ### Updated - Update drf-spectacular to 0.26.2 ([#4277](https://github.com/cookiecutter/cookiecutter-django/pull/4277)) - Update pytest to 7.3.1 ([#4272](https://github.com/cookiecutter/cookiecutter-django/pull/4272)) ## 2023.04.13 ### Updated - Update tox to 4.4.12 ([#4271](https://github.com/cookiecutter/cookiecutter-django/pull/4271)) ## 2023.04.10 ### Updated - Update pytest-sugar to 0.9.7 ([#4269](https://github.com/cookiecutter/cookiecutter-django/pull/4269)) - Update pytest to 7.3.0 ([#4268](https://github.com/cookiecutter/cookiecutter-django/pull/4268)) ## 2023.04.07 ### Updated - Upgrade traefik to 2.9.10 ([#4267](https://github.com/cookiecutter/cookiecutter-django/pull/4267)) ## 2023.04.05 ### Changed - Update indent for nginx config file ([#4260](https://github.com/cookiecutter/cookiecutter-django/pull/4260)) ### Updated - Update tox to 4.4.11 ([#4262](https://github.com/cookiecutter/cookiecutter-django/pull/4262)) - Update django to 4.1.8 ([#4258](https://github.com/cookiecutter/cookiecutter-django/pull/4258)) - Update pre-commit to 3.2.2 ([#4259](https://github.com/cookiecutter/cookiecutter-django/pull/4259)) ## 2023.04.04 ### Changed - Upgrade to Django 4.1 ([#4028](https://github.com/cookiecutter/cookiecutter-django/pull/4028)) - Remove deprecated security setting ([#4247](https://github.com/cookiecutter/cookiecutter-django/pull/4247)) ### Fixed - Replace `runserver_plus` with `runserver` ([#4255](https://github.com/cookiecutter/cookiecutter-django/pull/4255)) - Fix traefik rule priority for media router ([#4244](https://github.com/cookiecutter/cookiecutter-django/pull/4244)) ### Updated - Update sentry-sdk to 1.19.0 ([#4254](https://github.com/cookiecutter/cookiecutter-django/pull/4254)) - Update django-debug-toolbar to 4.0.0 ([#4251](https://github.com/cookiecutter/cookiecutter-django/pull/4251)) ## 2023.04.03 ### Changed - fix: Syntax for ignoring specific noqa errors ([#4250](https://github.com/cookiecutter/cookiecutter-django/pull/4250)) ### Updated - Update psycopg2-binary to 2.9.6 ([#4249](https://github.com/cookiecutter/cookiecutter-django/pull/4249)) - Update psycopg2 to 2.9.6 ([#4248](https://github.com/cookiecutter/cookiecutter-django/pull/4248)) ## 2023.04.01 ### Updated - Update pytest-instafail to 0.5.0 ([#4240](https://github.com/cookiecutter/cookiecutter-django/pull/4240)) - Update pillow to 9.5.0 ([#4242](https://github.com/cookiecutter/cookiecutter-django/pull/4242)) - Update django-allauth to 0.54.0 ([#4241](https://github.com/cookiecutter/cookiecutter-django/pull/4241)) ## 2023.03.29 ### Updated - Update redis to 4.5.4 ([#4239](https://github.com/cookiecutter/cookiecutter-django/pull/4239)) - Update pytz to 2023.3 ([#4238](https://github.com/cookiecutter/cookiecutter-django/pull/4238)) - Update black to 23.3.0 ([#4236](https://github.com/cookiecutter/cookiecutter-django/pull/4236)) ## 2023.03.27 ### Updated - Update watchfiles to 0.19.0 ([#4232](https://github.com/cookiecutter/cookiecutter-django/pull/4232)) ## 2023.03.26 ### Updated - Update pre-commit to 3.2.1 ([#4229](https://github.com/cookiecutter/cookiecutter-django/pull/4229)) ## 2023.03.25 ### Updated - Update pytz to 2023.2 ([#4228](https://github.com/cookiecutter/cookiecutter-django/pull/4228)) ## 2023.03.23 ### Updated - Bump traefik from 2.9.8 to 2.9.9 ([#4225](https://github.com/cookiecutter/cookiecutter-django/pull/4225)) ## 2023.03.22 ### Updated - Update redis to 4.5.3 ([#4227](https://github.com/cookiecutter/cookiecutter-django/pull/4227)) ## 2023.03.20 ### Updated - Update django-allauth to 0.53.1 ([#4223](https://github.com/cookiecutter/cookiecutter-django/pull/4223)) - Update redis to 4.5.2 ([#4222](https://github.com/cookiecutter/cookiecutter-django/pull/4222)) ## 2023.03.18 ### Updated - Update drf-spectacular to 0.26.1 ([#4221](https://github.com/cookiecutter/cookiecutter-django/pull/4221)) - Update pygithub to 1.58.1 ([#4220](https://github.com/cookiecutter/cookiecutter-django/pull/4220)) - Update pre-commit to 3.2.0 ([#4219](https://github.com/cookiecutter/cookiecutter-django/pull/4219)) ## 2023.03.16 ### Changed - Pin base Python Docker images to bugfix ([#4194](https://github.com/cookiecutter/cookiecutter-django/pull/4194)) ### Fixed - Trim leading and trailing space in `domain_name` and `email` ([#4163](https://github.com/cookiecutter/cookiecutter-django/pull/4163)) ### Updated - Update djangorestframework-stubs to 1.10.0 ([#4217](https://github.com/cookiecutter/cookiecutter-django/pull/4217)) - Update django-stubs to 1.16.0 ([#4216](https://github.com/cookiecutter/cookiecutter-django/pull/4216)) - Update coverage to 7.2.2 ([#4218](https://github.com/cookiecutter/cookiecutter-django/pull/4218)) - Update sentry-sdk to 1.17.0 ([#4215](https://github.com/cookiecutter/cookiecutter-django/pull/4215)) - Bump Docker python image from 3.10.9 to 3.10.10 on production Django ([#4214](https://github.com/cookiecutter/cookiecutter-django/pull/4214)) - Bump Docker python image from 3.10.9-slim-bullseye to 3.10.10-slim-bullseye for docs ([#4213](https://github.com/cookiecutter/cookiecutter-django/pull/4213)) - Bump Docker python image from 3.10.9-slim-bullseye to 3.10.10-slim-bullseye for local Django service ([#4212](https://github.com/cookiecutter/cookiecutter-django/pull/4212)) - Update uvicorn to 0.21.1 ([#4211](https://github.com/cookiecutter/cookiecutter-django/pull/4211)) - Update django-allauth to 0.53.0 ([#4210](https://github.com/cookiecutter/cookiecutter-django/pull/4210)) ## 2023.03.14 ### Updated - Update django-celery-beat to 2.5.0 ([#4208](https://github.com/cookiecutter/cookiecutter-django/pull/4208)) ## 2023.03.13 ### Updated - Update uvicorn to 0.21.0 ([#4203](https://github.com/cookiecutter/cookiecutter-django/pull/4203)) - Update django-anymail to 9.1 ([#4206](https://github.com/cookiecutter/cookiecutter-django/pull/4206)) - Update tox to 4.4.7 ([#4207](https://github.com/cookiecutter/cookiecutter-django/pull/4207)) ## 2023.03.09 ### Fixed - Fix the omit configuration for coverage ([#4201](https://github.com/cookiecutter/cookiecutter-django/pull/4201)) ### Updated - Update ipdb to 0.13.13 ([#4202](https://github.com/cookiecutter/cookiecutter-django/pull/4202)) ## 2023.03.07 ### Updated - Update mypy to 1.1.1 ([#4196](https://github.com/cookiecutter/cookiecutter-django/pull/4196)) - Update django-environ to 0.10.0 ([#4195](https://github.com/cookiecutter/cookiecutter-django/pull/4195)) ## 2023.03.04 ### Changed - Add option to serve media files locally using nginx ([#2457](https://github.com/cookiecutter/cookiecutter-django/pull/2457)) ### Documentation - Include contributing page to the docs ([#4144](https://github.com/cookiecutter/cookiecutter-django/pull/4144)) ### Updated - Update myst-parser to 0.19.1 ([#4193](https://github.com/cookiecutter/cookiecutter-django/pull/4193)) - Update pytest to 7.2.2 ([#4191](https://github.com/cookiecutter/cookiecutter-django/pull/4191)) - Update drf-spectacular to 0.26.0 ([#4192](https://github.com/cookiecutter/cookiecutter-django/pull/4192)) ## 2023.02.28 ### Updated - Update pre-commit to 3.1.1 ([#4188](https://github.com/cookiecutter/cookiecutter-django/pull/4188)) ## 2023.02.27 ### Updated - Update sentry-sdk to 1.16.0 ([#4187](https://github.com/cookiecutter/cookiecutter-django/pull/4187)) ## 2023.02.26 ### Changed - Fix readthedocs config file for generated project ([#4172](https://github.com/cookiecutter/cookiecutter-django/pull/4172)) ### Updated - Bump traefik from v2.2.11 to 2.9.8 ([#4164](https://github.com/cookiecutter/cookiecutter-django/pull/4164)) - Update coverage to 7.2.1 ([#4186](https://github.com/cookiecutter/cookiecutter-django/pull/4186)) ## 2023.02.25 ### Changed - Run linting with pre-commit on GitLab ([#4150](https://github.com/cookiecutter/cookiecutter-django/pull/4150)) ### Fixed - Disable caching for linter job on GitHub actions ([#4166](https://github.com/cookiecutter/cookiecutter-django/pull/4166)) ### Documentation - Add instuction to run celery beat ([#4162](https://github.com/cookiecutter/cookiecutter-django/pull/4162)) ### Updated - Bump garland/aws-cli-docker from 1.15.47 to 1.16.140 ([#4136](https://github.com/cookiecutter/cookiecutter-django/pull/4136)) - Update djangorestframework-stubs to 1.9.1 ([#4184](https://github.com/cookiecutter/cookiecutter-django/pull/4184)) - Update whitenoise to 6.4.0 ([#4180](https://github.com/cookiecutter/cookiecutter-django/pull/4180)) - Update django-stubs to 1.15.0 ([#4183](https://github.com/cookiecutter/cookiecutter-django/pull/4183)) - Update django-crispy-forms to 2.0 ([#4158](https://github.com/cookiecutter/cookiecutter-django/pull/4158)) - Update django-cors-headers to 3.14.0 ([#4181](https://github.com/cookiecutter/cookiecutter-django/pull/4181)) - Update python-slugify to 8.0.1 ([#4178](https://github.com/cookiecutter/cookiecutter-django/pull/4178)) - Update pre-commit to 3.1.0 ([#4176](https://github.com/cookiecutter/cookiecutter-django/pull/4176)) - Update mypy to 1.0.1 ([#4168](https://github.com/cookiecutter/cookiecutter-django/pull/4168)) - Update werkzeug to 2.2.3 ([#4160](https://github.com/cookiecutter/cookiecutter-django/pull/4160)) - Update coverage to 7.2.0 ([#4177](https://github.com/cookiecutter/cookiecutter-django/pull/4177)) - Update django to 4.0.10 ([#4159](https://github.com/cookiecutter/cookiecutter-django/pull/4159)) - Update hiredis to 2.2.2 ([#4156](https://github.com/cookiecutter/cookiecutter-django/pull/4156)) ## 2023.02.17 ### Changed - Update version of github actions on the template project ([#4167](https://github.com/cookiecutter/cookiecutter-django/pull/4167)) ## 2023.02.09 ### Changed - Remove unused pip cache paths in GHA & add a note for pre-commit.ci ([#4151](https://github.com/cookiecutter/cookiecutter-django/pull/4151)) ### Updated - Update mypy to 0.991 ([#4106](https://github.com/cookiecutter/cookiecutter-django/pull/4106)) ## 2023.02.08 ### Updated - Update sphinx to 6.1.3 ([#4148](https://github.com/cookiecutter/cookiecutter-django/pull/4148)) - Update redis to 4.5.1 ([#4147](https://github.com/cookiecutter/cookiecutter-django/pull/4147)) ## 2023.02.07 ### Updated - Bump postcss-preset-env from 7.8.3 to 8.0.1 ([#4115](https://github.com/cookiecutter/cookiecutter-django/pull/4115)) - Bump sass-loader from 12.6.0 to 13.2.0 ([#4116](https://github.com/cookiecutter/cookiecutter-django/pull/4116)) - Bump babel-loader from 8.3.0 to 9.1.2 ([#4117](https://github.com/cookiecutter/cookiecutter-django/pull/4117)) - Bump postcss-loader from 6.2.1 to 7.0.2 ([#4114](https://github.com/cookiecutter/cookiecutter-django/pull/4114)) - Bump webpack-cli from 4.10.0 to 5.0.1 ([#4118](https://github.com/cookiecutter/cookiecutter-django/pull/4118)) - Update redis to 4.5.0 ([#4142](https://github.com/cookiecutter/cookiecutter-django/pull/4142)) - Update sentry-sdk to 1.15.0 ([#4141](https://github.com/cookiecutter/cookiecutter-django/pull/4141)) ## 2023.02.06 ### Changed - Change `RequestFactory` to `APIRequestFactory` in tests for API views ([#4110](https://github.com/cookiecutter/cookiecutter-django/pull/4110)) ### Fixed - Fix django-webpack-loader setup when running tests ([#4128](https://github.com/cookiecutter/cookiecutter-django/pull/4128)) ### Documentation - Added AWS ECS Full Deployment Article to README ([#2630](https://github.com/cookiecutter/cookiecutter-django/pull/2630)) ### Updated - Update hiredis to 2.2.1 ([#4123](https://github.com/cookiecutter/cookiecutter-django/pull/4123)) - Update tox to 4.4.4 ([#4133](https://github.com/cookiecutter/cookiecutter-django/pull/4133)) - Update django to 4.0.9 ([#4134](https://github.com/cookiecutter/cookiecutter-django/pull/4134)) - Update django-webpack-loader to 1.8.1 ([#4132](https://github.com/cookiecutter/cookiecutter-django/pull/4132)) ## 2023.02.05 ### Documentation - Add note about which service to request when running locally with Docker & Webpack or Gulp ([#4130](https://github.com/cookiecutter/cookiecutter-django/pull/4130)) ## 2023.02.03 ### Updated - Update pre-commit to 3.0.4 ([#4127](https://github.com/cookiecutter/cookiecutter-django/pull/4127)) ## 2023.02.02 ### Updated - Update python-slugify to 8.0.0 ([#4111](https://github.com/cookiecutter/cookiecutter-django/pull/4111)) - Update pre-commit to 3.0.3 ([#4121](https://github.com/cookiecutter/cookiecutter-django/pull/4121)) - Update black to 23.1.0 ([#4120](https://github.com/cookiecutter/cookiecutter-django/pull/4120)) - Update black pre-commit hook ([#4122](https://github.com/cookiecutter/cookiecutter-django/pull/4122)) ## 2023.01.29 ### Changed - Add Webpack support ([#3623](https://github.com/cookiecutter/cookiecutter-django/pull/3623)) - Remove `BrokenLinkEmailsMiddleware` ([#4112](https://github.com/cookiecutter/cookiecutter-django/pull/4112)) ## 2023.01.28 ### Changed - Refactor `merge_production_dotenvs_in_dotenv.py` ([#4105](https://github.com/cookiecutter/cookiecutter-django/pull/4105)) ### Updated - Update isort to 5.12.0 ([#4109](https://github.com/cookiecutter/cookiecutter-django/pull/4109)) - Auto-update pre-commit hooks ([#4108](https://github.com/cookiecutter/cookiecutter-django/pull/4108)) ## 2023.01.27 ### Updated - Update django-stubs to 1.14.0 ([#4103](https://github.com/cookiecutter/cookiecutter-django/pull/4103)) ## 2023.01.26 ### Changed - Rename BASE_DIR_PATH to BASE_DIR ([#4102](https://github.com/cookiecutter/cookiecutter-django/pull/4102)) ### Updated - Update pre-commit to 3.0.1 ([#4104](https://github.com/cookiecutter/cookiecutter-django/pull/4104)) - Update tox to 4.4.2 ([#4101](https://github.com/cookiecutter/cookiecutter-django/pull/4101)) ## 2023.01.25 ### Changed - Rename ROOT_DIR to BASE_DIR ([#4086](https://github.com/cookiecutter/cookiecutter-django/pull/4086)) - Update postgres and redis to point to mini tiers ([#4099](https://github.com/cookiecutter/cookiecutter-django/pull/4099)) ### Updated - Update coverage to 7.1.0 ([#4100](https://github.com/cookiecutter/cookiecutter-django/pull/4100)) ## 2023.01.24 ### Updated - Update pre-commit to 3.0.0 ([#4098](https://github.com/cookiecutter/cookiecutter-django/pull/4098)) ## 2023.01.23 ### Updated - Update sentry-sdk to 1.14.0 ([#4096](https://github.com/cookiecutter/cookiecutter-django/pull/4096)) ## 2023.01.22 ### Updated - Update django-compressor to 4.3.1 ([#4094](https://github.com/cookiecutter/cookiecutter-django/pull/4094)) ## 2023.01.21 ### Updated - Update django-stubs to 1.13.2 ([#4093](https://github.com/cookiecutter/cookiecutter-django/pull/4093)) ## 2023.01.19 ### Fixed - Add sourcemaps support to Gulp ([#4089](https://github.com/cookiecutter/cookiecutter-django/pull/4089)) ### Updated - Update coverage to 7.0.5 ([#4092](https://github.com/cookiecutter/cookiecutter-django/pull/4092)) - Update redis to 4.4.2 ([#4091](https://github.com/cookiecutter/cookiecutter-django/pull/4091)) - Update requests to 2.28.2 ([#4090](https://github.com/cookiecutter/cookiecutter-django/pull/4090)) - Update tox to 4.3.5 ([#4087](https://github.com/cookiecutter/cookiecutter-django/pull/4087)) ## 2023.01.17 ### Updated - Update tox to 4.3.3 ([#4081](https://github.com/cookiecutter/cookiecutter-django/pull/4081)) ## 2023.01.15 ### Updated - Update pytest to 7.2.1 ([#4077](https://github.com/cookiecutter/cookiecutter-django/pull/4077)) - Update pytz to 2022.7.1 ([#4078](https://github.com/cookiecutter/cookiecutter-django/pull/4078)) ## 2023.01.12 ### Updated - Update sentry-sdk to 1.13.0 ([#4074](https://github.com/cookiecutter/cookiecutter-django/pull/4074)) ## 2023.01.11 ### Changed - Update Celery instructions in the documentation ([#4061](https://github.com/cookiecutter/cookiecutter-django/pull/4061)) ### Updated - Update tox to 4.2.7 ([#4073](https://github.com/cookiecutter/cookiecutter-django/pull/4073)) ## 2023.01.10 ### Changed - Add dump.rdb to gitignore ([#4062](https://github.com/cookiecutter/cookiecutter-django/pull/4062)) ### Fixed - Exclude `.venv` from code style checks ([#4069](https://github.com/cookiecutter/cookiecutter-django/pull/4069)) ### Updated - Update hiredis to 2.1.1 ([#4070](https://github.com/cookiecutter/cookiecutter-django/pull/4070)) ## 2023.01.08 ### Updated - Update redis to 4.4.1 ([#4068](https://github.com/cookiecutter/cookiecutter-django/pull/4068)) - Update coverage to 7.0.4 ([#4067](https://github.com/cookiecutter/cookiecutter-django/pull/4067)) ## 2023.01.07 ### Updated - Update tox to 4.2.6 ([#4064](https://github.com/cookiecutter/cookiecutter-django/pull/4064)) - Update django-storages to 1.13.2 ([#4057](https://github.com/cookiecutter/cookiecutter-django/pull/4057)) - Update isort to 5.11.4 ([#4058](https://github.com/cookiecutter/cookiecutter-django/pull/4058)) - Update rcssmin to 1.1.1 ([#4060](https://github.com/cookiecutter/cookiecutter-django/pull/4060)) - Update django-compressor to 4.3 ([#4063](https://github.com/cookiecutter/cookiecutter-django/pull/4063)) ## 2023.01.06 ### Changed - Add `.git` to `.dockerignore` ([#4054](https://github.com/cookiecutter/cookiecutter-django/pull/4054)) - Fix link and add non-Docker commands to testing page in the docs ([#4036](https://github.com/cookiecutter/cookiecutter-django/pull/4036)) ### Updated - Update tox to 4.2.3 ([#4051](https://github.com/cookiecutter/cookiecutter-django/pull/4051)) ## 2023.01.04 ### Changed - Fix typo on test settings ([#4049](https://github.com/cookiecutter/cookiecutter-django/pull/4049)) ### Updated - Update tox to 4.2.2 ([#4050](https://github.com/cookiecutter/cookiecutter-django/pull/4050)) - Update tox to 4.2.1 ([#4046](https://github.com/cookiecutter/cookiecutter-django/pull/4046)) - Update coverage to 7.0.3 ([#4047](https://github.com/cookiecutter/cookiecutter-django/pull/4047)) ## 2023.01.03 ### Updated - Update flake8-isort to 6.0.0 ([#4022](https://github.com/cookiecutter/cookiecutter-django/pull/4022)) - Update tox to 4.1.3 ([#4041](https://github.com/cookiecutter/cookiecutter-django/pull/4041)) - Update pillow to 9.4.0 ([#4040](https://github.com/cookiecutter/cookiecutter-django/pull/4040)) - Update gitpython to 3.1.30 ([#4032](https://github.com/cookiecutter/cookiecutter-django/pull/4032)) - Update coverage to 7.0.2 ([#4042](https://github.com/cookiecutter/cookiecutter-django/pull/4042)) - Update whitenoise to 6.3.0 ([#4044](https://github.com/cookiecutter/cookiecutter-django/pull/4044)) ## 2022.12.29 ### Updated - Update tox to 4.1.0 ([#4035](https://github.com/cookiecutter/cookiecutter-django/pull/4035)) - Update tox to 4.0.19 ([#4030](https://github.com/cookiecutter/cookiecutter-django/pull/4030)) - Update django-allauth to 0.52.0 ([#4033](https://github.com/cookiecutter/cookiecutter-django/pull/4033)) ## 2022.12.26 ### Updated - Update tox to 4.0.17 ([#4027](https://github.com/cookiecutter/cookiecutter-django/pull/4027)) - Update pre-commit to 2.21.0 ([#4026](https://github.com/cookiecutter/cookiecutter-django/pull/4026)) ## 2022.12.25 ### Updated - Auto-update pre-commit hooks ([#4021](https://github.com/cookiecutter/cookiecutter-django/pull/4021)) ## 2022.12.24 ### Updated - Update coverage to 7.0.1 ([#4024](https://github.com/cookiecutter/cookiecutter-django/pull/4024)) ## 2022.12.21 ### Changed - Retry when trying to store a Celery result in backend ([#3996](https://github.com/cookiecutter/cookiecutter-django/pull/3996)) - Update image URL for build status shield badge ([#4018](https://github.com/cookiecutter/cookiecutter-django/pull/4018)) ### Updated - Update pytz to 2022.7 ([#4020](https://github.com/cookiecutter/cookiecutter-django/pull/4020)) - Update ipdb to 0.13.11 ([#4019](https://github.com/cookiecutter/cookiecutter-django/pull/4019)) - Update tox to 4.0.16 ([#4017](https://github.com/cookiecutter/cookiecutter-django/pull/4017)) - Update sentry-sdk to 1.12.1 ([#4014](https://github.com/cookiecutter/cookiecutter-django/pull/4014)) - Update coverage to 7.0.0 ([#4013](https://github.com/cookiecutter/cookiecutter-django/pull/4013)) - Update django-anymail to 9.0 ([#4012](https://github.com/cookiecutter/cookiecutter-django/pull/4012)) - Auto-update pre-commit hooks ([#4005](https://github.com/cookiecutter/cookiecutter-django/pull/4005)) - Update isort to 5.11.3 ([#4010](https://github.com/cookiecutter/cookiecutter-django/pull/4010)) - Update drf-spectacular to 0.25.1 ([#4009](https://github.com/cookiecutter/cookiecutter-django/pull/4009)) - Update hiredis to 2.1.0 ([#4006](https://github.com/cookiecutter/cookiecutter-django/pull/4006)) ## 2022.12.13 ### Changed - Improve documentation for Getting started with Docker ([#4003](https://github.com/cookiecutter/cookiecutter-django/pull/4003)) ### Updated - Update isort to 5.11.1 ([#3999](https://github.com/cookiecutter/cookiecutter-django/pull/3999)) - Auto-update pre-commit hooks ([#3998](https://github.com/cookiecutter/cookiecutter-django/pull/3998)) - Update isort to 5.11.0 ([#3997](https://github.com/cookiecutter/cookiecutter-django/pull/3997)) ## 2022.12.10 ### Updated - Update tox to 4.0.5 ([#3993](https://github.com/cookiecutter/cookiecutter-django/pull/3993)) - Auto-update pre-commit hooks ([#3991](https://github.com/cookiecutter/cookiecutter-django/pull/3991)) ## 2022.12.09 ### Changed - Remove bind option mounts for docker compose volumes ([#3981](https://github.com/cookiecutter/cookiecutter-django/pull/3981)) ### Updated - Update djangorestframework-stubs to 1.8.0 ([#3990](https://github.com/cookiecutter/cookiecutter-django/pull/3990)) - Update black to 22.12.0 ([#3988](https://github.com/cookiecutter/cookiecutter-django/pull/3988)) ## 2022.12.08 ### Updated - Update tox to 4.0.3 ([#3987](https://github.com/cookiecutter/cookiecutter-django/pull/3987)) - Update tox to 4.0.2 ([#3985](https://github.com/cookiecutter/cookiecutter-django/pull/3985)) - Update django-stubs to 1.13.1 ([#3986](https://github.com/cookiecutter/cookiecutter-django/pull/3986)) ## 2022.12.07 ### Updated - Auto-update pre-commit hooks ([#3983](https://github.com/cookiecutter/cookiecutter-django/pull/3983)) ## 2022.12.06 ### Changed - Simplify production `DATABASES` setting to extend base definition ([#3969](https://github.com/cookiecutter/cookiecutter-django/pull/3969)) ### Fixed - Only set `SERVERS` for `drf-spectacular` in production ([#3609](https://github.com/cookiecutter/cookiecutter-django/pull/3609)) ### Updated - Update django-coverage-plugin to 3.0.0 ([#3979](https://github.com/cookiecutter/cookiecutter-django/pull/3979)) - Bump stefanzweifel/git-auto-commit-action from 4.15.4 to 4.16.0 ([#3978](https://github.com/cookiecutter/cookiecutter-django/pull/3978)) ## 2022.12.04 ### Updated - Update redis to 4.4.0 ([#3977](https://github.com/cookiecutter/cookiecutter-django/pull/3977)) - Update django-debug-toolbar to 3.8.1 ([#3976](https://github.com/cookiecutter/cookiecutter-django/pull/3976)) ## 2022.12.03 ### Updated - Auto-update pre-commit hooks ([#3975](https://github.com/cookiecutter/cookiecutter-django/pull/3975)) ## 2022.12.02 ### Updated - Update flake8 to 6.0.0 ([#3974](https://github.com/cookiecutter/cookiecutter-django/pull/3974)) ## 2022.11.30 ### Changed - Add Azure Storage as an option to serve static and media files ([#3967](https://github.com/cookiecutter/cookiecutter-django/pull/3967)) ### Updated - Auto-update pre-commit hooks ([#3970](https://github.com/cookiecutter/cookiecutter-django/pull/3970)) ## 2022.11.26 ### Changed - Fix typo in flower start for watching celery ([#3966](https://github.com/cookiecutter/cookiecutter-django/pull/3966)) ## 2022.11.24 ### Updated - Auto-update pre-commit hooks ([#3963](https://github.com/cookiecutter/cookiecutter-django/pull/3963)) ## 2022.11.23 ### Changed - Fix graceful shutdown of local dev containers and use watchfiles for beat + flower ([#3925](https://github.com/cookiecutter/cookiecutter-django/pull/3925)) - feat(celery): Enable sending the sent task event by default ([#3961](https://github.com/cookiecutter/cookiecutter-django/pull/3961)) ### Updated - Bump stefanzweifel/git-auto-commit-action from 4.15.3 to 4.15.4 ([#3940](https://github.com/cookiecutter/cookiecutter-django/pull/3940)) - Update django-model-utils to 4.3.1 ([#3948](https://github.com/cookiecutter/cookiecutter-django/pull/3948)) - Update flake8-isort to 5.0.3 ([#3952](https://github.com/cookiecutter/cookiecutter-django/pull/3952)) ## 2022.11.22 ### Changed - Remove USE_L10N due to deprecation ([#3960](https://github.com/cookiecutter/cookiecutter-django/pull/3960)) - Remove platform from compose file ([#3957](https://github.com/cookiecutter/cookiecutter-django/pull/3957)) - feat(celery): Send task events for Celery by default ([#3959](https://github.com/cookiecutter/cookiecutter-django/pull/3959)) ### Updated - Update python-slugify to 7.0.0 ([#3950](https://github.com/cookiecutter/cookiecutter-django/pull/3950)) - Update redis to 4.3.5 ([#3954](https://github.com/cookiecutter/cookiecutter-django/pull/3954)) - Update sentry-sdk to 1.11.1 ([#3955](https://github.com/cookiecutter/cookiecutter-django/pull/3955)) - Update uvicorn to 0.20.0 ([#3953](https://github.com/cookiecutter/cookiecutter-django/pull/3953)) - Update tox to 3.27.1 ([#3945](https://github.com/cookiecutter/cookiecutter-django/pull/3945)) ## 2022.11.11 ### Updated - Auto-update pre-commit hooks ([#3942](https://github.com/cookiecutter/cookiecutter-django/pull/3942)) ## 2022.11.07 ### Updated - Update watchfiles to 0.18.1 ([#3938](https://github.com/cookiecutter/cookiecutter-django/pull/3938)) ## 2022.11.06 ### Changed - Store extended Celery task attributes in backend ([#3855](https://github.com/cookiecutter/cookiecutter-django/pull/3855)) - add os requirements for Ubuntu 22.04 (Jammy) ([#3930](https://github.com/cookiecutter/cookiecutter-django/pull/3930)) ### Updated - Update pytest-sugar to 0.9.6 ([#3937](https://github.com/cookiecutter/cookiecutter-django/pull/3937)) - Update pygithub to 1.57 ([#3936](https://github.com/cookiecutter/cookiecutter-django/pull/3936)) - Update sphinx-rtd-theme to 1.1.1 ([#3935](https://github.com/cookiecutter/cookiecutter-django/pull/3935)) ## 2022.11.02 ### Changed - fix typo in CONTRIBUTING.md ([#3932](https://github.com/cookiecutter/cookiecutter-django/pull/3932)) ### Updated - Update crispy-bootstrap5 to 0.7 ([#3886](https://github.com/cookiecutter/cookiecutter-django/pull/3886)) - Update django-coverage-plugin to 2.0.4 ([#3927](https://github.com/cookiecutter/cookiecutter-django/pull/3927)) - Update pytz to 2022.6 ([#3928](https://github.com/cookiecutter/cookiecutter-django/pull/3928)) - Update sphinx-rtd-theme to 1.1.0 ([#3929](https://github.com/cookiecutter/cookiecutter-django/pull/3929)) - Update pillow to 9.3.0 ([#3922](https://github.com/cookiecutter/cookiecutter-django/pull/3922)) ## 2022.10.30 ### Updated - Auto-update pre-commit hooks ([#3924](https://github.com/cookiecutter/cookiecutter-django/pull/3924)) ## 2022.10.28 ### Updated - Bump stefanzweifel/git-auto-commit-action from 4.15.2 to 4.15.3 ([#3921](https://github.com/cookiecutter/cookiecutter-django/pull/3921)) ## 2022.10.26 ### Updated - Update uvicorn to 0.19.0 ([#3920](https://github.com/cookiecutter/cookiecutter-django/pull/3920)) - Update pytest to 7.2.0 ([#3919](https://github.com/cookiecutter/cookiecutter-django/pull/3919)) - Update tox to 3.27.0 ([#3917](https://github.com/cookiecutter/cookiecutter-django/pull/3917)) - Update psycopg2 to 2.9.5 ([#3918](https://github.com/cookiecutter/cookiecutter-django/pull/3918)) ## 2022.10.24 ### Changed - Upgrade Python version from 3.9 to 3.10 ([#3913](https://github.com/cookiecutter/cookiecutter-django/pull/3913)) ### Updated - Update sentry-sdk to 1.10.1 ([#3911](https://github.com/cookiecutter/cookiecutter-django/pull/3911)) - Bump stefanzweifel/git-auto-commit-action from 4.15.1 to 4.15.2 ([#3914](https://github.com/cookiecutter/cookiecutter-django/pull/3914)) ## 2022.10.19 ### Changed - Set AWS_S3_MAX_MEMORY_SIZE ([#3810](https://github.com/cookiecutter/cookiecutter-django/pull/3810)) - Upgrade to Django 4.0 ([#3848](https://github.com/cookiecutter/cookiecutter-django/pull/3848)) ### Updated - Update pytz to 2022.5 ([#3906](https://github.com/cookiecutter/cookiecutter-django/pull/3906)) - Update sphinx to 5.3.0 ([#3905](https://github.com/cookiecutter/cookiecutter-django/pull/3905)) - Update django-celery-beat to 2.4.0 ([#3908](https://github.com/cookiecutter/cookiecutter-django/pull/3908)) - Update watchfiles to 0.18.0 ([#3907](https://github.com/cookiecutter/cookiecutter-django/pull/3907)) ## 2022.10.13 ### Updated - Update pygithub to 1.56 ([#3904](https://github.com/cookiecutter/cookiecutter-django/pull/3904)) ## 2022.10.11 ### Updated - Auto-update pre-commit hooks ([#3899](https://github.com/cookiecutter/cookiecutter-django/pull/3899)) - Update flake8-isort to 5.0.0 ([#3901](https://github.com/cookiecutter/cookiecutter-django/pull/3901)) - Update gitpython to 3.1.29 ([#3902](https://github.com/cookiecutter/cookiecutter-django/pull/3902)) - Update psycopg2 to 2.9.4 ([#3896](https://github.com/cookiecutter/cookiecutter-django/pull/3896)) - Bump stefanzweifel/git-auto-commit-action from 4.15.0 to 4.15.1 ([#3903](https://github.com/cookiecutter/cookiecutter-django/pull/3903)) - Update black to 22.10.0 ([#3898](https://github.com/cookiecutter/cookiecutter-django/pull/3898)) ## 2022.10.04 ### Updated - Update django to 3.2.16 ([#3895](https://github.com/cookiecutter/cookiecutter-django/pull/3895)) - Update mypy to 0.982 ([#3893](https://github.com/cookiecutter/cookiecutter-django/pull/3893)) - Auto-update pre-commit hooks ([#3894](https://github.com/cookiecutter/cookiecutter-django/pull/3894)) ## 2022.10.03 ### Updated - Update sentry-sdk to 1.9.10 ([#3892](https://github.com/cookiecutter/cookiecutter-django/pull/3892)) ## 2022.10.02 ### Updated - Update pytz to 2022.4 ([#3891](https://github.com/cookiecutter/cookiecutter-django/pull/3891)) ## 2022.09.30 ### Updated - Update coverage to 6.5.0 ([#3890](https://github.com/cookiecutter/cookiecutter-django/pull/3890)) - Update mypy to 0.981 ([#3889](https://github.com/cookiecutter/cookiecutter-django/pull/3889)) - Update sentry-sdk to 1.9.9 ([#3888](https://github.com/cookiecutter/cookiecutter-django/pull/3888)) - Update sphinx to 5.2.3 ([#3887](https://github.com/cookiecutter/cookiecutter-django/pull/3887)) ## 2022.09.29 ### Changed - Remove outdated & optional Sendgrid settings from production config ([#3885](https://github.com/cookiecutter/cookiecutter-django/pull/3885)) ## 2022.09.27 ### Updated - Update sphinx to 5.2.2 ([#3884](https://github.com/cookiecutter/cookiecutter-django/pull/3884)) ## 2022.09.26 ### Updated - Update drf-spectacular to 0.24.2 ([#3882](https://github.com/cookiecutter/cookiecutter-django/pull/3882)) - Update djangorestframework to 3.14.0 ([#3881](https://github.com/cookiecutter/cookiecutter-django/pull/3881)) - Update django-debug-toolbar to 3.7.0 ([#3878](https://github.com/cookiecutter/cookiecutter-django/pull/3878)) - Auto-update pre-commit hooks ([#3877](https://github.com/cookiecutter/cookiecutter-django/pull/3877)) - Bump stefanzweifel/git-auto-commit-action from 4.14.1 to 4.15.0 ([#3880](https://github.com/cookiecutter/cookiecutter-django/pull/3880)) - Update sphinx to 5.2.1 ([#3879](https://github.com/cookiecutter/cookiecutter-django/pull/3879)) ## 2022.09.24 ### Fixed - Remove `--no-deps` in pip wheels command of docs Dockerfile ([#3875](https://github.com/cookiecutter/cookiecutter-django/pull/3875)) ## 2022.09.23 ### Changed - Reload uvicorn on html file change ([#3866](https://github.com/cookiecutter/cookiecutter-django/pull/3866)) - Mailjet default api url does not work out of the box ([#3871](https://github.com/cookiecutter/cookiecutter-django/pull/3871)) ### Updated - Auto-update pre-commit hooks ([#3872](https://github.com/cookiecutter/cookiecutter-django/pull/3872)) - Update django-extensions to 3.2.1 ([#3867](https://github.com/cookiecutter/cookiecutter-django/pull/3867)) - Update tox to 3.26.0 ([#3864](https://github.com/cookiecutter/cookiecutter-django/pull/3864)) - Update drf-spectacular to 0.24.1 ([#3874](https://github.com/cookiecutter/cookiecutter-django/pull/3874)) ## 2022.09.15 ### Updated - Update watchfiles to 0.17.0 ([#3869](https://github.com/cookiecutter/cookiecutter-django/pull/3869)) - Update drf-spectacular to 0.24.0 ([#3870](https://github.com/cookiecutter/cookiecutter-django/pull/3870)) ## 2022.09.05 ### Updated - Update sentry-sdk to 1.9.8 ([#3861](https://github.com/cookiecutter/cookiecutter-django/pull/3861)) ## 2022.09.02 ### Updated - Update pytest to 7.1.3 ([#3860](https://github.com/cookiecutter/cookiecutter-django/pull/3860)) - Update sentry-sdk to 1.9.7 ([#3859](https://github.com/cookiecutter/cookiecutter-django/pull/3859)) ## 2022.09.01 ### Changed - Add article to README about how to use a hosted DB ([#3844](https://github.com/cookiecutter/cookiecutter-django/pull/3844)) ### Updated - Update sentry-sdk to 1.9.6 ([#3856](https://github.com/cookiecutter/cookiecutter-django/pull/3856)) - Auto-update pre-commit hooks ([#3858](https://github.com/cookiecutter/cookiecutter-django/pull/3858)) - Update black to 22.8.0 ([#3857](https://github.com/cookiecutter/cookiecutter-django/pull/3857)) ## 2022.08.26 ### Changed - Fix formatting in docs ([#3850](https://github.com/cookiecutter/cookiecutter-django/pull/3850)) ## 2022.08.24 ### Updated - Update django-debug-toolbar to 3.6.0 ([#3847](https://github.com/cookiecutter/cookiecutter-django/pull/3847)) - Update werkzeug to 2.2.2 ([#3846](https://github.com/cookiecutter/cookiecutter-django/pull/3846)) - Update coverage to 6.4.4 ([#3842](https://github.com/cookiecutter/cookiecutter-django/pull/3842)) - Update uvicorn to 0.18.3 ([#3845](https://github.com/cookiecutter/cookiecutter-django/pull/3845)) - Update sentry-sdk to 1.9.5 ([#3841](https://github.com/cookiecutter/cookiecutter-django/pull/3841)) - Update flower to 1.2.0 ([#3836](https://github.com/cookiecutter/cookiecutter-django/pull/3836)) - Update django-storages to 1.13.1 ([#3833](https://github.com/cookiecutter/cookiecutter-django/pull/3833)) ## 2022.08.15 ### Updated - Update coverage to 6.4.3 ([#3835](https://github.com/cookiecutter/cookiecutter-django/pull/3835)) - Update pytz to 2022.2.1 ([#3840](https://github.com/cookiecutter/cookiecutter-django/pull/3840)) - Update sentry-sdk to 1.9.4 ([#3838](https://github.com/cookiecutter/cookiecutter-django/pull/3838)) ## 2022.08.09 ### Updated - Update sentry-sdk to 1.9.3 ([#3837](https://github.com/cookiecutter/cookiecutter-django/pull/3837)) ## 2022.08.05 ### Updated - Update sentry-sdk to 1.9.2 ([#3832](https://github.com/cookiecutter/cookiecutter-django/pull/3832)) ## 2022.08.04 ### Updated - Auto-update pre-commit hooks ([#3816](https://github.com/cookiecutter/cookiecutter-django/pull/3816)) - Update flake8 to 5.0.4 ([#3829](https://github.com/cookiecutter/cookiecutter-django/pull/3829)) - Update django-compressor to 4.1 ([#3823](https://github.com/cookiecutter/cookiecutter-django/pull/3823)) - Update flake8-isort to 4.2.0 ([#3828](https://github.com/cookiecutter/cookiecutter-django/pull/3828)) ## 2022.08.03 ### Updated - Update django to 3.2.15 ([#3822](https://github.com/cookiecutter/cookiecutter-django/pull/3822)) ## 2022.07.29 ### Updated - Update sentry-sdk to 1.9.0 ([#3815](https://github.com/cookiecutter/cookiecutter-django/pull/3815)) ## 2022.07.28 ### Updated - Update werkzeug to 2.2.1 ([#3814](https://github.com/cookiecutter/cookiecutter-django/pull/3814)) ## 2022.07.27 ### Updated - Update werkzeug to 2.2.0 ([#3813](https://github.com/cookiecutter/cookiecutter-django/pull/3813)) - Update sphinx to 5.1.1 ([#3811](https://github.com/cookiecutter/cookiecutter-django/pull/3811)) - Update drf-spectacular to 0.23.1 ([#3812](https://github.com/cookiecutter/cookiecutter-django/pull/3812)) ## 2022.07.26 ### Changed - Switch from `watchgod` to `watchfiles` ([#3791](https://github.com/cookiecutter/cookiecutter-django/pull/3791)) - Change Django settings file used by pylint ([#3806](https://github.com/cookiecutter/cookiecutter-django/pull/3806)) - Simplify database access in tests ([#3807](https://github.com/cookiecutter/cookiecutter-django/pull/3807)) - Provide more context when wating for PostgreSQL takes too long ([#3782](https://github.com/cookiecutter/cookiecutter-django/pull/3782)) ### Updated - Update django-compressor to 4.0 ([#3802](https://github.com/cookiecutter/cookiecutter-django/pull/3802)) - Update flake8-isort to 4.1.2.post0 ([#3809](https://github.com/cookiecutter/cookiecutter-django/pull/3809)) - Update sphinx to 5.1.0 ([#3808](https://github.com/cookiecutter/cookiecutter-django/pull/3808)) - Update sh to 1.14.3 ([#3798](https://github.com/cookiecutter/cookiecutter-django/pull/3798)) - Auto-update pre-commit hooks ([#3780](https://github.com/cookiecutter/cookiecutter-django/pull/3780)) ## 2022.07.22 ### Updated - Update pytest-sugar to 0.9.5 ([#3800](https://github.com/cookiecutter/cookiecutter-django/pull/3800)) - Update sphinx to 5.0.2 ([#3801](https://github.com/cookiecutter/cookiecutter-django/pull/3801)) - Update pillow to 9.2.0 ([#3799](https://github.com/cookiecutter/cookiecutter-django/pull/3799)) - Update werkzeug to 2.1.2 ([#3797](https://github.com/cookiecutter/cookiecutter-django/pull/3797)) ## 2022.07.21 ### Changed - Set user to form instance in update user view test ([#3776](https://github.com/cookiecutter/cookiecutter-django/pull/3776)) - Fix warning from django-coverage-plugin in tests ([#3790](https://github.com/cookiecutter/cookiecutter-django/pull/3790)) - Always use `const` instead of `var` in `gulpfile.js` ([#3786](https://github.com/cookiecutter/cookiecutter-django/pull/3786)) ### Updated - Update flower to 1.1.0 ([#3796](https://github.com/cookiecutter/cookiecutter-django/pull/3796)) - Update coverage to 6.4.2 ([#3783](https://github.com/cookiecutter/cookiecutter-django/pull/3783)) - Update mypy to 0.971 ([#3788](https://github.com/cookiecutter/cookiecutter-django/pull/3788)) - Update sentry-sdk to 1.8.0 ([#3792](https://github.com/cookiecutter/cookiecutter-django/pull/3792)) - Update pre-commit to 2.20.0 ([#3779](https://github.com/cookiecutter/cookiecutter-django/pull/3779)) - Update django-extensions to 3.2.0 ([#3774](https://github.com/cookiecutter/cookiecutter-django/pull/3774)) - Update tox to 3.25.1 ([#3767](https://github.com/cookiecutter/cookiecutter-django/pull/3767)) - Update uvicorn to 0.18.2 ([#3762](https://github.com/cookiecutter/cookiecutter-django/pull/3762)) - Update redis to 4.3.4 ([#3763](https://github.com/cookiecutter/cookiecutter-django/pull/3763)) - Update requests to 2.28.1 ([#3766](https://github.com/cookiecutter/cookiecutter-django/pull/3766)) ## 2022.07.10 ### Changed - Revert auto-update pre-commit hooks ([#3778](https://github.com/cookiecutter/cookiecutter-django/pull/3778)) ### Updated - Auto-update pre-commit hooks ([#3775](https://github.com/cookiecutter/cookiecutter-django/pull/3775)) ## 2022.07.06 ### Updated - Update django to 3.2.14 ([#3768](https://github.com/cookiecutter/cookiecutter-django/pull/3768)) ## 2022.06.28 ### Updated - Auto-update pre-commit hooks ([#3765](https://github.com/cookiecutter/cookiecutter-django/pull/3765)) - Update black to 22.6.0 ([#3764](https://github.com/cookiecutter/cookiecutter-django/pull/3764)) ## 2022.06.23 ### Updated - Update django-debug-toolbar to 3.5.0 ([#3760](https://github.com/cookiecutter/cookiecutter-django/pull/3760)) ## 2022.06.22 ### Updated - Update django-stubs to 1.12.0 ([#3757](https://github.com/cookiecutter/cookiecutter-django/pull/3757)) - Update sentry-sdk to 1.6.0 ([#3756](https://github.com/cookiecutter/cookiecutter-django/pull/3756)) - Update djangorestframework-stubs to 1.7.0 ([#3754](https://github.com/cookiecutter/cookiecutter-django/pull/3754)) ## 2022.06.15 ### Updated - Update django-environ to 0.9.0 ([#3751](https://github.com/cookiecutter/cookiecutter-django/pull/3751)) ## 2022.06.13 ### Updated - Update cookiecutter to 2.1.1 ([#3727](https://github.com/cookiecutter/cookiecutter-django/pull/3727)) ## 2022.06.11 ### Updated - Update requests to 2.28.0 ([#3748](https://github.com/cookiecutter/cookiecutter-django/pull/3748)) ## 2022.06.09 ### Updated - Bump actions/setup-python from 3 to 4 ([#3746](https://github.com/cookiecutter/cookiecutter-django/pull/3746)) ## 2022.06.08 ### Updated - Auto-update pre-commit hooks ([#3744](https://github.com/cookiecutter/cookiecutter-django/pull/3744)) ## 2022.06.07 ### Updated - Update django-allauth to 0.51.0 ([#3743](https://github.com/cookiecutter/cookiecutter-django/pull/3743)) - Auto-update pre-commit hooks ([#3742](https://github.com/cookiecutter/cookiecutter-django/pull/3742)) ## 2022.06.06 ### Updated - Bump pre-commit/action from 2.0.3 to 3.0.0 ([#3739](https://github.com/cookiecutter/cookiecutter-django/pull/3739)) ## 2022.06.05 ### Updated - Update whitenoise to 6.2.0 ([#3737](https://github.com/cookiecutter/cookiecutter-django/pull/3737)) - Update django-cors-headers to 3.13.0 ([#3738](https://github.com/cookiecutter/cookiecutter-django/pull/3738)) ## 2022.06.04 ### Updated - Update django-cors-headers to 3.12.0 ([#3736](https://github.com/cookiecutter/cookiecutter-django/pull/3736)) - Update djangorestframework-stubs to 1.6.0 ([#3718](https://github.com/cookiecutter/cookiecutter-django/pull/3718)) - Update django-stubs to 1.11.0 ([#3734](https://github.com/cookiecutter/cookiecutter-django/pull/3734)) - Update sphinx to 5.0.1 ([#3733](https://github.com/cookiecutter/cookiecutter-django/pull/3733)) - Update sphinx to 5.0.0 ([#3724](https://github.com/cookiecutter/cookiecutter-django/pull/3724)) - Update celery to 5.2.7 ([#3732](https://github.com/cookiecutter/cookiecutter-django/pull/3732)) - Update django-celery-beat to 2.3.0 ([#3731](https://github.com/cookiecutter/cookiecutter-django/pull/3731)) ## 2022.06.02 ### Updated - Update coverage to 6.4.1 ([#3729](https://github.com/cookiecutter/cookiecutter-django/pull/3729)) - Update redis to 4.3.3 ([#3728](https://github.com/cookiecutter/cookiecutter-django/pull/3728)) ## 2022.06.01 ### Updated - Update redis to 4.3.2 ([#3726](https://github.com/cookiecutter/cookiecutter-django/pull/3726)) ## 2022.05.24 ### Updated - Update coverage to 6.4 ([#3716](https://github.com/cookiecutter/cookiecutter-django/pull/3716)) ## 2022.05.18 ### Updated - Update pillow to 9.1.1 ([#3714](https://github.com/cookiecutter/cookiecutter-django/pull/3714)) ## 2022.05.16 ### Changed - Update postgres versions ([#3712](https://github.com/cookiecutter/cookiecutter-django/pull/3712)) ### Updated - Update django-anymail to 8.6 ([#3713](https://github.com/cookiecutter/cookiecutter-django/pull/3713)) ## 2022.05.14 ### Updated - Update coverage to 6.3.3 ([#3709](https://github.com/cookiecutter/cookiecutter-django/pull/3709)) - Update whitenoise to 6.1.0 ([#3707](https://github.com/cookiecutter/cookiecutter-django/pull/3707)) - Update sentry-sdk to 1.5.12 ([#3706](https://github.com/cookiecutter/cookiecutter-django/pull/3706)) - Update redis to 4.3.1 ([#3704](https://github.com/cookiecutter/cookiecutter-django/pull/3704)) ## 2022.05.07 ### Changed - Add pyupgrade to pre-commit config ([#3702](https://github.com/cookiecutter/cookiecutter-django/pull/3702)) - Set permissions for GitHub actions ([#3698](https://github.com/cookiecutter/cookiecutter-django/pull/3698)) ### Updated - Update jinja2 to 3.1.2 ([#3700](https://github.com/cookiecutter/cookiecutter-django/pull/3700)) ## 2022.05.06 ### Updated - Update pre-commit to 2.19.0 ([#3697](https://github.com/cookiecutter/cookiecutter-django/pull/3697)) ## 2022.05.04 ### Updated - Update django-coverage-plugin to 2.0.3 ([#3695](https://github.com/cookiecutter/cookiecutter-django/pull/3695)) ## 2022.05.03 ### Updated - Update django-debug-toolbar to 3.4.0 ([#3692](https://github.com/cookiecutter/cookiecutter-django/pull/3692)) - Update sentry-sdk to 1.5.11 ([#3693](https://github.com/cookiecutter/cookiecutter-django/pull/3693)) ## 2022.05.01 ### Updated - Update django-debug-toolbar to 3.3.0 ([#3690](https://github.com/cookiecutter/cookiecutter-django/pull/3690)) ## 2022.04.28 ### Changed - Add the possibility to set a max django version on create_django_issue script ([#3680](https://github.com/cookiecutter/cookiecutter-django/pull/3680)) ## 2022.04.27 ### Updated - Update mypy to 0.950 ([#3687](https://github.com/cookiecutter/cookiecutter-django/pull/3687)) - Update python-slugify to 6.1.2 ([#3686](https://github.com/cookiecutter/cookiecutter-django/pull/3686)) - Update drf-spectacular to 0.22.1 ([#3684](https://github.com/cookiecutter/cookiecutter-django/pull/3684)) ## 2022.04.25 ### Updated - Update pytest to 7.1.2 ([#3683](https://github.com/cookiecutter/cookiecutter-django/pull/3683)) ## 2022.04.19 ### Updated - Update tox to 3.25.0 ([#3675](https://github.com/cookiecutter/cookiecutter-django/pull/3675)) - Update sentry-sdk to 1.5.10 ([#3679](https://github.com/cookiecutter/cookiecutter-django/pull/3679)) ## 2022.04.13 ### Updated - Bump stefanzweifel/git-auto-commit-action from 4.14.0 to 4.14.1 ([#3677](https://github.com/cookiecutter/cookiecutter-django/pull/3677)) ## 2022.04.11 ### Updated - Update django to 3.2.13 ([#3676](https://github.com/cookiecutter/cookiecutter-django/pull/3676)) ## 2022.04.08 ### Updated - Auto-update pre-commit hooks ([#3673](https://github.com/cookiecutter/cookiecutter-django/pull/3673)) ## 2022.04.05 ### Updated - Update celery to 5.2.6 ([#3671](https://github.com/cookiecutter/cookiecutter-django/pull/3671)) ## 2022.04.04 ### Updated - Update redis to 4.2.2 ([#3670](https://github.com/cookiecutter/cookiecutter-django/pull/3670)) - Update celery to 5.2.5 ([#3669](https://github.com/cookiecutter/cookiecutter-django/pull/3669)) - Update pre-commit to 2.18.1 ([#3668](https://github.com/cookiecutter/cookiecutter-django/pull/3668)) - Update pillow to 9.1.0 ([#3665](https://github.com/cookiecutter/cookiecutter-django/pull/3665)) ## 2022.04.01 ### Changed - Update domain for Celery docs ([#3663](https://github.com/cookiecutter/cookiecutter-django/pull/3663)) ### Updated - Update watchgod to 0.8.2 ([#3664](https://github.com/cookiecutter/cookiecutter-django/pull/3664)) - Update redis to 4.2.1 ([#3660](https://github.com/cookiecutter/cookiecutter-django/pull/3660)) ## 2022.03.28 ### Changed - Update `black` version to `22.3.0` ([#3657](https://github.com/cookiecutter/cookiecutter-django/pull/3657)) ## 2022.03.27 ### Updated - Update sphinx to 4.5.0 ([#3654](https://github.com/cookiecutter/cookiecutter-django/pull/3654)) - Update jinja2 to 3.1.1 ([#3652](https://github.com/cookiecutter/cookiecutter-django/pull/3652)) - Update pylint-django to 2.5.3 ([#3650](https://github.com/cookiecutter/cookiecutter-django/pull/3650)) - Update django-allauth to 0.50.0 ([#3649](https://github.com/cookiecutter/cookiecutter-django/pull/3649)) - Update mypy to 0.942 ([#3648](https://github.com/cookiecutter/cookiecutter-django/pull/3648)) - Update jinja2 to 3.1.0 ([#3647](https://github.com/cookiecutter/cookiecutter-django/pull/3647)) - Update redis to 4.2.0 ([#3646](https://github.com/cookiecutter/cookiecutter-django/pull/3646)) - Update watchgod to 0.8.1 ([#3643](https://github.com/cookiecutter/cookiecutter-django/pull/3643)) - Bump stefanzweifel/git-auto-commit-action from 4.13.1 to 4.14.0 ([#3641](https://github.com/cookiecutter/cookiecutter-django/pull/3641)) - Update drf-spectacular to 0.22.0 ([#3642](https://github.com/cookiecutter/cookiecutter-django/pull/3642)) - Update pytz to 2022.1 ([#3639](https://github.com/cookiecutter/cookiecutter-django/pull/3639)) - Update sentry-sdk to 1.5.8 ([#3638](https://github.com/cookiecutter/cookiecutter-django/pull/3638)) - Update pytest to 7.1.1 ([#3637](https://github.com/cookiecutter/cookiecutter-django/pull/3637)) - Update uvicorn to 0.17.6 ([#3627](https://github.com/cookiecutter/cookiecutter-django/pull/3627)) ## 2022.03.23 ### Updated - Bump peter-evans/create-pull-request from 3.14.0 to 4 ([#3645](https://github.com/cookiecutter/cookiecutter-django/pull/3645)) ## 2022.03.20 ### Changed - Unify compressor, gulp and custom bootstrap options ([#3535](https://github.com/cookiecutter/cookiecutter-django/pull/3535)) ## 2022.03.14 ### Fixed - Fix broken link in README of generated projects ([#3634](https://github.com/cookiecutter/cookiecutter-django/pull/3634)) ## 2022.03.13 ### Changed - Add DRF spectacular link in requirements ([#3630](https://github.com/cookiecutter/cookiecutter-django/pull/3630)) ## 2022.03.09 ### Changed - Fix a few typos in the documentation ([#3625](https://github.com/cookiecutter/cookiecutter-django/pull/3625)) ## 2022.03.08 ### Updated - Update sentry-sdk to 1.5.7 ([#3624](https://github.com/cookiecutter/cookiecutter-django/pull/3624)) ## 2022.03.03 ### Updated - Upgrade actions/setup-python to v3 ([#3621](https://github.com/cookiecutter/cookiecutter-django/pull/3621)) ## 2022.03.02 ### Updated - Bump actions/checkout from 2 to 3 ([#3619](https://github.com/cookiecutter/cookiecutter-django/pull/3619)) ## 2022.03.01 ### Updated - Bump actions/setup-python from 2 to 3 ([#3617](https://github.com/cookiecutter/cookiecutter-django/pull/3617)) - Bump peter-evans/create-pull-request from 3.13.0 to 3.14.0 ([#3618](https://github.com/cookiecutter/cookiecutter-django/pull/3618)) ## 2022.02.28 ### Updated - Update python-slugify to 6.1.1 ([#3615](https://github.com/cookiecutter/cookiecutter-django/pull/3615)) - Bump peter-evans/create-pull-request from 3.12.1 to 3.13.0 ([#3616](https://github.com/cookiecutter/cookiecutter-django/pull/3616)) ## 2022.02.25 ### Updated - Bump actions/setup-node from 2 to 3 ([#3614](https://github.com/cookiecutter/cookiecutter-django/pull/3614)) ## 2022.02.24 ### Updated - Update django-allauth to 0.49.0 ([#3613](https://github.com/cookiecutter/cookiecutter-django/pull/3613)) - Update sentry-sdk to 1.5.6 ([#3611](https://github.com/cookiecutter/cookiecutter-django/pull/3611)) - Update python-slugify to 6.1.0 ([#3612](https://github.com/cookiecutter/cookiecutter-django/pull/3612)) ## 2022.02.21 ### Changed - Cancel previous CI runs on successive PR pushes with GitHub actions ([#3575](https://github.com/cookiecutter/cookiecutter-django/pull/3575)) ### Updated - Update coverage to 6.3.2 ([#3610](https://github.com/cookiecutter/cookiecutter-django/pull/3610)) - Update gitpython to 3.1.27 ([#3607](https://github.com/cookiecutter/cookiecutter-django/pull/3607)) - Update pylint-django to 2.5.2 ([#3602](https://github.com/cookiecutter/cookiecutter-django/pull/3602)) - Update python-slugify to 6.0.1 ([#3599](https://github.com/cookiecutter/cookiecutter-django/pull/3599)) - Update uvicorn to 0.17.5 ([#3596](https://github.com/cookiecutter/cookiecutter-django/pull/3596)) - Update redis to 4.1.4 ([#3595](https://github.com/cookiecutter/cookiecutter-django/pull/3595)) ## 2022.02.20 ### Changed - Fix incorrect createdb instruction in documentation ([#3606](https://github.com/cookiecutter/cookiecutter-django/pull/3606)) ## 2022.02.16 ### Fixed - Fix Swagger schema API endpoint & add a test for it ([#3592](https://github.com/cookiecutter/cookiecutter-django/pull/3592)) ## 2022.02.15 ### Changed - Update the drf-spectacular local dev server url to use http instead of https ([#3591](https://github.com/cookiecutter/cookiecutter-django/pull/3591)) ## 2022.02.13 ### Changed - Change docs port from 7000 to 9000 ([#3590](https://github.com/cookiecutter/cookiecutter-django/pull/3590)) ## 2022.02.12 ### Updated - Update pytest to 7.0.1 ([#3588](https://github.com/cookiecutter/cookiecutter-django/pull/3588)) ## 2022.02.11 ### Updated - Update sentry-sdk to 1.5.5 ([#3586](https://github.com/cookiecutter/cookiecutter-django/pull/3586)) ## 2022.02.10 ### Fixed - Fix GitLab CI error caused by Docker Compose's `platform` option ([#3585](https://github.com/cookiecutter/cookiecutter-django/pull/3585)) ### Updated - Update whitenoise to 6.0.0 ([#3583](https://github.com/cookiecutter/cookiecutter-django/pull/3583)) ## 2022.02.08 ### Fixed - Fixed some typos in drf-spectacular description and comments ([#3579](https://github.com/cookiecutter/cookiecutter-django/pull/3579)) ### Updated - Update redis to 4.1.3 ([#3577](https://github.com/cookiecutter/cookiecutter-django/pull/3577)) - Update werkzeug to 2.0.3 ([#3576](https://github.com/cookiecutter/cookiecutter-django/pull/3576)) ## 2022.02.07 ### Changed - Update black to 22.1.0 ([#3572](https://github.com/cookiecutter/cookiecutter-django/pull/3572)) ### Fixed - Fix docker-compose config on Apple silicon ([#3562](https://github.com/cookiecutter/cookiecutter-django/pull/3562)) ### Updated - Update uvicorn to 0.17.4 ([#3574](https://github.com/cookiecutter/cookiecutter-django/pull/3574)) - Update django-allauth to 0.48.0 ([#3573](https://github.com/cookiecutter/cookiecutter-django/pull/3573)) - Update pytest to 7.0.0 ([#3567](https://github.com/cookiecutter/cookiecutter-django/pull/3567)) - Update coverage to 6.3.1 ([#3561](https://github.com/cookiecutter/cookiecutter-django/pull/3561)) - Update pillow to 9.0.1 ([#3571](https://github.com/cookiecutter/cookiecutter-django/pull/3571)) - Bump peter-evans/create-pull-request from 3.12.0 to 3.12.1 ([#3558](https://github.com/cookiecutter/cookiecutter-django/pull/3558)) - Update drf-spectacular to 0.21.2 ([#3560](https://github.com/cookiecutter/cookiecutter-django/pull/3560)) - Update django to 3.2.12 ([#3559](https://github.com/cookiecutter/cookiecutter-django/pull/3559)) ## 2022.01.27 ### Updated - Update redis to 4.1.2 ([#3551](https://github.com/cookiecutter/cookiecutter-django/pull/3551)) ## 2022.01.26 ### Updated - Update coverage to 6.3 ([#3550](https://github.com/cookiecutter/cookiecutter-django/pull/3550)) - Update sentry-sdk to 1.5.4 ([#3549](https://github.com/cookiecutter/cookiecutter-django/pull/3549)) - Update django-crispy-forms to 1.14.0 ([#3548](https://github.com/cookiecutter/cookiecutter-django/pull/3548)) - Update uvicorn to 0.17.0.post1 ([#3547](https://github.com/cookiecutter/cookiecutter-django/pull/3547)) ## 2022.01.21 ### Changed - mysql support link ([#3544](https://github.com/cookiecutter/cookiecutter-django/pull/3544)) ### Updated - Update sentry-sdk to 1.5.3 ([#3543](https://github.com/cookiecutter/cookiecutter-django/pull/3543)) - Update django-anymail to 8.5 ([#3542](https://github.com/cookiecutter/cookiecutter-django/pull/3542)) ## 2022.01.19 ### Changed - Add swagger API documentation when DRF is enabled ([#3536](https://github.com/cookiecutter/cookiecutter-django/pull/3536)) ### Updated - Update pre-commit to 2.17.0 ([#3541](https://github.com/cookiecutter/cookiecutter-django/pull/3541)) ## 2022.01.17 ### Changed - Avoid docker image/volume collision by prefixing with project slug ([#3528](https://github.com/cookiecutter/cookiecutter-django/pull/3528)) ### Updated - Update redis to 4.1.1 ([#3540](https://github.com/cookiecutter/cookiecutter-django/pull/3540)) - Update sphinx to 4.4.0 ([#3537](https://github.com/cookiecutter/cookiecutter-django/pull/3537)) ## 2022.01.14 ### Updated - Update uvicorn to 0.17.0 ([#3534](https://github.com/cookiecutter/cookiecutter-django/pull/3534)) - Bump stefanzweifel/git-auto-commit-action from 4.13.0 to 4.13.1 ([#3532](https://github.com/cookiecutter/cookiecutter-django/pull/3532)) ## 2022.01.13 ### Changed - Add UserSignupForm and UserSocialSignupForm ([#3515](https://github.com/cookiecutter/cookiecutter-django/pull/3515)) ### Fixed - Fix high CPU usage when running `runserver_plus` in Docker ([#3531](https://github.com/cookiecutter/cookiecutter-django/pull/3531)) - Fix out-of-sync sequence for Site ID ([#3511](https://github.com/cookiecutter/cookiecutter-django/pull/3511)) ## 2022.01.11 ### Updated - Bump stefanzweifel/git-auto-commit-action from 4.12.0 to 4.13.0 ([#3527](https://github.com/cookiecutter/cookiecutter-django/pull/3527)) ## 2022.01.10 ### Updated - Update django-cors-headers to 3.11.0 ([#3526](https://github.com/cookiecutter/cookiecutter-django/pull/3526)) - Update sentry-sdk to 1.5.2 ([#3525](https://github.com/cookiecutter/cookiecutter-django/pull/3525)) - Update gitpython to 3.1.26 ([#3524](https://github.com/cookiecutter/cookiecutter-django/pull/3524)) ## 2022.01.09 ### Changed - Fix broken center align of image links in README ([#3522](https://github.com/cookiecutter/cookiecutter-django/pull/3522)) ## 2022.01.07 ### Fixed - Fix cache dependency path for linter job in CI workflow ([#3520](https://github.com/cookiecutter/cookiecutter-django/pull/3520)) - Fix `open` option for `initBrowserSync` when using Docker ([#3519](https://github.com/cookiecutter/cookiecutter-django/pull/3519)) ### Updated - Update mypy to 0.931 ([#3521](https://github.com/cookiecutter/cookiecutter-django/pull/3521)) - Update gitpython to 3.1.25 ([#3518](https://github.com/cookiecutter/cookiecutter-django/pull/3518)) ## 2022.01.06 ### Changed - Update output example in README ([#3512](https://github.com/cookiecutter/cookiecutter-django/pull/3512)) ## 2022.01.05 ### Changed - Update references to Bootstrap from v4 to v5 in README ([#3513](https://github.com/cookiecutter/cookiecutter-django/pull/3513)) ### Updated - Update requests to 2.27.1 ([#3516](https://github.com/cookiecutter/cookiecutter-django/pull/3516)) ## 2022.01.04 ### Changed - Double quote array expansions to avoid re-splitting elements ([#3514](https://github.com/cookiecutter/cookiecutter-django/pull/3514)) ### Updated - Update django to 3.2.11 ([#3510](https://github.com/cookiecutter/cookiecutter-django/pull/3510)) ## 2022.01.03 ### Changed - Convert top level RST files to Markdown ([#3489](https://github.com/cookiecutter/cookiecutter-django/pull/3489)) ### Updated - Update requests to 2.27.0 ([#3509](https://github.com/cookiecutter/cookiecutter-django/pull/3509)) - Update pillow to 9.0.0 ([#3508](https://github.com/cookiecutter/cookiecutter-django/pull/3508)) - Update pylint-django to 2.5.0 ([#3505](https://github.com/cookiecutter/cookiecutter-django/pull/3505)) ## 2021.12.29 ### Fixed - Add generated files to `.gitignore` when selecting Gulp ([#3500](https://github.com/cookiecutter/cookiecutter-django/pull/3500)) ### Updated - Update psycopg2-binary to 2.9.3 ([#3504](https://github.com/cookiecutter/cookiecutter-django/pull/3504)) - Update psycopg2 to 2.9.3 ([#3503](https://github.com/cookiecutter/cookiecutter-django/pull/3503)) - Update celery to 5.2.3 ([#3502](https://github.com/cookiecutter/cookiecutter-django/pull/3502)) - Update tox to 3.24.5 ([#3501](https://github.com/cookiecutter/cookiecutter-django/pull/3501)) ## 2021.12.28 ### Changed - Build the HTML for the documentation as part of the CI ([#3498](https://github.com/cookiecutter/cookiecutter-django/pull/3498)) ## 2021.12.27 ### Changed - Hides 'sign up' elements when ACCOUNT_ALLOW_REGISTRATION is disabled ([#1914](https://github.com/cookiecutter/cookiecutter-django/pull/1914)) ## 2021.12.26 ### Fixed - Fix missing psycopg2 dependency in docs Docker image ([#3494](https://github.com/cookiecutter/cookiecutter-django/pull/3494)) ### Updated - Update celery to 5.2.2 ([#3496](https://github.com/cookiecutter/cookiecutter-django/pull/3496)) - Update redis to 4.1.0 ([#3495](https://github.com/cookiecutter/cookiecutter-django/pull/3495)) ## 2021.12.25 ### Changed - Automatically add Django version label to issue ([#3492](https://github.com/cookiecutter/cookiecutter-django/pull/3492)) ### Updated - Auto-update pre-commit hooks ([#3493](https://github.com/cookiecutter/cookiecutter-django/pull/3493)) ## 2021.12.24 ### Changed - Simplify `TEMPLATES` settings with `APP_DIRS=True` ([#3488](https://github.com/cookiecutter/cookiecutter-django/pull/3488)) - Fix docs not building ([#3491](https://github.com/cookiecutter/cookiecutter-django/pull/3491)) - Remove pylint-django from VITAL_BUT_UNKNOWN ([#3490](https://github.com/cookiecutter/cookiecutter-django/pull/3490)) - Making docs image 40% smaller and also making python version upgrades easier for multi-stage builds. ([#2836](https://github.com/cookiecutter/cookiecutter-django/pull/2836)) - Added Django's current language to the lang attribute of the html tag ([#3174](https://github.com/cookiecutter/cookiecutter-django/pull/3174)) ### Updated - Update uvicorn to 0.16.0 ([#3454](https://github.com/cookiecutter/cookiecutter-django/pull/3454)) ## 2021.12.22 ### Changed - Use built-in pip caching from actions/setup-python in generated project ([#3481](https://github.com/cookiecutter/cookiecutter-django/pull/3481)) - Speed up CI tests on macOS ([#3480](https://github.com/cookiecutter/cookiecutter-django/pull/3480)) ### Updated - Update mypy to 0.930 ([#3487](https://github.com/cookiecutter/cookiecutter-django/pull/3487)) - Update redis to 4.0.2 ([#3486](https://github.com/cookiecutter/cookiecutter-django/pull/3486)) - Update django-redis to 5.2.0 ([#3485](https://github.com/cookiecutter/cookiecutter-django/pull/3485)) ## 2021.12.20 ### Changed - Add a PyCharm run configuration for docker-compose ([#3462](https://github.com/cookiecutter/cookiecutter-django/pull/3462)) ## 2021.12.19 ### Updated - Update mypy to 0.920 ([#3478](https://github.com/cookiecutter/cookiecutter-django/pull/3478)) - Update django-compressor to 3.1 ([#3476](https://github.com/cookiecutter/cookiecutter-django/pull/3476)) - Update sphinx to 4.3.2 ([#3477](https://github.com/cookiecutter/cookiecutter-django/pull/3477)) ## 2021.12.17 ### Fixed - Fix BrowserSync config on non-Docker setup ([#3461](https://github.com/cookiecutter/cookiecutter-django/pull/3461)) ## 2021.12.16 ### Fixed - Fix carriage return in `.gitignore` on Windows ([#3456](https://github.com/cookiecutter/cookiecutter-django/pull/3456)) ### Updated - Update django-debug-toolbar to 3.2.4 ([#3473](https://github.com/cookiecutter/cookiecutter-django/pull/3473)) ## 2021.12.15 ### Updated - Update djangorestframework to 3.13.1 ([#3472](https://github.com/cookiecutter/cookiecutter-django/pull/3472)) ## 2021.12.14 ### Changed - Update rcssmin & django-compressor ([#3470](https://github.com/cookiecutter/cookiecutter-django/pull/3470)) ### Updated - Update pytest-django to 4.5.2 ([#3471](https://github.com/cookiecutter/cookiecutter-django/pull/3471)) - Bump peter-evans/create-pull-request from 3.11.0 to 3.12.0 ([#3469](https://github.com/cookiecutter/cookiecutter-django/pull/3469)) ## 2021.12.13 ### Updated - Update djangorestframework to 3.13.0 ([#3468](https://github.com/cookiecutter/cookiecutter-django/pull/3468)) - Update sentry-sdk to 1.5.1 ([#3467](https://github.com/cookiecutter/cookiecutter-django/pull/3467)) - Update django-debug-toolbar to 3.2.3 ([#3466](https://github.com/cookiecutter/cookiecutter-django/pull/3466)) - Update argon2-cffi to 21.3.0 ([#3464](https://github.com/cookiecutter/cookiecutter-django/pull/3464)) - Update django-allauth to 0.47.0 ([#3459](https://github.com/cookiecutter/cookiecutter-django/pull/3459)) ## 2021.12.09 ### Updated - Auto-update pre-commit hooks ([#3457](https://github.com/cookiecutter/cookiecutter-django/pull/3457)) ## 2021.12.08 ### Changed - Reword introduction in documentation ([#3452](https://github.com/cookiecutter/cookiecutter-django/pull/3452)) ### Updated - Update argon2-cffi to 21.2.0 ([#3453](https://github.com/cookiecutter/cookiecutter-django/pull/3453)) ## 2021.12.07 ### Changed - Add docker, pip and npm to GitHub's Dependabot ([#3401](https://github.com/cookiecutter/cookiecutter-django/pull/3401)) - Configure Dependabot for npm packages at the template level ([#3436](https://github.com/cookiecutter/cookiecutter-django/pull/3436)) ### Updated - Update django to 3.2.10 ([#3451](https://github.com/cookiecutter/cookiecutter-django/pull/3451)) ## 2021.12.06 ### Updated - Auto-update pre-commit hooks ([#3449](https://github.com/cookiecutter/cookiecutter-django/pull/3449)) - Update black to 21.12b0 ([#3448](https://github.com/cookiecutter/cookiecutter-django/pull/3448)) - Update django-cors-headers to 3.10.1 ([#3447](https://github.com/cookiecutter/cookiecutter-django/pull/3447)) ## 2021.12.04 ### Changed - Removed mention of Foundation fork from readme ([#3445](https://github.com/cookiecutter/cookiecutter-django/pull/3445)) ### Updated - Update pytest-django to 4.5.1 ([#3443](https://github.com/cookiecutter/cookiecutter-django/pull/3443)) ## 2021.12.01 ### Updated - Update pre-commit to 2.16.0 ([#3442](https://github.com/cookiecutter/cookiecutter-django/pull/3442)) ## 2021.11.30 ### Updated - Update django-redis to 5.1.0 ([#3440](https://github.com/cookiecutter/cookiecutter-django/pull/3440)) - Update django-stubs to 1.9.0 ([#3439](https://github.com/cookiecutter/cookiecutter-django/pull/3439)) ## 2021.11.29 ### Fixed - Fix pre-commit config ([#3435](https://github.com/cookiecutter/cookiecutter-django/pull/3435)) ### Updated - Update sphinx to 4.3.1 ([#3438](https://github.com/cookiecutter/cookiecutter-django/pull/3438)) ## 2021.11.27 ### Updated - Update coverage to 6.2 ([#3437](https://github.com/cookiecutter/cookiecutter-django/pull/3437)) ## 2021.11.26 ### Changed - Setup pre-commit for the template files ([#3433](https://github.com/cookiecutter/cookiecutter-django/pull/3433)) ## 2021.11.25 ### Changed - Add an assertion to fix mypy type error ([#3150](https://github.com/cookiecutter/cookiecutter-django/pull/3150)) - Make `django` depend on `redis` in local Docker ([#3265](https://github.com/cookiecutter/cookiecutter-django/pull/3265)) ## 2021.11.24 ### Changed - Cache Python dependencies on our CI ([#3434](https://github.com/cookiecutter/cookiecutter-django/pull/3434)) - Small formatting fixes to Deploy to PythonAnywhere page ([#3432](https://github.com/cookiecutter/cookiecutter-django/pull/3432)) ### Updated - Upgrade to Django 3.2 ([#3425](https://github.com/cookiecutter/cookiecutter-django/pull/3425)) ## 2021.11.22 ### Changed - Removed unnecessary custom context processor exposing the DEBUG Template Context Variable ([#3042](https://github.com/cookiecutter/cookiecutter-django/pull/3042)) - Clean up trailing whitespace ([#3430](https://github.com/cookiecutter/cookiecutter-django/pull/3430)) ### Updated - Update redis to 4.0.2 ([#3431](https://github.com/cookiecutter/cookiecutter-django/pull/3431)) - Bump Postgres to 13.5 12.9 11.14 10.19; add 14.1 ([#3428](https://github.com/cookiecutter/cookiecutter-django/pull/3428)) ## 2021.11.20 ### Fixed - Update repos for pre-commit hooks ([#3424](https://github.com/cookiecutter/cookiecutter-django/pull/3424)) ### Updated - Bump pre-commit/action to 2.0.3 ([#3426](https://github.com/cookiecutter/cookiecutter-django/pull/3426)) ## 2021.11.19 ### Updated - Update celery to 5.2.1 ([#3423](https://github.com/cookiecutter/cookiecutter-django/pull/3423)) - Auto-update pre-commit hooks ([#3420](https://github.com/cookiecutter/cookiecutter-django/pull/3420)) ## 2021.11.18 ### Changed - Switch template to calendar versioning & automate releases ([#3415](https://github.com/cookiecutter/cookiecutter-django/pull/3415)) ### Updated - Update black to 21.11b1 ([#3421](https://github.com/cookiecutter/cookiecutter-django/pull/3421)) - Update redis to 4.0.1 ([#3416](https://github.com/cookiecutter/cookiecutter-django/pull/3416)) ## [2021-11-17] ### Updated - Update sentry-sdk to 1.5.0 ([#3417](https://github.com/cookiecutter/cookiecutter-django/pull/3417)) - Update black to 21.11b0 ([#3414](https://github.com/cookiecutter/cookiecutter-django/pull/3414)) ## [2021-11-16] ### Changed - Upgrade JS dependencies and upgrade to node 16 ([#3400](https://github.com/cookiecutter/cookiecutter-django/pull/3400)) ### Fixed - Fix ungraceful Celery workers shutdown in container ([#3405](https://github.com/cookiecutter/cookiecutter-django/pull/3405)) ### Updated - Update psycopg2-binary to 2.9.2 ([#3411](https://github.com/cookiecutter/cookiecutter-django/pull/3411)) - Update psycopg2 to 2.9.2 ([#3410](https://github.com/cookiecutter/cookiecutter-django/pull/3410)) - Update redis to 4.0.0 ([#3406](https://github.com/cookiecutter/cookiecutter-django/pull/3406)) - Update django-coverage-plugin to 2.0.2 ([#3409](https://github.com/cookiecutter/cookiecutter-django/pull/3409)) - Update black to 21.10b0 ([#3408](https://github.com/cookiecutter/cookiecutter-django/pull/3408)) ## [2021-11-15] ### Updated - Update django-allauth to 0.46.0 ([#3407](https://github.com/cookiecutter/cookiecutter-django/pull/3407)) ## [2021-11-13] ### Fixed - Fix incorrect node version in `package.json` ([#3399](https://github.com/cookiecutter/cookiecutter-django/pull/3399)) ## [2021-11-12] ### Changed - Add Django major/minor release table maker in GitHub issues ([#3288](https://github.com/cookiecutter/cookiecutter-django/pull/3288)) - Upgrade to Bootstrap 5 ([#3276](https://github.com/cookiecutter/cookiecutter-django/pull/3276)) ### Updated - Update requests to 2.26.0 ([#3397](https://github.com/cookiecutter/cookiecutter-django/pull/3397)) - Update crispy-bootstrap5 to 0.6 ([#3396](https://github.com/cookiecutter/cookiecutter-django/pull/3396)) ## [2021-11-11] ### Changed - Build all images on CI ([#3394](https://github.com/cookiecutter/cookiecutter-django/pull/3394)) ### Updated - Update coverage to 6.1.2 ([#3393](https://github.com/cookiecutter/cookiecutter-django/pull/3393)) ## [2021-11-10] ### Changed - Update sphinx to 4.3.0 ([#3392](https://github.com/cookiecutter/cookiecutter-django/pull/3392)) ### Updated - Auto-update pre-commit hooks ([#3389](https://github.com/cookiecutter/cookiecutter-django/pull/3389)) - Update jinja2 to 3.0.3 ([#3388](https://github.com/cookiecutter/cookiecutter-django/pull/3388)) ## [2021-11-09] ### Changed - refactor: remove user API methods parameter ([#3385](https://github.com/cookiecutter/cookiecutter-django/pull/3385)) - Get GitHub repo from environment ([#3387](https://github.com/cookiecutter/cookiecutter-django/pull/3387)) ### Updated - Update celery to 5.2.0 ([#3384](https://github.com/cookiecutter/cookiecutter-django/pull/3384)) - Update isort to 5.10.1 ([#3386](https://github.com/cookiecutter/cookiecutter-django/pull/3386)) ## [2021-11-08] ### Changed - Update docker and non-docker configs to Debian 11 (bullseye) ([#3372](https://github.com/cookiecutter/cookiecutter-django/pull/3372)) ## [2021-11-07] ### Updated - Update django-extensions to 3.1.5 ([#3383](https://github.com/cookiecutter/cookiecutter-django/pull/3383)) ## [2021-11-04] ### Changed - change path in docs Makefile to use APP variable ([#3379](https://github.com/cookiecutter/cookiecutter-django/pull/3379)) ### Fixed - fix help in docs Makefile ([#3380](https://github.com/cookiecutter/cookiecutter-django/pull/3380)) ### Updated - Bump peter-evans/create-pull-request from 3.10.1 to 3.11.0 ([#3382](https://github.com/cookiecutter/cookiecutter-django/pull/3382)) - Auto-update pre-commit hooks ([#3381](https://github.com/cookiecutter/cookiecutter-django/pull/3381)) - Update isort to 5.10.0 ([#3378](https://github.com/cookiecutter/cookiecutter-django/pull/3378)) ## [2021-11-02] ### Updated - Auto-update pre-commit hooks ([#3377](https://github.com/cookiecutter/cookiecutter-django/pull/3377)) ## [2021-11-01] ### Updated - Update django-storages to 1.12.3 ([#3374](https://github.com/cookiecutter/cookiecutter-django/pull/3374)) - Update coverage to 6.1.1 ([#3376](https://github.com/cookiecutter/cookiecutter-django/pull/3376)) ## [2021-10-28] ### Updated - Update factory-boy to 3.2.1 ([#3373](https://github.com/cookiecutter/cookiecutter-django/pull/3373)) ## [2021-10-26] ### Changed - use Wayback Machine to fix dead link for postgres user setup ([#3363](https://github.com/cookiecutter/cookiecutter-django/pull/3363)) - Fix pull request links to correct repo URL on CHANGELOG.md ([#3370](https://github.com/cookiecutter/cookiecutter-django/pull/3370)) ### Updated - Update pyyaml to 6.0 ([#3362](https://github.com/cookiecutter/cookiecutter-django/pull/3362)) - Update pillow to 8.4.0 ([#3364](https://github.com/cookiecutter/cookiecutter-django/pull/3364)) - Update django-storages to 1.12.2 ([#3365](https://github.com/cookiecutter/cookiecutter-django/pull/3365)) - Update django-environ to 0.8.1 ([#3368](https://github.com/cookiecutter/cookiecutter-django/pull/3368)) ## [2021-10-22] ### Changed - Move repo under cookiecutter organisation ([#3357](https://github.com/cookiecutter/cookiecutter-django/pull/3357)) ## [2021-10-18] ### Updated - Update django-environ to 0.8.0 ([#3367](https://github.com/cookiecutter/cookiecutter-django/pull/3367)) ## [2021-10-14] ### Updated - Update flake8 to 4.0.1 ([#3361](https://github.com/cookiecutter/cookiecutter-django/pull/3361)) - Update flake8-isort to 4.1.1 ([#3360](https://github.com/cookiecutter/cookiecutter-django/pull/3360)) - Update django-model-utils to 4.2.0 ([#3359](https://github.com/cookiecutter/cookiecutter-django/pull/3359)) ## [2021-10-13] ### Changed - Add drf stubs ([#3353](https://github.com/cookiecutter/cookiecutter-django/pull/3353)) ## [2021-10-12] ### Updated - Update coverage to 6.0.2 ([#3356](https://github.com/cookiecutter/cookiecutter-django/pull/3356)) ## [2021-10-11] ### Updated - Update werkzeug to 2.0.2 ([#3344](https://github.com/cookiecutter/cookiecutter-django/pull/3344)) - Update coverage to 6.0.1 ([#3348](https://github.com/cookiecutter/cookiecutter-django/pull/3348)) - Update django-coverage-plugin to 2.0.1 ([#3349](https://github.com/cookiecutter/cookiecutter-django/pull/3349)) - Update django-cors-headers to 3.10.0 ([#3345](https://github.com/cookiecutter/cookiecutter-django/pull/3345)) - Update jinja2 to 3.0.2 ([#3343](https://github.com/cookiecutter/cookiecutter-django/pull/3343)) - Update django-storages to 1.12.1 ([#3355](https://github.com/cookiecutter/cookiecutter-django/pull/3355)) ## [2021-10-03] ### Updated - Update pytz to 2021.3 ([#3340](https://github.com/cookiecutter/cookiecutter-django/pull/3340)) ## [2021-10-01] ### Changed - Fix the wrong pre-commit hyperlink in Prerequisites section ([#3338](https://github.com/cookiecutter/cookiecutter-django/pull/3338)) ## [2021-09-30] ### Updated - Update sentry-sdk to 1.4.3 ([#3334](https://github.com/cookiecutter/cookiecutter-django/pull/3334)) ## [2021-09-29] ### Updated - Update django-cors-headers to 3.9.0 ([#3332](https://github.com/cookiecutter/cookiecutter-django/pull/3332)) ## [2021-09-27] ### Updated - Update sentry-sdk to 1.4.2 ([#3329](https://github.com/cookiecutter/cookiecutter-django/pull/3329)) ## [2021-09-26] ### Updated - Update django-crispy-forms to 1.13.0 ([#3327](https://github.com/cookiecutter/cookiecutter-django/pull/3327)) ## [2021-09-24] ### Changed - Add django-settings-module to .pylintrc ([#3326](https://github.com/cookiecutter/cookiecutter-django/pull/3326)) ## [2021-09-23] ### Updated - Update sentry-sdk to 1.4.1 ([#3325](https://github.com/cookiecutter/cookiecutter-django/pull/3325)) ## [2021-09-22] ### Updated - Update sentry-sdk to 1.4.0 ([#3324](https://github.com/cookiecutter/cookiecutter-django/pull/3324)) ## [2021-09-16] ### Updated - Update tox to 3.24.4 ([#3323](https://github.com/cookiecutter/cookiecutter-django/pull/3323)) ## [2021-09-15] ### Updated - Auto-update pre-commit hooks ([#3322](https://github.com/cookiecutter/cookiecutter-django/pull/3322)) ## [2021-09-14] ### Updated - Update black to 21.9b0 ([#3321](https://github.com/cookiecutter/cookiecutter-django/pull/3321)) ## [2021-09-13] ### Updated - Bump stefanzweifel/git-auto-commit-action from 4.11.0 to 4.12.0 ([#3320](https://github.com/cookiecutter/cookiecutter-django/pull/3320)) - Update sphinx to 4.2.0 ([#3319](https://github.com/cookiecutter/cookiecutter-django/pull/3319)) ## [2021-09-11] ### Changed - Removing pycharm docs if app does not use pycharm ([#3139](https://github.com/cookiecutter/cookiecutter-django/pull/3139)) ### Updated - Update django-environ to 0.7.0 ([#3317](https://github.com/cookiecutter/cookiecutter-django/pull/3317)) ## [2021-09-06] ### Changed - Update Celery to v5 ([#3280](https://github.com/cookiecutter/cookiecutter-django/pull/3280)) ## [2021-09-05] ### Updated - Update django-environ to 0.6.0 ([#3314](https://github.com/cookiecutter/cookiecutter-django/pull/3314)) ## [2021-09-03] ### Changed - Update available postgres versions ([#3297](https://github.com/cookiecutter/cookiecutter-django/pull/3297)) ### Updated - Update pre-commit to 2.15.0 ([#3313](https://github.com/cookiecutter/cookiecutter-django/pull/3313)) - Auto-update pre-commit hooks ([#3307](https://github.com/cookiecutter/cookiecutter-django/pull/3307)) - Update pillow to 8.3.2 ([#3312](https://github.com/cookiecutter/cookiecutter-django/pull/3312)) - Update django-environ to 0.5.0 ([#3311](https://github.com/cookiecutter/cookiecutter-django/pull/3311)) - Update pytest to 6.2.5 ([#3310](https://github.com/cookiecutter/cookiecutter-django/pull/3310)) - Update black to 21.8b0 ([#3308](https://github.com/cookiecutter/cookiecutter-django/pull/3308)) - Update argon2-cffi to 21.1.0 ([#3306](https://github.com/cookiecutter/cookiecutter-django/pull/3306)) - Bump peter-evans/create-pull-request from 3.10.0 to 3.10.1 ([#3303](https://github.com/cookiecutter/cookiecutter-django/pull/3303)) - Update django-debug-toolbar to 3.2.2 ([#3296](https://github.com/cookiecutter/cookiecutter-django/pull/3296)) - Update django-cors-headers to 3.8.0 ([#3295](https://github.com/cookiecutter/cookiecutter-django/pull/3295)) - Update uvicorn to 0.15.0 ([#3294](https://github.com/cookiecutter/cookiecutter-django/pull/3294)) ## [2021-08-27] ### Updated - Update tox to 3.24.3 ([#3302](https://github.com/cookiecutter/cookiecutter-django/pull/3302)) ## [2021-08-20] ### Changed - Fix Jinja2 break line control on Procfile ([#3300](https://github.com/cookiecutter/cookiecutter-django/pull/3300)) ## [2021-08-19] ### Changed - Fix several minor typos ([#3301](https://github.com/cookiecutter/cookiecutter-django/pull/3301)) ## [2021-08-13] ### Changed - Upgrade to Redis 6 ([#3255](https://github.com/cookiecutter/cookiecutter-django/pull/3255)) ### Fixed - Fix RTD build image to support Python 3.9 ([#3293](https://github.com/cookiecutter/cookiecutter-django/pull/3293)) ## [2021-08-12] ### Changed - Add documentation for automating backups ([#3268](https://github.com/cookiecutter/cookiecutter-django/pull/3268)) - Add missing step to getting started locally in docs ([#3291](https://github.com/cookiecutter/cookiecutter-django/pull/3291)) - Moved isort config from `.editorconfig` to `setup.cfg` ([#3290](https://github.com/cookiecutter/cookiecutter-django/pull/3290)) - How to pre-commit in Docker Development ([#3287](https://github.com/cookiecutter/cookiecutter-django/pull/3287)) ### Updated - Update sentry-sdk to 1.3.1 ([#3281](https://github.com/cookiecutter/cookiecutter-django/pull/3281)) - Update tox to 3.24.1 ([#3285](https://github.com/cookiecutter/cookiecutter-django/pull/3285)) - Update pre-commit to 2.14.0 ([#3289](https://github.com/cookiecutter/cookiecutter-django/pull/3289)) ## [2021-07-30] ### Updated - Auto-update pre-commit hooks ([#3283](https://github.com/cookiecutter/cookiecutter-django/pull/3283)) - Update isort to 5.9.3 ([#3282](https://github.com/cookiecutter/cookiecutter-django/pull/3282)) ## [2021-07-27] ### Changed - Convert trans to translate in templates ([#3277](https://github.com/cookiecutter/cookiecutter-django/pull/3277)) ### Updated - Update hiredis to 2.0.0 ([#3110](https://github.com/cookiecutter/cookiecutter-django/pull/3110)) - Update mypy to 0.910 ([#3237](https://github.com/cookiecutter/cookiecutter-django/pull/3237)) - Update whitenoise to 5.3.0 ([#3273](https://github.com/cookiecutter/cookiecutter-django/pull/3273)) - Update tox to 3.24.0 ([#3269](https://github.com/cookiecutter/cookiecutter-django/pull/3269)) - Update django-allauth to 0.45.0 ([#3267](https://github.com/cookiecutter/cookiecutter-django/pull/3267)) - Update sentry-sdk to 1.3.0 ([#3262](https://github.com/cookiecutter/cookiecutter-django/pull/3262)) - Update sphinx to 4.1.2 ([#3278](https://github.com/cookiecutter/cookiecutter-django/pull/3278)) - Auto-update pre-commit hooks ([#3264](https://github.com/cookiecutter/cookiecutter-django/pull/3264)) - Update isort to 5.9.2 ([#3279](https://github.com/cookiecutter/cookiecutter-django/pull/3279)) - Update pillow to 8.3.1 ([#3259](https://github.com/cookiecutter/cookiecutter-django/pull/3259)) - Update black to 21.7b0 ([#3272](https://github.com/cookiecutter/cookiecutter-django/pull/3272)) ## [2021-07-12] ### Changed - Define REMAP_SIGTERM=SIGQUIT on Profile of Celery on Heroku ([#3263](https://github.com/cookiecutter/cookiecutter-django/pull/3263)) ## [2021-07-08] ### Updated - Update django to 3.1.13 ([#3247](https://github.com/cookiecutter/cookiecutter-django/pull/3247)) ## [2021-06-29] ### Changed - Improve github bug report template ([#3243](https://github.com/cookiecutter/cookiecutter-django/pull/3243)) ## [2021-06-28] ### Changed - Revert "Fix Celery ports error on local Docker" ([#3242](https://github.com/cookiecutter/cookiecutter-django/pull/3242)) ### Fixed - Fix Celery ports error on local Docker ([#3241](https://github.com/cookiecutter/cookiecutter-django/pull/3241)) ## [2021-06-25] ### Changed - Update `.gitignore` file for VSCode ([#3238](https://github.com/cookiecutter/cookiecutter-django/pull/3238)) ### Fixed - Wrap jQuery call in `DOMContentLoaded` event listener on account email page ([#3239](https://github.com/cookiecutter/cookiecutter-django/pull/3239)) ## [2021-06-22] ### Changed - Update docs/howto.rst ([#3230](https://github.com/cookiecutter/cookiecutter-django/pull/3230)) - Add support for PG 13. Drop PG 9. Update all minor versions ([#3154](https://github.com/cookiecutter/cookiecutter-django/pull/3154)) ### Updated - Update isort to 5.9.1 ([#3236](https://github.com/cookiecutter/cookiecutter-django/pull/3236)) - Auto-update pre-commit hooks ([#3235](https://github.com/cookiecutter/cookiecutter-django/pull/3235)) ## [2021-06-21] ### Updated - Update isort to 5.9.0 ([#3234](https://github.com/cookiecutter/cookiecutter-django/pull/3234)) - Update django-anymail to 8.4 ([#3225](https://github.com/cookiecutter/cookiecutter-django/pull/3225)) - Update django-redis to 5.0.0 ([#3205](https://github.com/cookiecutter/cookiecutter-django/pull/3205)) - Update pylint-django to 2.4.4 ([#3233](https://github.com/cookiecutter/cookiecutter-django/pull/3233)) - Auto-update pre-commit hooks ([#3220](https://github.com/cookiecutter/cookiecutter-django/pull/3220)) - Bump peter-evans/create-pull-request from 3.9.2 to 3.10.0 ([#3197](https://github.com/cookiecutter/cookiecutter-django/pull/3197)) - Update black to 21.6b0 ([#3232](https://github.com/cookiecutter/cookiecutter-django/pull/3232)) - Update pytest to 6.2.4 ([#3231](https://github.com/cookiecutter/cookiecutter-django/pull/3231)) - Update django-crispy-forms to 1.12.0 ([#3221](https://github.com/cookiecutter/cookiecutter-django/pull/3221)) - Update mypy to 0.902 ([#3219](https://github.com/cookiecutter/cookiecutter-django/pull/3219)) - Update django-coverage-plugin to 2.0.0 ([#3217](https://github.com/cookiecutter/cookiecutter-django/pull/3217)) - Update ipdb to 0.13.9 ([#3210](https://github.com/cookiecutter/cookiecutter-django/pull/3210)) - Update uvicorn to 0.14.0 ([#3207](https://github.com/cookiecutter/cookiecutter-django/pull/3207)) - Update pytest-cookies to 0.6.1 ([#3196](https://github.com/cookiecutter/cookiecutter-django/pull/3196)) - Update sphinx to 4.0.2 ([#3193](https://github.com/cookiecutter/cookiecutter-django/pull/3193)) - Update jinja2 to 3.0.1 ([#3189](https://github.com/cookiecutter/cookiecutter-django/pull/3189)) ## [2021-06-19] ### Updated - Update psycopg2 to 2.9.1 ([#3227](https://github.com/cookiecutter/cookiecutter-django/pull/3227)) - Update psycopg2-binary to 2.9.1 ([#3228](https://github.com/cookiecutter/cookiecutter-django/pull/3228)) ## [2021-06-14] ### Changed - Update black GitHub link in requirements ([#3222](https://github.com/cookiecutter/cookiecutter-django/pull/3222)) ## [2021-06-09] ### Changed - Fix link format in developing-locally.rst ([#3214](https://github.com/cookiecutter/cookiecutter-django/pull/3214)) ### Updated - Update pre-commit to 2.13.0 ([#3195](https://github.com/cookiecutter/cookiecutter-django/pull/3195)) - Update pytest-django to 4.4.0 ([#3212](https://github.com/cookiecutter/cookiecutter-django/pull/3212)) - Update mypy to 0.901 ([#3215](https://github.com/cookiecutter/cookiecutter-django/pull/3215)) - Auto-update pre-commit hooks ([#3206](https://github.com/cookiecutter/cookiecutter-django/pull/3206)) - Update black to 21.5b2 ([#3204](https://github.com/cookiecutter/cookiecutter-django/pull/3204)) ## [2021-06-06] ### Changed - Updated .pre-commit-config.yaml to self-update its dependencies ([#3208](https://github.com/cookiecutter/cookiecutter-django/pull/3208)) ## [2021-06-05] ### Changed - Shorthand for the officially supported buildpack ([#3211](https://github.com/cookiecutter/cookiecutter-django/pull/3211)) ## [2021-06-02] ### Updated - Update django to 3.1.12 ([#3209](https://github.com/cookiecutter/cookiecutter-django/pull/3209)) ## [2021-05-18] ### Changed - Move ARG PYTHON_VERSION=3.9-slim-buster to the global scope ([#3188](https://github.com/cookiecutter/cookiecutter-django/pull/3188)) ## [2021-05-17] ### Updated - Bump tiangolo/issue-manager from 0.3.0 to 0.4.0 ([#3186](https://github.com/cookiecutter/cookiecutter-django/pull/3186)) - Auto-update pre-commit hooks ([#3185](https://github.com/cookiecutter/cookiecutter-django/pull/3185)) ## [2021-05-15] ### Changed - Update watchgod to 0.7 ([#3177](https://github.com/cookiecutter/cookiecutter-django/pull/3177)) ### Updated - Auto-update pre-commit hooks ([#3184](https://github.com/cookiecutter/cookiecutter-django/pull/3184)) - Update black to 21.5b1 ([#3167](https://github.com/cookiecutter/cookiecutter-django/pull/3167)) - Update flake8 to 3.9.2 ([#3164](https://github.com/cookiecutter/cookiecutter-django/pull/3164)) - Update pytest-django to 4.3.0 ([#3182](https://github.com/cookiecutter/cookiecutter-django/pull/3182)) - Auto-update pre-commit hooks ([#3157](https://github.com/cookiecutter/cookiecutter-django/pull/3157)) - Update python-slugify to 5.0.2 ([#3161](https://github.com/cookiecutter/cookiecutter-django/pull/3161)) - Bump stefanzweifel/git-auto-commit-action from 4.10.0 to 4.11.0 ([#3171](https://github.com/cookiecutter/cookiecutter-django/pull/3171)) - Update sentry-sdk to 1.1.0 ([#3163](https://github.com/cookiecutter/cookiecutter-django/pull/3163)) - Bump actions/setup-python from 2 to 2.2.2 ([#3173](https://github.com/cookiecutter/cookiecutter-django/pull/3173)) - Update tox to 3.23.1 ([#3160](https://github.com/cookiecutter/cookiecutter-django/pull/3160)) - Update pytest to 6.2.4 ([#3156](https://github.com/cookiecutter/cookiecutter-django/pull/3156)) - Bump peter-evans/create-pull-request from 3.8.2 to 3.9.2 ([#3179](https://github.com/cookiecutter/cookiecutter-django/pull/3179)) - Update sphinx to 4.0.1 ([#3169](https://github.com/cookiecutter/cookiecutter-django/pull/3169)) - Update cookiecutter to 1.7.3 ([#3180](https://github.com/cookiecutter/cookiecutter-django/pull/3180)) - Update django to 3.1.11 ([#3178](https://github.com/cookiecutter/cookiecutter-django/pull/3178)) ## [2021-05-06] ### Updated - Update django to 3.1.10 ([#3162](https://github.com/cookiecutter/cookiecutter-django/pull/3162)) ## [2021-05-04] ### Updated - Update django to 3.1.9 ([#3155](https://github.com/cookiecutter/cookiecutter-django/pull/3155)) ## [2021-04-30] ### Fixed - Fix linting error in production.py ([#3148](https://github.com/cookiecutter/cookiecutter-django/pull/3148)) ## [2021-04-29] ### Updated - Update black to 21.4b2 ([#3147](https://github.com/cookiecutter/cookiecutter-django/pull/3147)) - Auto-update pre-commit hooks ([#3146](https://github.com/cookiecutter/cookiecutter-django/pull/3146)) ## [2021-04-28] ### Changed - Fix README link ([#3144](https://github.com/cookiecutter/cookiecutter-django/pull/3144)) ### Updated - Auto-update pre-commit hooks ([#3145](https://github.com/cookiecutter/cookiecutter-django/pull/3145)) ## [2021-04-27] ### Updated - Update pygithub to 1.55 ([#3141](https://github.com/cookiecutter/cookiecutter-django/pull/3141)) - Update black to 21.4b1 ([#3143](https://github.com/cookiecutter/cookiecutter-django/pull/3143)) ## [2021-04-26] ### Updated - Update black to 21.4b0 ([#3138](https://github.com/cookiecutter/cookiecutter-django/pull/3138)) - Auto-update pre-commit hooks ([#3137](https://github.com/cookiecutter/cookiecutter-django/pull/3137)) ## [2021-04-21] ### Updated - Auto-update pre-commit hooks ([#3133](https://github.com/cookiecutter/cookiecutter-django/pull/3133)) - Update django-extensions to 3.1.3 ([#3136](https://github.com/cookiecutter/cookiecutter-django/pull/3136)) - Update django-compressor to 2.4.1 ([#3135](https://github.com/cookiecutter/cookiecutter-django/pull/3135)) - Update pre-commit to 2.12.1 ([#3134](https://github.com/cookiecutter/cookiecutter-django/pull/3134)) - Update flake8 to 3.9.1 ([#3131](https://github.com/cookiecutter/cookiecutter-django/pull/3131)) - Update django-stubs to 1.8.0 ([#3127](https://github.com/cookiecutter/cookiecutter-django/pull/3127)) - Update sphinx to 3.5.4 ([#3126](https://github.com/cookiecutter/cookiecutter-django/pull/3126)) ## [2021-04-15] ### Updated - Update django-debug-toolbar to 3.2.1 ([#3129](https://github.com/cookiecutter/cookiecutter-django/pull/3129)) ## [2021-04-14] ### Updated - Bump stefanzweifel/git-auto-commit-action from v4.9.2 to v4.10.0 ([#3128](https://github.com/cookiecutter/cookiecutter-django/pull/3128)) ## [2021-04-11] ### Updated - Update pytest-django to 4.2.0 ([#3125](https://github.com/cookiecutter/cookiecutter-django/pull/3125)) - Update pylint-django to 2.4.3 ([#3122](https://github.com/cookiecutter/cookiecutter-django/pull/3122)) ## [2021-04-09] ### Changed - Update from Python 3.8 to Python 3.9 ([#3023](https://github.com/cookiecutter/cookiecutter-django/pull/3023)) ## [2021-04-08] ### Changed - Switch .dockerignore to explicit list ([#3121](https://github.com/cookiecutter/cookiecutter-django/pull/3121)) - Change Docker image to multi-stage build for Django ([#2815](https://github.com/cookiecutter/cookiecutter-django/pull/2815)) - Fix deprecated warning in middleware tests ([#3038](https://github.com/cookiecutter/cookiecutter-django/pull/3038)) ### Updated - Update pre-commit to 2.12.0 ([#3120](https://github.com/cookiecutter/cookiecutter-django/pull/3120)) ## [2021-04-07] ### Changed - Update django to 3.1.8 ([#3117](https://github.com/cookiecutter/cookiecutter-django/pull/3117)) ### Fixed - Fix linting via pre-commit on Github CI ([#3077](https://github.com/cookiecutter/cookiecutter-django/pull/3077)) - Fix gitlab-ci using duplicate key name for image ([#3112](https://github.com/cookiecutter/cookiecutter-django/pull/3112)) ### Updated - Update sentry-sdk to 1.0.0 ([#3080](https://github.com/cookiecutter/cookiecutter-django/pull/3080)) - Update gunicorn to 20.1.0 ([#3108](https://github.com/cookiecutter/cookiecutter-django/pull/3108)) - Update pre-commit to 2.12.0 ([#3118](https://github.com/cookiecutter/cookiecutter-django/pull/3118)) - Update django-extensions to 3.1.2 ([#3116](https://github.com/cookiecutter/cookiecutter-django/pull/3116)) - Update pillow to 8.2.0 ([#3113](https://github.com/cookiecutter/cookiecutter-django/pull/3113)) - Update pytest to 6.2.3 ([#3115](https://github.com/cookiecutter/cookiecutter-django/pull/3115)) ## [2021-03-26] ### Updated - Update djangorestframework to 3.12.4 ([#3107](https://github.com/cookiecutter/cookiecutter-django/pull/3107)) ## [2021-03-25] ### Updated - Update djangorestframework to 3.12.3 ([#3105](https://github.com/cookiecutter/cookiecutter-django/pull/3105)) ## [2021-03-22] ### Updated - Update django-crispy-forms to 1.11.2 ([#3104](https://github.com/cookiecutter/cookiecutter-django/pull/3104)) - Update sphinx to 3.5.3 ([#3103](https://github.com/cookiecutter/cookiecutter-django/pull/3103)) - Update ipdb to 0.13.7 ([#3102](https://github.com/cookiecutter/cookiecutter-django/pull/3102)) - Update sphinx-autobuild to 2021.3.14 ([#3101](https://github.com/cookiecutter/cookiecutter-django/pull/3101)) - Update isort to 5.8.0 ([#3100](https://github.com/cookiecutter/cookiecutter-django/pull/3100)) - Update pre-commit to 2.11.1 ([#3089](https://github.com/cookiecutter/cookiecutter-django/pull/3089)) - Update flake8 to 3.9.0 ([#3096](https://github.com/cookiecutter/cookiecutter-django/pull/3096)) - Update pillow to 8.1.2 ([#3084](https://github.com/cookiecutter/cookiecutter-django/pull/3084)) - Auto-update pre-commit hooks ([#3095](https://github.com/cookiecutter/cookiecutter-django/pull/3095)) ## [2021-03-05] ### Changed - Updated test_urls.py and views.py to re-use User.get_absolute_url() ([#3070](https://github.com/cookiecutter/cookiecutter-django/pull/3070)) ### Updated - Bump stefanzweifel/git-auto-commit-action from v4.9.1 to v4.9.2 ([#3082](https://github.com/cookiecutter/cookiecutter-django/pull/3082)) ## [2021-03-03] ### Updated - Update tox to 3.23.0 ([#3079](https://github.com/cookiecutter/cookiecutter-django/pull/3079)) - Update ipdb to 0.13.5 ([#3078](https://github.com/cookiecutter/cookiecutter-django/pull/3078)) ## [2021-03-02] ### Fixed - Fixes for pytest job in Github CI workflow ([#3076](https://github.com/cookiecutter/cookiecutter-django/pull/3076)) ### Updated - Update pillow to 8.1.1 ([#3075](https://github.com/cookiecutter/cookiecutter-django/pull/3075)) - Update coverage to 5.5 ([#3074](https://github.com/cookiecutter/cookiecutter-django/pull/3074)) ## [2021-02-24] ### Updated - Bump stefanzweifel/git-auto-commit-action from v4.9.0 to v4.9.1 ([#3069](https://github.com/cookiecutter/cookiecutter-django/pull/3069)) ## [2021-02-23] ### Changed - Update to Django 3.1 ([#3043](https://github.com/cookiecutter/cookiecutter-django/pull/3043)) - Lint with pre-commit on CI with Github actions ([#3066](https://github.com/cookiecutter/cookiecutter-django/pull/3066)) - Use exception var in status code pages if available ([#2992](https://github.com/cookiecutter/cookiecutter-django/pull/2992)) ## [2021-02-22] ### Changed - refactor: remove default cache settings in test.py ([#3064](https://github.com/cookiecutter/cookiecutter-django/pull/3064)) - Update django to 3.0.13 ([#3060](https://github.com/cookiecutter/cookiecutter-django/pull/3060)) ### Fixed - Fix missing Django Debug toolbar with node container ([#2865](https://github.com/cookiecutter/cookiecutter-django/pull/2865)) - Remove Email from User API ([#3055](https://github.com/cookiecutter/cookiecutter-django/pull/3055)) ### Updated - Bump stefanzweifel/git-auto-commit-action from v4.8.0 to v4.9.0 ([#3065](https://github.com/cookiecutter/cookiecutter-django/pull/3065)) - Update django-crispy-forms to 1.11.1 ([#3063](https://github.com/cookiecutter/cookiecutter-django/pull/3063)) - Update uvicorn to 0.13.4 ([#3062](https://github.com/cookiecutter/cookiecutter-django/pull/3062)) - Update mypy to 0.812 ([#3061](https://github.com/cookiecutter/cookiecutter-django/pull/3061)) - Update sentry-sdk to 0.20.3 ([#3059](https://github.com/cookiecutter/cookiecutter-django/pull/3059)) - Update tox to 3.22.0 ([#3057](https://github.com/cookiecutter/cookiecutter-django/pull/3057)) - Update sphinx to 3.5.1 ([#3056](https://github.com/cookiecutter/cookiecutter-django/pull/3056)) ## [2021-02-16] ### Updated - Update sentry-sdk to 0.20.2 ([#3054](https://github.com/cookiecutter/cookiecutter-django/pull/3054)) - Update sphinx to 3.5.0 ([#3053](https://github.com/cookiecutter/cookiecutter-django/pull/3053)) ## [2021-02-13] ### Updated - Update sentry-sdk to 0.20.1 ([#3052](https://github.com/cookiecutter/cookiecutter-django/pull/3052)) ## [2021-02-12] ### Updated - Update pre-commit to 2.10.1 ([#3045](https://github.com/cookiecutter/cookiecutter-django/pull/3045)) - Update sentry-sdk to 0.20.0 ([#3051](https://github.com/cookiecutter/cookiecutter-django/pull/3051)) ## [2021-02-10] ### Updated - Bump peter-evans/create-pull-request from v3.8.1 to v3.8.2 ([#3049](https://github.com/cookiecutter/cookiecutter-django/pull/3049)) ## [2021-02-08] ### Updated - Update django-extensions to 3.1.1 ([#3047](https://github.com/cookiecutter/cookiecutter-django/pull/3047)) - Bump peter-evans/create-pull-request from v3.8.0 to v3.8.1 ([#3046](https://github.com/cookiecutter/cookiecutter-django/pull/3046)) ## [2021-02-06] ### Changed - Removed Redundant test_case_sensitivity() and made test_not_authenticated() get the LOGIN_URL dynamically. ([#3041](https://github.com/cookiecutter/cookiecutter-django/pull/3041)) - Refactored users.forms to make the code more readeable ([#3029](https://github.com/cookiecutter/cookiecutter-django/pull/3029)) - Update django to 3.0.12 ([#3037](https://github.com/cookiecutter/cookiecutter-django/pull/3037)) ### Updated - Update tox to 3.21.4 ([#3044](https://github.com/cookiecutter/cookiecutter-django/pull/3044)) ## [2021-02-01] ### Updated - Update pytz to 2021.1 ([#3035](https://github.com/cookiecutter/cookiecutter-django/pull/3035)) - Update jinja2 to 2.11.3 ([#3033](https://github.com/cookiecutter/cookiecutter-django/pull/3033)) - Bump peter-evans/create-pull-request from v3.7.0 to v3.8.0 ([#3034](https://github.com/cookiecutter/cookiecutter-django/pull/3034)) ## [2021-01-31] ### Changed - Adding local celery instructions to developing-locally ([#3031](https://github.com/cookiecutter/cookiecutter-django/pull/3031)) ### Updated - Update django-crispy-forms to 1.11.0 ([#3032](https://github.com/cookiecutter/cookiecutter-django/pull/3032)) ## [2021-01-28] ### Updated - Update pre-commit to 2.10.0 ([#3028](https://github.com/cookiecutter/cookiecutter-django/pull/3028)) - Update django-anymail to 8.2 ([#3027](https://github.com/cookiecutter/cookiecutter-django/pull/3027)) - Update tox to 3.21.3 ([#3026](https://github.com/cookiecutter/cookiecutter-django/pull/3026)) ## [2021-01-26] ### Changed - Bump peter-evans/create-pull-request from v3.6.0 to v3.7.0 ([#3022](https://github.com/cookiecutter/cookiecutter-django/pull/3022)) - Using SuccessMessageMixin to send success message to django template ([#3021](https://github.com/cookiecutter/cookiecutter-django/pull/3021)) ### Fixed - Update admin to ignore *_name User attributes ([#3018](https://github.com/cookiecutter/cookiecutter-django/pull/3018)) ### Updated - Update coverage to 5.4 ([#3024](https://github.com/cookiecutter/cookiecutter-django/pull/3024)) - Update pytest to 6.2.2 ([#3020](https://github.com/cookiecutter/cookiecutter-django/pull/3020)) - Update django-cors-headers to 3.7.0 ([#3019](https://github.com/cookiecutter/cookiecutter-django/pull/3019)) ## [2021-01-24] ### Changed - Use defer for script tags (Fix #2922) ([#2927](https://github.com/cookiecutter/cookiecutter-django/pull/2927)) - Made Traefik conf much easier to understand and improved redirect res… ([#2838](https://github.com/cookiecutter/cookiecutter-django/pull/2838)) - Sentry Redis integration enabled by default in production. ([#2989](https://github.com/cookiecutter/cookiecutter-django/pull/2989)) - Add test for UserUpdateView.form_valid() ([#2949](https://github.com/cookiecutter/cookiecutter-django/pull/2949)) ### Fixed - Omit first_name and last_name in User model ([#2998](https://github.com/cookiecutter/cookiecutter-django/pull/2998)) ### Updated - Update django-celery-beat to 2.2.0 ([#3009](https://github.com/cookiecutter/cookiecutter-django/pull/3009)) - Update pyyaml to 5.4.1 ([#3011](https://github.com/cookiecutter/cookiecutter-django/pull/3011)) - Update mypy to 0.800 ([#3013](https://github.com/cookiecutter/cookiecutter-django/pull/3013)) - Update factory-boy to 3.2.0 ([#2986](https://github.com/cookiecutter/cookiecutter-django/pull/2986)) - Update tox to 3.21.2 ([#3010](https://github.com/cookiecutter/cookiecutter-django/pull/3010)) ## [2021-01-22] ### Changed - Use self.request.user instead of second query ([#3012](https://github.com/cookiecutter/cookiecutter-django/pull/3012)) ## [2021-01-14] ### Updated - Update tox to 3.21.1 ([#3006](https://github.com/cookiecutter/cookiecutter-django/pull/3006)) ## [2021-01-10] ### Updated - Update pylint-django to 2.4.2 ([#3003](https://github.com/cookiecutter/cookiecutter-django/pull/3003)) - Update tox to 3.21.0 ([#3002](https://github.com/cookiecutter/cookiecutter-django/pull/3002)) ## [2021-01-08] ### Changed - Upgrade Travis to Focal ([#2999](https://github.com/cookiecutter/cookiecutter-django/pull/2999)) ### Updated - Update pylint-django to 2.4.1 ([#3001](https://github.com/cookiecutter/cookiecutter-django/pull/3001)) - Update sphinx to 3.4.3 ([#3000](https://github.com/cookiecutter/cookiecutter-django/pull/3000)) - Update pylint-django to 2.4.0 ([#2996](https://github.com/cookiecutter/cookiecutter-django/pull/2996)) ## [2021-01-04] ### Updated - Update isort to 5.7.0 ([#2988](https://github.com/cookiecutter/cookiecutter-django/pull/2988)) - Update uvicorn to 0.13.3 ([#2987](https://github.com/cookiecutter/cookiecutter-django/pull/2987)) - Auto-update pre-commit hooks ([#2990](https://github.com/cookiecutter/cookiecutter-django/pull/2990)) - Update sphinx to 3.4.2 ([#2995](https://github.com/cookiecutter/cookiecutter-django/pull/2995)) - Update pillow to 8.1.0 ([#2993](https://github.com/cookiecutter/cookiecutter-django/pull/2993)) ## [2020-12-29] ### Updated - Update pygithub to 1.54.1 ([#2982](https://github.com/cookiecutter/cookiecutter-django/pull/2982)) - Update django-storages to 1.11.1 ([#2981](https://github.com/cookiecutter/cookiecutter-django/pull/2981)) ## [2020-12-26] ### Updated - Update sphinx to 3.4.1 ([#2985](https://github.com/cookiecutter/cookiecutter-django/pull/2985)) - Update pytz to 2020.5 ([#2984](https://github.com/cookiecutter/cookiecutter-django/pull/2984)) ## [2020-12-23] ### Changed - Bump peter-evans/create-pull-request from v3.5.2 to v3.6.0 ([#2980](https://github.com/cookiecutter/cookiecutter-django/pull/2980)) ### Updated - Update flower to 0.9.7 ([#2979](https://github.com/cookiecutter/cookiecutter-django/pull/2979)) - Update sphinx to 3.4.0 ([#2978](https://github.com/cookiecutter/cookiecutter-django/pull/2978)) - Update coverage to 5.3.1 ([#2977](https://github.com/cookiecutter/cookiecutter-django/pull/2977)) - Update uvicorn to 0.13.2 ([#2976](https://github.com/cookiecutter/cookiecutter-django/pull/2976)) ## [2020-12-18] ### Changed - Bump stefanzweifel/git-auto-commit-action from v4.7.2 to v4.8.0 ([#2972](https://github.com/cookiecutter/cookiecutter-django/pull/2972)) ### Updated - Update django-storages to 1.11 ([#2973](https://github.com/cookiecutter/cookiecutter-django/pull/2973)) - Update pytest to 6.2.1 ([#2971](https://github.com/cookiecutter/cookiecutter-django/pull/2971)) - Auto-update pre-commit hooks ([#2970](https://github.com/cookiecutter/cookiecutter-django/pull/2970)) ## [2020-12-14] ### Updated - Update pytest to 6.2.0 ([#2968](https://github.com/cookiecutter/cookiecutter-django/pull/2968)) - Update django-cors-headers to 3.6.0 ([#2967](https://github.com/cookiecutter/cookiecutter-django/pull/2967)) - Update uvicorn to 0.13.1 ([#2966](https://github.com/cookiecutter/cookiecutter-django/pull/2966)) ## [2020-12-10] ### Changed - Hot-reload support to celery ([#2554](https://github.com/cookiecutter/cookiecutter-django/pull/2554)) ### Updated - Update uvicorn to 0.13.0 ([#2962](https://github.com/cookiecutter/cookiecutter-django/pull/2962)) - Update sentry-sdk to 0.19.5 ([#2965](https://github.com/cookiecutter/cookiecutter-django/pull/2965)) ## [2020-12-09] ### Changed - Bump peter-evans/create-pull-request from v3.5.1 to v3.5.2 ([#2964](https://github.com/cookiecutter/cookiecutter-django/pull/2964)) ## [2020-12-08] ### Updated - Update pre-commit to 2.9.3 ([#2961](https://github.com/cookiecutter/cookiecutter-django/pull/2961)) ## [2020-12-04] ### Updated - Update django-debug-toolbar to 3.2 ([#2959](https://github.com/cookiecutter/cookiecutter-django/pull/2959)) ## [2020-12-02] ### Updated - Update django-model-utils to 4.1.1 ([#2957](https://github.com/cookiecutter/cookiecutter-django/pull/2957)) - Update pygithub to 1.54 ([#2958](https://github.com/cookiecutter/cookiecutter-django/pull/2958)) ## [2020-11-26] ### Updated - Update django-extensions to 3.1.0 ([#2947](https://github.com/cookiecutter/cookiecutter-django/pull/2947)) - Update pre-commit to 2.9.2 ([#2948](https://github.com/cookiecutter/cookiecutter-django/pull/2948)) - Update django-allauth to 0.44.0 ([#2945](https://github.com/cookiecutter/cookiecutter-django/pull/2945)) ## [2020-11-25] ### Changed - Bump peter-evans/create-pull-request from v3.5.0 to v3.5.1 ([#2944](https://github.com/cookiecutter/cookiecutter-django/pull/2944)) ## [2020-11-23] ### Updated - Update uvicorn to 0.12.3 ([#2943](https://github.com/cookiecutter/cookiecutter-django/pull/2943)) - Update pre-commit to 2.9.0 ([#2942](https://github.com/cookiecutter/cookiecutter-django/pull/2942)) ## [2020-11-21] ### Changed - Fix after uvicorn 0.12.0 - Ship extra dependencies ([#2939](https://github.com/cookiecutter/cookiecutter-django/pull/2939)) ## [2020-11-20] ### Updated - Update sentry-sdk to 0.19.4 ([#2938](https://github.com/cookiecutter/cookiecutter-django/pull/2938)) ## [2020-11-19] ### Updated - Update django-crispy-forms to 1.10.0 ([#2937](https://github.com/cookiecutter/cookiecutter-django/pull/2937)) ## [2020-11-17] ### Changed - Bump peter-evans/create-pull-request from v2 to v3.5.0 ([#2936](https://github.com/cookiecutter/cookiecutter-django/pull/2936)) ## [2020-11-15] ### Changed - Fix formatting in docs ([#2935](https://github.com/cookiecutter/cookiecutter-django/pull/2935)) ## [2020-11-13] ### Changed - Upgrade factory-boy to 3.1.0 ([#2932](https://github.com/cookiecutter/cookiecutter-django/pull/2932)) ### Updated - Update sentry-sdk to 0.19.3 ([#2933](https://github.com/cookiecutter/cookiecutter-django/pull/2933)) - Update sphinx to 3.3.1 ([#2934](https://github.com/cookiecutter/cookiecutter-django/pull/2934)) ## [2020-11-12] ### Changed - Migrate CI to Github Actions ([#2931](https://github.com/cookiecutter/cookiecutter-django/pull/2931)) ## [2020-11-06] ### Updated - Update djangorestframework to 3.12.2 ([#2930](https://github.com/cookiecutter/cookiecutter-django/pull/2930)) ## [2020-11-04] ### Changed - Fix docs service and add RTD support ([#2920](https://github.com/cookiecutter/cookiecutter-django/pull/2920)) - Bump stefanzweifel/git-auto-commit-action from v4.6.0 to v4.7.2 ([#2914](https://github.com/cookiecutter/cookiecutter-django/pull/2914)) ### Updated - Auto-update pre-commit hooks ([#2908](https://github.com/cookiecutter/cookiecutter-django/pull/2908)) - Update mypy to 0.790 ([#2886](https://github.com/cookiecutter/cookiecutter-django/pull/2886)) - Update django-stubs to 1.7.0 ([#2916](https://github.com/cookiecutter/cookiecutter-django/pull/2916)) ## [2020-11-03] ### Updated - Update sentry-sdk to 0.19.2 ([#2926](https://github.com/cookiecutter/cookiecutter-django/pull/2926)) - Update sphinx to 3.3.0 ([#2925](https://github.com/cookiecutter/cookiecutter-django/pull/2925)) - Update django to 3.0.11 ([#2924](https://github.com/cookiecutter/cookiecutter-django/pull/2924)) - Update pytz to 2020.4 ([#2923](https://github.com/cookiecutter/cookiecutter-django/pull/2923)) - Update pre-commit to 2.8.2 ([#2919](https://github.com/cookiecutter/cookiecutter-django/pull/2919)) - Update pytest to 6.1.2 ([#2917](https://github.com/cookiecutter/cookiecutter-django/pull/2917)) - Update sh to 1.14.1 ([#2912](https://github.com/cookiecutter/cookiecutter-django/pull/2912)) - Update pytest-django to 4.1.0 ([#2911](https://github.com/cookiecutter/cookiecutter-django/pull/2911)) - Update pillow to 8.0.1 ([#2910](https://github.com/cookiecutter/cookiecutter-django/pull/2910)) - Update django-celery-beat to 2.1.0 ([#2907](https://github.com/cookiecutter/cookiecutter-django/pull/2907)) - Update uvicorn to 0.12.2 ([#2906](https://github.com/cookiecutter/cookiecutter-django/pull/2906)) ## [2020-10-19] ### Updated - Update sentry-sdk to 0.19.1 ([#2905](https://github.com/cookiecutter/cookiecutter-django/pull/2905)) ## [2020-10-17] ### Updated - Update django-allauth to 0.43.0 ([#2901](https://github.com/cookiecutter/cookiecutter-django/pull/2901)) - Update pytest-django to 4.0.0 ([#2903](https://github.com/cookiecutter/cookiecutter-django/pull/2903)) ## [2020-10-15] ### Updated - Update pillow to 8.0.0 ([#2898](https://github.com/cookiecutter/cookiecutter-django/pull/2898)) ## [2020-10-14] ### Updated - Auto-update pre-commit hooks ([#2897](https://github.com/cookiecutter/cookiecutter-django/pull/2897)) - Update sentry-sdk to 0.19.0 ([#2896](https://github.com/cookiecutter/cookiecutter-django/pull/2896)) ## [2020-10-13] ### Updated - Update isort to 5.6.4 ([#2895](https://github.com/cookiecutter/cookiecutter-django/pull/2895)) ## [2020-10-12] ### Changed - Bump stefanzweifel/git-auto-commit-action from v4.5.1 to v4.6.0 ([#2893](https://github.com/cookiecutter/cookiecutter-django/pull/2893)) ### Updated - Auto-update pre-commit hooks ([#2892](https://github.com/cookiecutter/cookiecutter-django/pull/2892)) ## [2020-10-11] ### Updated - Auto-update pre-commit hooks ([#2890](https://github.com/cookiecutter/cookiecutter-django/pull/2890)) - Update isort to 5.6.3 ([#2891](https://github.com/cookiecutter/cookiecutter-django/pull/2891)) - Update django-anymail to 8.1 ([#2887](https://github.com/cookiecutter/cookiecutter-django/pull/2887)) - Update tox to 3.20.1 ([#2885](https://github.com/cookiecutter/cookiecutter-django/pull/2885)) ## [2020-10-09] ### Updated - Auto-update pre-commit hooks ([#2884](https://github.com/cookiecutter/cookiecutter-django/pull/2884)) - Update isort to 5.6.1 ([#2883](https://github.com/cookiecutter/cookiecutter-django/pull/2883)) ## [2020-10-08] ### Changed - Add dedicated websockets package ([#2881](https://github.com/cookiecutter/cookiecutter-django/pull/2881)) ### Updated - Update isort to 5.6.0 ([#2882](https://github.com/cookiecutter/cookiecutter-django/pull/2882)) ## [2020-10-04] ### Updated - Update pytest to 6.1.1 ([#2880](https://github.com/cookiecutter/cookiecutter-django/pull/2880)) - Update mypy and django-stubs ([#2874](https://github.com/cookiecutter/cookiecutter-django/pull/2874)) - Auto-update pre-commit hooks ([#2876](https://github.com/cookiecutter/cookiecutter-django/pull/2876)) - Update flake8 to 3.8.4 ([#2877](https://github.com/cookiecutter/cookiecutter-django/pull/2877)) ## [2020-10-01] ### Changed - Bump actions/setup-python from v2.1.2 to v2.1.3 ([#2869](https://github.com/cookiecutter/cookiecutter-django/pull/2869)) ### Updated - Update ipdb to 0.13.4 ([#2873](https://github.com/cookiecutter/cookiecutter-django/pull/2873)) - Auto-update pre-commit hooks ([#2867](https://github.com/cookiecutter/cookiecutter-django/pull/2867)) - Update uvicorn to 0.12.1 ([#2866](https://github.com/cookiecutter/cookiecutter-django/pull/2866)) - Update isort to 5.5.4 ([#2864](https://github.com/cookiecutter/cookiecutter-django/pull/2864)) - Update sentry-sdk to 0.18.0 ([#2863](https://github.com/cookiecutter/cookiecutter-django/pull/2863)) - Update djangorestframework to 3.12.1 ([#2862](https://github.com/cookiecutter/cookiecutter-django/pull/2862)) - Update pytest to 6.1.0 ([#2859](https://github.com/cookiecutter/cookiecutter-django/pull/2859)) - Update django-debug-toolbar to 3.1.1 ([#2855](https://github.com/cookiecutter/cookiecutter-django/pull/2855)) ## [2020-09-23] ### Updated - Update sentry-sdk to 0.17.7 ([#2847](https://github.com/cookiecutter/cookiecutter-django/pull/2847)) - Update django-debug-toolbar to 3.1 ([#2846](https://github.com/cookiecutter/cookiecutter-django/pull/2846)) ## [2020-09-21] ### Changed - Adding GitHub-Action CI Option ([#2837](https://github.com/cookiecutter/cookiecutter-django/pull/2837)) ### Updated - Update django-debug-toolbar to 3.0 ([#2842](https://github.com/cookiecutter/cookiecutter-django/pull/2842)) - Auto-update pre-commit hooks ([#2843](https://github.com/cookiecutter/cookiecutter-django/pull/2843)) - Update isort to 5.5.3 ([#2844](https://github.com/cookiecutter/cookiecutter-django/pull/2844)) ## [2020-09-18] ### Updated - Update django-extensions to 3.0.9 ([#2839](https://github.com/cookiecutter/cookiecutter-django/pull/2839)) ## [2020-09-16] ### Updated - Update sentry-sdk to 0.17.6 ([#2833](https://github.com/cookiecutter/cookiecutter-django/pull/2833)) - Update pytest-django to 3.10.0 ([#2832](https://github.com/cookiecutter/cookiecutter-django/pull/2832)) ## [2020-09-14] ### Fixed - Downgrade Celery to 4.4.6 ([#2829](https://github.com/cookiecutter/cookiecutter-django/pull/2829)) ### Updated - Update sentry-sdk to 0.17.5 ([#2828](https://github.com/cookiecutter/cookiecutter-django/pull/2828)) - Update coverage to 5.3 ([#2826](https://github.com/cookiecutter/cookiecutter-django/pull/2826)) - Update django-storages to 1.10.1 ([#2825](https://github.com/cookiecutter/cookiecutter-django/pull/2825)) ## [2020-09-12] ### Updated - Updating Traefik version from 2.0 to 2.2.11 ([#2814](https://github.com/cookiecutter/cookiecutter-django/pull/2814)) - Update pytest to 6.0.2 ([#2819](https://github.com/cookiecutter/cookiecutter-django/pull/2819)) - Update django-anymail to 8.0 ([#2818](https://github.com/cookiecutter/cookiecutter-django/pull/2818)) ## [2020-09-11] ### Updated - Auto-update pre-commit hooks ([#2809](https://github.com/cookiecutter/cookiecutter-django/pull/2809)) ## [2020-09-10] ### Updated - Update isort to 5.5.2 ([#2807](https://github.com/cookiecutter/cookiecutter-django/pull/2807)) - Update sentry-sdk to 0.17.4 ([#2805](https://github.com/cookiecutter/cookiecutter-django/pull/2805)) ## [2020-09-09] ### Changed - Update actions/setup-python requirement to v2.1.2 ([#2804](https://github.com/cookiecutter/cookiecutter-django/pull/2804)) - Clean up nested venv files from `.gitignore` ([#2800](https://github.com/cookiecutter/cookiecutter-django/pull/2800)) ## [2020-09-08] ### Changed - Traeffik and Django dockerfile changes ([#2801](https://github.com/cookiecutter/cookiecutter-django/pull/2801)) ## [2020-09-07] ### Changed - Add :z/:Z to mounted volumes in {local,production}.yml ([#2663](https://github.com/cookiecutter/cookiecutter-django/pull/2663)) - Remove --no-binary option for psycopg2 ([#2798](https://github.com/cookiecutter/cookiecutter-django/pull/2798)) - Updated Gitlab CI to use Python 3.8 instead of Python 3.7 ([#2794](https://github.com/cookiecutter/cookiecutter-django/pull/2794)) ### Fixed - Fix options for sphinx-autobuild in docs Makefile ([#2799](https://github.com/cookiecutter/cookiecutter-django/pull/2799)) ### Updated - Update psycopg2-binary to 2.8.6 ([#2797](https://github.com/cookiecutter/cookiecutter-django/pull/2797)) ## [2020-09-05] ### Updated - Auto-update pre-commit hooks ([#2793](https://github.com/cookiecutter/cookiecutter-django/pull/2793)) ## [2020-09-04] ### Updated - Update django-extensions to 3.0.8 ([#2792](https://github.com/cookiecutter/cookiecutter-django/pull/2792)) - Update isort to 5.5.1 ([#2791](https://github.com/cookiecutter/cookiecutter-django/pull/2791)) - Auto-update pre-commit hooks ([#2790](https://github.com/cookiecutter/cookiecutter-django/pull/2790)) - Update isort to 5.5.0 ([#2789](https://github.com/cookiecutter/cookiecutter-django/pull/2789)) ## [2020-09-02] ### Changed - Add environment and traces_sample_rate keyword to sentry_sdk.init ([#2777](https://github.com/cookiecutter/cookiecutter-django/pull/2777)) ### Updated - Update sentry-sdk to 0.17.3 ([#2788](https://github.com/cookiecutter/cookiecutter-django/pull/2788)) - Update django-extensions to 3.0.7 ([#2787](https://github.com/cookiecutter/cookiecutter-django/pull/2787)) ## [2020-09-01] ### Changed - Exclude venv directory and update document link ([#2780](https://github.com/cookiecutter/cookiecutter-django/pull/2780)) ### Updated - Update tox to 3.20.0 ([#2786](https://github.com/cookiecutter/cookiecutter-django/pull/2786)) - Update django-storages to 1.10 ([#2781](https://github.com/cookiecutter/cookiecutter-django/pull/2781)) - Update sentry-sdk to 0.17.2 ([#2784](https://github.com/cookiecutter/cookiecutter-django/pull/2784)) - Update django to 3.0.10 ([#2785](https://github.com/cookiecutter/cookiecutter-django/pull/2785)) - Update sphinx-autobuild to 2020.9.1 ([#2782](https://github.com/cookiecutter/cookiecutter-django/pull/2782)) - Update django-extensions to 3.0.6 ([#2783](https://github.com/cookiecutter/cookiecutter-django/pull/2783)) ## [2020-08-31] ### Updated - Update sh to 1.14.0 ([#2779](https://github.com/cookiecutter/cookiecutter-django/pull/2779)) - Update sentry-sdk to 0.17.1 ([#2778](https://github.com/cookiecutter/cookiecutter-django/pull/2778)) ## [2020-04-13] ### Changed - Updated to Python 3.8 (@codnee) - Moved coverage config in setup.cfg (@danihodovic) ## [2020-04-08] ### Fixed - Internal IPs for debug toolbar (@dudanogueira) ## [2020-04-04] ### Fixed - Added compress command with Django compressor (@gwiskur) ## [2020-03-23] ### Changed - Updated project to Django 3.0 ## [2020-03-17] ### Changed - Handle paths using Pathlib (@jules-ch) ### Fixed - Pre-commit hook regex (@demestav) ## [2020-03-16] ### Added - Support for all Anymail providers (@Andrew-Chen-Wang) ### Fixed - Django compressor setup (@jameswilliams1) ## [2020-01-23] ### Changed - Fix UserFactory to set the password if provided (@BoPeng) - Update documentation files with latest Sphinx (@howiezhao) ## [2020-01-12] ### Changed - Fix mypy setup and added django-stubs (@danifus) - Add Gitlab CI as option (@ikhomutov) ## [2020-01-11] ### Changed - Speed up & reduce size for production Django image (@maxp) - Bumped runtime version for Heroku (@Isaac12x) - Added Debian 10 (Buster) OS dependencies (@ddiazpinto) - Update Traefik to v2 (@blaxpy) - Switched Docker images from Alpine based to Debian based (@trungdong) ## [2019-10-06] ### Changed - Default Python version is now 3.7 (@nicolas471) ## [2019-10-04] ### Fixed - Fix static files handling on GCP (@caioariede) ## [2019-10-03] ### Fixed - Fix incompatible combination between Whitenoise and no cloud provider (@caioariede) ## [2019-07-09] ### Fixed - Always use test settings in pytest (@danihodovic) - Remove gunicorn from `INSTALLED_APPS` (@danihodovic) - Remove `EMAIL_HOST` and `EMAIL_PORT` with locmem backend (@danihodovic) ### Added - Add `EMAIL_TIMEOUT` (@danihodovic) ## [2019-06-22] ### Fixed - Remove redundant template debug setting (@danihodovic) ## [2019-06-19] ### Fixed - Fix removal carriage returns in docker scripts (@timclaessens) ## [2019-06-15] ### Fixed - Issue with Pycharm setup for running things in Docker compose (@foarsitter) ## [2019-06-06] ### Changed - Update generated Travis config (@browniebroke) ## [2019-06-03] ### Added - Installed `django-celery-beat` to keep scheduled tasks in DB (@keyvanm) ## [2019-05-28] ### Changed - Use GCP acronym rather than inconsistent GCE/GCS (@tanoabeleyra) ## [2019-05-27] ### Changed - Made cloud provider optional (@tanoabeleyra) - Updated to Django 2.2.1 (@browniebroke) ### Fixed - Celery worker-related setting names (@browniebroke) ## [2019-05-18] ### Removed - Remove the user list view (@browniebroke) ### Fixed - Static storage default ACL (@browniebroke) ## [2019-05-17] ### Fixed - Added `LocaleMiddleware` to the list of middlewares (@tanoabeleyra) - Added `LOCALE_PATH` to settings (@tanoabeleyra) ## [2019-05-16] ### Changed - Users app to have a translated verbose name (@tanoabeleyra) - Logging configuration for local (@browniebroke) ## [2019-05-08] ### Changed - Upgraded to Django 2.1 (@browniebroke) ## [2019-04-07] ### Added - Support for Google Cloud Storage (@ahhda) ## [2019-04-03] ### Added - Command to backup Db to AWS S3 (@foarsitter) ## [2019-03-25] ### Added - Node image to run Gulp with Docker (@browniebroke) ## [2019-03-19] ### Changed - Replaced Caddy with Traefik (@demestav) ## [2019-03-11] ### Changed - Sentry integration from Raven to Sentry-SDK (@gfabricio) - Made Redis config conditional on Celery locally (@demestav) ## [2019-03-11] ### Added - Automatic migrations on Heroku (@yunti) ## [2019-03-06] ### Fixed - Missing script tag in Travis config (@btknu) ## [2019-03-02] ### Changed - Celery eager setting in local setting with Docker (@keithjeb) ## [2019-03-01] ### Updated - All NPM dependencies (@takkaria) ## [2018-11-13] ### Changed - Security settings in Dev (@carlmjohnson) ## [2018-11-20] ### Fixed - Passing the CSRF header from the reverse proxy to Django server for DRF (@hpbruna) ## [2018-11-12] ### Fixed - Initialisation of Celery app (@glasslion) ## [2018-10-24] ### Fixed - Persisting of iPython history between sessions (@davitovmasyan) ### Added - Postgres 10.5 option (@jleclanche) ## [2018-09-18] ### Added - Included `mypy` in dependencies and run it in tests (@apirobot) ## [2018-09-18] ### Fixed - Avoid `$` in environment variables to workaround a bug from django-environ (@browniebroke) ## [2018-09-16] ### Fixed - Bug in ordering of Middleware for production config (@ChrisPappalardo) ## [2018-09-12] ### Fixed - URLs for Static and Media for S3 buckets in regions other than N. Virginia (@umrashrf) ## [2018-09-09] ### Changed - Name of static and media storage classes (@sfdye) ## [2018-09-01] ### Changed - Make static and media storage fully-fledged classes (@erfaan) ## [2018-08-28] ### Fixed - Running tests in docker test script (@apirobot) ## [2018-07-23] ### Changed - Test commands to use pytest (@jcass77) ### Removed - Some hacks leftovers from Bootstrap v4 beta in `project.js` (@hendrikschneider) ## [2018-07-12] ### Changed - Upgraded to Bootstrap 4.1.1 (@mostaszewski) ## [2018-06-25] ### Added - Flower integration with Docker (@webyneter) ## [2018-06-25] ### Changed - Rewrite user app test to use a pytest style (@webyneter) ## [2018-06-21] ### Added - Extend & update Celery config (@webyneter & @apirobot) ## [2018-05-25] ### Fixed - Build issues due to incompatibility between libressl & openssl (@SassanoM) ## [2018-05-21] ### Changed - Updated Caddy to 0.11 and pin its version (@webyneter) ## [2018-05-14] ### Changed - Replace `awesome-slugify` by `python-slugify` (@hongquan) - Migrate to Django 2.0+ URL style (@saschalalala) ## [2018-05-05] ### Fixed - Postgres backup & restore commands (@webyneter) ## [2018-04-10] ### Changed - Simplify configuration (@danidee10) ## [2018-04-08] ### Added - Adopt Black code style (@pydanny) ## [2018-03-27] ### Fixed - Simplified extra Celery config generated when opted out (@webyneter) ## [2018-03-21] ### Removed - Remove Opbeat support (@sfdye) ## [2018-03-16] ### Fixed - Install `psycopg2-binary` when using Docker locally (@browniebroke) ## [2018-03-14] ### Fixed - Fixed and improved Postgres backup & restore scripts (@webyneter) ## [2018-03-10] ### Changed - Simplify Mailgun setting (@browniebroke) ## [2018-03-06] ### Changed - Convert string formatting to f-strings (@sfdye) ## [2018-03-01] ### Changed - Celery to use JSON serialization by default (@adammsteele) - Use Docker version from Travis to run tests (@browniebroke) ## [2018-02-16] ### Changed - Upgraded to Django 2.0 (@epicwhale) ## [2018-01-15] ### Changed - Removed Elastic Beanstalk support (@pydanny) ## [2017-12-28] ### Changed - Upgraded to Django 1.11 (@pydanny) ## [2017-10-08] ### Changed - Elastic Beanstalk: Added --noinput to migrate command (@MightySCollins ) ## [2017-10-07] ### Added - Finished first pass at Elastic Beanstalk docs (@pydanny & @audreyr) ### Deleted - Removed Heroku instant deploy button (@pydanny) ##[2016-09-29] ### Added - Added default `AUTH_PASSWORD_VALIDATORS` configuration, generated by django 1.10 startproject. See [Password Validation docs](https://docs.djangoproject.com/en/1.10/topics/auth/passwords/#module-django.contrib.auth.password_validation") (@luzfcb) - Rename `MIDDLEWARE_CLASSES` to `MIDDLEWARE` to enable support to [new style middleware](https://github.com/django/deps/blob/master/final/0005-improved-middleware.rst) introduced in Django 1.10 (@luzfcb) - New setting `MAILGUN_SENDER_DOMAIN` to allow sending mail from any domain other than those registered with mailgun (@jangeador) - add `urlpatterns` configuration to django-debug-toolbar, because the automatic configuration of `urlpatterns` was removed from django-debug-toolbar (@luzfcb) - Added Temporary workaround on `requirements/local.txt` to fix django-debug-toolbar issue: https://github.com/cookiecutter/cookiecutter-django/issues/827 (@luzfcb) ### Changed - Upgrade to Django 1.10.1 (@luzfcb) - Upgrade django-model-utils to 2.6, django-redis to 4.5.0, redis to 2.10.5, Sphinx to 1.4.6, pytest-django to 3.0.0, django-anymail to 0.5, raven to 5.27.1, whitenoise to 3.2.2 (@luzfcb) - Upgrade to Bootstrap 4 Alpha 4, jQuery to 3.1.1, tether.js to 1.3.7 (@luzfcb) - Update `manage.py` to use same code of `manage.py` from Django 1.10 (@luzfcb) - Sync `sites` app migrations with django 1.10, and fix aditional migrations to `sites` and `user` app (@luzfcb) d changed 'admin' url on `config/urls.py`, to stay the same as generated by django 1.10 (@luzfcb) - Make test_docker.sh tests pass by passing new password auth rules (@ssteinerx) ### Removed - Removed django-autoslug because not support django 1.10 at this date (@luzfcb) ##[2016-09-10] ### Changed - Use app registry instead of INSTALLED_APPS to discover celery tasks (@dhepper) - PEP8 imports fix (@aleprovencio) ### Removed - Removed django-floppyforms (@pydanny) ##[2016-09-08] ### Removed - Webpack support, see #774 (@ssteinerx) ##[2016-08-10] ## Added - PostgreSQL versions are now selectable, instead of defaulting to 9.5; the minimum version is 9.2, which is supported by [Heroku](https://devcenter.heroku.com/articles/heroku-postgresql#version-support-and-legacy-infrastructure) and Django (@burhan) - Fixed minor issue in the README.rst (@burhan) ##[2016-08-03] ## Changed - Upgrade to Bootstrap 4 Alpha 3 and its dependencies, including jQuery (@audreyr) ##[2016-06-25] ## Changed - use `https` instead `ssh` to clone [cookiecutter-webpack](https://github.com/hzdg/cookiecutter-webpack) if `Webpack` is selected as `JS Task Runner` - fix issue #647 (@luzfcb and @resakse) ##[2016-06-24] ## Added - Settings file for running tests faster (@audreyr) - Add GPLv3 licence support (@cgaspoz) ## Changed - Makes the database backups compressed. restores compressed backups (@jangeador) - Review and edit django-allauth templates (@kappataumu) ##[2016-06-19] ## Added - Webpack as an option (@goldhand) ##[2016-06-17] ## Added - django-compressor support (@andresgz) - Debian Jessie OS Requirements (@ddiazpinto) ##[2016-06-14] ### Changed - Move Docker backups to their own section (@pydanny) ##[2016-06-13] ### Changed - Use latest redis image in Docker (@pydanny) - Documentation cleanup and corrections (@audreyr) ##[2016-06-12] ### Changed - Documentation cleanup and corrections (@kappataumu) ##[2016-06-11] ### Changed - Enhancements to the developing locally docs (@antoniablair) ##[2016-06-06] ### Changed - Pin Bootstrap CSS and JS to v4.0.0-alpha.2, use minified versions ##[2016-06-05] ### Added - Configurable admin for users (@pydanny, @jayfk, @dezoito) ##[2016-06-04] ### Added - Let's Encrypt automation and instruction (@mjsisley and @chrisdev) ##[2016-06-03] ### Added - Documentation for debugging with Docker (@mjsisley) - Apache 2 License option in `cookiecutter.json` (@dot2dotseurat) - Removed unnecessary version check from `pre_gen_project.py` (@suledev) - Add gulp alternative as a js task runner and fix navbar style issue (@viviangb and @xpostudio4) ### Deleted - AngularJS (@pydanny) - django-secure (@xpostudio4) ##[2016-06-02] ### Added - Added better instructions for installing postgres on Mac OS X (@dot2dotseurat ) ##[2016-05-22] ### Added - Added instructions for copying backups from docker to host (@phiberjenz) - Added mailhog docker container (@noisy) ##[2016-05-15] ### Added - Added GitLab continuous integration article to README.rst (@dezoito) ## [2016-05-13] ### Changed - Update version of pyflakes to 1.2.3, django-extensions to 1.6.7 and gunicorn to 19.5.0 (@luzfcb) - Update version of AngularJS to 1.5.5 (@luzfcb) ### Removed - Remove Raven 404 catch middleware. Fix #367 (@pydanny) ## [2016-05-09] ### Changed - Improved mailhog usage documentation on `developing-locally.rst` (@shireenrao) - Replaced all `readthedocs.org` referencies to point to the new domain `readthedocs.io` (@luzfcb) - Update version of pyflakes (@luzfcb) ## [2016-05-08] ### Changed - Updated whitenoise configuration to match changes in version 3.0 (@trungdong) ## [2016-05-07] ### Added - Added Ubuntu 16.04 dependencies on a new dependency file `requirements.apt.xenial` (@raonyguimaraes) ### Changed - Small improvements in ``install_os_dependencies.sh`` support new dependency file (@raonyguimaraes) ## [2016-05-06] ### Changed - Update version of pyflakes (@pydanny) ## [2016-05-03] ### Changed - Update version of Django, django-extensions, django-mailgun (@luzfcb) ### [2016-05-01] ### Changed - Restored the Pycharm project configuration files, that was accidentally removed in [15f350f](https://github.com/cookiecutter/cookiecutter-django/commit/15f350f05e2b49b4bdff0bdaa2b2ff260606e0f6) (@luzfcb @Newton715) ### [2016-04-30] ### Changed - Small fixes to utility scripts (@scast) ### [2016-04-26] ### Added - Instructions on how to install PythonAnywhere. (@hjwp) ### [2016-04-25] ### Added - Check to confirm that the user has a modern version of Cookiecutter. (@pydanny) ### Removed - Removed hitch per #529 (@pydanny) ### [2016-04-20] ### Changed - Default to today's date in cookiecutter.json. (@audreyr) - Change repo_name to project_slug for clarity. (@audreyr) - Transform project name to lowercase for slug. (@audreyr) ### [2016-04-19] ### Added - "Got Questions?" section in our README.rst. Yes, there is now a cookiecutter-django tag on Stack Overflow! (@pydanny) ### Changed - Update usage instructions with new prompts, minor cleanup (@audreyr) ### [2016-04-18] ### Added - removing duplication of depends_on in docker-compose.yml (@noisy) ### [2016-04-17] ### Added - "Built with Cookiecutter Django" badge to generated project README (@audreyr) - New introductory article (@krzysztofzuraw) ### Changed - Quote consistency, single quotes everywhere! (@blopker) ### [2016-04-15] ### Changed - Major project generation cleanup (@jayfk) ### Removed - Deleting unnecessary .idea dir from MAIN directory (@noisy) ### [2016-04-14] ### Added - Added typecheck in .pylintrc to fix pylint-django gets "no-member" error (@solvire) ### Changed - Downgrading python-dateutil to version 2.4.2 because pykwalify==1.5.0 (required by HitchTest) uses a [pinned version of python-dateutil](https://github.com/Grokzen/pykwalify/blob/1.5.0/setup.py#L31) (@noisy) - Update Pillow version to 3.2.0 (security fix) (@luzfcb) ### [2016-04-12] ### Changed - celeryworker and celerybeat missing the correct dockerfile (@jayfk) ### [2016-04-08] ### Changed - Move to named docker volumes (@jayfk) ### [2016-04-07] ### Changed - Pycharm Support (including debugging in Docker) @noisy - Set the correct License @epileptic-fish ### [2016-03-23] ### Changed - Fixed issue on LICENSE file generation (@romanosipenko) - In install_python_dependencies.sh file, Fixed wrong reference to python3 if use_python2 was set to y (@luzfcb @noisy) ### [2016-03-16] ### Changed - Set the correct postgres username in dev.yml (@calculuscowboy) ## [2016-03-14] ### Changed - Enforce `repo_name` as proper python module (@catherinedevlin) ## [2016-03-08] ### Changed - Docker configuration now uses docker-compose format v2 (@aeikenberry) - Make sure that STATIC_URL != MEDIA_URL (@cdvv7788) - fix minor typos in project README (@menzenski) - Updated docker docs (@jayfk) ### Added - Added database controls for docker (@jayfk) ## [2016-03-05] ### Changed - Update version of Django, celery, django-test-plus (@luzfcb) - Update version of Hitch tests dependencies: jupyter_client (@luzfcb) - Update 'now' date in cookiecutter.json (@luzfcb) - Update the usage example in README (@luzfcb) ## [2016-03-01] ### Changed - Update version of Django, flake8, pyflakes, pytest, factory_boy, ipdb, Werkzeug, gevent (@luzfcb) - Update version of Hitch tests dependencies: click, hitchserve, hitchsystem, hitchtest, ipython, psutil, python-dateutil(@luzfcb) - Update Tether (JS) version to 1.2.0 (@luzfcb) ## [2016-02-24] ### Added - Beginning support for `py.test` (@pydanny) ### Changed - Fixed missing div closing tag for "container" on user_list.html (@Eraldo) ## [2016-02-18] ### Changed - The status of the registration (open or closed) is now read from the project environment instead of hardcoded in the common settings file. (@Eraldo) - Renamed the adapter.py file to adapters.py to match the django naming convention. (@Eraldo) ## [2016-02-15] ### Changed - In `users` app adapter, fix `is_open_for_signup` missing parameter (@oryx2) - Fixes and improvements in Hitch tests , see [#485](https://github.com/cookiecutter/cookiecutter-django/pull/485) (@crdoconnor) ## [2016-02-12] ### Changed - Fixed typo (@yunti) ## [2016-02-07] ### Changed - In `users` app, use Django 1.9 `LoginRequiredMixin` instead of django-braces implementation (@yunti) - Update native OS libraries of Hitch Test, because [unixpackage](https://github.com/unixpackage/unixpackage) now supports multiple versions of same Linux distribution (@crdoconnor) - Update AngularJS version to 1.5.0 (@luzfcb) - Update version of wheel, Pillow, django_coverage_plugin (@luzfcb) - Update version of Hitch tests dependencies: decorator, hitchselenium, ipython, ptyprocess, selenium (@luzfcb) - Provided options for FOSS license choices, or for private efforts, no written license (@pydanny) ## [2016-02-01] ### Changed - Update version of Django and django-floppyforms (@luzfcb) - Update version of Hitch tests dependencies: hitchpython and selenium (@luzfcb) ## [2016-01-30] ### Changed - Update flake8 to 2.5.2 (@luzfcb) ## [2016-01-29] ### Changed - Update AngularJS version to 1.4.9 (@luzfcb) - Update jQuery version to 2.2.0 (@luzfcb) - Update 'now' date in cookiecutter.json (@luzfcb) - Update version of boto, celery, django_coverage_plugin, django-storages-redux, flake8, gevent, gunicorn, pep8, pytest, tox, Werkzeug (@luzfcb) - Update version of Hitch tests dependencies: colorama, decorator, hitchpostgres, hitchpython, hitchredis, hitchselenium, hitchserve, hitchsystem, hitchtest, ipython, patool, pickleshare, psutil, python-build, requests, selenium, tblib, traitlets (@luzfcb) ## [2016-01-26] ### Changed - Fixed NEW_RELIC_APP_NAME environment variable (@jayfk) ## [2016-1-18] ### Added - Added .dockerignore file (@bogdal) - Docker tests for travis (@jayfk) ### Changed - Removed the $-sign from allowed chars to generate the secret key (@jayfk) ## [2016-01-17] ### Added - Adding a section on third party articles referencing `cookiecutter-django` (@mjheo) ### Changed - Add celerybeat db to gitignore (@originell) ## [2016-01-16] ### Added - Adding an explanation for having `django.contrib.sites`. (@pydanny) ## [2016-01-13] ### Changed - Update setup.py version to 1.9.1 to match Django version. (@Collederas) - Require Wheel 0.26.0. Needed to install certain packages on CPython 3.5+ like Pillow and psycopg2 (@audreyr) ## [2016-01-09] ### Changed - Upgraded django-extensions to 1.6.1 as it fixes a [JSONField bug](https://github.com/django-extensions/django-extensions/blob/master/CHANGELOG.md#161) (@burhan) - Upgraded Pillow to version 3.1.0 ([upstream changelog](https://github.com/python-pillow/Pillow/blob/master/CHANGES.rst#310-2016-01-04)) (@burhan) - Upgraded django to 1.9.1 to integrate various [bugfixes](https://docs.djangoproject.com/en/1.9/releases/1.9.1/) (@burhan) - Upgraded django-crispy-forms to 1.6 for [BS4 and django 1.9 compatibility fixes](https://github.com/maraujop/django-crispy-forms/blob/dev/CHANGELOG.md#160-201617) (@burhan) - Upgraded django-model-utils to 2.4, to enable [support for django 1.9](https://github.com/carljm/django-model-utils/blob/master/CHANGES.rst#24-2015-12-03) (@burhan) ## [2016-01-08] ### Changed - Fixed redis url on docker (@jayfk) - Fixed docker on windows (@burhan) ## [2016-01-06] ### Added - You can now enable or disable user registration using the ACCOUNT_ALLOW_REGISTRATION setting. (@ddiazpinto) ### Changed - Use Postgres 9.5 on docker (@jayfk) ## [2016-01-04] ### Added - Add Tether.js because [is needed](http://v4-alpha.getbootstrap.com/components/tooltips/#overview) for proper positioning of Bootstrap tooltips (@EricZaporzan) ### Changed - Minor fixes in the docker documentation (@jayfk) - Made @burhan a core committer (@pydanny) ## [2015-12-30] ### Changed - Fixed a bug where the navbar was not displayed correctly (@jvanbrug) ## [2015-12-21] ### Changed - Added sentry logger to celery config (@jayfk) ## [2015-12-16] - Update preview 4xx error pages to accept `exception` argument (@theskumar) ## [2015-12-15] ### Changed - Fix celery worker app name in Procfile (@stepmr) ## [2015-12-13] ### Changed - Bumped Django to 1.9 (@areski) - Support opbeat logging with celery (@stepmr) - Update runtime.txt with PY2 support (@stepmr) ## [2015-12-12] ### Added - Celery worker to Heroku procfile (@stepmr) ## [2015-12-11] ### Changed - Fixed issue #436 - cookiecutter variable name was renamed from `celery_support` to `use_celery` in `tests/engine.py` (@luzfcb @otakucode) - Updated Heroku runtime.txt for python 3.5.1 (@yunti) ## [2015-12-06] ### Changed - Reorganization of contributors (@burhan) ## [2015-12-01] ### Changed - Update documentation to include the installation os dependencies before development requirements (@failsafe86) ## [2015-11-29] ### Changed - Update version of click and python-build (@luzfcb) ## [2015-11-25] ### Changed - Update version of psutil, ipython (@luzfcb) - Update version of gunicorn (@audreyr) - Remove debugging tools from non-generated part of cookiecutter-django, since those are personal prefs (@audreyr) - Update version of Django in setup.py (@luzfcb) ## [2015-11-24] ### Changed - Update version of Django, coverage and click (@luzfcb) - Fixed configuration for Celery in local.py. (@luzfcb @hackebrot) ## [2015-11-23] ### Changed - Update AngularJS version to 1.4.8 (@luzfcb) - Update version of cookiecutter, pytest, tox, whitenoise, django-test-plus, django_coverage_plugin, Werkzeug, hitchserve, tornado, unixpackage (@luzfcb) - Update 'now' date in cookiecutter.json (@luzfcb) - `sh` package version pinned to `1.11` (@luzfcb) ## [2015-11-22] ### Changed - Move div class unquote outside the django if tag (@jvanbrug) - Changed gevent to `1.1rc1` for python 3 users (@jondelmil / @jayfk) ## [2015-11-20] ### Changed - Using python 3.5 on Heroku/Travis (@bogdal) - Fixed typo in README (@tedmiston) ## [2015-11-18] ### Added - Mailhog as a replacement for Maildump (@keybits) ### Removed - Maildump because it didn't support Python 3 (@keybits) ## [2015-11-17] ### Added - initial configuration to support opbeat (@burhan) ### Removed - Took `*.pyc` out of .gitignore, because it's already covered by `*.py[cod]` (@audreyr) ## [2015-11-16] ### Changed - Cleanup of main README (@burhan) ## [2015-11-15] ### Added - Added `UserFactory` for users.User tests (@ad-m) ## [2015-11-12] ### Changed - Update version of django-allauth (@yunti) - Added a warning in README.rst: ```repo_name must be a valid Python module``` @cdvv7788 ### Removed - remove ```{% load url from future %}``` in templates - deprecated in django 1.9 (@yunti) ## [2015-11-11] ### Added - Added django_coverage_plugin to measure Django template coverage (@audreyr) ## [2015-11-09] ### Changed - Now using py.test for our test suite!! (@hackebrot) - Python version in travis.yml is now correct for the selected version of Django (@show0k) ## [2015-11-08] ### Changed - bump django-extensions version (@garrypolley) ## [2015-11-07] ### Added - newrelic support (@amjith) - DJANGO_SENTRY_DSN to env.example (@jayfk) ### Changed - Made `post_gen_hook.set_secret_key()` only changes one CHANGEME!!! at a time. (@pydanny) - Fixed an error where celery couldn't load the sentry DSN from settings (@jayfk) - Renamed ADMIN_URL to DJANGO_ADMIN_URL in env.example (@ChrisPappalardo) ## [2015-11-06] ### Added - \*tests\* to `.coveragerc`, because including it is cheating! (@pydanny) - Binaryornot to cookiecutter-django's own tests because otherwise Python 3 blows up (@audreyr) ### Changed - `.travis.yml` configuration to support Python 3.4 and 3.5 (@pydanny) - `.gitignore` configuration so py.test cache files don't show up in git status. ## [2015-11-05] ### Changed - Update version of django-extensions (@luzfcb) - Fix gevent requirement for Python 3 (@mcho421) ## [2015-11-04] ### Changed - Update version of Django, cookiecutter, celery, coverage, django-mailgun, django-redis, factory_boy, flake8, pytest and pytz (@luzfcb) - Update AngularJS version to 1.4.7 (@luzfcb) - Update 'now' date in cookiecutter.json (@luzfcb) ## [2015-10-28] ### Changed - Update deployment-on-heroku.rst for ADMIN_URL (@yunti) ## [2015-10-27] ### Added - Added sudo: true to the travis file (@MathijsHoogland) ## [2015-10-25] ### Added - Move current logging config into production.py since it's not useful locally anyway. Used only if not using Sentry. (@audreyr) - `setup.py` so we can list it on PyPI and therefore displayed on djangopackages.com as compatible with Python 3. (@pydanny) - Versioning and tagging policy (@pydanny) - Fixed flake8 issue (@pydanny) ## [2015-10-24] ### Changed - Update nav in base template to latest Bootstrap 4 version (@audreyr) - Replaced ADD with COPY in dockerfiles (@audreyr) - Simplified development dockerfile (@jayfk) - Moved the docker postgres volume on the development environment to it's own subfolder (@jayfk) - Renamed DJANGO_CACHE_URL to REDIS_URL (@jayfk / proposed by @pydanny) ## [2015-10-22] ### Removed - Remove unnecessary .gitkeep in static/images/ (@audreyr) ## [2015-10-21] ### Changed - Updated requirements (@theskumar) ### Removed - editorconfig comment that was just a isort settings link (@pydanny) ## [2015-10-19] ### Changed - On Windows, don't install psycopg2 locally. Still install it in test/prod which are assumed to be Unix. (@audreyr) ## [2015-10-15] ### Changed - Made `post_gen_hook` function to change secret keys in files more generic (@pydanny) - Set cryptographically randomized value to `DJANGO_SECRET_KEY` in `env.example` (@pydanny) ## [2015-10-14] ### Added - Documention of project options (@audreyr) ### Changed - Added clarification on building for local or production (@MathijsHoogland) - Whitespace correction in dev.yml (@MathijsHoogland) ## [2015-10-13] ### Changed - Requirements update (@theskumar) ## [2015-10-11] ### Changed - Fixed raven issue on development (#302) (@jazztpt) ## [2015-10-05] ### Changed - Update version of Django, Pillow, hitchselenium, psutil (@luzfcb) ## [2015-10-04] ### Changed - Remove stray closing tags and fix navbar margin in in base.html (@hairychris) - Docker docs to be functional and more understandable (@audreyr) ## [2015-09-30] ### Changed - Fixed Sentry logging with celery (@jayfk) - Added pep8 and pyflakes to requirements (@jayfk) - Fixed url() arguments in urls.py because String view arguments to url() is deprecated in django 1.9 (@siauPatrick) - Update version of cookiecutter, coverage, django-environ, django-extensions, hitchpython, hitchselenium, hitchserve, pytest, pytz, whitenoise (@luzfcb) - Update the usage example in README (@luzfcb) - Update 'now' date in cookiecutter.json (@luzfcb) ## [2015-09-29] ### Changed - Fix RST in Docker docs (@andor-pierdelacabeza) ## [2015-09-27] ### Added - Added advice on how to persist changes with boot2docker (@jayfk) ###Changed - Removed duplicate from `CONTRIBUTORS.rst` (@jayfk) ## [2015-09-26] ### Added - Add .pylintrc and .pep8 (@kaidokert) ### Changed - Move pep8 rules to setup.cfg (@audreyr) - Better pep8 rules for exclusion (@audreyr) - Document all linters (@audreyr) - Sass linting and improvements to alerts (@audreyr) ## [2015-09-25] ### Changed - django-mailgun requirement to 0.7.2 (@pydanny) - Remove commented-out flake8 ignore rule. (@audreyr) ## [2015-09-24] ### Changed - Add user-uploaded media dir to .gitignore (@audreyr) - Update .editorconfig to use 2 spaces for html, css, scss, json (@audreyr) - Have flake8 ignore node_modules dir (@audreyr) ## [2015-09-23] ### Changed - Add workaround for django-debug-toolbar conflict with Bootstrap 4 (@audreyr) ## [2015-09-22] ### Added - Add Python version option for deployment (@yunti) ## [2015-09-21] ### Changed - django-mailgun-redux to django-mailgun, because @pydanny now has commit rights ### Removed - Excess "loggers" from LOGGING setting (@siauPatrick) ## [2015-09-18] ### Changed - Major reorganization of docs (@pydanny) - Fix expanded navbar on mobile (@jayfk) - Update various requirements (@audreyr) ## [2015-09-17] ### Added - Fix for wsgi.py for Raven in dev (@yunti) ## [2015-09-15] ### Added - whitespace to allow proper rendering of RST (@IanLee1521 ) ## [2015-09-14] ### Added - Functionality to delete taskapp if celery isn't going to be used (@pydanny) ### Removed - Remove unused generated CSS styles (@audreyr) ### Changed - Use Bootstrap margin utility class `m-b-lg` and remove our custom `navbar-header` class (@audreyr) - Update Hitch requirements (@audreyr) ## [2015-09-13] ### Removed - Styles that already exist in Bootstrap 4 (or 3) (@audreyr) ### Changed - Fix issue #296 - change login.html to use [get_providers](https://github.com/pennersr/django-allauth/blob/master/allauth/socialaccount/templatetags/socialaccount.py#L84-L93) templatetag because ``allauth.socialaccount`` context processor now is [deprecated](http://django-allauth.readthedocs.io/en/latest/changelog.html#from-0-21-0) (@luzfcb) ## [2015-09-09] ### Added - post_gen_hook to generate a secret key for use in locals.py. You should define your own for production (@pydanny) ## [2015-09-09] ### Added - htmlcov to gitignore (@pydanny) ## [2015-09-04] ### Added - Easy deploy Heroku button and app.json file (@bogdal) ## [2015-09-03] ### Added - For security reasons, we set explicitly the list of allowed hosts (@bogdal) ## [2015-08-31] ### Removed - Dokku in favor of docker-compose and other modern Django tools (@pydanny) ## [2015-08-30] ### Changed - Moved from Bootstrap 3 to Bootstrap 4 (@audreyr) - Slight Reorganization of the README docs (@pydanny) - Dokku docs are out of the README and in the docs folder (@pydanny) - Small improvements in ``install_python_dependencies.sh`` and ``install_os_dependencies.sh`` scripts (@luzfcb) - Update version of django-crispy-forms, django-extensions, django-test-plus, gevent, coverage, hitchpython and hitchtest (@luzfcb) - Update AngularJS version to 1.4.4 (@luzfcb) - Update the usage example on README (@luzfcb) ## [2015-08-28] ### Changed - Switched to django-mailgun-redux so mail doesn't blow up on Python 3 (@pydanny) ## [2015-08-27] ### Changed - Grunt Updates: use libsass, add postcss (@288) ## [2015-08-20] ### Changed - requirements files to match current dependency versions (@pydanny) ## [2015-08-18] ### Added - Docker support and docker-compose (@jayfk) ## [2015-08-12] ### Added - hitch for end-to-end testing functionality (@crdoconnor) ## [2015-08-09] ### Added - test coverage, bringing it to 100% (@pydanny) ## 2015-08-08 ### Added - Gitter badge (@pydanny) ### Changed - Refactor of cookiecutter-django render tests (@burhan) ## [2015-08-06] ### Added - More test coverage, up to 97% (@pydanny) - Slight optimization to celery configuration (@jayfk) ## [2015-08-05] ### Added - Sentry support (@burhan) ### Changed - Made the user object python 2 and 3 friendly (@pydanny) - When using maildump, pin gevent. (@audreyr) - Updated coverage version. (@audreyr) ## [2015-08-04] ### Added - Better specification of migrations in .coveragerc. (@audreyr) ## [2015-08-03] ### Added - Instructions for using coverage and generating reports (@audreyr) - Coverage project-level config file (@audreyr) - factory-boy package for improved testing (@pydanny) - Error message for duplicate usernames in `users.admin.MyUserCreationForm` (@pydanny) - Tests on `users.admin.MyUserCreationForm` (@pydanny) ### Changed - update django-all-auth to 0.23.0 (@pydanny) - update django-test-plus to 1.0.7 (@pydanny) ### Removed - Unnecessary users/forms.py module (@pydanny) ## [2015-07-30] ### Changed - update django-floppyforms version to 1.5.2 ## [2015-07-29] ### Removed - Removed legacy permalink decorator from the users.User model. (@pydanny) ## [2015-07-27] ### Removed - removed django-allauth template context processors because is deprecated now. see: https://github.com/pennersr/django-allauth/commit/634f4fe60e67c266aadcfba2981074f005db340c (@burhan) ### Changed - update version of ipython, django-allauth (@luzfcb) - update version of django-braces, django-floppyforms, django-model-utils (#287)(@burhan) ## [2015-07-21] ### Changed - memcached is as a cache is replace with redis (#258)(@burhan) ## [2015-07-18] ### Changed - Heroku deployment docs (@stepmr) - Heroku's free postgres tier is now "hobby-dev" - pg:backups require a scheduled time - add missing Mailgun API key - Django recommends setting the PYTHONHASHSEED environment variable to random. See: https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/#python-options - Use openssl to generate a secure, random secret_key ## [2015-07-17] ### Added - @models.permalink decorator to User.get_absolute_url() method ### Fixed - Broken user_form.html (@pydanny) ## [2015-07-16] ### Added - django-test-plus (@pydanny) - option use maildump instead of ConsoleEmailHandler (@burhan) - Changelog.md (@pydanny) ### Fixed - where 'DEFAULT_FROM_EMAIL' was used to cast the value (@jayfk) ### Removed - unnecessary header block tag and 'user:' prefix. (@pydanny) ================================================ FILE: CODE_OF_CONDUCT.md ================================================ ## Code of Conduct Everyone who interacts in the Cookiecutter project's codebase, issue trackers, chat rooms, and mailing lists is expected to follow the [PSF Code of Conduct](https://www.python.org/psf/conduct/) ================================================ FILE: CONTRIBUTING.md ================================================ # How to Contribute Always happy to get issues identified and pull requests! ## General considerations 1. Keep it small. The smaller the change, the more likely we are to accept. 2. Changes that fix a current issue get priority for review. 3. Check out [GitHub guide][submit-a-pr] if you've never created a pull request before. ## Getting started 1. Fork the repo 2. Clone your fork 3. Create a branch for your changes This last step is very important, don't start developing from main, it'll cause pain if you need to send another change later. ## Testing You'll need to run the tests using Python 3.13. We recommend using [tox](https://tox.readthedocs.io/en/latest/) to run the tests. 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/). We'll also run the tests on GitHub actions when you send your pull request, but it's a good idea to run them locally before you send it. ### Installation We use uv to manage our environment and manage our Python installation. You can install it following the instructions at https://docs.astral.sh/uv/getting-started/installation/ ### Run the template's test suite To run the tests of the template using the current Python version: ```bash $ uv run tox run -e py ``` This uses `pytest `under the hood, and you can pass options to it after a `--`. So to run a particular test: ```bash $ uv run tox run -e py -- -k test_default_configuration ``` For further information, please consult the [pytest usage docs](https://pytest.org/en/latest/how-to/usage.html#specifying-which-tests-to-run). ### Run the generated project tests The template tests are checking that the generated project is fully rendered and that it passes `flake8`. We also have some test scripts which generate a specific project combination, install the dependencies, run the tests of the generated project, install FE dependencies and generate the docs. They will install the template dependencies, so make sure you create and activate a virtual environment first. ```bash $ python -m venv venv $ source venv/bin/activate ``` These tests are slower and can be run with or without Docker: - Without Docker: `tests/test_bare.sh` (for bare metal) - With Docker: `tests/test_docker.sh` All arguments to these scripts will be passed to the `cookiecutter` CLI, letting you set options, for example: ```bash $ tests/test_bare.sh use_celery=y ``` ## Submitting a pull request Once you're happy with your changes and they look ok locally, push and send [a pull request][submit-a-pr] to the main repo, which will trigger the tests on GitHub actions. If they fail, try to fix them. A maintainer should take a look at your change and give you feedback or merge it. [submit-a-pr]: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request ================================================ FILE: CONTRIBUTORS.md ================================================ # Contributors ## Core Developers These contributors have commit flags for the repository, and are able to accept and merge pull requests.
Name Github Twitter
Daniel Roy Greenfeld pydanny pydanny
Audrey Roy Greenfeld audreyr audreyr
Fábio C. Barrionuevo da Luz luzfcb luzfcb
Saurabh Kumar theskumar _theskumar
Jannis Gebauer jayfk
Burhan Khalid burhan burhan
Shupeyko Nikita webyneter webyneter
Bruno Alla browniebroke _BrunoAlla
Wan Liuyang sfdye sfdye
Jelmer Draaijer foarsitter
_Audrey is also the creator of Cookiecutter. Audrey and Daniel are on the Cookiecutter core team._ ## Other Contributors Listed in alphabetical order.
Name Github Twitter
18 dezoito
2O4 2O4
a7p a7p
Aadith PM aadithpm
Aaron Eikenberry aeikenberry
Abdul Qoyyuum Qoyyuum Qoyyuum
Abdullah Adeel mabdullahadeel abdadeel_
Abe Hanoka abe-101 abe__101
Adam Bogdał bogdal
Adam Dobrawy ad-m
Adam Steele adammsteele
Adin Hodovic adinhodovic
Agam Dua
Agustín Scaramuzza scaramagus scaramagus
aiden anyidea
Aidos Kanapyanov aidoskanapyanov
Alan Cyment acyment
Alberto Sanchez alb3rto
Alex Kanavos alexkanavos
Alex Tsai caffodian
Alexandr Artemyev Mogost MOGOST
Ali Shamakhi ali-shamakhi
Alvaro [Andor] andor-pierdelacabeza
Amjith Ramanujam amjith
Andreas Meistad ameistad
Andres Gonzalez andresgz
Andrew Chen Wang Andrew-Chen-Wang
Andrew Mikhnevich zcho
Andy Rose
Anna Callahan jazztpt
Anna Sidwell takkaria
Antonia Blair antoniablair antoniablairart
Anuj Bansal ahhda
Arcuri Davide dadokkio
Areski Belaid areski
Arkadiusz Michał Ryś arrys
Arnav Choudhury arnav13081994
Artur Barseghyan barseghyanartur
AsheKR ashekr
Ashley Camba
asmo a5m0
Barclay Gauld yunti
Bartek btknu
Ben Lopatin
Ben Warren bwarren2
Benjamin Abel
Bert de Miranda bertdemiranda
Birtibu Birtibu
Bo Lopker blopker
Bo Peng BoPeng
Bogdan Mateescu mateesville93
Bouke Haarsma
Brandon Rumiser brumiser1550
Brent Payne brentpayne brentpayne
Bruce Olivier bolivierjr
Caio Ariede caioariede caioariede
Carl Johnson carlmjohnson carlmjohnson
Catherine Devlin catherinedevlin
Cebrail Yılmaz b1sar
Chao Yang Wu goatwu1993
Charlie Macfarlane Brodie tannart
Charlie Smith chuckus
Chris Curvey ccurvey
Chris Franklin
Chris Franklin hairychris
Chris Pappalardo ChrisPappalardo
Christian González nerdoc
Christian Jauvin cjauvin
Christian Jensen jensenbox cjensen
Christopher Clarke chrisdev
Cole Mackenzie cmackenzie1
Cole Maclean cole cole
Collederas Collederas
Corey Garvey coreygarvey
Craig Margieson cmargieson
Cristian Vargas cdvv7788
Cullen Rhodes c-rhodes
Curtis St Pierre curtisstpierre cstpierre1388
Cédric Gaspoz cgaspoz
dalrrard dalrrard
Dan Shultz shultz
Dani Hodovic danihodovic
Daniel Hepper dhepper danielhepper
Daniel Hillier danifus
Daniel Sears highpost highpost
Daniele Tricoli eriol
David buckldav
David Díaz ddiazpinto DavidDiazPinto
David Păcioianu DavidPacioianu
Davit Tovmasyan davitovmasyan
Davur Clementsen dsclementsen davur
Delio Castillo jangeador jangeador
Delphine LEMIRE DelphineLemire
Demetris Stavrou demestav
Denis Bobrov delneg
Denis Darii DNX
Denis Orehovsky apirobot
Denis Savran blaxpy
DevForsure DevForsure
Diane Chen purplediane purplediane88
Diego Montes d57montes
Dominique Plante dominiqueplante
Dong Huynh trungdong
Donghoon Nam codenamenam
Douglas douglascdev
Duda Nogueira dudanogueira dudanogueira
duffn duffn
Dónal Adams epileptic-fish
Ed Morley edmorley
Emanuel Calso bloodpet bloodpet
enchance enchance
Eraldo Energy eraldo
Eric Groom ericgroom
Ernesto Cedeno codnee
Eyad Al Sibai eyadsibai
Fabian Affolter fabaff fabaff
farwill farwill
Fateme Fouladkar FatemeFouladkar
Felipe Arruda arruda
Filipe Nascimento FilipeNas
Florian Idelberger step21 windrush
Floyd Hightower fhightower
Francisco Navarro Morales spothound
Freddy Hraesvelg
Fuzzwah Fuzzwah
Gabriel Mejia elgartoinf elgartoinf
Garry Cairns garry-cairns
Garry Polley garrypolley
Geo Maciolek GeoMaciolek
ghazi-git ghazi-git
Gilbishkosma Gilbishkosma
GitBib GitBib
Glenn Wiskur gwiskur
Grant McLean grantm grantmnz
Guilherme Guy guilherme1guy
GvS GvS666
Hamish Durkin durkode
Hana Belay earthcomfy
Hana Quadara hanaquadara
Hannah Lazarus hanhanhan
Harry Moreno morenoh149 morenoh149
Harry Percival hjwp
Harshit Ranjan HarshitR2004
Haseeb ur Rehman professorhaseeb professorhaseeb
Hendrik Schneider hendrikschneider
henningbra henningbra
Henrique G. G. Pereira ikkebr
hleroy hleroy
Hoai-Thu Vuong thuvh
Howie Zhao howiezhao
Ian Lee IanLee1521
Igor Jerosimić igor-wl
Imran Rahman infraredCoding
innicoder innicoder
Irfan Ahmad erfaan erfaan
Isaac12x Isaac12x
itisnotyourenv itisnotyourenv
Ivan Khomutov ikhomutov
JAEGYUN JUNG TGoddessana
Jakub Boukal SukiCZ
Jakub Musko umgelurgel
James Williams jameswilliams1
Jan Fabry janfabry
Jan Van Bruggen jvanbrug
Jason Mok jasonmokk
Jeff Foster jeffpfoster
Jens Kaeske jkaeske
Jens Nilsson phiberjenz
Jeongseok Kang rapsealk
Jerome Caisip jeromecaisip
Jerome Leclanche jleclanche Adys
Jimmy Gitonga Afrowave afrowave
jlitrell jlitrell
John thorrak
John Cass jcass77 cass_john
Johnny Metz johnnymetz
Jonathan Thompson nojanath
Jorge Valdez jorgeavaldez
Joseph Hanna sanchimenea
Josh596 Josh596
jugglinmike jugglinmike
Jules Cheron jules-ch
Julien Almarcha sladinji
Julio Castillo juliocc
Kaido Kert kaidokert
kappataumu kappataumu kappataumu
Kaveh ka7eh
Kawsar Alam Foysal iamfoysal
Keith Bailey keithjeb
Keith Callenberg keithcallenberg
Keith Webber townie
Kevin A. Stone
Kevin Mills millsks
Kevin Ndung'u kevgathuku
Keyvan Mosharraf keyvanm
krati yadav krati5
Krzysztof Szumny noisy
Krzysztof Żuraw krzysztofzuraw
Kuo Chao Cheng wwwtony5488
lcd1232 lcd1232
LECbg LECbg
Leifur Halldor Asgeirsson leifurhauks
Leo won leollon
Leo Zhou glasslion
Leon Kim PilhwanKim
Leonardo Jimenez xpostudio4
Liam Brenner SableWalnut
Lin Xianyi iynaix
LJFP ljfp
Lucas Klasa lucaskbr
Luis Nell originell
Lukas Klein
Lyla Fischer
Malik Sulaimanov flyudvik flyudvik
Manas Mallick ManDun
Manjit Pardeshi Manjit2003
Marcio Mazza marciomazza marciomazza
Marios Frixou frixou89
Mariot Tsitoara mariot
Marlon Castillo mcastle
Martin Blech
Martin Saizar msaizar
Martín Blech martinblech
masavini masavini
Mateusz Ostaszewski mostaszewski
Matheus Jardim Bernardes matheusjardimb
Mathijs Hoogland MathijsHoogland
Matt Braymer-Hayes mattayes mattayes
Matt Knapper mknapper1
Matt Linares
Matt Menzenski menzenski
Matt Warren mfwarren
Matthew Foster Walsh mfosterw
Matthew Sisley mjsisley
Matthias Sieber manonthemat MatzeOne
Maurício Gioachini MauGx3
Meghan Heintz dot2dotseurat
Meraj ichbinmeraj merajsafari
Mesut Yılmaz myilmaz
Michael Gecht mimischi _mischi
Michael Samoylov msamoylov
Michael V. Battista mvbattista mvbattista
Mike97M Mike97M
milvagox milvagox milvagox
Min ho Kim minho42
MinWoo Sung SungMinWoo
Mohamed Feddad mrf345
monosans monosans
Morten Kaae MortenKaae
Mounir mounirmesselmeni
mozillazg mozillazg
mpoli mpoli
mpsantos mpsantos
Nadav Peretz nadavperetz
Naveen naveensrinivasan snaveen
Nico Stefani nicolas471 moby_dick91
Nikita Sobolev sobolevn
Nix Siow nixsiow nixsiow
Noah H nthall
Oleg Russkin rolep
Omer-5 Omer-5
Pablo oubiga
Pamela Fox pamelafox pamelafox
Param Kapur paramkpr ParamKapur
Parbhat Puri parbhat
Patrick Tran theptrk
Patrick Zhang PatDuJour
Paul Wulff mtmpaulwulff
Pawan Chaurasia rjsnh1522
Pedro Campos pcampos119104
Pepa 07pepa
Peter Bittner bittner
Peter Coles mrcoles
Philipp Matthies canonnervio
Pierre Chiquet pchiquet
PJ Hoberman pjhoberman
Plurific paulschwenn
Pulse-Mind pulse-mind
quroom quroom
qwerrrqw qwerrrqw
Raony Guimarães Corrêa raonyguimaraes
Raphael Pierzina hackebrot
Ray Besiga raybesiga raybesiga
Reggie Riser reggieriser
René Muhl rm--
rguptar rguptar
Richard Hajdu Tusky
Robin Kaffeetasse
Roman Afanaskin siauPatrick
Roman Osipenko romanosipenko
Russell Davies
rxm7706 rxm7706
Ryan Fitch ryfi
Sadra Yahyapour lnxpy lnxpylnxpy
Sam Collins MightySCollins
Sascha saschalalala saschalalala
Sebastian Reyes Espinosa sebastian-code sebastianreyese
Shayan Karimi shywn-mrk shywn_mrk
Simeon Emanuilov s-emanuilov s_emanuilov
Simon Rey eqqe
Soldatov Serhii soldatov-ss
Sorasful sorasful
Srinivas Nyayapati shireenrao
stepmr stepmr
Steve Steiner ssteinerX
Sudarshan Wadkar wadkar
Sule Marshall suledev
Sławek Ehlert slafs
TAKAHASHI Shuuji shuuji3
Tames McTigue Tamerz
Tano Abeleyra tanoabeleyra
Taylor Baldwin
Tharushan Tharushan
Thibault J. thibault thibault
Thomas Booij ThomasBooij95
Théo Segonds show0k
tildebox tildebox
Tim Claessens timclaessens
Tim Freund timfreund
Timm Simpkins PoDuck
tmajerech tmajerech
Tom Atkins knitatoms
Tom Offermann
Tosinibikunle Tosinibikunle
Travis McNeill Travistock tavistock_esq
Tubo Shi Tubo
Umair Ashraf umrashrf fabumair
Vadim Iskuchekov Egregors egregors
Vageeshan Mankala vagi8
vascop vascop
Vicente G. Reyes reyesvicente highcenburg
Vikas Yadav vik-y
villancikos villancikos
Vincent Leduc leducvin
Vitaly Babiy
Vivian Guillen viviangb
Vlad Doster vladdoster
Wes Turner westurner westurner
Will novucs
Will Farley goldhand g01dhand
Will Gordon wgordon17
William Archinal archinal
Xaver Y.R. Chen yrchen yrchen
Yaroslav Halchenko
Yotam Tal yotamtal
Yuchen Xie mapx
Zach Borboa zachborboa
zhaoruibing zhaoruibing
### Special Thanks The following haven't provided code directly, but have provided guidance and advice. - Jannis Leidel - Nate Aune - Barry Morrison ================================================ FILE: LICENSE ================================================ Copyright (c) 2013-2020, Daniel Roy Greenfeld All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Cookiecutter Django nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: README.md ================================================ # Cookiecutter Django [![Build Status](https://img.shields.io/github/actions/workflow/status/cookiecutter/cookiecutter-django/ci.yml?branch=main)](https://github.com/cookiecutter/cookiecutter-django/actions/workflows/ci.yml?query=branch%3Amain) [![Documentation Status](https://readthedocs.org/projects/cookiecutter-django/badge/?version=latest)](https://cookiecutter-django.readthedocs.io/en/latest/?badge=latest) [![pre-commit.ci status](https://results.pre-commit.ci/badge/github/cookiecutter/cookiecutter-django/main.svg)](https://results.pre-commit.ci/latest/github/cookiecutter/cookiecutter-django/main) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black) [![Updates](https://pyup.io/repos/github/cookiecutter/cookiecutter-django/shield.svg)](https://pyup.io/repos/github/cookiecutter/cookiecutter-django/) [![Join our Discord](https://img.shields.io/badge/Discord-cookiecutter-5865F2?style=flat&logo=discord&logoColor=white)](https://discord.gg/rAWFUP47d2) [![Code Helpers Badge](https://www.codetriage.com/cookiecutter/cookiecutter-django/badges/users.svg)](https://www.codetriage.com/cookiecutter/cookiecutter-django) Powered by [Cookiecutter](https://github.com/cookiecutter/cookiecutter), Cookiecutter Django is a framework for jumpstarting production-ready Django projects quickly. - Documentation: - See [Troubleshooting](https://cookiecutter-django.readthedocs.io/en/latest/5-help/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 6.0 - Works with Python 3.13 - Renders Django projects with 100% starting test coverage - Twitter [Bootstrap](https://github.com/twbs/bootstrap) v5 - [12-Factor](https://12factor.net) based settings via [django-environ](https://github.com/joke2k/django-environ) - Secure by default. We believe in SSL. - Optimized development and production settings - Registration via [django-allauth](https://github.com/pennersr/django-allauth) - Comes with custom user model ready to go - Optional basic ASGI setup for Websockets - Optional custom static build using Gulp or Webpack - Send emails via [Anymail](https://github.com/anymail/django-anymail) (using [Mailgun](http://www.mailgun.com/) by default or Amazon SES if AWS is selected cloud provider, but switchable) - Media storage using Amazon S3, Google Cloud Storage, Azure Storage or nginx - Docker support using [docker-compose](https://github.com/docker/compose) for development and production (using [Traefik](https://traefik.io/) with [LetsEncrypt](https://letsencrypt.org/) support) - [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, Azure Storage or [Whitenoise](https://whitenoise.readthedocs.io/) - Configuration for [Celery](https://docs.celeryq.dev) and [Flower](https://github.com/mher/flower) (the latter in Docker setup only) - Integration with [Mailpit](https://github.com/axllent/mailpit/) 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: 14 - 18 ([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 an open source project run by volunteers. You can sponsor us via [OpenCollective](https://opencollective.com/cookiecutter-django) or individually via GitHub Sponsors: - Daniel Roy Greenfeld, Project Lead ([GitHub](https://github.com/pydanny), [Patreon](https://www.patreon.com/danielroygreenfeld)): expertise in Django and AWS ELB. - Fabio C. Barrionuevo, Core Developer ([GitHub](https://github.com/luzfcb)): expertise in Python/Django, hands-on DevOps and frontend experience. - Bruno Alla, Core Developer ([GitHub](https://github.com/browniebroke)): expertise in Python/Django and DevOps. - 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: ### Two Scoops of Django [![Cover of the book "Two Scoops of Django 3.x"](https://f004.backblazeb2.com/file/feldroycom/images/book-TSD3-800.jpg)](https://www.feldroy.com/two-scoops-of-django) Two Scoops of Django 3.x is the best ice cream-themed Django reference in the universe! ### PyUp [![PyUp Logo](https://pyup.io/static/images/logo.png)](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](https://github.com/cookiecutter/cookiecutter) to do all the work. First, get Cookiecutter. Trust me, it's awesome: uv tool install "cookiecutter>=1.7.0" Now run it against this repo: uvx 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/1-getting-started/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 Select username_type: 1 - username 2 - email Choose from 1, 2 [1]: 1 timezone [UTC]: America/Los_Angeles windows [n]: n Select an editor to use. The choices are: 1 - None 2 - PyCharm 3 - VS Code Choose from 1, 2, 3 [1]: 1 use_docker [n]: n Select postgresql_version: 1 - 18 2 - 17 3 - 16 4 - 15 5 - 14 Choose from 1, 2, 3, 4 [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 - Brevo (formerly SendinBlue) 8 - SparkPost 9 - Other SMTP Choose from 1, 2, 3, 4, 5, 6, 7, 8, 9 [1]: 1 Select rest_api [None]: 1 - None 2 - DRF 3 - Django Ninja Choose from 1, 2, 3 [1]: 1 use_async [n]: n Select frontend_pipeline: 1 - None 2 - Django Compressor 3 - Gulp 4 - Webpack Choose from 1, 2, 3, 4 [1]: 1 use_celery [n]: y use_mailpit [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 main 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](https://cookiecutter-django.readthedocs.io/en/latest/2-local-development/developing-locally.html) - [Developing locally using docker](https://cookiecutter-django.readthedocs.io/en/latest/2-local-development/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/uFXweDQc5a). Contributors ## 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 ## 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 - [Why cookiecutter-django is Essential for Your Next Django Project](https://medium.com/@millsks/why-cookiecutter-django-is-essential-for-your-next-django-project-7d3c00cdce51) - Aug. 4, 2024 - [How to Make Your Own Django Cookiecutter Template!](https://medium.com/@FatemeFouladkar/how-to-make-your-own-django-cookiecutter-template-a753d4cbb8c2) - Aug. 10, 2023 - [Cookiecutter Django With Amazon RDS](https://haseeburrehman.com/posts/cookiecutter-django-with-amazon-rds/) - Apr, 2, 2021 - [Complete Walkthrough: Blue/Green Deployment to AWS ECS using GitHub actions](https://github.com/Andrew-Chen-Wang/cookiecutter-django-ecs-github) - June 10, 2020 - [Using cookiecutter-django with Google Cloud Storage](https://ahhda.github.io/cloud/gce/django/2019/03/12/using-django-cookiecutter-cloud-storage.html) - Mar. 12, 2019 - [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. ================================================ FILE: cookiecutter.json ================================================ { "project_name": "My Awesome Project", "project_slug": "{{ cookiecutter.project_name.lower()|replace(' ', '_')|replace('-', '_')|replace('.', '_')|trim() }}", "description": "Behold My Awesome Project!", "author_name": "Daniel Roy Greenfeld", "domain_name": "example.com", "email": "{{ cookiecutter.author_name.lower() | trim() |replace(' ', '-') }}@{{ cookiecutter.domain_name.lower() | trim() }}", "version": "0.1.0", "open_source_license": [ "MIT", "BSD", "GPLv3", "Apache Software License 2.0", "Not open source" ], "username_type": ["username", "email"], "timezone": "UTC", "windows": "n", "editor": ["None", "PyCharm", "VS Code"], "use_docker": "n", "postgresql_version": ["18", "17", "16", "15", "14"], "cloud_provider": ["AWS", "GCP", "Azure", "None"], "mail_service": [ "Mailgun", "Amazon SES", "Mailjet", "Mandrill", "Postmark", "Sendgrid", "Brevo", "SparkPost", "Other SMTP" ], "rest_api": ["None", "DRF", "Django Ninja"], "use_async": "n", "frontend_pipeline": ["None", "Django Compressor", "Gulp", "Webpack"], "use_celery": "n", "use_mailpit": "n", "use_sentry": "n", "use_whitenoise": "n", "use_heroku": "n", "ci_tool": ["None", "Travis", "Gitlab", "Github", "Drone"], "keep_local_envs_in_vcs": "y", "debug": "n" } ================================================ FILE: docs/1-getting-started/project-generation-options.rst ================================================ .. _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. project_slug: Your project's slug without dashes or spaces. Used to name your repo and in other places where a Python-importable version of your project name is needed. description: Describes your project and gets used in places like ``README.rst`` and such. author_name: This is you! The value goes into places like ``LICENSE`` and such. email: The email address you want to identify yourself in the project. username_type: The type of username you want to use in the project. This can be either ``username`` or ``email``. If you choose ``username``, the ``email`` field will be included. If you choose ``email``, the ``username`` field will be excluded. It is best practice to always include an email field, so there is no option for having just the ``username`` field. domain_name: The domain name you plan to use for your project once it goes live. Note that it can be safely changed later on whenever you need to. version: The version of the project at its inception. open_source_license: A software license for the project. The choices are: 1. MIT_ 2. BSD_ 3. GPLv3_ 4. `Apache Software License 2.0`_ 5. Not open source timezone: The value to be used for the ``TIME_ZONE`` setting of the project. windows: Indicates whether the project should be configured for development on Windows. editor: Select an editor to use. The choices are: 1. None 2. PyCharm_ 3. `VS Code`_ use_docker: Indicates whether the project should be configured to use Docker_, `Docker Compose`_ and `devcontainer`_. postgresql_version: Select a PostgreSQL_ version to use. The choices are: 1. 18 2. 17 3. 16 4. 15 5. 14 cloud_provider: Select a cloud provider for static & media files. The choices are: 1. AWS_ 2. GCP_ 3. Azure_ 4. None If you choose no cloud provider and docker, the production stack will serve the media files via an nginx Docker service. Without Docker, the media files won't work. mail_service: Select an email service that Django-Anymail provides 1. Mailgun_ 2. `Amazon SES`_ 3. Mailjet_ 4. Mandrill_ 5. Postmark_ 6. SendGrid_ 7. `Brevo (formerly SendinBlue)`_ 8. SparkPost_ 9. `Other SMTP`_ rest_api: Select a REST API framework to use. The choices are: 1. None 2. `Django Rest Framework`_ 3. `Django Ninja`_ use_async: Indicates whether the project should use web sockets with Uvicorn + Gunicorn. frontend_pipeline: Select a pipeline to compile and optimise frontend assets (JS, CSS, ...): 1. None 2. `Django Compressor`_ 3. `Gulp`_ 4. `Webpack`_ Both Gulp and Webpack support Bootstrap recompilation with real-time variables alteration. use_celery: Indicates whether the project should be configured to use Celery_. use_mailpit: Indicates whether the project should be configured to use Mailpit_. use_sentry: Indicates whether the project should be configured to use Sentry_. use_whitenoise: Indicates whether the project should be configured to use WhiteNoise_. use_heroku: Indicates whether the project should be configured so as to be deployable to Heroku_. ci_tool: Select a CI tool for running tests. The choices are: 1. None 2. `Travis CI`_ 3. `Gitlab CI`_ 4. `Github Actions`_ 5. `Drone CI`_ keep_local_envs_in_vcs: Indicates whether the project’s .envs/.local/ should be kept in VCS (comes in handy when working in teams where local environment reproducibility is strongly encouraged). debug: Indicates whether the project should be configured for debugging. This option is relevant for Cookiecutter Django developers only. .. _MIT: https://opensource.org/licenses/MIT .. _BSD: https://opensource.org/licenses/BSD-3-Clause .. _GPLv3: https://www.gnu.org/licenses/gpl.html .. _Apache Software License 2.0: https://www.apache.org/licenses/LICENSE-2.0 .. _PyCharm: https://www.jetbrains.com/pycharm/ .. _VS Code: https://github.com/microsoft/vscode .. _Docker: https://github.com/docker/docker .. _Docker Compose: https://docs.docker.com/compose/ .. _devcontainer: https://containers.dev/ .. _PostgreSQL: https://www.postgresql.org/docs/ .. _Gulp: https://github.com/gulpjs/gulp .. _Webpack: https://webpack.js.org .. _AWS: https://aws.amazon.com/s3/ .. _GCP: https://cloud.google.com/storage/ .. _Azure: https://azure.microsoft.com/en-us/products/storage/blobs/ .. _Amazon SES: https://aws.amazon.com/ses/ .. _Mailgun: https://www.mailgun.com .. _Mailjet: https://www.mailjet.com .. _Mandrill: http://mandrill.com .. _Postmark: https://postmarkapp.com .. _SendGrid: https://sendgrid.com .. _Brevo (formerly SendinBlue): https://www.brevo.com .. _SparkPost: https://www.sparkpost.com .. _Other SMTP: https://anymail.readthedocs.io/en/stable/ .. _Django Rest Framework: https://github.com/encode/django-rest-framework/ .. _Django Ninja: https://github.com/vitalik/django-ninja .. _Django Compressor: https://github.com/django-compressor/django-compressor .. _Celery: https://github.com/celery/celery .. _Mailpit: https://github.com/axllent/mailpit .. _Sentry: https://github.com/getsentry/sentry .. _WhiteNoise: https://github.com/evansd/whitenoise .. _Heroku: https://github.com/heroku/heroku-buildpack-python .. _Travis CI: https://travis-ci.org/ .. _GitLab CI: https://docs.gitlab.com/ee/ci/ .. _Drone CI: https://docs.drone.io/pipeline/overview/ .. _Github Actions: https://docs.github.com/en/actions ================================================ FILE: docs/1-getting-started/settings.rst ================================================ .. _settings: Settings ======== This project relies extensively on environment settings which **will not work with Apache/mod_wsgi setups**. It has been deployed successfully with both Gunicorn/Nginx and even uWSGI/Nginx. For configuration purposes, the following table maps environment variables to their Django setting and project settings: ======================================= =========================== ============================================== ====================================================================== Environment Variable Django Setting Development Default Production Default ======================================= =========================== ============================================== ====================================================================== DJANGO_READ_DOT_ENV_FILE READ_DOT_ENV_FILE False False ======================================= =========================== ============================================== ====================================================================== ======================================= =========================== ============================================== ====================================================================== Environment Variable Django Setting Development Default Production Default ======================================= =========================== ============================================== ====================================================================== DATABASE_URL DATABASES auto w/ Docker; postgres://project_slug w/o raises error DJANGO_ADMIN_URL n/a 'admin/' raises error DJANGO_DEBUG DEBUG True False DJANGO_SECRET_KEY SECRET_KEY auto-generated raises error DJANGO_SECURE_SSL_REDIRECT SECURE_SSL_REDIRECT n/a True DJANGO_SECURE_CONTENT_TYPE_NOSNIFF SECURE_CONTENT_TYPE_NOSNIFF n/a True DJANGO_SECURE_FRAME_DENY SECURE_FRAME_DENY n/a True DJANGO_SECURE_HSTS_INCLUDE_SUBDOMAINS HSTS_INCLUDE_SUBDOMAINS n/a True DJANGO_SESSION_COOKIE_HTTPONLY SESSION_COOKIE_HTTPONLY n/a True DJANGO_SESSION_COOKIE_SECURE SESSION_COOKIE_SECURE n/a False DJANGO_DEFAULT_FROM_EMAIL DEFAULT_FROM_EMAIL n/a "your_project_name " DJANGO_SERVER_EMAIL SERVER_EMAIL n/a "your_project_name " DJANGO_EMAIL_SUBJECT_PREFIX EMAIL_SUBJECT_PREFIX n/a "[your_project_name] " DJANGO_ALLOWED_HOSTS ALLOWED_HOSTS ['*'] ['your_domain_name'] ======================================= =========================== ============================================== ====================================================================== The following table lists settings and their defaults for third-party applications, which may or may not be part of your project: ======================================= =========================== ============================================== ====================================================================== Environment Variable Django Setting Development Default Production Default ======================================= =========================== ============================================== ====================================================================== DJANGO_AWS_ACCESS_KEY_ID AWS_ACCESS_KEY_ID n/a raises error DJANGO_AWS_SECRET_ACCESS_KEY AWS_SECRET_ACCESS_KEY n/a raises error DJANGO_AWS_STORAGE_BUCKET_NAME AWS_STORAGE_BUCKET_NAME n/a raises error DJANGO_AWS_S3_REGION_NAME AWS_S3_REGION_NAME n/a None DJANGO_AWS_S3_CUSTOM_DOMAIN AWS_S3_CUSTOM_DOMAIN n/a None DJANGO_AWS_S3_MAX_MEMORY_SIZE AWS_S3_MAX_MEMORY_SIZE n/a 100_000_000 DJANGO_GCP_STORAGE_BUCKET_NAME GS_BUCKET_NAME n/a raises error GOOGLE_APPLICATION_CREDENTIALS n/a n/a raises error DJANGO_AZURE_ACCOUNT_KEY AZURE_ACCOUNT_KEY n/a raises error DJANGO_AZURE_ACCOUNT_NAME AZURE_ACCOUNT_NAME n/a raises error DJANGO_AZURE_CONTAINER_NAME AZURE_CONTAINER n/a raises error SENTRY_DSN SENTRY_DSN n/a raises error SENTRY_ENVIRONMENT n/a n/a production SENTRY_TRACES_SAMPLE_RATE n/a n/a 0.0 DJANGO_SENTRY_LOG_LEVEL SENTRY_LOG_LEVEL n/a logging.INFO MAILGUN_API_KEY MAILGUN_API_KEY n/a raises error MAILGUN_DOMAIN MAILGUN_SENDER_DOMAIN n/a raises error MAILGUN_API_URL n/a n/a "https://api.mailgun.net/v3" MAILJET_API_KEY MAILJET_API_KEY n/a raises error MAILJET_SECRET_KEY MAILJET_SECRET_KEY n/a raises error MAILJET_API_URL n/a n/a "https://api.mailjet.com/v3" MANDRILL_API_KEY MANDRILL_API_KEY n/a raises error MANDRILL_API_URL n/a n/a "https://mandrillapp.com/api/1.0" POSTMARK_SERVER_TOKEN POSTMARK_SERVER_TOKEN n/a raises error POSTMARK_API_URL n/a n/a "https://api.postmarkapp.com/" SENDGRID_API_KEY SENDGRID_API_KEY n/a raises error SENDGRID_GENERATE_MESSAGE_ID True n/a raises error SENDGRID_MERGE_FIELD_FORMAT None n/a raises error SENDGRID_API_URL n/a n/a "https://api.sendgrid.com/v3/" BREVO_API_KEY BREVO_API_KEY n/a raises error BREVO_API_URL n/a n/a "https://api.brevo.com/v3/" SPARKPOST_API_KEY SPARKPOST_API_KEY n/a raises error SPARKPOST_API_URL n/a n/a "https://api.sparkpost.com/api/v1" ======================================= =========================== ============================================== ====================================================================== -------------------------- Other Environment Settings -------------------------- DJANGO_ACCOUNT_ALLOW_REGISTRATION (=True) Allow enable or disable user registration through `django-allauth` without disabling other characteristics like authentication and account management. (Django Setting: ACCOUNT_ALLOW_REGISTRATION) DJANGO_ADMIN_FORCE_ALLAUTH (=False) Force the `admin` sign in process to go through the `django-allauth` workflow. ================================================ FILE: docs/2-local-development/developing-locally-docker.rst ================================================ Getting Up and Running Locally With Docker ========================================== .. index:: Docker .. note:: If you're new to Docker, please be aware that some resources are cached system-wide and might reappear if you generate a project multiple times with the same name (e.g. :ref:`this issue with Postgres `). 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 `pre-commit`_. * Cookiecutter; refer to the official GitHub repository of `Cookiecutter`_ .. _`installation instructions`: https://docs.docker.com/install/ .. _`installation guide`: https://docs.docker.com/compose/install/ .. _`pre-commit`: https://pre-commit.com/#install .. _`Cookiecutter`: https://github.com/cookiecutter/cookiecutter Before Getting Started ---------------------- .. include:: generate-project-block.rst Build the Stack --------------- This can take a while, especially the first time you run this particular command on your development system:: docker compose -f docker-compose.local.yml build Generally, if you want to emulate production environment use ``docker-compose.production.yml`` instead. And this is true for any other actions you might need to perform: whenever a switch is required, just do it! After we have created our initial image we nee to generate a lockfile for our dependencies. Docker cannot write to the host system during builds, so we have to run the command to generate the lockfile in the container. This is important for reproducible builds and to ensure that the dependencies are installed correctly in the container. Updating the lockfile manually is normally not necessary when you add packages through `uv add `. docker compose -f docker-compose.local.yml run --rm django uv lock This is done by running the following command: :: docker compose -f docker-compose.local.yml run --rm django uv lock To be sure we are on the right track we need to build our image again: :: docker compose -f docker-compose.local.yml build Before doing any git commit, `pre-commit`_ should be installed globally on your local machine, and then:: git init pre-commit install Failing to do so will result with a bunch of CI and Linter errors that can be avoided with pre-commit. Run the Stack ------------- This brings up both Django and PostgreSQL. The first time it is run it might take a while to get started, but subsequent runs will occur quickly. Open a terminal at the project root and run the following for local development:: docker compose -f docker-compose.local.yml up You can also set the environment variable ``COMPOSE_FILE`` pointing to ``docker-compose.local.yml`` like this:: export COMPOSE_FILE=docker-compose.local.yml And then run:: docker compose up To run in a detached (background) mode, just:: docker compose up -d These commands don't run the docs service. In order to run docs service you can run:: docker compose -f docker-compose.docs.yml up To run the docs with local services just use:: docker compose -f docker-compose.local.yml -f docker-compose.docs.yml up The site should start and be accessible at http://localhost:3000 if you selected Webpack or Gulp as frontend pipeline and http://localhost:8000 otherwise. Execute Management Commands --------------------------- As with any shell command that we wish to run in our container, this is done using the ``docker compose -f docker-compose.local.yml run --rm`` command: :: docker compose -f docker-compose.local.yml run --rm django python manage.py migrate docker compose -f docker-compose.local.yml run --rm django python manage.py createsuperuser Here, ``django`` is the target service we are executing the commands against. Also, please note that the ``docker exec`` does not work for running management commands. (Optionally) Designate your Docker Development Server IP -------------------------------------------------------- When ``DEBUG`` is set to ``True``, the host is validated against ``['localhost', '127.0.0.1', '[::1]']``. This is adequate when running a ``virtualenv``. For Docker, in the ``config.settings.local``, add your host development server IP to ``INTERNAL_IPS`` or ``ALLOWED_HOSTS`` if the variable exists. .. _envs: Configuring the Environment --------------------------- This is the excerpt from your project's ``docker-compose.local.yml``: :: # ... postgres: build: context: . dockerfile: ./compose/production/postgres/Dockerfile volumes: - local_postgres_data:/var/lib/postgresql/data - local_postgres_data_backups:/backups env_file: - ./.envs/.local/.postgres # ... The most important thing for us here now is ``env_file`` section enlisting ``./.envs/.local/.postgres``. Generally, the stack's behavior is governed by a number of environment variables (`env(s)`, for short) residing in ``envs/``, for instance, this is what we generate for you: :: .envs ├── .local │ ├── .django │ └── .postgres └── .production ├── .django └── .postgres By convention, for any service ``sI`` in environment ``e`` (you know ``someenv`` is an environment when there is a ``someenv.yml`` file in the project root), given ``sI`` requires configuration, a ``.envs/.e/.sI`` `service configuration` file exists. Consider the aforementioned ``.envs/.local/.postgres``: :: # PostgreSQL # ------------------------------------------------------------------------------ POSTGRES_HOST=postgres POSTGRES_DB= POSTGRES_USER=XgOWtQtJecsAbaIyslwGvFvPawftNaqO POSTGRES_PASSWORD=jSljDz4whHuwO3aJIgVBrqEml5Ycbghorep4uVJ4xjDYQu0LfuTZdctj7y0YcCLu The three envs we are presented with here are ``POSTGRES_DB``, ``POSTGRES_USER``, and ``POSTGRES_PASSWORD`` (by the way, their values have also been generated for you). You might have figured out already where these definitions will end up; it's all the same with ``django`` service container envs. One final touch: should you ever need to merge ``.envs/.production/*`` in a single ``.env`` run the ``merge_production_dotenvs_in_dotenv.py``: :: python merge_production_dotenvs_in_dotenv.py The ``.env`` file will then be created, with all your production envs residing beside each other. Tips & Tricks ------------- Activate a Docker Machine ~~~~~~~~~~~~~~~~~~~~~~~~~ This tells our computer that all future commands are specifically for the dev1 machine. Using the ``eval`` command we can switch machines as needed.:: eval "$(docker-machine env dev1)" Add 3rd party python packages ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ To install a new 3rd party python package, you cannot use ``uv add ``, that would only add the package to the container. The container is ephemeral, so that new library won't be persisted if you run another container. Instead, you should modify the Docker image: You have to modify pyproject.toml and either add it to project.dependencies or to tool.uv.dev-dependencies by adding: :: "==" To get this change picked up, you'll need to rebuild the image(s) and restart the running container: :: docker compose -f docker-compose.local.yml build docker compose -f docker-compose.local.yml up Debugging ~~~~~~~~~ ipdb """"" If you are using the following within your code to debug: :: import ipdb; ipdb.set_trace() Then you may need to run the following for it to work as desired: :: docker compose -f docker-compose.local.yml run --rm --service-ports django django-debug-toolbar """""""""""""""""""" In order for ``django-debug-toolbar`` to work designate your Docker Machine IP with ``INTERNAL_IPS`` in ``local.py``. docker """""" The ``container_name`` from the yml file can be used to check on containers with docker commands, for example: :: docker logs _local_celeryworker docker top _local_celeryworker Notice that the ``container_name`` is generated dynamically using your project slug as a prefix Mailpit ~~~~~~~ When developing locally you can go with Mailpit_ for email testing provided ``use_mailpit`` was set to ``y`` on setup. To proceed, #. make sure ``_local_mailpit`` container is up and running; #. open up ``http://127.0.0.1:8025``. .. _Mailpit: https://github.com/axllent/mailpit/ .. _`CeleryTasks`: Celery tasks in local development ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ When not using docker Celery tasks are set to run in Eager mode, so that a full stack is not needed. When using docker the task scheduler will be used by default. If you need tasks to be executed on the main thread during development set ``CELERY_TASK_ALWAYS_EAGER = True`` in ``config/settings/local.py``. Possible uses could be for testing, or ease of profiling with DJDT. .. _`CeleryFlower`: Celery Flower ~~~~~~~~~~~~~ `Flower`_ is a "real-time monitor and web admin for Celery distributed task queue". Prerequisites: * ``use_docker`` was set to ``y`` on project initialization; * ``use_celery`` was set to ``y`` on project initialization. By default, it's enabled both in local and production environments (``docker-compose.local.yml`` and ``docker-compose.production.yml`` Docker Compose configs, respectively) through a ``flower`` service. For added security, ``flower`` requires its clients to provide authentication credentials specified as the corresponding environments' ``.envs/.local/.django`` and ``.envs/.production/.django`` ``CELERY_FLOWER_USER`` and ``CELERY_FLOWER_PASSWORD`` environment variables. Check out ``localhost:5555`` and see for yourself. .. _`Flower`: https://github.com/mher/flower Using Webpack or Gulp ~~~~~~~~~~~~~~~~~~~~~ If you've opted for Gulp or Webpack as front-end pipeline, the project comes configured with `Sass`_ compilation and `live reloading`_. As you change your Sass/JS source files, the task runner will automatically rebuild the corresponding CSS and JS assets and reload them in your browser without refreshing the page. The stack comes with a dedicated node service to build the static assets, watch for changes and proxy requests to the Django app with live reloading scripts injected in the response. For everything to work smoothly, you need to access the application at the port served by the node service, which is http://localhost:3000 by default. .. _Sass: https://sass-lang.com/ .. _live reloading: https://browsersync.io Using Just for Docker Commands ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ We have included a ``justfile`` to simplify the use of frequent Docker commands for local development. .. warning:: Currently, "Just" does not reliably handle signals or forward them to its subprocesses. As a result, pressing CTRL+C (or sending other signals like SIGTERM, SIGINT, or SIGHUP) may only interrupt "Just" itself rather than its subprocesses. For more information, see `this GitHub issue `_. First, install Just using one of the methods described in the `official documentation `_. Here are the available commands: - ``just build`` Builds the Python image using the local Docker Compose file. - ``just up`` Starts the containers in detached mode and removes orphaned containers. - ``just down`` Stops the running containers. - ``just prune`` Stops and removes containers along with their volumes. You can optionally pass an argument with the service name to prune a single container. - ``just logs`` Shows container logs. You can optionally pass an argument with the service name to view logs for a specific service. - ``just manage `` Runs Django management commands within the container. Replace ```` with any valid Django management command, such as ``migrate``, ``createsuperuser``, or ``shell``. (Optionally) Developing locally with HTTPS ------------------------------------------ Nginx ~~~~~ If you want to add some sort of social authentication with a OAuth provider such as Facebook, securing your communication to the local development environment will be necessary. These providers usually require that you use an HTTPS URL for the OAuth redirect URL for the Facebook login to work appropriately. Here is a link to an article on `how to add HTTPS using Nginx`_ to your local docker installation. This also includes how to serve files from the ``media`` location, in the event that you are want to serve user-uploaded content. .. _`how to add HTTPS using Nginx`: https://afroshok.com/cookiecutter-https Webpack ~~~~~~~ If you are using Webpack, first install `mkcert`_. It is a simple by design tool that hides all the arcane knowledge required to generate valid TLS certificates. It works for any hostname or IP, including localhost. It supports macOS, Linux, and Windows, and Firefox, Chrome and Java. It even works on mobile devices with a couple manual steps. See https://blog.filippo.io/mkcert-valid-https-certificates-for-localhost/ .. _`mkcert`: https://github.com/FiloSottile/mkcert/blob/master/README.md#supported-root-stores These are the places that you should configure to secure your local environment. Take the certificates that you generated and place them in a folder called ``certs`` in the project's root folder. Configure an ``nginx`` reverse-proxy server as a ``service`` in the ``docker-compose.local.yml``. This makes sure that it does not interfere with our ``traefik`` configuration that is reserved for production environments. 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``. 1. Add the ``nginx-proxy`` service to the ``docker-compose.local.yml``. :: nginx-proxy: image: jwilder/nginx-proxy:alpine container_name: nginx-proxy ports: - "80:80" - "443:443" volumes: - /var/run/docker.sock:/tmp/docker.sock:ro - ./certs:/etc/nginx/certs restart: always depends_on: - node environment: - VIRTUAL_HOST=my-dev-env.local - VIRTUAL_PORT=3000 2. Add the local secure domain to the ``config/settings/local.py``. You should allow the new hostname :: ALLOWED_HOSTS = ["localhost", "0.0.0.0", "127.0.0.1", "my-dev-env.local"] 3. Add the following configuration to the ``devServer`` section of ``webpack/dev.config.js`` :: client: { webSocketURL: 'auto://0.0.0.0:0/ws', // note the `:0` after `0.0.0.0` }, Rebuild your ``docker`` application. :: docker compose -f docker-compose.local.yml up -d --build Go to your browser and type in your URL bar ``https://my-dev-env.local``. For more on this configuration, see `https with nginx`_. .. _`https with nginx`: https://codewithhugo.com/docker-compose-local-https/ ================================================ FILE: docs/2-local-development/developing-locally.rst ================================================ Getting Up and Running Locally ============================== .. index:: PostgreSQL Setting Up Development Environment ---------------------------------- Make sure to have the following on your host: * uv https://docs.astral.sh/uv/getting-started/installation/ * PostgreSQL_. * Redis_, if using Celery * Cookiecutter_ #. .. include:: generate-project-block.rst #. Install development requirements: :: cd uv sync git init # A git repo is required for pre-commit to install uv run pre-commit install .. note:: the `pre-commit` hook exists in the generated project as default. For the details of `pre-commit`, follow the `pre-commit`_ site. #. Create a new PostgreSQL database using createdb_: :: createdb --username=postgres ``project_slug`` is what you have entered as the project_slug at the setup stage. .. note:: if this is the first time a database is created on your machine you might need an `initial PostgreSQL set up`_ to allow local connections & set a password for the ``postgres`` user. The `postgres documentation`_ explains the syntax of the config file that you need to change. #. Set the environment variables for your database(s): :: export DATABASE_URL=postgres://postgres:@127.0.0.1:5432/ .. note:: Check out the :ref:`settings` page for a comprehensive list of the environments variables. .. seealso:: To help setting up your environment variables, you have a few options: * create an ``.env`` file in the root of your project and define all the variables you need in it. Then you just need to have ``DJANGO_READ_DOT_ENV_FILE=True`` in your machine and all the variables will be read. * Use a local environment manager like `direnv`_ #. Apply migrations: :: uv run python manage.py migrate #. If you're running synchronously, see the application being served through Django development server: :: uv run python manage.py runserver 0.0.0.0:8000 or if you're running asynchronously: :: uv run uvicorn config.asgi:application --host 0.0.0.0 --reload --reload-include '*.html' If you've opted for Webpack or Gulp as frontend pipeline, please see the :ref:`dedicated section ` below. .. _PostgreSQL: https://www.postgresql.org/download/ .. _Redis: https://redis.io/download .. _CookieCutter: https://github.com/cookiecutter/cookiecutter .. _createdb: https://www.postgresql.org/docs/current/static/app-createdb.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/ Creating Your First Django App ------------------------------- After setting up your environment, you're ready to add your first app. This project uses the setup from "Two Scoops of Django" with a two-tier layout: - **Top Level Repository Root** has config files, documentation, `manage.py`, and more. - **Second Level Django Project Root** is where your Django apps live. - **Second Level Configuration Root** holds settings and URL configurations. The project layout looks something like this: :: / ├── config/ │ ├── settings/ │ │ ├── __init__.py │ │ ├── base.py │ │ ├── local.py │ │ └── production.py │ ├── urls.py │ └── wsgi.py ├── / │ ├── / │ │ ├── migrations/ │ │ ├── admin.py │ │ ├── apps.py │ │ ├── models.py │ │ ├── tests.py │ │ └── views.py │ ├── __init__.py │ └── ... ├── requirements/ │ ├── base.txt │ ├── local.txt │ └── production.txt ├── manage.py ├── README.md └── ... Following this structured approach, here's how to add a new app: #. **Create the app** using Django's ``startapp`` command, replacing ```` with your desired app name: :: uv run python manage.py startapp #. **Move the app** to the Django Project Root, maintaining the project's two-tier structure: :: mv / #. **Edit the app's apps.py** change ``name = ''`` to ``name = '.'``. #. **Register the new app** by adding it to the ``LOCAL_APPS`` list in ``config/settings/base.py``, integrating it as an official component of your project. Setup Email Backend ------------------- Mailpit ~~~~~~~ .. note:: In order for the project to support Mailpit_ it must have been bootstrapped with ``use_mailpit`` set to ``y``. Mailpit is used to receive emails during development, it is written in Go and has no external dependencies. For instance, one of the packages we depend upon, ``django-allauth`` sends verification emails to new users signing up as well as to the existing ones who have not yet verified themselves. #. `Download the latest Mailpit release`_ for your OS. #. Copy the binary file to the project root. #. Make it executable: :: chmod +x mailpit #. Spin up another terminal window and start it there: :: ./mailpit #. Check out ``_ to see how it goes. Now you have your own mail server running locally, ready to receive whatever you send it. .. _`Download the latest Mailpit release`: https://github.com/axllent/mailpit Console ~~~~~~~ .. note:: If you have generated your project with ``use_mailpit`` set to ``n`` this will be a default setup. Alternatively, deliver emails over console via ``EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'``. In production, we have Mailgun_ configured to have your back! .. _Mailgun: https://www.mailgun.com/ Celery ------ If the project is configured to use Celery as a task scheduler then, by default, tasks are set to run on the main thread when developing locally instead of getting sent to a broker. However, if you have Redis setup on your local machine, you can set the following in ``config/settings/local.py``:: CELERY_TASK_ALWAYS_EAGER = False Next, make sure `redis-server` is installed (per the `Getting started with Redis`_ guide) and run the server in one terminal:: redis-server Start the Celery worker by running the following command in another terminal:: uv run celery -A config.celery_app worker --loglevel=info That Celery worker should be running whenever your app is running, typically as a background process, so that it can pick up any tasks that get queued. Learn more from the `Celery Workers Guide`_. The project comes with a simple task for manual testing purposes, inside `/users/tasks.py`. To queue that task locally, start the Django shell, import the task, and call `delay()` on it:: uv run python manage.py shell >> from .users.tasks import get_users_count >> get_users_count.delay() You can also use Django admin to queue up tasks, thanks to the `django-celerybeat`_ package. .. _Getting started with Redis: https://redis.io/docs/latest/get-started/ .. _Celery Workers Guide: https://docs.celeryq.dev/en/stable/userguide/workers.html .. _django-celerybeat: https://django-celery-beat.readthedocs.io/en/latest/ .. _bare-metal-webpack-gulp: Using Webpack or Gulp --------------------- If you've opted for Gulp or Webpack as front-end pipeline, the project comes configured with `Sass`_ compilation and `live reloading`_. As you change your Sass/JS source files, the task runner will automatically rebuild the corresponding CSS and JS assets and reload them in your browser without refreshing the page. #. Make sure that `Node.js`_ v18 is installed on your machine. #. In the project root, install the JS dependencies with:: npm install #. Now - with your virtualenv activated - start the application by running:: npm run dev This will start 2 processes in parallel: the static assets build loop on one side, and the Django server on the other. #. Access your application at the address of the ``node`` service in order to see your correct styles. This is http://localhost:3000 by default. .. note:: Do NOT access the application using the Django port (8000 by default), as it will result in broken styles and 404s when accessing static assets. .. _Node.js: http://nodejs.org/download/ .. _Sass: https://sass-lang.com/ .. _live reloading: https://browsersync.io Summary ------- Congratulations, you have made it! Keep on reading to unleash full potential of Cookiecutter Django. ================================================ FILE: docs/2-local-development/generate-project-block.rst ================================================ Generate a new cookiecutter-django project: :: $ cookiecutter gh:cookiecutter/cookiecutter-django For more information refer to :ref:`Project Generation Options `. ================================================ FILE: docs/3-deployment/deployment-on-heroku.rst ================================================ Deployment on Heroku ==================== .. index:: Heroku Script ------ Run these commands to deploy the project to Heroku: .. code-block:: bash heroku create --buildpack heroku/python # Note: this is not a free plan heroku addons:create heroku-postgresql:essential-0 # On Windows use double quotes for the time zone, e.g. # heroku pg:backups schedule --at "02:00 America/Los_Angeles" DATABASE_URL heroku pg:backups schedule --at '02:00 America/Los_Angeles' DATABASE_URL heroku pg:promote DATABASE_URL heroku addons:create heroku-redis:mini # Assuming you chose Mailgun as mail service (see below for others) heroku addons:create mailgun:starter heroku config:set DJANGO_DEBUG=False heroku config:set DJANGO_SETTINGS_MODULE=config.settings.production heroku config:set DJANGO_SECRET_KEY="$(openssl rand -base64 64)" # Generating a 32 character-long random string without any of the visually similar characters "IOl01": heroku config:set DJANGO_ADMIN_URL="$(openssl rand -base64 4096 | tr -dc 'A-HJ-NP-Za-km-z2-9' | head -c 32)/" # Set this to your Heroku app url, e.g. 'bionic-beaver-28392.herokuapp.com' heroku config:set DJANGO_ALLOWED_HOSTS= # Assign with AWS_ACCESS_KEY_ID heroku config:set DJANGO_AWS_ACCESS_KEY_ID= # Assign with AWS_SECRET_ACCESS_KEY heroku config:set DJANGO_AWS_SECRET_ACCESS_KEY= # Assign with AWS_STORAGE_BUCKET_NAME heroku config:set DJANGO_AWS_STORAGE_BUCKET_NAME= git push heroku main heroku run python manage.py createsuperuser heroku run python manage.py check --deploy 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 `_ to know which environment variables to set. Heroku provides other `add-ons for emails `_ (e.g. Sendgrid) which can be configured with a similar one line command. .. warning:: .. include:: ../includes/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 ---------------- Celery ++++++ Celery requires a few extra environment variables to be ready operational. Also, the worker is created, it's in the ``Procfile``, but is turned off by default: .. code-block:: bash # Scale dyno to 1 instance heroku ps:scale worker=1 Sentry ++++++ If you're opted for Sentry error tracking, you can either install it through the `Sentry add-on`_: .. code-block:: bash heroku addons:create sentry:f1 Or add the DSN for your account, if you already have one: .. code-block:: bash heroku config:set SENTRY_DSN=https://xxxx@sentry.io/12345 .. _Sentry add-on: https://elements.heroku.com/addons/sentry Gulp or Webpack +++++++++++++++ If you've opted for Gulp or Webpack as frontend pipeline, you'll most likely need to setup your app to use `multiple buildpacks`_: one for Python & one for Node.js: .. code-block:: bash heroku buildpacks:add --index 1 heroku/nodejs At time of writing, this should do the trick: during deployment, the Heroku should run ``npm install`` and then ``npm build``, which run the SASS compilation & JS bundling. If things don't work, please refer to the Heroku docs. .. _multiple buildpacks: https://devcenter.heroku.com/articles/managing-buildpacks ================================================ FILE: docs/3-deployment/deployment-on-pythonanywhere.rst ================================================ Deployment on PythonAnywhere ============================ .. index:: PythonAnywhere Overview -------- Full instructions follow, but here's a high-level view. **First time config**: 1. Pull your code down to PythonAnywhere using a *Bash console* and install your dependencies 2. Set your config variables in the *postactivate* script 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* 5. Set your config variables in the PythonAnywhere *WSGI config file* 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 -------------------------------------------------------------- Make sure your project is fully committed and pushed up to Github, GitLab or wherever it may be. Then, log into your PythonAnywhere account, open up a **Bash** console, clone your repo, and install your project: .. code-block:: bash git clone cd my-project-name uv sync --locked --no-dev # may take a few minutes Setting environment variables ----------------------------- Generate a secret key for yourself, e.g. like this: .. code-block:: bash uv run python -c 'import secrets;import string; print("".join(secrets.choice(string.digits + string.ascii_letters + string.punctuation) for _ in range(50)))' Make a note of it, since we'll need it here in the console and later on in the web app config tab. Set environment variables via the ``.env`` file: .. code-block:: bash vi .env .. note:: If you don't like vi, you can also edit this file via the PythonAnywhere "Files" menu. Add these env variables: .. code-block:: bash WEB_CONCURRENCY=4 DJANGO_SETTINGS_MODULE='config.settings.production' DJANGO_SECRET_KEY='' DJANGO_ALLOWED_HOSTS='' DJANGO_ADMIN_URL='' MAILGUN_API_KEY='' MAILGUN_DOMAIN='' DJANGO_AWS_ACCESS_KEY_ID= DJANGO_AWS_SECRET_ACCESS_KEY= DJANGO_AWS_STORAGE_BUCKET_NAME= DATABASE_URL='' REDIS_URL='' .. 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 -------------- Go to the PythonAnywhere **Databases tab** and configure your database. Using Postgres, setup your superuser password, then open a Postgres console and run a ``CREATE DATABASE my-db-name``. You should probably also set up a specific role and permissions for your app, rather than using the superuser credentials. Make a note of the address and port of your postgres server. Now go back to the ``.env`` file and set the ``DATABASE_URL`` environment variable: .. code-block:: bash DATABASE_URL='postgres://:@:/' Now run the migration, and collectstatic: .. code-block:: bash export UV_ENV_FILE=.env export UV_NO_DEV=1 uv run python manage.py migrate uv run python manage.py compress # optional, if using django-compressor uv run python manage.py collectstatic # and, optionally uv run python manage.py createsuperuser Redis ----- PythonAnywhere does NOT `offer a built-in solution `_ 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 `_) 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 Python 3.13. .. 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**, which should be something like ``/home///.venv``. Click through to the **WSGI configuration file** link (near the top) and edit the wsgi file. Make it look something like this, repeating the environment variables you used earlier: .. code-block:: python import os import sys PROJECT_PATH = '/home//' if PROJECT_PATH not in sys.path: sys.path.append(PROJECT_PATH) os.environ['DJANGO_SETTINGS_MODULE='] = 'config.settings.production' os.environ['DJANGO_READ_DOT_ENV_FILE'] = '1' from django.core.wsgi import get_wsgi_application application = get_wsgi_application() 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 `these instructions `_ 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 `in this article `_. Future deployments ------------------ For subsequent deployments, the procedure is much simpler. In a Bash console: .. code-block:: bash cd project-directory git pull uv run python manage.py migrate uv run python manage.py compress # optional, if using django-compressor uv run python manage.py collectstatic And then go to the Web tab and hit **Reload** .. note:: If you're really keen, you can set up git-push based deployments: https://blog.pythonanywhere.com/87/ ================================================ FILE: docs/3-deployment/deployment-with-docker.rst ================================================ Deployment with Docker ====================== .. index:: deployment, docker, docker compose, compose Prerequisites ------------- * Docker 17.05+. * Docker Compose 1.17+ Understanding the Docker Compose Setup -------------------------------------- Before you begin, check out the ``docker-compose.production.yml`` file in the root of this project. Keep note of how it provides configuration for the following services: * ``django``: your application running behind ``Gunicorn``; * ``postgres``: PostgreSQL database with the application's relational data; * ``redis``: Redis instance for caching; * ``traefik``: Traefik reverse proxy with HTTPS on by default. Provided you have opted for Celery (via setting ``use_celery`` to ``y``) there are three more services: * ``celeryworker`` running a Celery worker process; * ``celerybeat`` running a Celery beat process; * ``flower`` running Flower_. The ``flower`` service is served by Traefik over HTTPS, through the port ``5555``. For more information about Flower and its login credentials, check out :ref:`CeleryFlower` instructions for local environment. .. _`Flower`: https://github.com/mher/flower Configuring the Stack --------------------- The majority of services above are configured through the use of environment variables. Just check out :ref:`envs` and you will know the drill. To obtain logs and information about crashes in a production setup, make sure that you have access to an external Sentry instance (e.g. by creating an account with `sentry.io`_), and set the ``SENTRY_DSN`` variable. Logs of level `logging.ERROR` are sent as Sentry events. Therefore, in order to send a Sentry event use: .. code-block:: python import logging logging.error("This event is sent to Sentry", extra={"": ""}) The `extra` parameter allows you to send additional information about the context of this error. You will probably also need to setup the Mail backend, for example by adding a `Mailgun`_ API key and a `Mailgun`_ sender domain, otherwise, the account creation view will crash and result in a 500 error when the backend attempts to send an email to the account owner. .. _sentry.io: https://sentry.io/welcome .. _Mailgun: https://mailgun.com .. warning:: .. include:: ../includes/mailgun.rst Optional: Use AWS IAM Role for EC2 instance ------------------------------------------- If you are deploying to AWS, you can use the IAM role to substitute AWS credentials, after which it's safe to remove the ``AWS_ACCESS_KEY_ID`` AND ``AWS_SECRET_ACCESS_KEY`` from ``.envs/.production/.django``. To do it, create an `IAM role`_ and `attach`_ it to the existing EC2 instance or create a new EC2 instance with that role. The role should assume, at minimum, the ``AmazonS3FullAccess`` permission. .. _IAM role: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html .. _attach: https://aws.amazon.com/blogs/security/easily-replace-or-attach-an-iam-role-to-an-existing-ec2-instance-by-using-the-ec2-console/ HTTPS is On by Default ---------------------- SSL (Secure Sockets Layer) is a standard security technology for establishing an encrypted link between a server and a client, typically in this case, a web server (website) and a browser. Not having HTTPS means that malicious network users can sniff authentication credentials between your website and end users' browser. It is always better to deploy a site behind HTTPS and will become crucial as the web services extend to the IoT (Internet of Things). For this reason, we have set up a number of security defaults to help make your website secure: * If you are not using a subdomain of the domain name set in the project, then remember to put your staging/production IP address in the ``DJANGO_ALLOWED_HOSTS`` environment variable (see :ref:`settings`) before you deploy your website. Failure to do this will mean you will not have access to your website through the HTTP protocol. * Access to the Django admin is set up by default to require HTTPS in production or once *live*. The Traefik reverse proxy used in the default configuration will get you a valid certificate from Lets Encrypt and update it automatically. All you need to do to enable this is to make sure that your DNS records are pointing to the server Traefik runs on. You can read more about this feature and how to configure it, at `Automatic HTTPS`_ in the Traefik docs. .. _Automatic HTTPS: https://docs.traefik.io/https/acme/ .. _webpack-whitenoise-limitation: Webpack without Whitenoise limitation ------------------------------------- If you opt for Webpack without Whitenoise, Webpack needs to know the static URL at build time, when running ``docker compose build`` (See ``webpack/prod.config.js``). Depending on your setup, this URL may come from the following environment variables: - ``AWS_STORAGE_BUCKET_NAME`` - ``DJANGO_AWS_S3_CUSTOM_DOMAIN`` - ``DJANGO_GCP_STORAGE_BUCKET_NAME`` - ``DJANGO_AZURE_CONTAINER_NAME`` The Django settings are getting these values at runtime via the ``.envs/.production/.django`` file , but Docker does not read this file at build time, it only look for a ``.env`` in the root of the project. Failing to pass the values correctly will result in a page without CSS styles nor javascript. To solve this, you can either: 1. merge all the env files into ``.env`` by running:: merge_production_dotenvs_in_dotenv.py 2. create a ``.env`` file in the root of the project with just variables you need. You'll need to also define them in ``.envs/.production/.django`` (hence duplicating them). 3. set these variables when running the build command:: DJANGO_AWS_S3_CUSTOM_DOMAIN=example.com docker compose -f docker-compose.production.yml build``. None of these options are ideal, we're open to suggestions on how to improve this. If you think you have one, please open an issue or a pull request. (Optional) Postgres Data Volume Modifications --------------------------------------------- Postgres is saving its database files to the ``production_postgres_data`` volume by default. Change that if you want something else and make sure to make backups since this is not done automatically. Building & Running Production Stack ----------------------------------- You will need to build the stack first. To do that, run:: docker compose -f docker-compose.production.yml build Once this is ready, you can run it with:: docker compose -f docker-compose.production.yml up To run the stack and detach the containers, run:: docker compose -f docker-compose.production.yml up -d To run a migration, open up a second terminal and run:: docker compose -f docker-compose.production.yml run --rm django python manage.py migrate To create a superuser, run:: docker compose -f docker-compose.production.yml run --rm django python manage.py createsuperuser If you need a shell, run:: docker compose -f docker-compose.production.yml run --rm django python manage.py shell To check the logs out, run:: docker compose -f docker-compose.production.yml logs If you want to scale your application, run:: docker compose -f docker-compose.production.yml up --scale django=4 docker compose -f docker-compose.production.yml up --scale celeryworker=2 .. warning:: don't try to scale ``postgres``, ``celerybeat``, or ``traefik``. To see how your containers are doing run:: docker compose -f docker-compose.production.yml ps Example: Supervisor ------------------- Once you are ready with your initial setup, you want to make sure that your application is run by a process manager to survive reboots and auto restarts in case of an error. You can use the process manager you are most familiar with. All it needs to do is to run ``docker compose -f docker-compose.production.yml up`` in your projects root directory. If you are using ``supervisor``, you can use this file as a starting point:: [program:{{cookiecutter.project_slug}}] command=docker compose -f docker-compose.production.yml up directory=/path/to/{{cookiecutter.project_slug}} redirect_stderr=true autostart=true autorestart=true priority=10 Move it to ``/etc/supervisor/conf.d/{{cookiecutter.project_slug}}.conf`` and run:: supervisorctl reread supervisorctl update supervisorctl start {{cookiecutter.project_slug}} For status check, run:: supervisorctl status Media files without cloud provider ---------------------------------- If you chose no cloud provider and Docker, the media files will be served by an nginx service, from a ``production_django_media`` volume. Make sure to keep this around to avoid losing any media files. ================================================ FILE: docs/4-guides/docker-postgres-backups.rst ================================================ PostgreSQL Backups with Docker ============================== .. note:: For brevity it is assumed that you will be running the below commands against local environment, however, this is by no means mandatory so feel free to switch to ``docker-compose.production.yml`` when needed. Prerequisites ------------- #. the project was generated with ``use_docker`` set to ``y``; #. the stack is up and running: ``docker compose -f docker-compose.local.yml up -d postgres``. Creating a Backup ----------------- To create a backup, run:: $ docker compose -f docker-compose.local.yml exec postgres backup Assuming your project's database is named ``my_project`` here is what you will see: :: Backing up the 'my_project' database... SUCCESS: 'my_project' database backup 'backup_2018_03_13T09_05_07.sql.gz' has been created and placed in '/backups'. Keep in mind that ``/backups`` is the ``postgres`` container directory. Viewing the Existing Backups ---------------------------- To list existing backups, :: $ docker compose -f docker-compose.local.yml exec postgres backups These are the sample contents of ``/backups``: :: These are the backups you have got: total 24K -rw-r--r-- 1 root root 5.2K Mar 13 09:05 backup_2018_03_13T09_05_07.sql.gz -rw-r--r-- 1 root root 5.2K Mar 12 21:13 backup_2018_03_12T21_13_03.sql.gz -rw-r--r-- 1 root root 5.2K Mar 12 21:12 backup_2018_03_12T21_12_58.sql.gz Copying Backups Locally ----------------------- If you want to copy backups from your ``postgres`` container locally, ``docker cp`` command_ will help you on that. For example, given ``9c5c3f055843`` is the container ID copying all the backups over to a local directory is as simple as :: $ docker cp 9c5c3f055843:/backups ./backups With a single backup file copied to ``.`` that would be :: $ docker cp 9c5c3f055843:/backups/backup_2018_03_13T09_05_07.sql.gz . You can also get the container ID using ``docker compose -f docker-compose.local.yml ps -q postgres`` so if you want to automate your backups, you don't have to check the container ID manually every time. Here is the full command :: $ docker cp $(docker compose -f docker-compose.local.yml ps -q postgres):/backups ./backups .. _`command`: https://docs.docker.com/engine/reference/commandline/cp/ Restoring from the Existing Backup ---------------------------------- To restore from one of the backups you have already got (take the ``backup_2018_03_13T09_05_07.sql.gz`` for example), :: $ docker compose -f docker-compose.local.yml exec postgres restore backup_2018_03_13T09_05_07.sql.gz You will see something like :: Restoring the 'my_project' database from the '/backups/backup_2018_03_13T09_05_07.sql.gz' backup... INFO: Dropping the database... INFO: Creating a new database... INFO: Applying the backup to the new database... SET SET SET SET SET set_config ------------ (1 row) SET # ... ALTER TABLE SUCCESS: The 'my_project' database has been restored from the '/backups/backup_2018_03_13T09_05_07.sql.gz' backup. Backup to Amazon S3 ---------------------------------- For uploading your backups to Amazon S3 you can use the aws cli container. There is an upload command for uploading the postgres /backups directory recursively and there is a download command for downloading a specific backup. The default S3 environment variables are used. :: $ docker compose -f docker-compose.production.yml run --rm awscli upload $ docker compose -f docker-compose.production.yml run --rm awscli download backup_2018_03_13T09_05_07.sql.gz Remove Backup ---------------------------------- To remove backup you can use the ``rmbackup`` command. This will remove the backup from the ``/backups`` directory. :: $ docker compose -f docker-compose.local.yml exec postgres rmbackup backup_2018_03_13T09_05_07.sql.gz Upgrading PostgreSQL ---------------------------------- Upgrading PostgreSQL in your project requires a series of carefully executed steps. Start by halting all containers, excluding the postgres container. Following this, create a backup and proceed to remove the outdated data volume. :: $ docker compose -f docker-compose.local.yml down $ docker compose -f docker-compose.local.yml up -d postgres $ docker compose -f docker-compose.local.yml run --rm postgres backup $ docker compose -f docker-compose.local.yml down $ docker volume rm my_project_postgres_data .. note:: Neglecting to remove the old data volume may lead to issues, such as the new postgres container failing to start with errors like ``FATAL: database files are incompatible with server``, and ``could not translate host name "postgres" to address: Name or service not known``. To complete the upgrade, update the PostgreSQL version in the corresponding Dockerfile (e.g. ``compose/production/postgres/Dockerfile``) and build a new version of PostgreSQL. :: $ docker compose -f docker-compose.local.yml build postgres $ docker compose -f docker-compose.local.yml up -d postgres $ docker compose -f docker-compose.local.yml run --rm postgres restore backup_2018_03_13T09_05_07.sql.gz $ docker compose -f docker-compose.local.yml up -d ================================================ FILE: docs/4-guides/document.rst ================================================ .. _document: Document ========= This project uses Sphinx_ documentation generator. After you have set up to `develop locally`_, run the following command from the project directory to build and serve HTML documentation: :: $ make -C docs livehtml If you set up your project to `develop locally with docker`_, run the following command: :: $ docker compose -f docker-compose.docs.yml up Navigate to port 9000 on your host to see the documentation. This will be opened automatically at `localhost`_ for local, non-docker development. Note: using Docker for documentation sets up a temporary SQLite file by setting the environment variable ``DATABASE_URL=sqlite:///readthedocs.db`` in ``docs/conf.py`` to avoid a dependency on PostgreSQL. Generate API documentation ---------------------------- Edit the ``docs`` files and project application docstrings to create your documentation. Sphinx can automatically include class and function signatures and docstrings in generated documentation. See the generated project documentation for more examples. Setting up ReadTheDocs ---------------------- To setup your documentation on `ReadTheDocs`_, you must 1. Go to `ReadTheDocs`_ and login/create an account 2. Add your GitHub repository 3. Trigger a build Additionally, you can auto-build Pull Request previews, but `you must enable it`_. .. _localhost: http://localhost:9000/ .. _Sphinx: https://www.sphinx-doc.org/en/master/index.html .. _develop locally: ../2-local-development/developing-locally.html .. _develop locally with docker: ../2-local-development/developing-locally-docker.html .. _ReadTheDocs: https://readthedocs.org/ .. _you must enable it: https://docs.readthedocs.com/platform/latest/pull-requests.html#features ================================================ FILE: docs/4-guides/linters.rst ================================================ Linters ======= .. index:: linters ruff ------ Ruff is a Python linter and code formatter, written in Rust. It is a aggregation of flake8, pylint, pyupgrade and many more. Ruff comes with a linter (``ruff check``) and a formatter (``ruff format``). The linter is a wrapper around flake8, pylint, and other linters, and the formatter is a wrapper around black, isort, and other formatters. To run ruff without modifying your files: :: $ ruff format --diff . $ ruff check . Ruff is capable of fixing most of the problems it encounters. Be sure you commit first before running `ruff` so you can restore to a savepoint (and amend afterwards to prevent a double commit. : :: $ ruff format . $ ruff check --fix . # be careful with the --unsafe-fixes option, it can break your code $ ruff check --fix --unsafe-fixes . The config for ruff is located in pyproject.toml. On of the most important option is `tool.ruff.lint.select`. `select` determines which linters are run. In example, `DJ `_ refers to flake8-django. For a full list of available linters, see `https://docs.astral.sh/ruff/rules/ `_ ================================================ FILE: docs/4-guides/testing.rst ================================================ .. _testing: Testing ======== We encourage users to build application tests. As best practice, this should be done immediately after documentation of the application being built, before starting on any coding. Pytest ------ This project uses the Pytest_, a framework for easily building simple and scalable tests. After you have set up to `develop locally`_, run the following commands to make sure the testing environment is ready: :: $ pytest You will get a readout of the `users` app that has already been set up with tests. If you do not want to run the `pytest` on the entire project, you can target a particular app by typing in its location: :: $ pytest If you set up your project to `develop locally with docker`_, run the following command: :: $ docker compose -f docker-compose.local.yml run --rm django pytest Targeting particular apps for testing in ``docker`` follows a similar pattern as previously shown above. Coverage -------- You should build your tests to provide the highest level of **code coverage**. You can run the ``pytest`` with code ``coverage`` by typing in the following command: :: $ coverage run -m pytest Once the tests are complete, in order to see the code coverage, run the following command: :: $ coverage report If you're running the project locally with Docker, use these commands instead: :: $ docker compose -f docker-compose.local.yml run --rm django coverage run -m pytest $ docker compose -f docker-compose.local.yml run --rm django coverage report .. note:: At the root of the project folder, you will find the `pytest.ini` file. You can use this to customize_ the ``pytest`` to your liking. The configuration for ``coverage`` can be found in ``pyproject.toml``. You can find out more about `configuring`_ ``coverage``. .. seealso:: For unit tests, run: :: $ python manage.py test Since this is a fresh install, and there are no tests built using the Python `unittest`_ library yet, you should get feedback that says there were no tests carried out. .. _Pytest: https://docs.pytest.org/en/latest/example/simple.html .. _develop locally: ./developing-locally.html .. _develop locally with docker: ./developing-locally-docker.html .. _customize: https://docs.pytest.org/en/latest/customize.html .. _unittest: https://docs.python.org/3/library/unittest.html#module-unittest .. _configuring: https://coverage.readthedocs.io/en/latest/config.html ================================================ FILE: docs/4-guides/websocket.rst ================================================ .. _websocket: ========= Websocket ========= You can enable web sockets if you select ``use_async`` option when creating a project. That indicates whether the project can use web sockets with Uvicorn + Gunicorn. Usage ----- JavaScript example: :: > ws = new WebSocket('ws://localhost:8000/') // or 'wss:///' in prod WebSocket {url: "ws://localhost:8000/", readyState: 0, bufferedAmount: 0, onopen: null, onerror: null, …} > ws.onmessage = event => console.log(event.data) event => console.log(event.data) > ws.send("ping") undefined pong! If you don't use Traefik, you might have to configure your reverse proxy accordingly (example with Nginx_). .. _Nginx: https://www.nginx.com/blog/websocket-nginx/ ================================================ FILE: docs/5-help/faq.rst ================================================ FAQ === .. index:: FAQ, 12-Factor App Why is there a django.contrib.sites directory in Cookiecutter Django? --------------------------------------------------------------------- It is there to add a migration so you don't have to manually change the ``sites.Site`` record from ``example.com`` to whatever your domain is. Instead, your ``{{cookiecutter.domain_name}}`` and ``{{cookiecutter.project_name}}`` value is placed by **Cookiecutter** in the domain and name fields respectively. See `0003_set_site_domain_and_name.py`_. .. _`0003_set_site_domain_and_name.py`: https://github.com/cookiecutter/cookiecutter-django/blob/main/%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) ---------------------------------------------------------------------- TODO .. TODO Why doesn't this follow the layout from Two Scoops of Django? ------------------------------------------------------------- You may notice that some elements of this project do not exactly match what we describe in chapter 3 of `Two Scoops of Django 3.x`_. 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. .. _Two Scoops of Django 3.x: https://www.feldroy.com/two-scoops-of-django ================================================ FILE: docs/5-help/troubleshooting.rst ================================================ Troubleshooting =============== This page contains some advice about errors and problems commonly encountered during the development of Cookiecutter Django applications. Server Error on sign-up/log-in ------------------------------ Make sure you have configured the mail backend (e.g. Mailgun) by adding the API key and sender domain .. include:: ../includes/mailgun.rst .. _docker-postgres-auth-failed: Docker: Postgres authentication failed -------------------------------------- Examples of logs:: postgres_1 | 2018-06-07 19:11:23.963 UTC [81] FATAL: password authentication failed for user "pydanny" postgres_1 | 2018-06-07 19:11:23.963 UTC [81] DETAIL: Password does not match for user "pydanny". postgres_1 | Connection matched pg_hba.conf line 95: "host all all all md5" If you recreate the project multiple times with the same name, Docker would preserve the volumes for the postgres container between projects. Here is what happens: #. You generate the project the first time. The .env postgres file is populated with the random password #. You run the docker compose and the containers are created. The postgres container creates the database based on the .env file credentials #. You "regenerate" the project with the same name, so the postgres .env file is populated with a new random password #. You run docker compose. Since the names of the containers are the same, docker will try to start them (not create them from scratch i.e. it won't execute the Dockerfile to recreate the database). When this happens, it tries to start the database based on the new credentials which do not match the ones that the database was created with, and you get the error message above. To fix this, you can either: - Clear your project-related Docker cache with ``docker compose -f docker-compose.local.yml down --volumes --rmi all``. - Use the Docker volume sub-commands to find volumes (`ls`_) and remove them (`rm`_). - Use the `prune`_ command to clear system-wide (use with care!). .. _ls: https://docs.docker.com/engine/reference/commandline/volume_ls/ .. _rm: https://docs.docker.com/engine/reference/commandline/volume_rm/ .. _prune: https://docs.docker.com/v17.09/engine/reference/commandline/system_prune/ Variable is not set. Defaulting to a blank string ------------------------------------------------- Example:: WARN[0000] The "DJANGO_AWS_STORAGE_BUCKET_NAME" variable is not set. Defaulting to a blank string. WARN[0000] The "DJANGO_AWS_S3_CUSTOM_DOMAIN" variable is not set. Defaulting to a blank string. You have probably opted for Docker + Webpack without Whitenoise. This is a know limitation of the combination, which needs a little bit of manual intervention. See the :ref:`dedicated section about it `. Others ------ #. ``project_slug`` must be a valid Python module name or you will have issues on imports. #. ``jinja2.exceptions.TemplateSyntaxError: Encountered unknown tag 'now'.``: please upgrade your cookiecutter version to >= 1.4 (see `#528`_) #. 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/cookiecutter/cookiecutter-django/issues/528#issuecomment-212650373 .. _#1725: https://github.com/cookiecutter/cookiecutter-django/issues/1725#issuecomment-407493176 ================================================ FILE: docs/6-about/contributing.md ================================================ ```{include} ../../CONTRIBUTING.md ``` ================================================ FILE: docs/6-about/generative-ai.md ================================================ # Generative AI You are encouraged to use all the tools you want to do your work and contribute as efficiently as possible, this includes AI (LLM) tools, etc. Nevertheless, contributions should have meaningful human intervention, judgement, context, etc. Generative AI tools have evolved rapidly, and their suggested results can be helpful. As with using any tool, the resulting contribution is the responsibility of the contributor. We value good code, concise accurate documentation, and avoiding unneeded code churn. Discretion, good judgment, and critical thinking are the foundation of all good contributions, regardless of the tools used in their creation. ## Acceptable uses Some of the acceptable uses of generative AI include: - Assistance with writing comments, especially in a non-native language. - Gaining understanding of existing code. - Supplementing contributor knowledge for code, tests, and documentation. ## Unacceptable uses Maintainers may close issues and PRs that are not useful or productive, including those that are fully generated by AI. If a contributor repeatedly opens unproductive issues or PRs, they may be blocked. The same applies to comments and descriptions, please don't copy paste the content generated by an LLM. A good rule of thumb is that if you can't make yourself carefully read some LLM output that you generated, nobody else wants to read it either. ## Human Effort Denial of Service Using automated tools and AI to submit PRs or comments that we have to carefully review and handle would be the equivalent of a [Denial-of-service attack](https://en.wikipedia.org/wiki/Denial-of-service_attack) on our human effort. It would be very little effort from the person submitting the PR (an LLM prompt) that generates a large amount of effort on our side (carefully reviewing code). Please don't do that. We'll need to block accounts that spam us with repeated automated PRs or comments. ================================================ FILE: docs/6-about/maintainer-guide.md ================================================ # Maintainer guide This document is intended for maintainers of the template. ## Automated updates We use 2 separate services to keep our dependencies up-to-date: - Dependabot, which manages updates of Python deps of the template, GitHub actions, npm packages and Docker images. - PyUp, which manages the Python deps for the generated project. We don't use Dependabot for the generated project deps because our requirements files are templated, and Dependabot fails to parse them. PyUp is -AFAIK- the only service out there that supports having Jinja tags in the requirements file. Updates for the template should be labelled as `project infrastructure` while the ones about the generated project should be labelled as `update`. This is use to work in conjunction with our changelog script (see later). ## Automation scripts We have a few workflows which have been automated over time. They usually run using GitHub actions and might need a few small manual actions to work nicely. Some have a few limitations which we should document here. ### CI `ci.yml` The CI workflow tries to cover 2 main aspects of the template: - Check all combinations to make sure that valid files are generated with no major linting issues. Issues which are fixed by an auto-formatter after generation aren't considered major, and only aim for best effort. This is under the `test` job. - Run more in-depth tests on a few combinations, by installing dependencies, running type checker and the test suite of the generated project. We try to cover docker (`docker` job) and non-docker (`bare` job) setups. We also run the deployment checks, but we don't do much more beyond that for testing the production setup. ### Django issue checker `django-issue-checker.yml` This workflow runs daily, on schedule, and checks if there is a new major version of Django (not in the pure SemVer sense) released that we are not running, and list our dependencies compatibility. For example, at time of writing, we use Django 4.2, but the latest version of Django is 5.0, so the workflow created a ["Django 5.0" issue](https://github.com/cookiecutter/cookiecutter-django/issues/4724) in GitHub, with a compatibility table and keeps it up to date every day. #### Limitations Here are a few current and past limitations of the script - ~~When a new dependency is added to the template, the script fails to update an existing issue~~ - Not sure what happens when a deps is removed - ~~Unable to parse classifiers without minor version~~ - ~~Creates an issue even if we are on the latest version~~ ### Issue manager `issue-manager.yml` A workflow that uses [Sebastian Ramirez' issue-manager](https://github.com/tiangolo/issue-manager) to help us automate issue management. The tag line from the repo explains it well: > Automatically close issues or Pull Requests that have a label, after a custom delay, if no one replies back. It runs on a schedule as well as when some actions are taken on issues and pull requests. We wait 10 days before closing issues, and we have a few customised reasons, which are configured in the workflow itself. The config should be fairly self-explanatory. ### Pre-commit auto-update `pre-commit-autoupdate.yml` Run daily, to do `pre-commit autoupdate` on the template as well as the generated project, and opens a pull request with the changes. #### Limitations - The PR is open as GitHub action which means that CI does NOT run. The documentation for create-pull-request action [explains why](https://github.com/peter-evans/create-pull-request/blob/main/docs/concepts-guidelines.md#triggering-further-workflow-runs). - Some hooks are also installed as local dependencies (via `requirements/local.txt`), but these are updated separately via PyUP. ### Update changelog `update-changelog.yml` Run daily at 2AM to update our changelog and create a GitHub release. This runs a custom script which: - List all pull requests merged the day before - The release name is calendar based, so `YYYY.MM.DD` - For each PR: - Get the PR title to summarize the change - Look at the PR labels to classify it in a section of the release notes: - anything labelled `project infrastructure` is excluded - label `update` goes in section "Updated" - label `bug` goes in section "Fixed" - label `docs` goes in section "Documentation" - Default to section "Changed" With that in mind, when merging changes, it's a good idea to set the labels and rename the PR title to give a good summary of the change, in the context of the changelog. #### Limitations - Dependabot updates for npm & Docker have a verbose title, try to rename them to be more readable: `Bump webpack-dev-server from 4.15.1 to 5.0.2 in /{{cookiecutter.project_slug}}` -> `Bump webpack-dev-server to 5.0.2` - ~~Dependencies updates for the template repo (tox, cookiecutter, etc...) don't need to appear in changelog, and need to be labelled as `project infrastructure` manually. By default, they come from PyUp labelled as `update`.~~ ### Update contributors `update-contributors.yml` Runs on each push to main branch. List the 5 most recently merged pull requests and extract their author. If any of the authors is a new one, updates the `.github/contributors.json`, regenerate the `CONTRIBUTORS.md` from it, and push back the changes to master. #### Limitations - If you merge a pull request from a new contributor, and merge another one right after, the push to main will fail as the remote will be out of date. - If you merge more than 5 pull requests in a row like this, the new contributor might fail to be added. ================================================ FILE: docs/Makefile ================================================ # Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = uv run --group docs sphinx-build SOURCEDIR = . BUILDDIR = _build .PHONY: help clean livehtml linkcheck help: @echo "Please use \`make ' where is one of" @echo "html Build the docs as HTML" @awk '/^#/{c=substr($$0,3);next}c&&/^[[:alpha:]][[:alnum:]_-]+:/{print substr($$1,1,index($$1,":")),c}1{c=0}' $(MAKEFILE_LIST) | column -s: -t # Clean the build output clean: -rm -rf $(BUILDDIR)/* # Build and serve docs with live reload livehtml: sphinx-autobuild -b html --port 9000 --watch . -c . $(SOURCEDIR) $(BUILDDIR)/html # Check all external links for integrity linkcheck: $(SPHINXBUILD) -b linkcheck $(SPHINXOPTS) $(SOURCEDIR) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -c . ================================================ FILE: docs/__init__.py ================================================ # Included so that Django's startproject comment runs against the docs directory ================================================ FILE: docs/_static/.gitkeep ================================================ ================================================ FILE: docs/conf.py ================================================ # cookiecutter-django documentation build configuration file. # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. from datetime import datetime now = datetime.now() # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # sys.path.insert(0, os.path.abspath('.')) # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. # needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ["myst_parser"] # Add any paths that contain templates here, relative to this directory. templates_path = ["_templates"] # The suffix of source filenames. source_suffix = { ".rst": "restructuredtext", ".md": "markdown", } # The encoding of source files. # source_encoding = 'utf-8-sig' # The master toctree document. master_doc = "index" # General information about the project. project = "Cookiecutter Django" copyright = f"2013-{now.year}, Daniel Roy Greenfeld" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = "{}.{}.{}".format(*now.isocalendar()) # The full version, including alpha/beta/rc tags. release = "{}.{}.{}".format(*now.isocalendar()) # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: # today = '' # Else, today_fmt is used as the format for a strftime call. # today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ["_build"] # The reST default role (used for this markup: `text`) to use for all documents. # default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. # add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). # add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. # show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = "sphinx" # A list of ignored prefixes for module index sorting. # modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. 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 # documentation. # html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. # html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". # html_title = None # A shorter title for the navigation bar. Default is the same as html_title. # html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. # html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. # html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ["_static"] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. # html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. # html_use_smartypants = True # Custom sidebar templates, maps document names to template names. # html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. # html_additional_pages = {} # If false, no module index is generated. # html_domain_indices = True # If false, no index is generated. # html_use_index = True # If true, the index is split into individual pages for each letter. # html_split_index = False # If true, links to the reST sources are added to the pages. # html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. # html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. # html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. # html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). # html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = "cookiecutter-djangodoc" # -- Options for LaTeX output -------------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). # 'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). # 'pointsize': '10pt', # Additional stuff for the LaTeX preamble. # 'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ( "index", "cookiecutter-django.tex", "cookiecutter-django Documentation", "cookiecutter-django", "manual", ), ] # The name of an image file (relative to this directory) to place at the top of # the title page. # latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. # latex_use_parts = False # If true, show page references after internal links. # latex_show_pagerefs = False # If true, show URL addresses after external links. # latex_show_urls = False # Documents to append as an appendix to all manuals. # latex_appendices = [] # If false, no module index is generated. # latex_domain_indices = True # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ( "index", "Cookiecutter Django", "Cookiecutter Django documentation", ["Daniel Roy Greenfeld"], 1, ), ] # If true, show URL addresses after external links. # man_show_urls = False # -- Options for Texinfo output ------------------------------------------------ # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ( "index", "Cookiecutter Django", "Cookiecutter Django documentation", "Daniel Roy Greenfeld", "Cookiecutter Django", "A Cookiecutter template for creating production-ready Django projects quickly.", "Miscellaneous", ) ] # Documents to append as an appendix to all manuals. # texinfo_appendices = [] # If false, no module index is generated. # texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. # texinfo_show_urls = 'footnote' ================================================ FILE: docs/includes/mailgun.rst ================================================ 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`_, which means it'll send a verification email when an unverified user tries to log-in or when someone tries to sign-up. This may happen just after you've setup your Mailgun account, which is running in a sandbox subdomain by default. Either add your email to the list of authorized recipients or verify your domain. .. _have emails verifications mandatory: https://docs.allauth.org/en/latest/account/configuration.html#email-verification ================================================ FILE: docs/index.rst ================================================ .. cookiecutter-django documentation master file. Welcome to Cookiecutter Django's documentation! =============================================== 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 ` to learn more about each of them. .. _cookiecutter: https://github.com/cookiecutter/cookiecutter .. toctree:: :maxdepth: 2 :caption: Getting Started 1-getting-started/project-generation-options 1-getting-started/settings .. toctree:: :maxdepth: 2 :caption: Local Development 2-local-development/developing-locally 2-local-development/developing-locally-docker .. toctree:: :maxdepth: 2 :caption: Deployment 3-deployment/deployment-on-pythonanywhere 3-deployment/deployment-on-heroku 3-deployment/deployment-with-docker .. toctree:: :maxdepth: 2 :caption: Guides 4-guides/docker-postgres-backups 4-guides/linters 4-guides/testing 4-guides/document 4-guides/websocket .. toctree:: :maxdepth: 2 :caption: Help 5-help/faq 5-help/troubleshooting .. toctree:: :maxdepth: 2 :caption: About 6-about/contributing 6-about/generative-ai 6-about/maintainer-guide Indices and tables ------------------ * :ref:`genindex` * :ref:`search` .. At some point it would be good to have a module index of the high level things we are doing. Then we can * :ref:`modindex` back in. ================================================ FILE: docs/make.bat ================================================ @ECHO OFF REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set SOURCEDIR=. set BUILDDIR=_build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% set I18NSPHINXOPTS=%SPHINXOPTS% . if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. clean to clean the build directory echo. html to make standalone HTML files echo. livehtml to build and serve docs with live reload echo. linkcheck to check all external links for integrity goto end ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% %SOURCEDIR% %BUILDDIR%/html if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/html. goto end ) if "%1" == "livehtml" ( sphinx-autobuild -b html --port 9000 --watch . -c . %SOURCEDIR% %BUILDDIR%/html %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html if errorlevel 1 exit /b 1 goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %SOURCEDIR% %BUILDDIR%/linkcheck if errorlevel 1 exit /b 1 echo. echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. goto end ) :end ================================================ FILE: hooks/__init__.py ================================================ ================================================ FILE: hooks/post_gen_project.py ================================================ # ruff: noqa: PLR0133 import json import os import random import shutil import string import subprocess import sys from pathlib import Path try: # Inspired by # https://github.com/django/django/blob/main/django/utils/crypto.py random = random.SystemRandom() using_sysrandom = True except NotImplementedError: using_sysrandom = False TERMINATOR = "\x1b[0m" WARNING = "\x1b[1;33m [WARNING]: " INFO = "\x1b[1;33m [INFO]: " HINT = "\x1b[3;33m" SUCCESS = "\x1b[1;32m [SUCCESS]: " DEBUG_VALUE = "debug" def remove_open_source_files(): file_names = ["CONTRIBUTORS.txt", "LICENSE"] for file_name in file_names: Path(file_name).unlink() def remove_gplv3_files(): file_names = ["COPYING"] for file_name in file_names: Path(file_name).unlink() def remove_custom_user_manager_files(): users_path = Path("{{cookiecutter.project_slug}}", "users") (users_path / "managers.py").unlink() (users_path / "tests" / "test_managers.py").unlink() def remove_pycharm_files(): idea_dir_path = Path(".idea") if idea_dir_path.exists(): shutil.rmtree(idea_dir_path) docs_dir_path = Path("docs", "pycharm") if docs_dir_path.exists(): shutil.rmtree(docs_dir_path) def remove_docker_files(): shutil.rmtree(".devcontainer") shutil.rmtree("compose") file_names = [ "docker-compose.local.yml", "docker-compose.production.yml", ".dockerignore", "justfile", ] for file_name in file_names: Path(file_name).unlink() if "{{ cookiecutter.editor }}" == "PyCharm": file_names = ["docker_compose_up_django.xml", "docker_compose_up_docs.xml"] for file_name in file_names: Path(".idea", "runConfigurations", file_name).unlink() def remove_nginx_docker_files(): shutil.rmtree(Path("compose", "production", "nginx")) def remove_utility_files(): shutil.rmtree("utility") def remove_heroku_files(): file_names = ["Procfile"] for file_name in file_names: if file_name == "requirements.txt" and "{{ cookiecutter.ci_tool }}".lower() == "travis": # Don't remove the file if we are using Travis CI but not using Heroku continue Path(file_name).unlink() shutil.rmtree("bin") def remove_sass_files(): shutil.rmtree(Path("{{cookiecutter.project_slug}}", "static", "sass")) def remove_gulp_files(): file_names = ["gulpfile.mjs"] for file_name in file_names: Path(file_name).unlink() def remove_webpack_files(): shutil.rmtree("webpack") remove_vendors_js() def remove_vendors_js(): vendors_js_path = Path("{{ cookiecutter.project_slug }}", "static", "js", "vendors.js") if vendors_js_path.exists(): vendors_js_path.unlink() def remove_project_css(): project_css_path = Path("{{ cookiecutter.project_slug }}", "static", "css", "project.css") if project_css_path.exists(): project_css_path.unlink() def remove_packagejson_file(): file_names = ["package.json"] for file_name in file_names: Path(file_name).unlink() def update_package_json(remove_dev_deps=None, remove_keys=None, scripts=None): remove_dev_deps = remove_dev_deps or [] remove_keys = remove_keys or [] scripts = scripts or {} package_json = Path("package.json") content = json.loads(package_json.read_text()) for package_name in remove_dev_deps: content["devDependencies"].pop(package_name) for key in remove_keys: content.pop(key) content["scripts"].update(scripts) updated_content = json.dumps(content, ensure_ascii=False, indent=2) + "\n" package_json.write_text(updated_content) def handle_js_runner(choice, use_docker, use_async): if choice == "Gulp": update_package_json( remove_dev_deps=[ "@babel/core", "@babel/preset-env", "babel-loader", "concurrently", "css-loader", "mini-css-extract-plugin", "postcss-loader", "postcss-preset-env", "sass-loader", "webpack", "webpack-bundle-tracker", "webpack-cli", "webpack-dev-server", "webpack-merge", ], remove_keys=["babel"], scripts={ "dev": "gulp", "build": "gulp build", }, ) remove_webpack_files() elif choice == "Webpack": scripts = { "dev": "webpack serve --config webpack/dev.config.js", "build": "webpack --config webpack/prod.config.js", } remove_dev_deps = [ "browser-sync", "cssnano", "gulp", "gulp-concat", "gulp-imagemin", "gulp-plumber", "gulp-postcss", "gulp-rename", "gulp-sass", "gulp-uglify-es", ] if not use_docker: dev_django_cmd = ( "uvicorn config.asgi:application --reload" if use_async else "python manage.py runserver_plus" ) scripts.update( { "dev": "concurrently npm:dev:*", "dev:webpack": "webpack serve --config webpack/dev.config.js", "dev:django": dev_django_cmd, }, ) else: remove_dev_deps.append("concurrently") update_package_json(remove_dev_deps=remove_dev_deps, scripts=scripts) remove_gulp_files() def remove_prettier_pre_commit(): remove_repo_from_pre_commit_config("mirrors-prettier") def remove_repo_from_pre_commit_config(repo_to_remove: str): pre_commit_config = Path(".pre-commit-config.yaml") content = pre_commit_config.read_text().splitlines(keepends=True) removing = False new_lines = [] for line in content: if removing and "- repo:" in line: removing = False if repo_to_remove in line: removing = True if not removing: new_lines.append(line) pre_commit_config.write_text("".join(new_lines)) def remove_celery_files(): file_paths = [ Path("config", "celery_app.py"), Path("{{ cookiecutter.project_slug }}", "users", "tasks.py"), Path("{{ cookiecutter.project_slug }}", "users", "tests", "test_tasks.py"), ] for file_path in file_paths: file_path.unlink() def remove_async_files(): file_paths = [ Path("config", "asgi.py"), Path("config", "websocket.py"), ] for file_path in file_paths: file_path.unlink() def remove_dottravisyml_file(): Path(".travis.yml").unlink() def remove_dotgitlabciyml_file(): Path(".gitlab-ci.yml").unlink() def remove_dotgithub_folder(): shutil.rmtree(".github") def remove_dotdrone_file(): Path(".drone.yml").unlink() def generate_random_string(length, using_digits=False, using_ascii_letters=False, using_punctuation=False): # noqa: FBT002 """ Example: opting out for 50 symbol-long, [a-z][A-Z][0-9] string would yield log_2((26+26+50)^50) ~= 334 bit strength. """ if not using_sysrandom: return None symbols = [] if using_digits: symbols += string.digits if using_ascii_letters: symbols += string.ascii_letters if using_punctuation: all_punctuation = set(string.punctuation) # These symbols can cause issues in environment variables unsuitable = {"'", '"', "\\", "$"} suitable = all_punctuation.difference(unsuitable) symbols += "".join(suitable) return "".join([random.choice(symbols) for _ in range(length)]) def set_flag(file_path: Path, flag, value=None, formatted=None, *args, **kwargs): if value is None: 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 " f"system. Please, make sure to manually {flag} later.", ) random_string = flag if formatted is not None: random_string = formatted.format(random_string) value = random_string with file_path.open("r+") as f: file_contents = f.read().replace(flag, value) f.seek(0) f.write(file_contents) f.truncate() return value def set_django_secret_key(file_path: Path): return set_flag( file_path, "!!!SET DJANGO_SECRET_KEY!!!", length=64, using_digits=True, using_ascii_letters=True, ) def set_django_admin_url(file_path: Path): return set_flag( file_path, "!!!SET DJANGO_ADMIN_URL!!!", formatted="{}/", length=32, using_digits=True, using_ascii_letters=True, ) def generate_random_user(): return generate_random_string(length=32, using_ascii_letters=True) def generate_postgres_user(debug=False): # noqa: FBT002 return DEBUG_VALUE if debug else generate_random_user() def set_postgres_user(file_path, value): return set_flag(file_path, "!!!SET POSTGRES_USER!!!", value=value) def set_postgres_password(file_path, value=None): return set_flag( file_path, "!!!SET POSTGRES_PASSWORD!!!", value=value, length=64, using_digits=True, using_ascii_letters=True, ) def set_celery_flower_user(file_path, value): return set_flag(file_path, "!!!SET CELERY_FLOWER_USER!!!", value=value) def set_celery_flower_password(file_path, value=None): return set_flag( file_path, "!!!SET CELERY_FLOWER_PASSWORD!!!", value=value, length=64, using_digits=True, using_ascii_letters=True, ) def append_to_gitignore_file(ignored_line): with Path(".gitignore").open("a") as gitignore_file: gitignore_file.write(ignored_line) gitignore_file.write("\n") def set_flags_in_envs(postgres_user, celery_flower_user, debug=False): # noqa: FBT002 local_django_envs_path = Path(".envs", ".local", ".django") production_django_envs_path = Path(".envs", ".production", ".django") local_postgres_envs_path = Path(".envs", ".local", ".postgres") production_postgres_envs_path = Path(".envs", ".production", ".postgres") set_django_secret_key(production_django_envs_path) set_django_admin_url(production_django_envs_path) set_postgres_user(local_postgres_envs_path, value=postgres_user) set_postgres_password(local_postgres_envs_path, value=DEBUG_VALUE if debug else None) set_postgres_user(production_postgres_envs_path, value=postgres_user) set_postgres_password(production_postgres_envs_path, value=DEBUG_VALUE if debug else None) set_celery_flower_user(local_django_envs_path, value=celery_flower_user) set_celery_flower_password(local_django_envs_path, value=DEBUG_VALUE if debug else None) set_celery_flower_user(production_django_envs_path, value=celery_flower_user) set_celery_flower_password(production_django_envs_path, value=DEBUG_VALUE if debug else None) def set_flags_in_settings_files(): set_django_secret_key(Path("config", "settings", "local.py")) set_django_secret_key(Path("config", "settings", "test.py")) def remove_envs_and_associated_files(): shutil.rmtree(".envs") Path("merge_production_dotenvs_in_dotenv.py").unlink() shutil.rmtree("tests") def remove_celery_compose_dirs(): shutil.rmtree(Path("compose", "local", "django", "celery")) shutil.rmtree(Path("compose", "production", "django", "celery")) def remove_node_dockerfile(): shutil.rmtree(Path("compose", "local", "node")) def remove_aws_dockerfile(): shutil.rmtree(Path("compose", "production", "aws")) def remove_drf_starter_files(): Path("config", "api_router.py").unlink() Path("{{cookiecutter.project_slug}}", "users", "api", "serializers.py").unlink() def remove_ninja_starter_files(): Path("config", "api.py").unlink() Path("{{cookiecutter.project_slug}}", "users", "api", "schema.py").unlink() def remove_rest_api_files(): remove_drf_starter_files() remove_ninja_starter_files() shutil.rmtree(Path("{{cookiecutter.project_slug}}", "users", "api")) shutil.rmtree(Path("{{cookiecutter.project_slug}}", "users", "tests", "api")) def main(): # noqa: C901, PLR0912, PLR0915 debug = "{{ cookiecutter.debug }}".lower() == "y" set_flags_in_envs( DEBUG_VALUE if debug else generate_random_user(), DEBUG_VALUE if debug else generate_random_user(), debug=debug, ) set_flags_in_settings_files() if "{{ cookiecutter.open_source_license }}" == "Not open source": remove_open_source_files() if "{{ cookiecutter.open_source_license}}" != "GPLv3": remove_gplv3_files() if "{{ cookiecutter.username_type }}" == "username": remove_custom_user_manager_files() if "{{ cookiecutter.editor }}" != "PyCharm": remove_pycharm_files() if "{{ cookiecutter.use_docker }}".lower() == "y": remove_utility_files() if "{{ cookiecutter.cloud_provider }}".lower() != "none": remove_nginx_docker_files() else: remove_docker_files() if "{{ cookiecutter.use_docker }}".lower() == "y" and "{{ cookiecutter.cloud_provider}}" != "AWS": remove_aws_dockerfile() if "{{ cookiecutter.use_heroku }}".lower() == "n": remove_heroku_files() if "{{ cookiecutter.use_docker }}".lower() == "n" and "{{ cookiecutter.use_heroku }}".lower() == "n": if "{{ cookiecutter.keep_local_envs_in_vcs }}".lower() == "y": print( INFO + ".env(s) are only utilized when Docker Compose and/or " "Heroku support is enabled. Keeping them as requested, but they may not be useful " "in your current setup." + TERMINATOR, ) else: remove_envs_and_associated_files() else: append_to_gitignore_file(".env") append_to_gitignore_file(".envs/*") if "{{ cookiecutter.keep_local_envs_in_vcs }}".lower() == "y": append_to_gitignore_file("!.envs/.local/") if "{{ cookiecutter.frontend_pipeline }}" in ["None", "Django Compressor"]: remove_gulp_files() remove_webpack_files() remove_sass_files() remove_packagejson_file() remove_prettier_pre_commit() if "{{ cookiecutter.use_docker }}".lower() == "y": remove_node_dockerfile() else: remove_project_css() handle_js_runner( "{{ cookiecutter.frontend_pipeline }}", use_docker=("{{ cookiecutter.use_docker }}".lower() == "y"), use_async=("{{ cookiecutter.use_async }}".lower() == "y"), ) if "{{ cookiecutter.cloud_provider }}" == "None" and "{{ cookiecutter.use_docker }}".lower() == "n": print( WARNING + "You chose to not use any cloud providers nor Docker, " "media files won't be served in production." + TERMINATOR, ) if "{{ cookiecutter.use_celery }}".lower() == "n": remove_celery_files() if "{{ cookiecutter.use_docker }}".lower() == "y": remove_celery_compose_dirs() if "{{ cookiecutter.ci_tool }}" != "Travis": remove_dottravisyml_file() if "{{ cookiecutter.ci_tool }}" != "Gitlab": remove_dotgitlabciyml_file() if "{{ cookiecutter.ci_tool }}" != "Github": remove_dotgithub_folder() if "{{ cookiecutter.ci_tool }}" != "Drone": remove_dotdrone_file() if "{{ cookiecutter.rest_api }}" == "DRF": remove_ninja_starter_files() elif "{{ cookiecutter.rest_api }}" == "Django Ninja": remove_drf_starter_files() else: remove_rest_api_files() if "{{ cookiecutter.use_async }}".lower() == "n": remove_async_files() setup_dependencies() print(SUCCESS + "Project initialized, keep up the good work!" + TERMINATOR) def setup_dependencies(): print("Installing python dependencies using uv...") if "{{ cookiecutter.use_docker }}".lower() == "y": # Build a trimmed down Docker image add dependencies with uv uv_docker_image_path = Path("compose/local/uv/Dockerfile") uv_image_tag = "cookiecutter-django-uv-runner:latest" try: subprocess.run( # noqa: S603 [ # noqa: S607 "docker", "build", "--load", "-t", uv_image_tag, "-f", str(uv_docker_image_path), "-q", ".", ], check=True, env={ **os.environ, "DOCKER_BUILDKIT": "1", }, ) except subprocess.CalledProcessError as e: print(f"Error building Docker image: {e}", file=sys.stderr) sys.exit(1) current_path = Path.cwd().absolute() # Use Docker to run the uv command uv_cmd = ["docker", "run", "--rm", "-v", f"{current_path}:/app", uv_image_tag, "uv"] else: # Use uv command directly uv_cmd = ["uv"] # Install production dependencies try: subprocess.run([*uv_cmd, "add", "--no-sync", "-r", "requirements/production.txt"], check=True) # noqa: S603 except subprocess.CalledProcessError as e: print(f"Error installing production dependencies: {e}", file=sys.stderr) sys.exit(1) # Install local (development) dependencies try: subprocess.run([*uv_cmd, "add", "--no-sync", "--dev", "-r", "requirements/local.txt"], check=True) # noqa: S603 except subprocess.CalledProcessError as e: print(f"Error installing local dependencies: {e}", file=sys.stderr) sys.exit(1) # Remove the requirements directory requirements_dir = Path("requirements") if requirements_dir.exists(): try: shutil.rmtree(requirements_dir) except Exception as e: # noqa: BLE001 print(f"Error removing 'requirements' folder: {e}", file=sys.stderr) sys.exit(1) uv_image_parent_dir_path = Path("compose/local/uv") if uv_image_parent_dir_path.exists(): shutil.rmtree(str(uv_image_parent_dir_path)) print("Setup complete!") if __name__ == "__main__": main() ================================================ FILE: hooks/pre_gen_project.py ================================================ # ruff: noqa: PLR0133 import sys TERMINATOR = "\x1b[0m" WARNING = "\x1b[1;33m [WARNING]: " INFO = "\x1b[1;33m [INFO]: " HINT = "\x1b[3;33m" SUCCESS = "\x1b[1;32m [SUCCESS]: " # The content of this string is evaluated by Jinja, and plays an important role. # It updates the cookiecutter context to trim leading and trailing spaces # from domain/email values """ {{ cookiecutter.update({ "domain_name": cookiecutter.domain_name | trim }) }} {{ cookiecutter.update({ "email": cookiecutter.email | trim }) }} """ project_slug = "{{ cookiecutter.project_slug }}" if hasattr(project_slug, "isidentifier"): assert project_slug.isidentifier(), f"'{project_slug}' project slug is not a valid Python identifier." assert project_slug == project_slug.lower(), f"'{project_slug}' project slug should be all lowercase" assert "\\" not in "{{ cookiecutter.author_name }}", "Don't include backslashes in author name." if "{{ cookiecutter.use_whitenoise }}".lower() == "n" and "{{ cookiecutter.cloud_provider }}" == "None": print("You should either use Whitenoise or select a Cloud Provider to serve static files") sys.exit(1) if "{{ cookiecutter.mail_service }}" == "Amazon SES" and "{{ cookiecutter.cloud_provider }}" != "AWS": print("You should either use AWS or select a different Mail Service for sending emails.") sys.exit(1) ================================================ FILE: pyproject.toml ================================================ [project] name = "cookiecutter-django" version = "2026.03.19" description = "A Cookiecutter template for creating production-ready Django projects quickly." readme = "README.md" keywords = [ "cookiecutter", "django", "project template", "scaffolding", "skeleton", ] license = { text = "BSD" } authors = [ { name = "Daniel Roy Greenfeld", email = "pydanny@gmail.com" }, ] requires-python = "==3.13.*" classifiers = [ "Development Status :: 4 - Beta", "Environment :: Console", "Framework :: Django :: 6.0", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Natural Language :: English", "Programming Language :: Python", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: Implementation :: CPython", "Topic :: Software Development", ] dependencies = [ "binaryornot==0.6.0", "cookiecutter==2.7.1", "django-upgrade==1.30.0", "djlint==1.36.4", "gitpython==3.1.46", "jinja2==3.1.6", "pre-commit==4.5.1", "pygithub==2.8.1", "pytest==9.0.2", "pytest-cookies==0.7", "pytest-instafail==0.5", "pytest-xdist==3.8.0", "pyyaml==6.0.3", "requests==2.32.5", "ruff==0.15.7", "sh==2.2.2; sys_platform!='win23'", "tox==4.50.3", "tox-uv>=1.17", ] urls = { Repository = "https://github.com/cookiecutter/cookiecutter-django" } [dependency-groups] docs = [ "myst-parser>=4", "sphinx>=8.0.2", "sphinx-autobuild>=2024.10.3", "sphinx-rtd-theme>=3", ] [tool.ruff] target-version = "py39" line-length = 119 # Exclude the template content as most files aren't parseable extend-exclude = [ "[{]{2}cookiecutter.project_slug[}]{2}/*", "docs/*", ] lint.select = [ "A", # "ANN", # flake8-annotations: we should support this in the future but many errors atm "ASYNC", "B", "BLE", "C4", "C90", "COM", "DTZ", "E", "EM", "ERA", "EXE", "F", "FA", "FBT", "FLY", "G", "I", "ICN", "INP", "INT", "ISC", "N", "PD", "PERF", "PGH", "PIE", "PL", "PT", # "ARG", # Unused function argument "PTH", "PYI", "Q", "RET", "RSE", # "FURB", # "LOG", "RUF", "S", "SIM", "SLF", "SLOT", "T10", "TC", "TID", "TRY", "UP", "W", "YTT", ] lint.ignore = [ "EM101", "RUF012", # Mutable class attributes should be annotated with `typing.ClassVar` "S101", # Use of assert detected https://docs.astral.sh/ruff/rules/assert/ "SIM102", # sometimes it's better to nest "TRY003", # Avoid specifying long messages outside the exception class ] lint.isort.force-single-line = true [tool.pyproject-fmt] keep_full_version = true # ==== pytest ==== [tool.pytest] minversion = "9.0" addopts = [ "-v", "--tb=short" ] norecursedirs = [ ".tox", ".git", "*/migrations/*", "*/static/*", "docs", "venv", "*/{{cookiecutter.project_slug}}/*", ] # ==== djLint ==== [tool.djlint] blank_line_after_tag = "load,extends" close_void_tags = true format_css = true format_js = true # TODO: remove T002 when fixed https://github.com/Riverside-Healthcare/djLint/issues/687 ignore = "H006,H030,H031,T002,T028" ignore_blocks = "raw" include = "H017,H035" indent = 2 max_line_length = 119 profile = "jinja" css.indent_size = 2 js.indent_size = 2 ================================================ FILE: scripts/__init__.py ================================================ ================================================ FILE: scripts/create_django_issue.py ================================================ """ 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 from typing import Any from typing import NamedTuple import requests from github import Github if TYPE_CHECKING: from collections.abc import Iterable 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)) @classmethod def parse_to_tuple(cls, version_str: str): version = cls.parse(version_str=version_str) return version.major, version.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) # noqa: S113 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( django_max_version: tuple[DjVersion] | None = None, ) -> 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. """ _django_max_version = (99, 99) if django_max_version: _django_max_version = django_max_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.lower(): 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 current_minor_version < django_version <= _django_max_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("{%") and not line.startswith(" #") and not line.startswith("#") 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: self.close_issue(issue) 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)) > 0: print(f"Found {package_name} at {index=}") _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" and "." in tokens[4]: # noqa: PLR2004 version = DjVersion.parse(tokens[4]) if len(version) == 2: # noqa: PLR2004 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"], "✅" 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.strip()} " f"| {compat_version.strip()} " 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}") @staticmethod def close_issue(issue: Issue): issue.edit(state="closed") print(f"Closed issue {issue.title} (ID: [{issue.id}]({issue.url}))") def generate(self): for version in self.needed_dj_versions: print(f"Handling GitHub issue for Django {version}") md_content = self.generate_markdown(version) print(f"Generated markdown:\n\n{md_content}") self.create_or_edit_issue(version, md_content) def main(django_max_version=None) -> None: # Check if there are any djs current_dj, latest_djs = get_all_latest_django_versions(django_max_version=django_max_version) # Run the setup, which might close old issues manager = GitHubManager(current_dj, latest_djs) manager.setup() if not latest_djs: print("No new Django versions to update. Exiting...") sys.exit(0) manager.generate() if __name__ == "__main__": if GITHUB_REPO is None: raise RuntimeError("No github repo, please set the environment variable GITHUB_REPOSITORY") max_version = None last_arg = sys.argv[-1] if CURRENT_FILE.name not in last_arg: max_version = DjVersion.parse_to_tuple(version_str=last_arg) main(django_max_version=max_version) ================================================ FILE: scripts/node_version.py ================================================ from __future__ import annotations import json from pathlib import Path ROOT = Path(__file__).parent.parent TEMPLATED_ROOT = ROOT / "{{cookiecutter.project_slug}}" DOCKERFILE = TEMPLATED_ROOT / "compose" / "local" / "node" / "Dockerfile" PROD_DOCKERFILE = TEMPLATED_ROOT / "compose" / "production" / "django" / "Dockerfile" PACKAGE_JSON = TEMPLATED_ROOT / "package.json" def main() -> None: new_version = get_version_from_dockerfile() old_version = get_version_from_package_json() if old_version != new_version: update_package_json_version(old_version, new_version) update_production_node_version(old_version, new_version) def get_version_from_dockerfile() -> str: # Extract version out of base image name: # FROM docker.io/node:22.13-bookworm-slim # -> 22.13 with DOCKERFILE.open("r") as f: for line in f: if "FROM docker.io/node:" in line: _, _, docker_tag = line.partition(":") version_str, _, _ = docker_tag.partition("-") return version_str raise RuntimeError("Could not find version in Dockerfile") def get_version_from_package_json() -> str: package_json = json.loads(PACKAGE_JSON.read_text()) return package_json["engines"]["node"] def update_package_json_version(old_version: str, new_version: str) -> None: package_json_text = PACKAGE_JSON.read_text() package_json_text = package_json_text.replace( f'"node": "{old_version}"', f'"node": "{new_version}"', ) PACKAGE_JSON.write_text(package_json_text) def update_production_node_version(old_version: str, new_version: str) -> None: dockerfile_content = PROD_DOCKERFILE.read_text() dockerfile_content = dockerfile_content.replace( f"FROM docker.io/node:{old_version}", f"FROM docker.io/node:{new_version}", ) PROD_DOCKERFILE.write_text(dockerfile_content) if __name__ == "__main__": main() ================================================ FILE: scripts/ruff_version.py ================================================ from __future__ import annotations import subprocess from pathlib import Path import tomllib ROOT = Path(__file__).parent.parent TEMPLATED_ROOT = ROOT / "{{cookiecutter.project_slug}}" REQUIREMENTS_LOCAL_TXT = TEMPLATED_ROOT / "requirements" / "local.txt" TEMPLATE_PRE_COMMIT_CONFIG = ROOT / ".pre-commit-config.yaml" PRE_COMMIT_CONFIG = TEMPLATED_ROOT / ".pre-commit-config.yaml" PYPROJECT_TOML = ROOT / "pyproject.toml" def main() -> None: new_version = get_requirements_txt_version() old_version = get_pyproject_toml_version() if old_version == new_version: return update_ruff_version(old_version, new_version) subprocess.run(["uv", "lock", "--no-upgrade"], cwd=ROOT, check=False) # noqa: S607 def get_requirements_txt_version() -> str: content = REQUIREMENTS_LOCAL_TXT.read_text() for line in content.split("\n"): if line.startswith("ruff"): return line.split(" ")[0].split("==")[1] raise RuntimeError("Could not find ruff version in requirements/local.txt") def get_pyproject_toml_version() -> str: data = tomllib.loads(PYPROJECT_TOML.read_text()) for dependency in data["project"]["dependencies"]: if dependency.startswith("ruff=="): return dependency.split("==")[1] raise RuntimeError("Could not find ruff version in pyproject.toml") def update_ruff_version(old_version: str, new_version: str) -> None: # Update pyproject.toml new_content = PYPROJECT_TOML.read_text().replace( f"ruff=={old_version}", f"ruff=={new_version}", ) PYPROJECT_TOML.write_text(new_content) # Update pre-commit configs for config_file in [PRE_COMMIT_CONFIG, TEMPLATE_PRE_COMMIT_CONFIG]: new_content = config_file.read_text().replace( f"repo: https://github.com/astral-sh/ruff-pre-commit\n rev: v{old_version}", f"repo: https://github.com/astral-sh/ruff-pre-commit\n rev: v{new_version}", ) config_file.write_text(new_content) if __name__ == "__main__": main() ================================================ FILE: scripts/update_changelog.py ================================================ import datetime as dt import os import re import subprocess from collections.abc import Iterable from pathlib import Path import git import github.PullRequest import github.Repository from github import Github from jinja2 import Template CURRENT_FILE = Path(__file__) ROOT = CURRENT_FILE.parents[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. """ # Generate changelog for PRs merged yesterday merged_date = dt.date.today() - dt.timedelta(days=1) # noqa: DTZ011 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 # Group pull requests by type of change grouped_pulls = group_pulls_by_change_type(merged_pulls) if not any(grouped_pulls.values()): print("Pull requests merged aren't worth a changelog mention.") return # Generate portion of markdown release_changes_summary = generate_md(grouped_pulls) print(f"Summary of changes: {release_changes_summary}") # Update CHANGELOG.md file 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 / "pyproject.toml" update_version(setup_py_path, release) print(f"Updated version in {setup_py_path}") # Run uv lock uv_lock_path = ROOT / "uv.lock" subprocess.run(["uv", "lock", "--no-upgrade"], cwd=ROOT, check=False) # noqa: S607 # Commit changes, create tag and push update_git_repo([changelog_path, setup_py_path, uv_lock_path], release) # Create GitHub release github_release = repo.create_git_release( tag=release, name=release, message=release_changes_summary, ) print(f"Created release on GitHub {github_release}") 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.""" recent_pulls = repo.get_pulls( state="closed", sort="updated", direction="desc", ).get_page(0) for pull in recent_pulls: if pull.merged and pull.merged_at.date() == merged_date: yield pull 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": [], "Fixed": [], "Documentation": [], "Updated": [], } for pull in pull_requests_list: label_names = {label.name for label in pull.labels} if "project infrastructure" in label_names: # Don't mention it in the changelog continue if "update" in label_names: group_name = "Updated" elif "bug" in label_names: group_name = "Fixed" elif "docs" in label_names: group_name = "Documentation" else: group_name = "Changed" grouped_pulls[group_name].append(pull) return 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(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( "", f"\n\n{content}", ) file_path.write_text(updated_content) def update_version(file_path: Path, release: str) -> None: """Update template version in pyproject.toml.""" 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() ================================================ FILE: scripts/update_contributors.py ================================================ import json import os from pathlib import Path from github import Github from github.NamedUser import NamedUser 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: """ Script entry point. 1. Fetch recent contributors from the Github API 2. Add missing ones to the JSON file 3. Generate Markdown from JSON file """ recent_authors = set(iter_recent_authors()) # Add missing users to the JSON file contrib_file = ContributorsJSONFile() for author in recent_authors: print(f"Checking if {author.login} should be added") if author.login not in contrib_file: contrib_file.add_contributor(author) print(f"Added {author.login} to contributors") contrib_file.save() # Generate MD file from JSON file write_md_file(contrib_file.content) def iter_recent_authors(): """ Fetch users who opened recently merged pull requests. Use GitHub API to fetch recent authors rather than git CLI to work with GitHub usernames. """ 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) for pull in recent_pulls: if pull.merged and pull.user.type == "User" and pull.user.login not in BOT_LOGINS: yield pull.user class ContributorsJSONFile: """Helper to interact with the JSON file.""" file_path = ROOT / ".github" / "contributors.json" content = None def __init__(self) -> None: """Read initial content.""" self.content = json.loads(self.file_path.read_text()) def __contains__(self, github_login: str): """Provide a nice API to do: `username in file`.""" return any( # Github usernames are case insensitive github_login.lower() == contrib["github_login"].lower() for contrib in self.content ) def add_contributor(self, user: NamedUser): """Append the contributor data we care about at the end.""" contributor_data = { "name": user.name or user.login, "github_login": user.login, "twitter_username": user.twitter_username or "", } self.content.append(contributor_data) def save(self): """Write the file to disk with indentation.""" text_content = json.dumps(self.content, indent=2, ensure_ascii=False) self.file_path.write_text(text_content) def write_md_file(contributors): """Generate markdown file from Jinja template.""" contributors_template = ROOT / ".github" / "CONTRIBUTORS-template.md" template = Template(contributors_template.read_text(), autoescape=True) core_contributors = [c for c in contributors if c.get("is_core", False)] other_contributors = (c for c in contributors if not c.get("is_core", False)) other_contributors = sorted(other_contributors, key=lambda c: c["name"].lower()) content = template.render(core_contributors=core_contributors, other_contributors=other_contributors) file_path = ROOT / "CONTRIBUTORS.md" file_path.write_text(content) if __name__ == "__main__": if GITHUB_REPO is None: raise RuntimeError("No github repo, please set the environment variable GITHUB_REPOSITORY") main() ================================================ FILE: tests/__init__.py ================================================ ================================================ FILE: tests/test_bare.sh ================================================ #!/bin/sh # this is a very simple script that tests the docker configuration for cookiecutter-django # it is meant to be run from the root directory of the repository, eg: # sh tests/test_bare.sh set -o errexit set -x # create a cache directory mkdir -p .cache/bare cd .cache/bare # create the project using the default settings in cookiecutter.json uv run cookiecutter ../../ --no-input --overwrite-if-exists use_docker=n "$@" cd my_awesome_project # Install OS deps sudo utility/install_os_dependencies.sh install # Install Python deps uv sync # run the project's tests uv run pytest # Make sure the check doesn't raise any warnings uv run python manage.py check --fail-level WARNING # Run npm build script if package.json is present if [ -f "package.json" ] then npm install npm run build fi # Generate the HTML for the documentation cd docs && uv run make html ================================================ FILE: tests/test_cookiecutter_generation.py ================================================ import glob # noqa: EXE002 import os import re import sys from collections.abc import Iterable from pathlib import Path import pytest import tomllib 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) # Run auto-fixable styles checks - skipped on CI by default. These can be fixed # automatically by running pre-commit after generation. However, they are tedious # to fix in the template, so we don't insist too much on fixing them. AUTOFIXABLE_STYLES = os.getenv("AUTOFIXABLE_STYLES") == "1" auto_fixable = pytest.mark.skipif(not AUTOFIXABLE_STYLES, reason="auto-fixable") @pytest.fixture def context(): return { "project_name": "My Test Project", "project_slug": "my_test_project", "author_name": "Test Author", "email": "test@example.com", "description": "A short description of the project.", "domain_name": "example.com", "version": "0.1.0", "timezone": "UTC", } SUPPORTED_COMBINATIONS = [ {"username_type": "username"}, {"username_type": "email"}, {"open_source_license": "MIT"}, {"open_source_license": "BSD"}, {"open_source_license": "GPLv3"}, {"open_source_license": "Apache Software License 2.0"}, {"open_source_license": "Not open source"}, {"windows": "y"}, {"windows": "n"}, {"editor": "None"}, {"editor": "PyCharm"}, {"editor": "VS Code"}, {"use_docker": "y"}, {"use_docker": "n"}, {"postgresql_version": "18"}, {"postgresql_version": "17"}, {"postgresql_version": "16"}, {"postgresql_version": "15"}, {"postgresql_version": "14"}, {"cloud_provider": "AWS", "use_whitenoise": "y"}, {"cloud_provider": "AWS", "use_whitenoise": "n"}, {"cloud_provider": "GCP", "use_whitenoise": "y"}, {"cloud_provider": "GCP", "use_whitenoise": "n"}, {"cloud_provider": "Azure", "use_whitenoise": "y"}, {"cloud_provider": "Azure", "use_whitenoise": "n"}, {"cloud_provider": "None", "use_whitenoise": "y", "mail_service": "Mailgun"}, {"cloud_provider": "None", "use_whitenoise": "y", "mail_service": "Mailjet"}, {"cloud_provider": "None", "use_whitenoise": "y", "mail_service": "Mandrill"}, {"cloud_provider": "None", "use_whitenoise": "y", "mail_service": "Postmark"}, {"cloud_provider": "None", "use_whitenoise": "y", "mail_service": "Sendgrid"}, {"cloud_provider": "None", "use_whitenoise": "y", "mail_service": "Brevo"}, {"cloud_provider": "None", "use_whitenoise": "y", "mail_service": "SparkPost"}, {"cloud_provider": "None", "use_whitenoise": "y", "mail_service": "Other SMTP"}, # Note: cloud_provider=None AND use_whitenoise=n is not supported {"cloud_provider": "AWS", "mail_service": "Mailgun"}, {"cloud_provider": "AWS", "mail_service": "Amazon SES"}, {"cloud_provider": "AWS", "mail_service": "Mailjet"}, {"cloud_provider": "AWS", "mail_service": "Mandrill"}, {"cloud_provider": "AWS", "mail_service": "Postmark"}, {"cloud_provider": "AWS", "mail_service": "Sendgrid"}, {"cloud_provider": "AWS", "mail_service": "Brevo"}, {"cloud_provider": "AWS", "mail_service": "SparkPost"}, {"cloud_provider": "AWS", "mail_service": "Other SMTP"}, {"cloud_provider": "GCP", "mail_service": "Mailgun"}, {"cloud_provider": "GCP", "mail_service": "Mailjet"}, {"cloud_provider": "GCP", "mail_service": "Mandrill"}, {"cloud_provider": "GCP", "mail_service": "Postmark"}, {"cloud_provider": "GCP", "mail_service": "Sendgrid"}, {"cloud_provider": "GCP", "mail_service": "Brevo"}, {"cloud_provider": "GCP", "mail_service": "SparkPost"}, {"cloud_provider": "GCP", "mail_service": "Other SMTP"}, {"cloud_provider": "Azure", "mail_service": "Mailgun"}, {"cloud_provider": "Azure", "mail_service": "Mailjet"}, {"cloud_provider": "Azure", "mail_service": "Mandrill"}, {"cloud_provider": "Azure", "mail_service": "Postmark"}, {"cloud_provider": "Azure", "mail_service": "Sendgrid"}, {"cloud_provider": "Azure", "mail_service": "Brevo"}, {"cloud_provider": "Azure", "mail_service": "SparkPost"}, {"cloud_provider": "Azure", "mail_service": "Other SMTP"}, # Note: cloud_providers GCP, Azure, and None # with mail_service Amazon SES is not supported {"rest_api": "None"}, {"rest_api": "DRF"}, {"rest_api": "Django Ninja"}, {"use_async": "y"}, {"use_async": "n"}, {"frontend_pipeline": "None"}, {"frontend_pipeline": "Django Compressor"}, {"frontend_pipeline": "Gulp"}, {"frontend_pipeline": "Webpack"}, {"use_celery": "y"}, {"use_celery": "n"}, {"use_mailpit": "y"}, {"use_mailpit": "n"}, {"use_sentry": "y"}, {"use_sentry": "n"}, {"use_whitenoise": "y"}, {"use_whitenoise": "n"}, {"use_heroku": "y"}, {"use_heroku": "n"}, {"ci_tool": "None"}, {"ci_tool": "Travis"}, {"ci_tool": "Gitlab"}, {"ci_tool": "Github"}, {"ci_tool": "Drone"}, {"keep_local_envs_in_vcs": "y"}, {"keep_local_envs_in_vcs": "n"}, {"debug": "y"}, {"debug": "n"}, ] UNSUPPORTED_COMBINATIONS = [ {"cloud_provider": "None", "use_whitenoise": "n"}, {"cloud_provider": "GCP", "mail_service": "Amazon SES"}, {"cloud_provider": "Azure", "mail_service": "Amazon SES"}, {"cloud_provider": "None", "mail_service": "Amazon SES"}, ] def _fixture_id(ctx): """Helper to get a user-friendly test name from the parametrized context.""" return "-".join(f"{key}:{value}" for key, value in ctx.items()) def build_files_list(base_path: Path): """Build a list containing absolute paths to the generated files.""" excluded_dirs = {".venv", "__pycache__"} f = [] for dirpath, subdirs, files in base_path.walk(): subdirs[:] = [d for d in subdirs if d not in excluded_dirs] f.extend(dirpath / file_path for file_path in files) return f def check_paths(paths: Iterable[Path]): """Method to check all paths have correct substitutions.""" # Assert that no match is found in any of the files for path in paths: if is_binary(str(path)): continue content = path.read_text() match = RE_OBJ.search(content) assert match is None, f"cookiecutter variable not replaced in {path}" @pytest.mark.parametrize("context_override", SUPPORTED_COMBINATIONS, ids=_fixture_id) def test_project_generation(cookies, context, context_override): """Test that project is generated and fully rendered.""" result = cookies.bake(extra_context={**context, **context_override}) assert result.exit_code == 0 assert result.exception is None assert result.project_path.name == context["project_slug"] assert result.project_path.is_dir() paths = build_files_list(result.project_path) assert paths check_paths(paths) @pytest.mark.parametrize("context_override", SUPPORTED_COMBINATIONS, ids=_fixture_id) def test_ruff_check_passes(cookies, context_override): """Generated project should pass ruff check.""" result = cookies.bake(extra_context=context_override) try: sh.ruff("check", ".", _cwd=str(result.project_path)) except sh.ErrorReturnCode as e: pytest.fail(e.stdout.decode()) @auto_fixable @pytest.mark.parametrize("context_override", SUPPORTED_COMBINATIONS, ids=_fixture_id) def test_ruff_format_passes(cookies, context_override): """Check whether generated project passes ruff format.""" result = cookies.bake(extra_context=context_override) try: sh.ruff( "format", ".", _cwd=str(result.project_path), ) except sh.ErrorReturnCode as e: pytest.fail(e.stdout.decode()) @auto_fixable @pytest.mark.parametrize("context_override", SUPPORTED_COMBINATIONS, ids=_fixture_id) def test_django_upgrade_passes(cookies, context_override): """Check whether generated project passes django-upgrade.""" result = cookies.bake(extra_context=context_override) python_files = [ file_path.removeprefix(f"{result.project_path}/") for file_path in glob.glob(str(result.project_path / "**" / "*.py"), recursive=True) # noqa: PTH207 ] try: sh.django_upgrade( "--target-version", "5.0", *python_files, _cwd=str(result.project_path), ) except sh.ErrorReturnCode as e: pytest.fail(e.stdout.decode()) @pytest.mark.parametrize("context_override", SUPPORTED_COMBINATIONS, ids=_fixture_id) def test_djlint_lint_passes(cookies, context_override): """Check whether generated project passes djLint --lint.""" result = cookies.bake(extra_context=context_override) autofixable_rules = "H014,T001" # TODO: remove T002 when fixed https://github.com/Riverside-Healthcare/djLint/issues/687 ignored_rules = "H006,H030,H031,T002" try: sh.djlint( "--lint", "--ignore", f"{autofixable_rules},{ignored_rules}", ".", _cwd=str(result.project_path), ) except sh.ErrorReturnCode as e: pytest.fail(e.stdout.decode()) @auto_fixable @pytest.mark.parametrize("context_override", SUPPORTED_COMBINATIONS, ids=_fixture_id) def test_djlint_check_passes(cookies, context_override): """Check whether generated project passes djLint --check.""" result = cookies.bake(extra_context=context_override) try: sh.djlint("--check", ".", _cwd=str(result.project_path)) except sh.ErrorReturnCode as e: pytest.fail(e.stdout.decode()) @pytest.mark.parametrize( ("use_docker", "expected_test_script"), [ ("n", "uv run pytest"), ("y", "docker compose -f docker-compose.local.yml run django pytest"), ], ) def test_travis_invokes_pytest(cookies, context, use_docker, expected_test_script): context.update({"ci_tool": "Travis", "use_docker": use_docker}) result = cookies.bake(extra_context=context) assert result.exit_code == 0 assert result.exception is None assert result.project_path.name == context["project_slug"] assert result.project_path.is_dir() with (result.project_path / ".travis.yml").open() as travis_yml: try: yml = yaml.safe_load(travis_yml)["jobs"]["include"] assert yml[0]["script"] == ["ruff check ."] assert yml[1]["script"] == [expected_test_script] except yaml.YAMLError as e: pytest.fail(str(e)) @pytest.mark.parametrize( ("use_docker", "expected_test_script"), [ ("n", "uv run pytest"), ("y", "docker compose -f docker-compose.local.yml run django pytest"), ], ) def test_gitlab_invokes_precommit_and_pytest(cookies, context, use_docker, expected_test_script): context.update({"ci_tool": "Gitlab", "use_docker": use_docker}) result = cookies.bake(extra_context=context) assert result.exit_code == 0 assert result.exception is None assert result.project_path.name == context["project_slug"] assert result.project_path.is_dir() with (result.project_path / ".gitlab-ci.yml").open() as gitlab_yml: try: gitlab_config = yaml.safe_load(gitlab_yml) assert gitlab_config["precommit"]["script"] == [ "uv run pre-commit run --show-diff-on-failure --color=always --all-files", ] assert gitlab_config["pytest"]["script"] == [expected_test_script] except yaml.YAMLError as e: pytest.fail(e) @pytest.mark.parametrize( ("use_docker", "expected_test_script"), [ ("n", "uv run pytest"), ("y", "docker compose -f docker-compose.local.yml run django pytest"), ], ) def test_github_invokes_linter_and_pytest(cookies, context, use_docker, expected_test_script): context.update({"ci_tool": "Github", "use_docker": use_docker}) result = cookies.bake(extra_context=context) assert result.exit_code == 0 assert result.exception is None assert result.project_path.name == context["project_slug"] assert result.project_path.is_dir() with (result.project_path / ".github" / "workflows" / "ci.yml").open() as github_yml: try: github_config = yaml.safe_load(github_yml) linter_present = False for action_step in github_config["jobs"]["linter"]["steps"]: if action_step.get("uses", "NA").startswith("pre-commit"): linter_present = True assert linter_present expected_test_script_present = False for action_step in github_config["jobs"]["pytest"]["steps"]: if action_step.get("run") == expected_test_script: expected_test_script_present = True assert expected_test_script_present except yaml.YAMLError as e: pytest.fail(e) @pytest.mark.parametrize("slug", ["project slug", "Project_Slug"]) def test_invalid_slug(cookies, context, slug): """Invalid slug should fail pre-generation hook.""" context.update({"project_slug": slug}) result = cookies.bake(extra_context=context) assert result.exit_code != 0 assert isinstance(result.exception, FailedHookException) @pytest.mark.parametrize("invalid_context", UNSUPPORTED_COMBINATIONS) def test_error_if_incompatible(cookies, context, invalid_context): """It should not generate project an incompatible combination is selected.""" context.update(invalid_context) result = cookies.bake(extra_context=context) assert result.exit_code != 0 assert isinstance(result.exception, FailedHookException) @pytest.mark.parametrize( ("editor", "pycharm_docs_exist"), [ ("None", False), ("PyCharm", True), ("VS Code", False), ], ) def test_pycharm_docs_removed(cookies, context, editor, pycharm_docs_exist): context.update({"editor": editor}) result = cookies.bake(extra_context=context) index_rst = result.project_path / "docs" / "index.rst" has_pycharm_docs = "pycharm/configuration" in index_rst.read_text() assert has_pycharm_docs is pycharm_docs_exist def test_trim_domain_email(cookies, context): """Check that leading and trailing spaces are trimmed in domain and email.""" context.update( { "use_docker": "y", "domain_name": " example.com ", "email": " me@example.com ", }, ) result = cookies.bake(extra_context=context) assert result.exit_code == 0 prod_django_env = result.project_path / ".envs" / ".production" / ".django" assert "DJANGO_ALLOWED_HOSTS=.example.com" in prod_django_env.read_text() base_settings = result.project_path / "config" / "settings" / "base.py" assert "" in base_settings.read_text() def test_pyproject_toml(cookies, context): author_name = "Project Author" author_email = "me@example.com" context.update( { "description": "DESCRIPTION", "domain_name": "example.com", "email": author_email, "author_name": author_name, }, ) result = cookies.bake(extra_context=context) assert result.exit_code == 0 pyproject_toml = result.project_path / "pyproject.toml" data = tomllib.loads(pyproject_toml.read_text()) assert data assert data["project"]["authors"][0]["email"] == author_email assert data["project"]["authors"][0]["name"] == author_name assert data["project"]["name"] == context["project_slug"] def test_pre_commit_without_heroku(cookies, context): context.update({"use_heroku": "n"}) result = cookies.bake(extra_context=context) assert result.exit_code == 0 pre_commit_config = result.project_path / ".pre-commit-config.yaml" data = pre_commit_config.read_text() assert "uv-pre-commit" not in data ================================================ FILE: tests/test_docker.sh ================================================ #!/bin/sh # this is a very simple script that tests the docker configuration for cookiecutter-django # it is meant to be run from the root directory of the repository, eg: # sh tests/test_docker.sh set -o errexit set -x set -e finish() { # Your cleanup code here docker compose -f docker-compose.local.yml down --remove-orphans docker volume rm my_awesome_project_my_awesome_project_local_postgres_data } # the cleanup doesn't work in the github actions if [ -z "$GITHUB_ACTIONS" ]; then trap finish EXIT fi # create a cache directory mkdir -p .cache/docker cd .cache/docker sudo rm -rf my_awesome_project # create the project using the default settings in cookiecutter.json uv run cookiecutter ../../ --no-input --overwrite-if-exists use_docker=y "$@" cd my_awesome_project # make sure all images build docker compose -f docker-compose.local.yml build docker compose -f docker-compose.local.yml run django uv lock docker compose -f docker-compose.local.yml build # run the project's type checks docker compose -f docker-compose.local.yml run --rm django mypy my_awesome_project # run the project's tests docker compose -f docker-compose.local.yml run --rm django pytest # return non-zero status code if there are migrations that have not been created docker compose -f docker-compose.local.yml run --rm django python manage.py makemigrations --check || { echo "ERROR: there were changes in the models, but migration listed above have not been created and are not saved in version control"; exit 1; } # Test support for translations docker compose -f docker-compose.local.yml run --rm django python manage.py makemessages --all # Make sure the check doesn't raise any warnings docker compose -f docker-compose.local.yml run --rm \ -e DJANGO_SECRET_KEY="$(openssl rand -base64 64)" \ -e REDIS_URL=redis://redis:6379/0 \ -e DJANGO_AWS_ACCESS_KEY_ID=x \ -e DJANGO_AWS_SECRET_ACCESS_KEY=x \ -e DJANGO_AWS_STORAGE_BUCKET_NAME=x \ -e DJANGO_ADMIN_URL=x \ -e MAILGUN_API_KEY=x \ -e MAILGUN_DOMAIN=x \ django python manage.py check --settings=config.settings.production --deploy --database default --fail-level WARNING # Generate the HTML for the documentation docker compose -f docker-compose.docs.yml run --rm docs make html docker build -f ./compose/production/django/Dockerfile -t django-prod . docker run --rm \ --env-file .envs/.local/.django \ --env-file .envs/.local/.postgres \ --network my_awesome_project_default \ -e DJANGO_SECRET_KEY="$(openssl rand -base64 64)" \ -e REDIS_URL=redis://redis:6379/0 \ -e DJANGO_AWS_ACCESS_KEY_ID=x \ -e DJANGO_AWS_SECRET_ACCESS_KEY=x \ -e DJANGO_AWS_STORAGE_BUCKET_NAME=x \ -e DJANGO_ADMIN_URL=x \ -e MAILGUN_API_KEY=x \ -e MAILGUN_DOMAIN=x \ django-prod python manage.py check --settings=config.settings.production --deploy --database default --fail-level WARNING # Run npm build script if package.json is present if [ -f "package.json" ] then docker compose -f docker-compose.local.yml run --rm node npm run build fi ================================================ FILE: tests/test_hooks.py ================================================ """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" ================================================ FILE: tox.ini ================================================ [tox] skipsdist = true envlist = py313 [testenv] passenv = AUTOFIXABLE_STYLES commands = pytest --instafail -n auto {posargs:./tests} ================================================ FILE: {{cookiecutter.project_slug}}/.devcontainer/bash_history ================================================ ================================================ FILE: {{cookiecutter.project_slug}}/.devcontainer/bashrc.override.sh ================================================ # # .bashrc.override.sh # # persistent bash history HISTFILE=~/.bash_history PROMPT_COMMAND="history -a; $PROMPT_COMMAND" # set some django env vars source /entrypoint # restore default shell options set +o errexit set +o pipefail set +o nounset # start ssh-agent # https://code.visualstudio.com/docs/remote/troubleshooting eval "$(ssh-agent -s)" ================================================ FILE: {{cookiecutter.project_slug}}/.devcontainer/devcontainer.json ================================================ // For format details, see https://containers.dev/implementors/json_reference/ { "name": "{{cookiecutter.project_slug}}_dev", "dockerComposeFile": [ "../docker-compose.local.yml" ], "init": true, "mounts": [ { "source": "./.devcontainer/bash_history", "target": "/home/dev-user/.bash_history", "type": "bind" }, { "source": "~/.ssh", "target": "/home/dev-user/.ssh", "type": "bind" } ], // Tells devcontainer.json supporting services / tools whether they should run // /bin/sh -c "while sleep 1000; do :; done" when starting the container instead of the container’s default command "overrideCommand": false, "service": "django", // "remoteEnv": {"PATH": "/home/dev-user/.local/bin:${containerEnv:PATH}"}, "remoteUser": "dev-user", "workspaceFolder": "/app", // Set *default* container specific settings.json values on container create. "customizations": { {%- if cookiecutter.editor == "VS Code" %} "vscode": { "settings": { "editor.formatOnSave": true, "[python]": { "analysis.autoImportCompletions": true, "analysis.typeCheckingMode": "basic", "defaultInterpreterPath": "/usr/local/bin/python", "editor.codeActionsOnSave": { "source.organizeImports": "always" }, "editor.defaultFormatter": "charliermarsh.ruff", "languageServer": "Pylance", "linting.enabled": true, "linting.mypyEnabled": true, "linting.mypyPath": "/usr/local/bin/mypy", } }, // https://code.visualstudio.com/docs/remote/devcontainerjson-reference#_vs-code-specific-properties // Add the IDs of extensions you want installed when the container is created. "extensions": [ "davidanson.vscode-markdownlint", "mrmlnc.vscode-duplicate", "visualstudioexptteam.vscodeintellicode", "visualstudioexptteam.intellicode-api-usage-examples", // python "ms-python.python", "ms-python.vscode-pylance", "charliermarsh.ruff", // django "batisteo.vscode-django" ] } {%- endif %} }, // Uncomment the next line if you want start specific services in your Docker Compose config. // "runServices": [], // Uncomment the next line if you want to keep your containers running after VS Code shuts down. // "shutdownAction": "none", // Uncomment the next line to run commands after the container is created. "postCreateCommand": "cat .devcontainer/bashrc.override.sh >> ~/.bashrc" } ================================================ FILE: {{cookiecutter.project_slug}}/.dockerignore ================================================ .editorconfig .gitattributes .github .gitignore .gitlab-ci.yml .idea .pre-commit-config.yaml .readthedocs.yml .travis.yml venv .git .envs/ ================================================ FILE: {{cookiecutter.project_slug}}/.drone.yml ================================================ kind: pipeline name: default environment: POSTGRES_USER: '{{ cookiecutter.project_slug }}' POSTGRES_PASSWORD: '' POSTGRES_DB: 'test_{{ cookiecutter.project_slug }}' POSTGRES_HOST_AUTH_METHOD: trust {%- if cookiecutter.use_celery == 'y' %} REDIS_URL: 'redis://redis:6379/0' {%- endif %} steps: - name: lint pull: if-not-exists image: ghcr.io/astral-sh/uv:python3.13 environment: PRE_COMMIT_HOME: ${CI_PROJECT_DIR}/.cache/pre-commit volumes: - name: pre-commit cache path: ${PRE_COMMIT_HOME} commands: - export PRE_COMMIT_HOME=$CI_PROJECT_DIR/.cache/pre-commit - uv pip install -q pre-commit pre-commit-uv - uv run pre-commit run --show-diff-on-failure --color=always --all-files - name: test pull: if-not-exists {%- if cookiecutter.use_docker == 'y' %} image: docker:25.0 environment: DATABASE_URL: pgsql://$POSTGRES_USER:$POSTGRES_PASSWORD@postgres/$POSTGRES_DB commands: - docker-compose -f docker-compose.local.yml build - docker-compose -f docker-compose.docs.yml build - docker-compose -f docker-compose.local.yml run --rm django python manage.py migrate - docker-compose -f docker-compose.local.yml up -d - docker-compose -f docker-compose.local.yml run django pytest {%- else %} image: ghcr.io/astral-sh/uv:python3.13 commands: - uv sync --locked - uv run pytest {%- endif%} volumes: - name: pre-commit cache host: path: /tmp/drone/cache/pre-commit ================================================ FILE: {{cookiecutter.project_slug}}/.editorconfig ================================================ # http://editorconfig.org root = true [*] charset = utf-8 end_of_line = lf insert_final_newline = true trim_trailing_whitespace = true [*.{py,rst,ini}] indent_style = space indent_size = 4 [*.{html,css,scss,json,yml,xml,toml}] indent_style = space indent_size = 2 [*.md] trim_trailing_whitespace = false [Makefile] indent_style = tab [default.conf] indent_style = space indent_size = 2 ================================================ FILE: {{cookiecutter.project_slug}}/.envs/.local/.django ================================================ # General # ------------------------------------------------------------------------------ USE_DOCKER=yes IPYTHONDIR=/app/.ipython {%- if cookiecutter.use_celery == 'y' %} # Redis # ------------------------------------------------------------------------------ REDIS_URL=redis://redis:6379/0 # Celery # ------------------------------------------------------------------------------ # Flower CELERY_FLOWER_USER=!!!SET CELERY_FLOWER_USER!!! CELERY_FLOWER_PASSWORD=!!!SET CELERY_FLOWER_PASSWORD!!! {%- endif %} ================================================ FILE: {{cookiecutter.project_slug}}/.envs/.local/.postgres ================================================ # PostgreSQL # ------------------------------------------------------------------------------ POSTGRES_HOST=postgres POSTGRES_PORT=5432 POSTGRES_DB={{ cookiecutter.project_slug }} POSTGRES_USER=!!!SET POSTGRES_USER!!! POSTGRES_PASSWORD=!!!SET POSTGRES_PASSWORD!!! ================================================ FILE: {{cookiecutter.project_slug}}/.envs/.production/.django ================================================ # General # ------------------------------------------------------------------------------ # DJANGO_READ_DOT_ENV_FILE=True DJANGO_SETTINGS_MODULE=config.settings.production DJANGO_SECRET_KEY=!!!SET DJANGO_SECRET_KEY!!! DJANGO_ADMIN_URL=!!!SET DJANGO_ADMIN_URL!!! DJANGO_ALLOWED_HOSTS=.{{ cookiecutter.domain_name }} # Security # ------------------------------------------------------------------------------ # TIP: better off using DNS, however, redirect is OK too DJANGO_SECURE_SSL_REDIRECT=False # Email # ------------------------------------------------------------------------------ DJANGO_SERVER_EMAIL= {% if cookiecutter.mail_service == 'Mailgun' %} MAILGUN_API_KEY= MAILGUN_DOMAIN= {% elif cookiecutter.mail_service == 'Mailjet' %} MAILJET_API_KEY= MAILJET_SECRET_KEY= {% elif cookiecutter.mail_service == 'Mandrill' %} MANDRILL_API_KEY= {% elif cookiecutter.mail_service == 'Postmark' %} POSTMARK_SERVER_TOKEN= {% elif cookiecutter.mail_service == 'Sendgrid' %} SENDGRID_API_KEY= SENDGRID_GENERATE_MESSAGE_ID=True SENDGRID_MERGE_FIELD_FORMAT=None {% elif cookiecutter.mail_service == 'Brevo' %} BREVO_API_KEY= {% elif cookiecutter.mail_service == 'SparkPost' %} SPARKPOST_API_KEY= {% endif %} {% if cookiecutter.cloud_provider == 'AWS' %} # AWS # ------------------------------------------------------------------------------ DJANGO_AWS_ACCESS_KEY_ID= DJANGO_AWS_SECRET_ACCESS_KEY= DJANGO_AWS_STORAGE_BUCKET_NAME= {% elif cookiecutter.cloud_provider == 'GCP' %} # GCP # ------------------------------------------------------------------------------ GOOGLE_APPLICATION_CREDENTIALS= DJANGO_GCP_STORAGE_BUCKET_NAME= {% elif cookiecutter.cloud_provider == 'Azure' %} # Azure # ------------------------------------------------------------------------------ DJANGO_AZURE_ACCOUNT_KEY= DJANGO_AZURE_ACCOUNT_NAME= DJANGO_AZURE_CONTAINER_NAME= {% endif %} # django-allauth # ------------------------------------------------------------------------------ DJANGO_ACCOUNT_ALLOW_REGISTRATION=True # Gunicorn # ------------------------------------------------------------------------------ WEB_CONCURRENCY=4 {% if cookiecutter.use_sentry == 'y' %} # Sentry # ------------------------------------------------------------------------------ SENTRY_DSN= {% endif %} # Redis # ------------------------------------------------------------------------------ REDIS_URL=redis://redis:6379/0 {% if cookiecutter.use_celery == 'y' %} # Celery # ------------------------------------------------------------------------------ # Flower CELERY_FLOWER_USER=!!!SET CELERY_FLOWER_USER!!! CELERY_FLOWER_PASSWORD=!!!SET CELERY_FLOWER_PASSWORD!!! {% endif %} ================================================ FILE: {{cookiecutter.project_slug}}/.envs/.production/.postgres ================================================ # PostgreSQL # ------------------------------------------------------------------------------ POSTGRES_HOST=postgres POSTGRES_PORT=5432 POSTGRES_DB={{ cookiecutter.project_slug }} POSTGRES_USER=!!!SET POSTGRES_USER!!! POSTGRES_PASSWORD=!!!SET POSTGRES_PASSWORD!!! ================================================ FILE: {{cookiecutter.project_slug}}/.gitattributes ================================================ * text=auto ================================================ FILE: {{cookiecutter.project_slug}}/.github/dependabot.yml ================================================ # Config for Dependabot updates. See Documentation here: # https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file version: 2 updates: # Update GitHub actions in workflows - package-ecosystem: 'github-actions' directory: '/' # Every weekday schedule: interval: 'daily' groups: github-actions: patterns: - '*' {%- if cookiecutter.use_docker == 'y' %} # Enable version updates for Docker - package-ecosystem: 'docker' # Look for a `Dockerfile` in the `compose/local/django` directory directories: - 'compose/local/django/' - 'compose/local/docs/' - 'compose/production/django/' # Every weekday schedule: interval: 'daily' # Ignore minor version updates (3.10 -> 3.11) but update patch versions ignore: - dependency-name: '*' update-types: - 'version-update:semver-major' - 'version-update:semver-minor' groups: docker-python: patterns: - '*' - package-ecosystem: 'docker' # Look for a `Dockerfile` in the listed directories directories: - 'compose/local/node/' - 'compose/production/aws/' - 'compose/production/postgres/' - 'compose/production/traefik/' {%- if cookiecutter.cloud_provider == 'None' %} - 'compose/production/nginx/' {%- endif %} # Every weekday schedule: interval: 'daily' # Enable version updates for Docker Compose files - package-ecosystem: 'docker-compose' directories: - '/' # Every weekday schedule: interval: 'daily' {%- endif %} # Enable version updates for Python/uv - package-ecosystem: 'uv' # Look for a `pyproject.toml` in the `root` directory directory: '/' # Every weekday schedule: interval: 'daily' groups: python: update-types: - 'minor' - 'patch' {%- if cookiecutter.frontend_pipeline == 'Gulp' %} # Enable version updates for javascript/npm - package-ecosystem: 'npm' # Look for a `packages.json` in the `root` directory directory: '/' # Every weekday schedule: interval: 'daily' groups: javascript: update-types: - 'minor' - 'patch' {%- endif %} ================================================ FILE: {{cookiecutter.project_slug}}/.github/workflows/ci.yml ================================================ name: CI # Enable Buildkit and let compose use it to speed up image building env: DOCKER_BUILDKIT: 1 COMPOSE_DOCKER_CLI_BUILD: 1 on: pull_request: branches: ['main'] paths-ignore: ['docs/**'] push: branches: ['main'] paths-ignore: ['docs/**'] concurrency: group: {% raw %}${{ github.head_ref || github.run_id }}{% endraw %} cancel-in-progress: true jobs: linter: runs-on: ubuntu-latest steps: - name: Checkout Code Repository uses: actions/checkout@v6 - name: Set up Python uses: actions/setup-python@v6 with: python-version-file: '.python-version' {%- if cookiecutter.open_source_license != 'Not open source' %} # Consider using pre-commit.ci for open source project {%- endif %} - name: Run pre-commit uses: pre-commit/action@v3.0.1 # With no caching at all the entire ci process takes 3m to complete! pytest: runs-on: ubuntu-latest {%- if cookiecutter.use_docker == 'n' %} services: {%- if cookiecutter.use_celery == 'y' %} redis: image: redis:7.2 ports: - 6379:6379 {%- endif %} postgres: image: postgres:{{ cookiecutter.postgresql_version }} ports: - 5432:5432 env: POSTGRES_PASSWORD: postgres env: {%- if cookiecutter.use_celery == 'y' %} REDIS_URL: 'redis://localhost:6379/0' {%- endif %} # postgres://user:password@host:port/database DATABASE_URL: 'postgres://postgres:postgres@localhost:5432/postgres' {%- endif %} steps: - name: Checkout Code Repository uses: actions/checkout@v6 {%- if cookiecutter.use_docker == 'y' %} - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Build and cache local backend uses: docker/bake-action@v6 with: push: false load: true files: docker-compose.local.yml targets: django set: | django.cache-from=type=gha,scope=django-cached-tests django.cache-to=type=gha,scope=django-cached-tests,mode=max postgres.cache-from=type=gha,scope=postgres-cached-tests postgres.cache-to=type=gha,scope=postgres-cached-tests,mode=max - name: Build and cache docs uses: docker/bake-action@v6 with: push: false load: true files: docker-compose.docs.yml set: | docs.cache-from=type=gha,scope=cached-docs docs.cache-to=type=gha,scope=cached-docs,mode=max - name: Check DB Migrations run: docker compose -f docker-compose.local.yml run --rm django python manage.py makemigrations --check - name: Run DB Migrations run: docker compose -f docker-compose.local.yml run --rm django python manage.py migrate - name: Run Django Tests run: docker compose -f docker-compose.local.yml run django pytest - name: Tear down the Stack run: docker compose -f docker-compose.local.yml down {%- else %} - name: Install uv uses: astral-sh/setup-uv@v5 with: enable-cache: "true" - name: Set up Python uses: actions/setup-python@v6 with: python-version-file: ".python-version" - name: Install dependencies run: uv sync --locked - name: Check DB Migrations run: uv run python manage.py makemigrations --check - name: Run DB Migrations run: uv run python manage.py migrate - name: Test with pytest run: uv run pytest {%- endif %} ================================================ FILE: {{cookiecutter.project_slug}}/.gitignore ================================================ ### Python template # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # C extensions *.so # Distribution / packaging .Python build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ *.egg-info/ .installed.cfg *.egg # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *.cover .hypothesis/ # Translations *.mo *.pot # Django stuff: staticfiles/ # Sphinx documentation docs/_build/ # PyBuilder target/ {% if cookiecutter.use_celery == 'y' -%} # celery beat schedule file celerybeat-schedule {%- endif %} # Environments .venv venv/ ENV/ # Rope project settings .ropeproject # mkdocs documentation /site # mypy .mypy_cache/ ### Node template # Logs logs *.log npm-debug.log* yarn-debug.log* yarn-error.log* # Runtime data pids *.pid *.seed *.pid.lock # Directory for instrumented libs generated by jscoverage/JSCover lib-cov # Coverage directory used by tools like istanbul coverage # nyc test coverage .nyc_output # Bower dependency directory (https://bower.io/) bower_components # node-waf configuration .lock-wscript # Compiled binary addons (http://nodejs.org/api/addons.html) build/Release # Dependency directories node_modules/ jspm_packages/ # Typescript v1 declaration files typings/ # Optional npm cache directory .npm # Optional eslint cache .eslintcache # Optional REPL history .node_repl_history # Output of 'npm pack' *.tgz # Yarn Integrity file .yarn-integrity ### Linux template *~ # temporary files which can be created if a process still has a handle open of a deleted file .fuse_hidden* # KDE directory preferences .directory # Linux trash folder which might appear on any partition or disk .Trash-* # .nfs files are created when an open file is removed but is still being accessed .nfs* ### VisualStudioCode template .vscode/* !.vscode/settings.json !.vscode/tasks.json !.vscode/launch.json !.vscode/extensions.json *.code-workspace # Local History for devcontainer .devcontainer/bash_history {% if cookiecutter.editor == 'PyCharm' -%} # Provided default Pycharm Run/Debug Configurations should be tracked by git # In case of local modifications made by Pycharm, use update-index command # for each changed file, like this: # git update-index --assume-unchanged .idea/{{cookiecutter.project_slug}}.iml ### JetBrains template # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 # User-specific stuff: .idea/**/workspace.xml .idea/**/tasks.xml .idea/dictionaries # Sensitive or high-churn files: .idea/**/dataSources/ .idea/**/dataSources.ids .idea/**/dataSources.xml .idea/**/dataSources.local.xml .idea/**/sqlDataSources.xml .idea/**/dynamic.xml .idea/**/uiDesigner.xml # Gradle: .idea/**/gradle.xml .idea/**/libraries # CMake cmake-build-debug/ # Mongo Explorer plugin: .idea/**/mongoSettings.xml ## File-based project format: *.iws ## Plugin-specific files: # IntelliJ out/ # mpeltonen/sbt-idea plugin .idea_modules/ # JIRA plugin atlassian-ide-plugin.xml # Cursive Clojure plugin .idea/replstate.xml # Crashlytics plugin (for Android Studio and IntelliJ) com_crashlytics_export_strings.xml crashlytics.properties crashlytics-build.properties fabric.properties {% endif %} ### Windows template # Windows thumbnail cache files Thumbs.db ehthumbs.db ehthumbs_vista.db # Dump file *.stackdump # Folder config file Desktop.ini # Recycle Bin used on file shares $RECYCLE.BIN/ # Windows Installer files *.cab *.msi *.msm *.msp # Windows shortcuts *.lnk ### macOS template # General *.DS_Store .AppleDouble .LSOverride # Icon must end with two \r Icon # Thumbnails ._* # Files that might appear in the root of a volume .DocumentRevisions-V100 .fseventsd .Spotlight-V100 .TemporaryItems .Trashes .VolumeIcon.icns .com.apple.timemachine.donotpresent # Directories potentially created on remote AFP share .AppleDB .AppleDesktop Network Trash Folder Temporary Items .apdisk ### SublimeText template # Cache files for Sublime Text *.tmlanguage.cache *.tmPreferences.cache *.stTheme.cache # Workspace files are user-specific *.sublime-workspace # Project files should be checked into the repository, unless a significant # proportion of contributors will probably not be using Sublime Text # *.sublime-project # SFTP configuration file sftp-config.json # Package control specific files Package Control.last-run Package Control.ca-list Package Control.ca-bundle Package Control.system-ca-bundle Package Control.cache/ Package Control.ca-certs/ Package Control.merged-ca-bundle Package Control.user-ca-bundle oscrypto-ca-bundle.crt bh_unicode_properties.cache # Sublime-github package stores a github token in this file # https://packagecontrol.io/packages/sublime-github GitHub.sublime-settings ### Vim template # Swap [._]*.s[a-v][a-z] [._]*.sw[a-p] [._]s[a-v][a-z] [._]sw[a-p] # Session Session.vim # Temporary .netrwhist # Auto-generated tag files tags # Redis dump file dump.rdb ### Project template {%- if cookiecutter.use_mailpit == 'y' and cookiecutter.use_docker == 'n' %} mailpit {%- endif %} {{ cookiecutter.project_slug }}/media/ .pytest_cache/ {%- if cookiecutter.use_docker == 'y' %} .ipython/ {%- endif %} {%- if cookiecutter.frontend_pipeline == 'Gulp' %} project.css project.min.css vendors.js *.min.js *.min.js.map {%- endif %} {%- if cookiecutter.frontend_pipeline == 'Webpack' %} {{ cookiecutter.project_slug }}/static/webpack_bundles/ webpack-stats.json {%- endif %} ================================================ FILE: {{cookiecutter.project_slug}}/.gitlab-ci.yml ================================================ stages: - lint - test variables: POSTGRES_USER: '{{ cookiecutter.project_slug }}' POSTGRES_PASSWORD: '' POSTGRES_DB: 'test_{{ cookiecutter.project_slug }}' POSTGRES_HOST_AUTH_METHOD: trust {%- if cookiecutter.use_celery == 'y' %} REDIS_URL: 'redis://redis:6379/0' {%- endif %} precommit: stage: lint image: ghcr.io/astral-sh/uv:python3.13-bookworm variables: PRE_COMMIT_HOME: ${CI_PROJECT_DIR}/.cache/pre-commit cache: paths: - ${PRE_COMMIT_HOME} before_script: - uv venv - uv pip install -q pre-commit pre-commit-uv script: - uv run pre-commit run --show-diff-on-failure --color=always --all-files pytest: stage: test {%- if cookiecutter.use_docker == 'y' %} image: docker:25.0 services: - docker:dind before_script: - docker compose -f docker-compose.local.yml build - docker compose -f docker-compose.docs.yml build # Ensure celerybeat does not crash due to non-existent tables - docker compose -f docker-compose.local.yml run --rm django python manage.py migrate - docker compose -f docker-compose.local.yml up -d script: - docker compose -f docker-compose.local.yml run django pytest {%- else %} image: ghcr.io/astral-sh/uv:python3.13 services: - postgres:{{ cookiecutter.postgresql_version }} variables: DATABASE_URL: pgsql://$POSTGRES_USER:$POSTGRES_PASSWORD@postgres/$POSTGRES_DB before_script: - uv sync --locked script: - uv run pytest {%- endif %} ================================================ FILE: {{cookiecutter.project_slug}}/.pre-commit-config.yaml ================================================ exclude: '^docs/|/migrations/|devcontainer.json' default_stages: [pre-commit] minimum_pre_commit_version: "3.2.0" default_language_version: python: python3.13 repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v6.0.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer - id: check-json - id: check-toml - id: check-xml - id: check-yaml - id: debug-statements - id: check-builtin-literals - id: check-case-conflict - id: check-docstring-first - id: detect-private-key - repo: https://github.com/pre-commit/mirrors-prettier rev: v4.0.0-alpha.8 hooks: - id: prettier args: ['--tab-width', '2', '--single-quote'] exclude: '{{cookiecutter.project_slug}}/templates/' - repo: https://github.com/adamchainz/django-upgrade rev: '1.30.0' hooks: - id: django-upgrade args: ['--target-version', '6.0'] # Run the Ruff linter. - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.15.7 hooks: # Linter - id: ruff-check args: [--fix, --exit-non-zero-on-fix] # Formatter - id: ruff-format - repo: https://github.com/tox-dev/pyproject-fmt rev: v2.20.0 hooks: - id: pyproject-fmt - repo: https://github.com/Riverside-Healthcare/djLint rev: v1.36.4 hooks: - id: djlint-reformat-django - id: djlint-django # sets up .pre-commit-ci.yaml to ensure pre-commit dependencies stay up to date ci: autoupdate_schedule: weekly skip: [] submodules: false ================================================ FILE: {{cookiecutter.project_slug}}/.readthedocs.yml ================================================ # Read the Docs configuration file # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details version: 2 build: os: ubuntu-24.04 tools: python: "3.13" jobs: pre_create_environment: - asdf plugin add uv - asdf install uv latest - asdf global uv latest create_environment: - uv venv "${READTHEDOCS_VIRTUALENV_PATH}" install: - UV_PROJECT_ENVIRONMENT="${READTHEDOCS_VIRTUALENV_PATH}" uv sync --frozen --no-dev --only-group docs sphinx: configuration: docs/conf.py ================================================ FILE: {{cookiecutter.project_slug}}/.travis.yml ================================================ dist: focal language: python python: - "3.13" services: - {% if cookiecutter.use_docker == 'y' %}docker{% else %}postgresql{% endif %} jobs: include: - name: "Linter" before_script: - pip install -q ruff script: - ruff check . - name: "Django Test" {%- if cookiecutter.use_docker == 'y' %} before_script: - docker compose -v - docker -v - docker compose -f docker-compose.local.yml build - docker compose -f docker-compose.docs.yml build # Ensure celerybeat does not crash due to non-existent tables - docker compose -f docker-compose.local.yml run --rm django python manage.py migrate - docker compose -f docker-compose.local.yml up -d script: - docker compose -f docker-compose.local.yml run django pytest after_failure: - docker compose -f docker-compose.local.yml logs {%- else %} before_install: - sudo apt-get update -qq - sudo apt-get install -qq build-essential gettext python-dev zlib1g-dev libpq-dev xvfb - sudo apt-get install -qq libjpeg8-dev libfreetype6-dev libwebp-dev - sudo apt-get install -qq graphviz-dev python-setuptools python3-dev python-virtualenv python-pip - sudo apt-get install -qq firefox automake libtool libreadline6 libreadline6-dev libreadline-dev - sudo apt-get install -qq libsqlite3-dev libxml2 libxml2-dev libssl-dev libbz2-dev wget curl llvm language: python python: - "3.13" install: - pip install uv - uv sync script: - uv run pytest {%- endif %} ================================================ FILE: {{cookiecutter.project_slug}}/CONTRIBUTORS.txt ================================================ {{ cookiecutter.author_name }} ================================================ FILE: {{cookiecutter.project_slug}}/COPYING ================================================ GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . ================================================ FILE: {{cookiecutter.project_slug}}/LICENSE ================================================ {% if cookiecutter.open_source_license == 'MIT' %} The MIT License (MIT) Copyright (c) {% now 'utc', '%Y' %}, {{ cookiecutter.author_name }} Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. {%- elif cookiecutter.open_source_license == 'BSD' %} Copyright (c) {% now 'utc', '%Y' %}, {{ cookiecutter.author_name }} All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of {{ cookiecutter.project_name }} nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. {%- elif cookiecutter.open_source_license == 'GPLv3' %} Copyright (c) {% now 'utc', '%Y' %}, {{ cookiecutter.author_name }} This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . {%- elif cookiecutter.open_source_license == 'Apache Software License 2.0' %} Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS Copyright {% now 'utc', '%Y' %} {{ cookiecutter.author_name }} Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. {%- endif %} ================================================ FILE: {{cookiecutter.project_slug}}/Procfile ================================================ release: python manage.py migrate {%- if cookiecutter.use_async == "y" %} web: gunicorn config.asgi:application -k uvicorn_worker.UvicornWorker {%- else %} web: gunicorn config.wsgi:application {%- endif %} {%- 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 %} ================================================ FILE: {{cookiecutter.project_slug}}/README.md ================================================ # {{cookiecutter.project_name}} {{ cookiecutter.description }} [![Built with Cookiecutter Django](https://img.shields.io/badge/built%20with-Cookiecutter%20Django-ff69b4.svg?logo=cookiecutter)](https://github.com/cookiecutter/cookiecutter-django/) [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff) {%- if cookiecutter.open_source_license != "Not open source" %} License: {{cookiecutter.open_source_license}} {%- endif %} ## Settings Moved to [settings](https://cookiecutter-django.readthedocs.io/en/latest/1-getting-started/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 a **superuser account**, use this command: uv run 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: uv run mypy {{cookiecutter.project_slug}} ### Test coverage To run the tests, check your test coverage, and generate an HTML coverage report: uv run coverage run -m pytest uv run coverage html uv run open htmlcov/index.html #### Running tests with pytest uv run pytest ### Live reloading and Sass CSS compilation Moved to [Live reloading and SASS compilation](https://cookiecutter-django.readthedocs.io/en/latest/2-local-development/developing-locally.html#using-webpack-or-gulp). {%- if cookiecutter.use_celery == "y" %} ### Celery This app comes with Celery. To run a celery worker: ```bash cd {{cookiecutter.project_slug}} uv run 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. To run [periodic tasks](https://docs.celeryq.dev/en/stable/userguide/periodic-tasks.html), you'll need to start the celery beat scheduler service. You can start it as a standalone process: ```bash cd {{cookiecutter.project_slug}} uv run celery -A config.celery_app beat ``` or you can embed the beat service inside a worker with the `-B` option (not recommended for production use): ```bash cd {{cookiecutter.project_slug}} uv run celery -A config.celery_app worker -B -l info ``` {%- endif %} {%- if cookiecutter.use_mailpit == "y" %} ### Email Server {%- if cookiecutter.use_docker == "y" %} In development, it is often nice to be able to see emails that are being sent from your application. For that reason local SMTP server [Mailpit](https://github.com/axllent/mailpit) with a web interface is available as docker container. Container mailpit will start automatically when you will run all docker containers. Please check [cookiecutter-django Docker documentation](https://cookiecutter-django.readthedocs.io/en/latest/2-local-development/developing-locally-docker.html) for more details how to start all containers. With Mailpit running, to view messages that are sent by your application, open your browser and go to `http://127.0.0.1:8025` {%- else %} In development, it is often nice to be able to see emails that are being sent from your application. If you choose to use [Mailpit](https://github.com/axllent/mailpit) when generating the project a local SMTP server with a web interface will be available. 1. [Download the latest Mailpit release](https://github.com/axllent/mailpit/releases) for your OS. 2. Copy the binary file to the project root. 3. Make it executable: chmod +x mailpit 4. Spin up another terminal window and start it there: ./mailpit 5. Check out 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 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](https://cookiecutter-django.readthedocs.io/en/latest/3-deployment/deployment-on-heroku.html). {%- endif %} {%- if cookiecutter.use_docker.lower() == "y" %} ### Docker See detailed [cookiecutter-django Docker documentation](https://cookiecutter-django.readthedocs.io/en/latest/3-deployment/deployment-with-docker.html). {%- endif %} {%- if cookiecutter.frontend_pipeline in ['Gulp', 'Webpack'] %} ### 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/v5.1.3/scss/_variables.scss), or get explanations on them in the [Bootstrap docs](https://getbootstrap.com/docs/5.1/customize/sass/). Bootstrap's javascript as well as its dependencies are concatenated into a single file: `static/js/vendors.js`. {%- endif %} ================================================ FILE: {{cookiecutter.project_slug}}/bin/post_compile ================================================ #!/usr/bin/env bash {%- if cookiecutter.frontend_pipeline == "Django Compressor" %} compress_enabled() { python << END import sys from environ import Env env = Env(COMPRESS_ENABLED=(bool, True)) if env('COMPRESS_ENABLED'): sys.exit(0) else: sys.exit(1) END } if compress_enabled then python manage.py compress fi {%- endif %} python manage.py collectstatic --noinput python manage.py compilemessages -i site-packages ================================================ FILE: {{cookiecutter.project_slug}}/compose/local/django/Dockerfile ================================================ # define an alias for the specific python version used in this file. FROM ghcr.io/astral-sh/uv:python3.13-bookworm-slim AS python # Python build stage FROM python AS python-build-stage ARG APP_HOME=/app WORKDIR ${APP_HOME} # we need to move the virtualenv outside of the $APP_HOME directory because it will be overriden by the docker compose mount ENV UV_COMPILE_BYTECODE=1 UV_LINK_MODE=copy UV_PYTHON_DOWNLOADS=0 # Install apt packages RUN apt-get update && apt-get install --no-install-recommends -y \ # dependencies for building Python packages build-essential \ # psycopg dependencies libpq-dev \ gettext \ wait-for-it # Requirements are installed here to ensure they will be cached. RUN --mount=type=cache,target=/root/.cache/uv \ --mount=type=bind,source=pyproject.toml,target=pyproject.toml \ --mount=type=bind,source=uv.lock,target=uv.lock:rw \ uv sync --no-install-project COPY . ${APP_HOME} RUN --mount=type=cache,target=/root/.cache/uv \ --mount=type=bind,source=pyproject.toml,target=pyproject.toml \ --mount=type=bind,source=uv.lock,target=uv.lock:rw \ uv sync # devcontainer dependencies and utils RUN apt-get update && apt-get install --no-install-recommends -y \ sudo git bash-completion nano ssh # Create devcontainer user and add it to sudoers RUN groupadd --gid 1000 dev-user \ && useradd --uid 1000 --gid dev-user --shell /bin/bash --create-home dev-user \ && echo dev-user ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/dev-user \ && chmod 0440 /etc/sudoers.d/dev-user ENV PATH="/${APP_HOME}/.venv/bin:$PATH" ENV PYTHONPATH="${APP_HOME}/.venv/lib/python3.13/site-packages:$PYTHONPATH" COPY ./compose/production/django/entrypoint /entrypoint RUN sed -i 's/\r$//g' /entrypoint RUN chmod +x /entrypoint COPY ./compose/local/django/start /start RUN sed -i 's/\r$//g' /start RUN chmod +x /start {% if cookiecutter.use_celery == "y" %} COPY ./compose/local/django/celery/worker/start /start-celeryworker RUN sed -i 's/\r$//g' /start-celeryworker RUN chmod +x /start-celeryworker COPY ./compose/local/django/celery/beat/start /start-celerybeat RUN sed -i 's/\r$//g' /start-celerybeat RUN chmod +x /start-celerybeat COPY ./compose/local/django/celery/flower/start /start-flower RUN sed -i 's/\r$//g' /start-flower RUN chmod +x /start-flower {% endif %} ENTRYPOINT ["/entrypoint"] ================================================ FILE: {{cookiecutter.project_slug}}/compose/local/django/celery/beat/start ================================================ #!/bin/bash set -o errexit set -o nounset rm -f './celerybeat.pid' exec watchfiles --filter python celery.__main__.main --args '-A config.celery_app beat -l INFO' ================================================ FILE: {{cookiecutter.project_slug}}/compose/local/django/celery/flower/start ================================================ #!/bin/bash set -o errexit set -o nounset until timeout 10 celery -A config.celery_app inspect ping; do >&2 echo "Celery workers not available" done echo 'Starting flower' exec watchfiles --filter python celery.__main__.main \ --args \ "-A config.celery_app -b \"${REDIS_URL}\" flower --basic_auth=\"${CELERY_FLOWER_USER}:${CELERY_FLOWER_PASSWORD}\"" ================================================ FILE: {{cookiecutter.project_slug}}/compose/local/django/celery/worker/start ================================================ #!/bin/bash set -o errexit set -o nounset exec watchfiles --filter python celery.__main__.main --args '-A config.celery_app worker -l INFO' ================================================ FILE: {{cookiecutter.project_slug}}/compose/local/django/start ================================================ #!/bin/bash set -o errexit set -o pipefail set -o nounset python manage.py migrate {%- if cookiecutter.use_async == 'y' %} exec uvicorn config.asgi:application --host 0.0.0.0 --reload --reload-include '*.html' {%- else %} exec python manage.py runserver_plus 0.0.0.0:8000 {%- endif %} ================================================ FILE: {{cookiecutter.project_slug}}/compose/local/docs/Dockerfile ================================================ # define an alias for the specific python version used in this file. FROM ghcr.io/astral-sh/uv:python3.13-bookworm-slim AS python # Python build stage FROM python AS python-build-stage ARG APP_HOME=/app WORKDIR ${APP_HOME} RUN apt-get update && apt-get install --no-install-recommends -y \ # dependencies for building Python packages build-essential \ # psycopg dependencies 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. RUN --mount=type=cache,target=/root/.cache/uv \ --mount=type=bind,source=uv.lock,target=uv.lock \ --mount=type=bind,source=pyproject.toml,target=pyproject.toml \ uv sync --no-install-project COPY . ${APP_HOME} RUN --mount=type=cache,target=/root/.cache/uv \ uv sync # 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 \ # psycopg 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 --chown=app:app /app /app COPY ./compose/local/docs/start /start-docs RUN sed -i 's/\r$//g' /start-docs RUN chmod +x /start-docs ENV PATH="/app/.venv/bin:$PATH" WORKDIR /docs ================================================ FILE: {{cookiecutter.project_slug}}/compose/local/docs/start ================================================ #!/bin/bash set -o errexit set -o pipefail set -o nounset exec make livehtml ================================================ FILE: {{cookiecutter.project_slug}}/compose/local/node/Dockerfile ================================================ FROM docker.io/node:24.14-bookworm-slim WORKDIR /app COPY ./package.json /app RUN npm install && npm cache clean --force ENV PATH=./node_modules/.bin/:$PATH ================================================ FILE: {{cookiecutter.project_slug}}/compose/local/uv/Dockerfile ================================================ FROM ghcr.io/astral-sh/uv:python3.13-bookworm-slim AS python ARG APP_HOME=/app WORKDIR ${APP_HOME} ================================================ FILE: {{cookiecutter.project_slug}}/compose/production/aws/Dockerfile ================================================ FROM docker.io/amazon/aws-cli:2.34.0 # Clear entrypoint from the base image, otherwise it's always calling the aws CLI ENTRYPOINT [] CMD ["/bin/bash"] COPY ./compose/production/aws/maintenance /usr/local/bin/maintenance COPY ./compose/production/postgres/maintenance/_sourced /usr/local/bin/maintenance/_sourced RUN chmod +x /usr/local/bin/maintenance/* RUN mv /usr/local/bin/maintenance/* /usr/local/bin \ && rmdir /usr/local/bin/maintenance ================================================ FILE: {{cookiecutter.project_slug}}/compose/production/aws/maintenance/download ================================================ #!/bin/sh ### Download a file from your Amazon S3 bucket to the postgres /backups folder ### ### Usage: ### $ docker compose -f docker-compose.production.yml run --rm awscli <1> set -o errexit set -o pipefail set -o nounset working_dir="$(dirname ${0})" source "${working_dir}/_sourced/constants.sh" source "${working_dir}/_sourced/messages.sh" export AWS_ACCESS_KEY_ID="${DJANGO_AWS_ACCESS_KEY_ID}" export AWS_SECRET_ACCESS_KEY="${DJANGO_AWS_SECRET_ACCESS_KEY}" export AWS_STORAGE_BUCKET_NAME="${DJANGO_AWS_STORAGE_BUCKET_NAME}" aws s3 cp s3://${AWS_STORAGE_BUCKET_NAME}${BACKUP_DIR_PATH}/${1} ${BACKUP_DIR_PATH}/${1} message_success "Finished downloading ${1}." ================================================ FILE: {{cookiecutter.project_slug}}/compose/production/aws/maintenance/upload ================================================ #!/bin/sh ### Upload the /backups folder to Amazon S3 ### ### Usage: ### $ docker compose -f docker-compose.production.yml run --rm awscli upload set -o errexit set -o pipefail set -o nounset working_dir="$(dirname ${0})" source "${working_dir}/_sourced/constants.sh" source "${working_dir}/_sourced/messages.sh" export AWS_ACCESS_KEY_ID="${DJANGO_AWS_ACCESS_KEY_ID}" export AWS_SECRET_ACCESS_KEY="${DJANGO_AWS_SECRET_ACCESS_KEY}" export AWS_STORAGE_BUCKET_NAME="${DJANGO_AWS_STORAGE_BUCKET_NAME}" message_info "Upload the backups directory to S3 bucket {$AWS_STORAGE_BUCKET_NAME}" aws s3 cp ${BACKUP_DIR_PATH} s3://${AWS_STORAGE_BUCKET_NAME}${BACKUP_DIR_PATH} --recursive message_info "Cleaning the directory ${BACKUP_DIR_PATH}" rm -rf ${BACKUP_DIR_PATH}/* message_success "Finished uploading and cleaning." ================================================ FILE: {{cookiecutter.project_slug}}/compose/production/django/Dockerfile ================================================ {% if cookiecutter.frontend_pipeline in ['Gulp', 'Webpack'] -%} FROM docker.io/node:24.14-bookworm-slim AS client-builder ARG APP_HOME=/app WORKDIR ${APP_HOME} COPY ./package.json ${APP_HOME} RUN npm install && npm cache clean --force COPY . ${APP_HOME} {%- if cookiecutter.frontend_pipeline == 'Webpack' and cookiecutter.use_whitenoise == 'n' %} {%- if cookiecutter.cloud_provider == 'AWS' %} ARG DJANGO_AWS_STORAGE_BUCKET_NAME ENV DJANGO_AWS_STORAGE_BUCKET_NAME=${DJANGO_AWS_STORAGE_BUCKET_NAME} ARG DJANGO_AWS_S3_CUSTOM_DOMAIN ENV DJANGO_AWS_S3_CUSTOM_DOMAIN=${DJANGO_AWS_S3_CUSTOM_DOMAIN} {%- elif cookiecutter.cloud_provider == 'GCP' %} ARG DJANGO_GCP_STORAGE_BUCKET_NAME ENV DJANGO_GCP_STORAGE_BUCKET_NAME=${DJANGO_GCP_STORAGE_BUCKET_NAME} {%- elif cookiecutter.cloud_provider == 'Azure' %} ARG DJANGO_AZURE_ACCOUNT_NAME ENV DJANGO_AZURE_ACCOUNT_NAME=${DJANGO_AZURE_ACCOUNT_NAME} {%- endif %} {%- endif %} RUN npm run build {%- endif %} # define an alias for the specific python version used in this file. FROM ghcr.io/astral-sh/uv:python3.13-bookworm-slim AS python-build-stage ENV UV_COMPILE_BYTECODE=1 UV_LINK_MODE=copy UV_PYTHON_DOWNLOADS=0 ARG APP_HOME=/app WORKDIR ${APP_HOME} # Install apt packages RUN apt-get update && apt-get install --no-install-recommends -y \ # dependencies for building Python packages build-essential \ # psycopg dependencies libpq-dev # Requirements are installed here to ensure they will be cached. RUN --mount=type=cache,target=/root/.cache/uv \ --mount=type=bind,source=uv.lock,target=uv.lock \ --mount=type=bind,source=pyproject.toml,target=pyproject.toml \ uv sync --locked --no-install-project --no-dev {%- if cookiecutter.frontend_pipeline in ['Gulp', 'Webpack'] %} COPY --from=client-builder ${APP_HOME} ${APP_HOME} {% else %} COPY . ${APP_HOME} {%- endif %} RUN --mount=type=cache,target=/root/.cache/uv \ --mount=type=bind,source=uv.lock,target=uv.lock \ --mount=type=bind,source=pyproject.toml,target=pyproject.toml \ uv sync --locked --no-dev # Python 'run' stage FROM python:3.13-slim-bookworm AS python-run-stage ARG APP_HOME=/app WORKDIR ${APP_HOME} RUN addgroup --system django \ && adduser --system --ingroup django django # Install required system dependencies RUN apt-get update && apt-get install --no-install-recommends -y \ # psycopg dependencies libpq-dev \ # Translations dependencies gettext \ # entrypoint wait-for-it \ # cleaning up unused files && apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \ && rm -rf /var/lib/apt/lists/* COPY --chown=django:django ./compose/production/django/entrypoint /entrypoint RUN sed -i 's/\r$//g' /entrypoint RUN chmod +x /entrypoint COPY --chown=django:django ./compose/production/django/start /start RUN sed -i 's/\r$//g' /start RUN chmod +x /start {%- if cookiecutter.use_celery == "y" %} COPY --chown=django:django ./compose/production/django/celery/worker/start /start-celeryworker RUN sed -i 's/\r$//g' /start-celeryworker RUN chmod +x /start-celeryworker COPY --chown=django:django ./compose/production/django/celery/beat/start /start-celerybeat RUN sed -i 's/\r$//g' /start-celerybeat RUN chmod +x /start-celerybeat COPY --chown=django:django ./compose/production/django/celery/flower/start /start-flower RUN sed -i 's/\r$//g' /start-flower RUN chmod +x /start-flower {%- endif %} # Copy the application from the builder COPY --from=python-build-stage --chown=django:django ${APP_HOME} ${APP_HOME} {%- if cookiecutter.cloud_provider == 'None' %} # explicitly create the media folder before changing ownership below RUN mkdir -p ${APP_HOME}/{{ cookiecutter.project_slug }}/media {%- endif %} # make django owner of the WORKDIR directory as well. RUN chown django:django ${APP_HOME} # Place executables in the environment at the front of the path ENV PATH="/app/.venv/bin:$PATH" USER django RUN DATABASE_URL="" \ DJANGO_SETTINGS_MODULE="config.settings.test" \ python manage.py compilemessages ENTRYPOINT ["/entrypoint"] ================================================ FILE: {{cookiecutter.project_slug}}/compose/production/django/celery/beat/start ================================================ #!/bin/bash set -o errexit set -o pipefail set -o nounset exec celery -A config.celery_app beat -l INFO ================================================ FILE: {{cookiecutter.project_slug}}/compose/production/django/celery/flower/start ================================================ #!/bin/bash set -o errexit set -o nounset until timeout 10 celery -A config.celery_app inspect ping; do >&2 echo "Celery workers not available" done echo 'Starting flower' exec celery \ -A config.celery_app \ -b "${REDIS_URL}" \ flower \ --basic_auth="${CELERY_FLOWER_USER}:${CELERY_FLOWER_PASSWORD}" ================================================ FILE: {{cookiecutter.project_slug}}/compose/production/django/celery/worker/start ================================================ #!/bin/bash set -o errexit set -o pipefail set -o nounset exec celery -A config.celery_app worker -l INFO ================================================ FILE: {{cookiecutter.project_slug}}/compose/production/django/entrypoint ================================================ #!/bin/bash set -o errexit set -o pipefail set -o nounset if [ -z "${POSTGRES_USER}" ]; then base_postgres_image_default_user='postgres' export POSTGRES_USER="${base_postgres_image_default_user}" fi export DATABASE_URL="postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}" wait-for-it "${POSTGRES_HOST}:${POSTGRES_PORT}" -t 30 >&2 echo 'PostgreSQL is available' exec "$@" ================================================ FILE: {{cookiecutter.project_slug}}/compose/production/django/start ================================================ #!/bin/bash set -o errexit set -o pipefail set -o nounset python /app/manage.py collectstatic --noinput {% if cookiecutter.use_whitenoise == 'y' and cookiecutter.frontend_pipeline == 'Django Compressor' %} compress_enabled() { python << END import sys from environ import Env env = Env(COMPRESS_ENABLED=(bool, True)) if env('COMPRESS_ENABLED'): sys.exit(0) else: sys.exit(1) END } if compress_enabled; then # NOTE this command will fail if django-compressor is disabled python /app/manage.py compress fi {%- endif %} {%- if cookiecutter.use_async == 'y' %} exec gunicorn config.asgi --bind 0.0.0.0:5000 --chdir=/app -k uvicorn_worker.UvicornWorker {%- else %} exec gunicorn config.wsgi --bind 0.0.0.0:5000 --chdir=/app {%- endif %} ================================================ FILE: {{cookiecutter.project_slug}}/compose/production/nginx/Dockerfile ================================================ FROM docker.io/nginx:1.29.6-alpine COPY ./compose/production/nginx/default.conf /etc/nginx/conf.d/default.conf ================================================ FILE: {{cookiecutter.project_slug}}/compose/production/nginx/default.conf ================================================ server { listen 80; server_name localhost; location /media/ { alias /usr/share/nginx/media/; } } ================================================ FILE: {{cookiecutter.project_slug}}/compose/production/postgres/Dockerfile ================================================ FROM docker.io/postgres:{{ cookiecutter.postgresql_version }} COPY ./compose/production/postgres/maintenance /usr/local/bin/maintenance RUN chmod +x /usr/local/bin/maintenance/* RUN mv /usr/local/bin/maintenance/* /usr/local/bin \ && rmdir /usr/local/bin/maintenance ================================================ FILE: {{cookiecutter.project_slug}}/compose/production/postgres/maintenance/_sourced/constants.sh ================================================ #!/usr/bin/env bash BACKUP_DIR_PATH='/backups' BACKUP_FILE_PREFIX='backup' ================================================ FILE: {{cookiecutter.project_slug}}/compose/production/postgres/maintenance/_sourced/countdown.sh ================================================ #!/usr/bin/env bash countdown() { declare desc="A simple countdown. Source: https://superuser.com/a/611582" local seconds="${1}" local d=$(($(date +%s) + "${seconds}")) while [ "$d" -ge `date +%s` ]; do echo -ne "$(date -u --date @$(($d - `date +%s`)) +%H:%M:%S)\r"; sleep 0.1 done } ================================================ FILE: {{cookiecutter.project_slug}}/compose/production/postgres/maintenance/_sourced/messages.sh ================================================ #!/usr/bin/env bash message_newline() { echo } message_debug() { echo -e "DEBUG: ${@}" } message_welcome() { echo -e "\e[1m${@}\e[0m" } message_warning() { echo -e "\e[33mWARNING\e[0m: ${@}" } message_error() { echo -e "\e[31mERROR\e[0m: ${@}" } message_info() { echo -e "\e[37mINFO\e[0m: ${@}" } message_suggestion() { echo -e "\e[33mSUGGESTION\e[0m: ${@}" } message_success() { echo -e "\e[32mSUCCESS\e[0m: ${@}" } ================================================ FILE: {{cookiecutter.project_slug}}/compose/production/postgres/maintenance/_sourced/yes_no.sh ================================================ #!/usr/bin/env bash yes_no() { declare desc="Prompt for confirmation. \$\"\{1\}\": confirmation message." local arg1="${1}" local response= read -r -p "${arg1} (y/[n])? " response if [[ "${response}" =~ ^[Yy]$ ]] then exit 0 else exit 1 fi } ================================================ FILE: {{cookiecutter.project_slug}}/compose/production/postgres/maintenance/backup ================================================ #!/usr/bin/env bash ### Create a database backup. ### ### Usage: ### $ docker compose -f .yml (exec |run --rm) postgres backup set -o errexit set -o pipefail set -o nounset working_dir="$(dirname ${0})" source "${working_dir}/_sourced/constants.sh" source "${working_dir}/_sourced/messages.sh" message_welcome "Backing up the '${POSTGRES_DB}' database..." if [[ "${POSTGRES_USER}" == "postgres" ]]; then message_error "Backing up as 'postgres' user is not supported. Assign 'POSTGRES_USER' env with another one and try again." exit 1 fi export PGHOST="${POSTGRES_HOST}" export PGPORT="${POSTGRES_PORT}" export PGUSER="${POSTGRES_USER}" export PGPASSWORD="${POSTGRES_PASSWORD}" export PGDATABASE="${POSTGRES_DB}" backup_filename="${BACKUP_FILE_PREFIX}_$(date +'%Y_%m_%dT%H_%M_%S').sql.gz" pg_dump | gzip > "${BACKUP_DIR_PATH}/${backup_filename}" message_success "'${POSTGRES_DB}' database backup '${backup_filename}' has been created and placed in '${BACKUP_DIR_PATH}'." ================================================ FILE: {{cookiecutter.project_slug}}/compose/production/postgres/maintenance/backups ================================================ #!/usr/bin/env bash ### View backups. ### ### Usage: ### $ docker compose -f .yml (exec |run --rm) postgres backups set -o errexit set -o pipefail set -o nounset working_dir="$(dirname ${0})" source "${working_dir}/_sourced/constants.sh" source "${working_dir}/_sourced/messages.sh" message_welcome "These are the backups you have got:" ls -lht "${BACKUP_DIR_PATH}" ================================================ FILE: {{cookiecutter.project_slug}}/compose/production/postgres/maintenance/restore ================================================ #!/usr/bin/env bash ### Restore database from a backup. ### ### Parameters: ### <1> filename of an existing backup. ### ### Usage: ### $ docker compose -f .yml (exec |run --rm) postgres restore <1> set -o errexit set -o pipefail set -o nounset working_dir="$(dirname ${0})" source "${working_dir}/_sourced/constants.sh" source "${working_dir}/_sourced/messages.sh" if [[ -z ${1+x} ]]; then message_error "Backup filename is not specified yet it is a required parameter. Make sure you provide one and try again." exit 1 fi backup_filename="${BACKUP_DIR_PATH}/${1}" if [[ ! -f "${backup_filename}" ]]; then message_error "No backup with the specified filename found. Check out the 'backups' maintenance script output to see if there is one and try again." exit 1 fi message_welcome "Restoring the '${POSTGRES_DB}' database from the '${backup_filename}' backup..." if [[ "${POSTGRES_USER}" == "postgres" ]]; then message_error "Restoring as 'postgres' user is not supported. Assign 'POSTGRES_USER' env with another one and try again." exit 1 fi export PGHOST="${POSTGRES_HOST}" export PGPORT="${POSTGRES_PORT}" export PGUSER="${POSTGRES_USER}" export PGPASSWORD="${POSTGRES_PASSWORD}" export PGDATABASE="${POSTGRES_DB}" message_info "Dropping the database..." dropdb "${PGDATABASE}" message_info "Creating a new database..." createdb --owner="${POSTGRES_USER}" message_info "Applying the backup to the new database..." gunzip -c "${backup_filename}" | psql "${POSTGRES_DB}" message_success "The '${POSTGRES_DB}' database has been restored from the '${backup_filename}' backup." ================================================ FILE: {{cookiecutter.project_slug}}/compose/production/postgres/maintenance/rmbackup ================================================ #!/usr/bin/env bash ### Remove a database backup. ### ### Parameters: ### <1> filename of a backup to remove. ### ### Usage: ### $ docker-compose -f .yml (exec |run --rm) postgres rmbackup <1> set -o errexit set -o pipefail set -o nounset working_dir="$(dirname ${0})" source "${working_dir}/_sourced/constants.sh" source "${working_dir}/_sourced/messages.sh" if [[ -z ${1+x} ]]; then message_error "Backup filename is not specified yet it is a required parameter. Make sure you provide one and try again." exit 1 fi backup_filename="${BACKUP_DIR_PATH}/${1}" if [[ ! -f "${backup_filename}" ]]; then message_error "No backup with the specified filename found. Check out the 'backups' maintenance script output to see if there is one and try again." exit 1 fi message_welcome "Removing the '${backup_filename}' backup file..." rm -r "${backup_filename}" message_success "The '${backup_filename}' database backup has been removed." ================================================ FILE: {{cookiecutter.project_slug}}/compose/production/traefik/Dockerfile ================================================ FROM docker.io/traefik:v3.6.11 RUN mkdir -p /etc/traefik/acme \ && touch /etc/traefik/acme/acme.json \ && chmod 600 /etc/traefik/acme/acme.json COPY ./compose/production/traefik/traefik.yml /etc/traefik ================================================ FILE: {{cookiecutter.project_slug}}/compose/production/traefik/traefik.yml ================================================ log: level: INFO entryPoints: web: # http address: ':80' http: # https://doc.traefik.io/traefik/routing/entrypoints/#entrypoint redirections: entryPoint: to: web-secure web-secure: # https address: ':443' {%- if cookiecutter.use_celery == 'y' %} flower: address: ':5555' {%- endif %} certificatesResolvers: letsencrypt: # https://doc.traefik.io/traefik/https/acme/#lets-encrypt acme: email: '{{ cookiecutter.email }}' storage: /etc/traefik/acme/acme.json # https://doc.traefik.io/traefik/https/acme/#httpchallenge httpChallenge: entryPoint: web http: routers: web-secure-router: {%- if cookiecutter.domain_name.count('.') == 1 %} rule: 'Host(`{{ cookiecutter.domain_name }}`) || Host(`www.{{ cookiecutter.domain_name }}`)' {%- else %} rule: 'Host(`{{ cookiecutter.domain_name }}`)' {%- endif %} entryPoints: - web-secure middlewares: - csrf service: django tls: # https://doc.traefik.io/traefik/routing/routers/#certresolver certResolver: letsencrypt {%- if cookiecutter.use_celery == 'y' %} flower-secure-router: rule: 'Host(`{{ cookiecutter.domain_name }}`)' entryPoints: - flower service: flower tls: # https://doc.traefik.io/traefik/master/routing/routers/#certresolver certResolver: letsencrypt {%- endif %} {%- if cookiecutter.cloud_provider == 'None' %} web-media-router: {%- if cookiecutter.domain_name.count('.') == 1 %} rule: '(Host(`{{ cookiecutter.domain_name }}`) || Host(`www.{{ cookiecutter.domain_name }}`)) && PathPrefix(`/media/`)' {%- else %} rule: 'Host(`{{ cookiecutter.domain_name }}`) && PathPrefix(`/media/`)' {%- endif %} entryPoints: - web-secure middlewares: - csrf service: django-media tls: certResolver: letsencrypt {%- endif %} middlewares: csrf: # https://doc.traefik.io/traefik/master/middlewares/http/headers/#hostsproxyheaders # https://docs.djangoproject.com/en/dev/ref/csrf/#ajax headers: hostsProxyHeaders: ['X-CSRFToken'] services: django: loadBalancer: servers: - url: http://django:5000 {%- if cookiecutter.use_celery == 'y' %} flower: loadBalancer: servers: - url: http://flower:5555 {%- endif %} {%- if cookiecutter.cloud_provider == 'None' %} django-media: loadBalancer: servers: - url: http://nginx:80 {%- endif %} providers: # https://doc.traefik.io/traefik/master/providers/file/ file: filename: /etc/traefik/traefik.yml watch: true ================================================ FILE: {{cookiecutter.project_slug}}/config/__init__.py ================================================ {% if cookiecutter.use_celery == 'y' -%} # This will make sure the app is always imported when # Django starts so that shared_task will use this app. from .celery_app import app as celery_app __all__ = ("celery_app",) {% endif -%} ================================================ FILE: {{cookiecutter.project_slug}}/config/api.py ================================================ from django.contrib.admin.views.decorators import staff_member_required from ninja import NinjaAPI from ninja.security import SessionAuth api = NinjaAPI( urls_namespace="api", auth=SessionAuth(), docs_decorator=staff_member_required, ) api.add_router("/users/", "{{ cookiecutter.project_slug }}.users.api.views.router") ================================================ FILE: {{cookiecutter.project_slug}}/config/api_router.py ================================================ from django.conf import settings from rest_framework.routers import DefaultRouter from rest_framework.routers import SimpleRouter from {{ cookiecutter.project_slug }}.users.api.views import UserViewSet router = DefaultRouter() if settings.DEBUG else SimpleRouter() router.register("users", UserViewSet) app_name = "api" urlpatterns = router.urls ================================================ FILE: {{cookiecutter.project_slug}}/config/asgi.py ================================================ """ ASGI config for {{ cookiecutter.project_name }} project. It exposes the ASGI callable as a module-level variable named ``application``. For more information on this file, see https://docs.djangoproject.com/en/dev/howto/deployment/asgi/ """ import os import sys from pathlib import Path from django.core.asgi import get_asgi_application # This allows easy placement of apps within the interior # {{ cookiecutter.project_slug }} directory. BASE_DIR = Path(__file__).resolve(strict=True).parent.parent sys.path.append(str(BASE_DIR / "{{ cookiecutter.project_slug }}")) # If DJANGO_SETTINGS_MODULE is unset, default to the local settings os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.local") # This application object is used by any ASGI server configured to use this file. django_application = get_asgi_application() # Import websocket application here, so apps from django_application are loaded first from config.websocket import websocket_application # noqa: E402 async def application(scope, receive, send): if scope["type"] == "http": await django_application(scope, receive, send) elif scope["type"] == "websocket": await websocket_application(scope, receive, send) else: msg = f"Unknown scope type {scope['type']}" raise NotImplementedError(msg) ================================================ FILE: {{cookiecutter.project_slug}}/config/celery_app.py ================================================ import os from celery import Celery from celery.signals import setup_logging # set the default Django settings module for the 'celery' program. os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.local") app = Celery("{{cookiecutter.project_slug}}") # Using a string here means the worker doesn't have to serialize # the configuration object to child processes. # - namespace='CELERY' means all celery-related configuration keys # should have a `CELERY_` prefix. app.config_from_object("django.conf:settings", namespace="CELERY") @setup_logging.connect def config_loggers(*args, **kwargs): from logging.config import dictConfig # noqa: PLC0415 from django.conf import settings # noqa: PLC0415 dictConfig(settings.LOGGING) # Load task modules from all registered Django app configs. app.autodiscover_tasks() ================================================ FILE: {{cookiecutter.project_slug}}/config/settings/__init__.py ================================================ ================================================ FILE: {{cookiecutter.project_slug}}/config/settings/base.py ================================================ # ruff: noqa: ERA001, E501 """Base settings to build other settings files upon.""" {% if cookiecutter.use_celery == 'y' %} import ssl {%- endif %} from pathlib import Path import environ BASE_DIR = Path(__file__).resolve(strict=True).parent.parent.parent # {{ cookiecutter.project_slug }}/ APPS_DIR = BASE_DIR / "{{ cookiecutter.project_slug }}" env = environ.Env() READ_DOT_ENV_FILE = env.bool("DJANGO_READ_DOT_ENV_FILE", default=False) if READ_DOT_ENV_FILE: # OS environment variables take precedence over variables from .env env.read_env(str(BASE_DIR / ".env")) # GENERAL # ------------------------------------------------------------------------------ # https://docs.djangoproject.com/en/dev/ref/settings/#debug DEBUG = env.bool("DJANGO_DEBUG", False) # Local time zone. Choices are # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name # though not all of them may be available with every OS. # In Windows, this must be set to your system time zone. TIME_ZONE = "{{ cookiecutter.timezone }}" # https://docs.djangoproject.com/en/dev/ref/settings/#language-code LANGUAGE_CODE = "en-us" # https://docs.djangoproject.com/en/dev/ref/settings/#languages # from django.utils.translation import gettext_lazy as _ # LANGUAGES = [ # ('en', _('English')), # ('fr-fr', _('French')), # ('pt-br', _('Portuguese')), # ] # https://docs.djangoproject.com/en/dev/ref/settings/#site-id SITE_ID = 1 # https://docs.djangoproject.com/en/dev/ref/settings/#use-i18n USE_I18N = True # https://docs.djangoproject.com/en/dev/ref/settings/#use-tz USE_TZ = True # https://docs.djangoproject.com/en/dev/ref/settings/#locale-paths LOCALE_PATHS = [str(BASE_DIR / "locale")] # DATABASES # ------------------------------------------------------------------------------ # https://docs.djangoproject.com/en/dev/ref/settings/#databases {% if cookiecutter.use_docker == "y" -%} DATABASES = {"default": env.db("DATABASE_URL")} {%- else %} DATABASES = { "default": env.db( "DATABASE_URL", default="postgres://{% if cookiecutter.windows == 'y' %}localhost{% endif %}/{{cookiecutter.project_slug}}", ), } {%- 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 # ------------------------------------------------------------------------------ # https://docs.djangoproject.com/en/dev/ref/settings/#root-urlconf ROOT_URLCONF = "config.urls" # https://docs.djangoproject.com/en/dev/ref/settings/#wsgi-application WSGI_APPLICATION = "config.wsgi.application" # APPS # ------------------------------------------------------------------------------ DJANGO_APPS = [ "django.contrib.auth", "django.contrib.contenttypes", "django.contrib.sessions", "django.contrib.sites", "django.contrib.messages", "django.contrib.staticfiles", # "django.contrib.humanize", # Handy template tags "django.contrib.admin", "django.forms", ] THIRD_PARTY_APPS = [ "crispy_forms", "crispy_bootstrap5", "allauth", "allauth.account", "allauth.mfa", "allauth.socialaccount", {%- if cookiecutter.use_celery == 'y' %} "django_celery_beat", {%- endif %} {%- if cookiecutter.rest_api == 'DRF' %} "rest_framework", "rest_framework.authtoken", "corsheaders", "drf_spectacular", {%- elif cookiecutter.rest_api == 'Django Ninja' %} "corsheaders", {%- endif %} {%- if cookiecutter.frontend_pipeline == 'Webpack' %} "webpack_loader", {%- endif %} ] LOCAL_APPS = [ "{{ cookiecutter.project_slug }}.users", # Your stuff: custom apps go here ] # https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS # MIGRATIONS # ------------------------------------------------------------------------------ # https://docs.djangoproject.com/en/dev/ref/settings/#migration-modules MIGRATION_MODULES = {"sites": "{{ cookiecutter.project_slug }}.contrib.sites.migrations"} # AUTHENTICATION # ------------------------------------------------------------------------------ # https://docs.djangoproject.com/en/dev/ref/settings/#authentication-backends AUTHENTICATION_BACKENDS = [ "django.contrib.auth.backends.ModelBackend", "allauth.account.auth_backends.AuthenticationBackend", ] # https://docs.djangoproject.com/en/dev/ref/settings/#auth-user-model AUTH_USER_MODEL = "users.User" # https://docs.djangoproject.com/en/dev/ref/settings/#login-redirect-url LOGIN_REDIRECT_URL = "users:redirect" # https://docs.djangoproject.com/en/dev/ref/settings/#login-url LOGIN_URL = "account_login" # PASSWORDS # ------------------------------------------------------------------------------ # https://docs.djangoproject.com/en/dev/ref/settings/#password-hashers PASSWORD_HASHERS = [ # https://docs.djangoproject.com/en/dev/topics/auth/passwords/#using-argon2-with-django "django.contrib.auth.hashers.Argon2PasswordHasher", "django.contrib.auth.hashers.PBKDF2PasswordHasher", "django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher", "django.contrib.auth.hashers.BCryptSHA256PasswordHasher", ] # https://docs.djangoproject.com/en/dev/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [ { "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", }, {"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator"}, {"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator"}, {"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator"}, ] # MIDDLEWARE # ------------------------------------------------------------------------------ # https://docs.djangoproject.com/en/dev/ref/settings/#middleware MIDDLEWARE = [ "django.middleware.security.SecurityMiddleware", {%- if cookiecutter.rest_api != 'None' %} "corsheaders.middleware.CorsMiddleware", {%- endif %} {%- if cookiecutter.use_whitenoise == 'y' %} "whitenoise.middleware.WhiteNoiseMiddleware", {%- endif %} "django.contrib.sessions.middleware.SessionMiddleware", "django.middleware.locale.LocaleMiddleware", "django.middleware.common.CommonMiddleware", "django.middleware.csrf.CsrfViewMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware", "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", "allauth.account.middleware.AccountMiddleware", ] # STATIC # ------------------------------------------------------------------------------ # https://docs.djangoproject.com/en/dev/ref/settings/#static-root STATIC_ROOT = str(BASE_DIR / "staticfiles") # https://docs.djangoproject.com/en/dev/ref/settings/#static-url STATIC_URL = "/static/" # https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#std:setting-STATICFILES_DIRS STATICFILES_DIRS = [str(APPS_DIR / "static")] # https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#staticfiles-finders STATICFILES_FINDERS = [ "django.contrib.staticfiles.finders.FileSystemFinder", "django.contrib.staticfiles.finders.AppDirectoriesFinder", ] # MEDIA # ------------------------------------------------------------------------------ # https://docs.djangoproject.com/en/dev/ref/settings/#media-root MEDIA_ROOT = str(APPS_DIR / "media") # https://docs.djangoproject.com/en/dev/ref/settings/#media-url MEDIA_URL = "/media/" # TEMPLATES # ------------------------------------------------------------------------------ # https://docs.djangoproject.com/en/dev/ref/settings/#templates 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/#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-context-processors "context_processors": [ "django.template.context_processors.debug", "django.template.context_processors.request", "django.contrib.auth.context_processors.auth", "django.template.context_processors.i18n", "django.template.context_processors.media", "django.template.context_processors.static", "django.template.context_processors.tz", "django.contrib.messages.context_processors.messages", "{{cookiecutter.project_slug}}.users.context_processors.allauth_settings", ], }, }, ] # https://docs.djangoproject.com/en/dev/ref/settings/#form-renderer FORM_RENDERER = "django.forms.renderers.TemplatesSetting" # http://django-crispy-forms.readthedocs.io/en/latest/install.html#template-packs CRISPY_TEMPLATE_PACK = "bootstrap5" CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5" # FIXTURES # ------------------------------------------------------------------------------ # https://docs.djangoproject.com/en/dev/ref/settings/#fixture-dirs FIXTURE_DIRS = (str(APPS_DIR / "fixtures"),) # SECURITY # ------------------------------------------------------------------------------ # https://docs.djangoproject.com/en/dev/ref/settings/#session-cookie-httponly SESSION_COOKIE_HTTPONLY = True # https://docs.djangoproject.com/en/dev/ref/settings/#csrf-cookie-httponly CSRF_COOKIE_HTTPONLY = True # https://docs.djangoproject.com/en/dev/ref/settings/#x-frame-options X_FRAME_OPTIONS = "DENY" # EMAIL # ------------------------------------------------------------------------------ # https://docs.djangoproject.com/en/dev/ref/settings/#email-backend EMAIL_BACKEND = env( "DJANGO_EMAIL_BACKEND", default="django.core.mail.backends.smtp.EmailBackend", ) # https://docs.djangoproject.com/en/dev/ref/settings/#email-timeout EMAIL_TIMEOUT = 5 # ADMIN # ------------------------------------------------------------------------------ # Django Admin URL. ADMIN_URL = "admin/" # https://docs.djangoproject.com/en/dev/ref/settings/#admins ADMINS = ['"{{cookiecutter.author_name}}" <{{cookiecutter.email}}>'] # https://docs.djangoproject.com/en/dev/ref/settings/#managers MANAGERS = ADMINS # https://cookiecutter-django.readthedocs.io/en/latest/settings.html#other-environment-settings # Force the `admin` sign in process to go through the `django-allauth` workflow DJANGO_ADMIN_FORCE_ALLAUTH = env.bool("DJANGO_ADMIN_FORCE_ALLAUTH", default=False) # LOGGING # ------------------------------------------------------------------------------ # https://docs.djangoproject.com/en/dev/ref/settings/#logging # See https://docs.djangoproject.com/en/dev/topics/logging for # more details on how to customize your logging configuration. LOGGING = { "version": 1, "disable_existing_loggers": False, "formatters": { "verbose": { "format": "%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s", }, }, "handlers": { "console": { "level": "DEBUG", "class": "logging.StreamHandler", "formatter": "verbose", }, }, "root": {"level": "INFO", "handlers": ["console"]}, } REDIS_URL = env("REDIS_URL", default="redis://{% if cookiecutter.use_docker == 'y' %}redis{%else%}localhost{% endif %}:6379/0") REDIS_SSL = REDIS_URL.startswith("rediss://") {% if cookiecutter.use_celery == 'y' -%} # Celery # ------------------------------------------------------------------------------ if USE_TZ: # https://docs.celeryq.dev/en/stable/userguide/configuration.html#std:setting-timezone CELERY_TIMEZONE = TIME_ZONE # https://docs.celeryq.dev/en/stable/userguide/configuration.html#std:setting-broker_url CELERY_BROKER_URL = REDIS_URL # https://docs.celeryq.dev/en/stable/userguide/configuration.html#redis-backend-use-ssl CELERY_BROKER_USE_SSL = {"ssl_cert_reqs": ssl.CERT_NONE} if REDIS_SSL else None # https://docs.celeryq.dev/en/stable/userguide/configuration.html#std:setting-result_backend CELERY_RESULT_BACKEND = REDIS_URL # https://docs.celeryq.dev/en/stable/userguide/configuration.html#redis-backend-use-ssl CELERY_REDIS_BACKEND_USE_SSL = CELERY_BROKER_USE_SSL # https://docs.celeryq.dev/en/stable/userguide/configuration.html#result-extended CELERY_RESULT_EXTENDED = True # https://docs.celeryq.dev/en/stable/userguide/configuration.html#result-backend-always-retry # https://github.com/celery/celery/pull/6122 CELERY_RESULT_BACKEND_ALWAYS_RETRY = True # https://docs.celeryq.dev/en/stable/userguide/configuration.html#result-backend-max-retries CELERY_RESULT_BACKEND_MAX_RETRIES = 10 # https://docs.celeryq.dev/en/stable/userguide/configuration.html#std:setting-accept_content CELERY_ACCEPT_CONTENT = ["json"] # https://docs.celeryq.dev/en/stable/userguide/configuration.html#std:setting-task_serializer CELERY_TASK_SERIALIZER = "json" # https://docs.celeryq.dev/en/stable/userguide/configuration.html#std:setting-result_serializer CELERY_RESULT_SERIALIZER = "json" # https://docs.celeryq.dev/en/stable/userguide/configuration.html#task-time-limit # TODO: set to whatever value is adequate in your circumstances CELERY_TASK_TIME_LIMIT = 5 * 60 # https://docs.celeryq.dev/en/stable/userguide/configuration.html#task-soft-time-limit # TODO: set to whatever value is adequate in your circumstances CELERY_TASK_SOFT_TIME_LIMIT = 60 # https://docs.celeryq.dev/en/stable/userguide/configuration.html#beat-scheduler CELERY_BEAT_SCHEDULER = "django_celery_beat.schedulers:DatabaseScheduler" # https://docs.celeryq.dev/en/stable/userguide/configuration.html#worker-send-task-events CELERY_WORKER_SEND_TASK_EVENTS = True # https://docs.celeryq.dev/en/stable/userguide/configuration.html#std-setting-task_send_sent_event CELERY_TASK_SEND_SENT_EVENT = True # https://docs.celeryq.dev/en/stable/userguide/configuration.html#worker-hijack-root-logger CELERY_WORKER_HIJACK_ROOT_LOGGER = False {%- endif %} # django-allauth # ------------------------------------------------------------------------------ ACCOUNT_ALLOW_REGISTRATION = env.bool("DJANGO_ACCOUNT_ALLOW_REGISTRATION", True) # https://docs.allauth.org/en/latest/account/configuration.html ACCOUNT_LOGIN_METHODS = {"{{cookiecutter.username_type}}"} # https://docs.allauth.org/en/latest/account/configuration.html {%- if cookiecutter.username_type == "username" %} ACCOUNT_SIGNUP_FIELDS = ["email*", "username*", "password1*", "password2*"] {%- else %} ACCOUNT_SIGNUP_FIELDS = ["email*", "password1*", "password2*"] # https://docs.allauth.org/en/latest/account/configuration.html ACCOUNT_USER_MODEL_USERNAME_FIELD = None {%- endif %} # https://docs.allauth.org/en/latest/account/configuration.html ACCOUNT_EMAIL_VERIFICATION = "mandatory" # https://docs.allauth.org/en/latest/account/configuration.html ACCOUNT_ADAPTER = "{{cookiecutter.project_slug}}.users.adapters.AccountAdapter" # https://docs.allauth.org/en/latest/account/forms.html ACCOUNT_FORMS = {"signup": "{{cookiecutter.project_slug}}.users.forms.UserSignupForm"} # https://docs.allauth.org/en/latest/socialaccount/configuration.html SOCIALACCOUNT_ADAPTER = "{{cookiecutter.project_slug}}.users.adapters.SocialAccountAdapter" # https://docs.allauth.org/en/latest/socialaccount/configuration.html SOCIALACCOUNT_FORMS = {"signup": "{{cookiecutter.project_slug}}.users.forms.UserSocialSignupForm"} {% if cookiecutter.frontend_pipeline == 'Django Compressor' -%} # django-compressor # ------------------------------------------------------------------------------ # https://django-compressor.readthedocs.io/en/latest/quickstart/#installation INSTALLED_APPS += ["compressor"] STATICFILES_FINDERS += ["compressor.finders.CompressorFinder"] {%- endif %} {% if cookiecutter.rest_api == 'DRF' -%} # django-rest-framework # ------------------------------------------------------------------------------- # django-rest-framework - https://www.django-rest-framework.org/api-guide/settings/ REST_FRAMEWORK = { "DEFAULT_AUTHENTICATION_CLASSES": ( "rest_framework.authentication.SessionAuthentication", "rest_framework.authentication.TokenAuthentication", ), "DEFAULT_PERMISSION_CLASSES": ("rest_framework.permissions.IsAuthenticated",), "DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema", } # 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(s). You can change permission classes 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 endpoints of {{ cookiecutter.project_name }}", "VERSION": "1.0.0", "SERVE_PERMISSIONS": ["rest_framework.permissions.IsAdminUser"], "SCHEMA_PATH_PREFIX": "/api/", } {%- endif %} {%- if cookiecutter.frontend_pipeline == 'Webpack' %} # django-webpack-loader # ------------------------------------------------------------------------------ WEBPACK_LOADER = { "DEFAULT": { "CACHE": not DEBUG, "STATS_FILE": BASE_DIR / "webpack-stats.json", "POLL_INTERVAL": 0.1, "IGNORE": [r".+\.hot-update.js", r".+\.map"], }, } {%- endif %} # Your stuff... # ------------------------------------------------------------------------------ ================================================ FILE: {{cookiecutter.project_slug}}/config/settings/local.py ================================================ from .base import * # noqa: F403 from .base import INSTALLED_APPS from .base import MIDDLEWARE {%- if cookiecutter.frontend_pipeline == 'Webpack' %} from .base import WEBPACK_LOADER {%- endif %} from .base import env # GENERAL # ------------------------------------------------------------------------------ # https://docs.djangoproject.com/en/dev/ref/settings/#debug DEBUG = True # https://docs.djangoproject.com/en/dev/ref/settings/#secret-key SECRET_KEY = env( "DJANGO_SECRET_KEY", default="!!!SET DJANGO_SECRET_KEY!!!", ) # https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts ALLOWED_HOSTS = ["localhost", "0.0.0.0", "127.0.0.1"] # noqa: S104 # CACHES # ------------------------------------------------------------------------------ # https://docs.djangoproject.com/en/dev/ref/settings/#caches CACHES = { "default": { "BACKEND": "django.core.cache.backends.locmem.LocMemCache", "LOCATION": "", }, } # EMAIL # ------------------------------------------------------------------------------ {% if cookiecutter.use_mailpit == 'y' and cookiecutter.use_docker == 'y' -%} # https://docs.djangoproject.com/en/dev/ref/settings/#email-host EMAIL_HOST = env("EMAIL_HOST", default="mailpit") # https://docs.djangoproject.com/en/dev/ref/settings/#email-port EMAIL_PORT = 1025 {%- elif cookiecutter.use_mailpit == 'y' and cookiecutter.use_docker == 'n' -%} # https://docs.djangoproject.com/en/dev/ref/settings/#email-host EMAIL_HOST = "localhost" # https://docs.djangoproject.com/en/dev/ref/settings/#email-port EMAIL_PORT = 1025 {%- else -%} # https://docs.djangoproject.com/en/dev/ref/settings/#email-backend EMAIL_BACKEND = env( "DJANGO_EMAIL_BACKEND", default="django.core.mail.backends.console.EmailBackend", ) {%- endif %} {%- if cookiecutter.use_whitenoise == 'y' %} # WhiteNoise # ------------------------------------------------------------------------------ # http://whitenoise.evans.io/en/latest/django.html#using-whitenoise-in-development INSTALLED_APPS = ["whitenoise.runserver_nostatic", *INSTALLED_APPS] {% endif %} # django-debug-toolbar # ------------------------------------------------------------------------------ # https://django-debug-toolbar.readthedocs.io/en/latest/installation.html#prerequisites INSTALLED_APPS += ["debug_toolbar"] # https://django-debug-toolbar.readthedocs.io/en/latest/installation.html#middleware MIDDLEWARE += ["debug_toolbar.middleware.DebugToolbarMiddleware"] # https://django-debug-toolbar.readthedocs.io/en/latest/configuration.html#debug-toolbar-config DEBUG_TOOLBAR_CONFIG = { "DISABLE_PANELS": [ "debug_toolbar.panels.redirects.RedirectsPanel", # Disable profiling panel due to an issue with Python 3.12+: # https://github.com/jazzband/django-debug-toolbar/issues/1875 "debug_toolbar.panels.profiling.ProfilingPanel", ], "SHOW_TEMPLATE_CONTEXT": True, } # https://django-debug-toolbar.readthedocs.io/en/latest/installation.html#internal-ips INTERNAL_IPS = ["127.0.0.1", "10.0.2.2"] {% if cookiecutter.use_docker == 'y' -%} if env("USE_DOCKER") == "yes": import socket hostname, _, ips = socket.gethostbyname_ex(socket.gethostname()) INTERNAL_IPS += [".".join([*ip.split(".")[:-1], "1"]) for ip in ips] {%- if cookiecutter.frontend_pipeline in ['Gulp', 'Webpack'] %} try: _, _, ips = socket.gethostbyname_ex("node") INTERNAL_IPS.extend(ips) except socket.gaierror: # The node container isn't started (yet?) pass {%- endif %} {%- if cookiecutter.windows == 'y' %} # RunServerPlus # ------------------------------------------------------------------------------ # This is a custom setting for RunServerPlus to fix reloader issue in Windows docker environment # Werkzeug reloader type [auto, watchdog, or stat] RUNSERVERPLUS_POLLER_RELOADER_TYPE = 'stat' # If you have CPU and IO load issues, you can increase this poller interval e.g) 5 RUNSERVERPLUS_POLLER_RELOADER_INTERVAL = 1 {%- endif %} {%- endif %} # django-extensions # ------------------------------------------------------------------------------ # https://django-extensions.readthedocs.io/en/latest/installation_instructions.html#configuration INSTALLED_APPS += ["django_extensions"] {% if cookiecutter.use_celery == 'y' -%} # Celery # ------------------------------------------------------------------------------ {% if cookiecutter.use_docker == 'n' -%} # https://docs.celeryq.dev/en/stable/userguide/configuration.html#task-always-eager CELERY_TASK_ALWAYS_EAGER = True {%- endif %} # https://docs.celeryq.dev/en/stable/userguide/configuration.html#task-eager-propagates CELERY_TASK_EAGER_PROPAGATES = True {%- endif %} {%- if cookiecutter.frontend_pipeline == 'Webpack' %} # django-webpack-loader # ------------------------------------------------------------------------------ WEBPACK_LOADER["DEFAULT"]["CACHE"] = not DEBUG {%- endif %} # Your stuff... # ------------------------------------------------------------------------------ ================================================ FILE: {{cookiecutter.project_slug}}/config/settings/production.py ================================================ # ruff: noqa: E501 {% if cookiecutter.use_sentry == 'y' -%} import logging import sentry_sdk {%- if cookiecutter.use_celery == 'y' %} from sentry_sdk.integrations.celery import CeleryIntegration {%- endif %} from sentry_sdk.integrations.django import DjangoIntegration from sentry_sdk.integrations.logging import LoggingIntegration from sentry_sdk.integrations.redis import RedisIntegration {% endif -%} from .base import * # noqa: F403 from .base import DATABASES from .base import INSTALLED_APPS from .base import REDIS_URL {%- if cookiecutter.rest_api == 'DRF' %} from .base import SPECTACULAR_SETTINGS {%- endif %} from .base import env # GENERAL # ------------------------------------------------------------------------------ # https://docs.djangoproject.com/en/dev/ref/settings/#secret-key SECRET_KEY = env("DJANGO_SECRET_KEY") # https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts ALLOWED_HOSTS = env.list("DJANGO_ALLOWED_HOSTS", default=["{{ cookiecutter.domain_name }}"]) # DATABASES # ------------------------------------------------------------------------------ DATABASES["default"]["CONN_MAX_AGE"] = env.int("CONN_MAX_AGE", default=60) # CACHES # ------------------------------------------------------------------------------ CACHES = { "default": { "BACKEND": "django_redis.cache.RedisCache", "LOCATION": REDIS_URL, "OPTIONS": { "CLIENT_CLASS": "django_redis.client.DefaultClient", # Mimicking memcache behavior. # https://github.com/jazzband/django-redis#memcached-exceptions-behavior "IGNORE_EXCEPTIONS": True, }, }, } # SECURITY # ------------------------------------------------------------------------------ # https://docs.djangoproject.com/en/dev/ref/settings/#secure-proxy-ssl-header SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") # https://docs.djangoproject.com/en/dev/ref/settings/#secure-ssl-redirect SECURE_SSL_REDIRECT = env.bool("DJANGO_SECURE_SSL_REDIRECT", default=True) # https://docs.djangoproject.com/en/dev/ref/settings/#session-cookie-secure SESSION_COOKIE_SECURE = True # https://docs.djangoproject.com/en/dev/ref/settings/#session-cookie-name SESSION_COOKIE_NAME = "__Secure-sessionid" # https://docs.djangoproject.com/en/dev/ref/settings/#csrf-cookie-secure CSRF_COOKIE_SECURE = True # https://docs.djangoproject.com/en/dev/ref/settings/#csrf-cookie-name CSRF_COOKIE_NAME = "__Secure-csrftoken" # https://docs.djangoproject.com/en/dev/topics/security/#ssl-https # https://docs.djangoproject.com/en/dev/ref/settings/#secure-hsts-seconds # TODO: set this to 60 seconds first and then to 518400 once you prove the former works SECURE_HSTS_SECONDS = 60 # https://docs.djangoproject.com/en/dev/ref/settings/#secure-hsts-include-subdomains SECURE_HSTS_INCLUDE_SUBDOMAINS = env.bool( "DJANGO_SECURE_HSTS_INCLUDE_SUBDOMAINS", default=True, ) # https://docs.djangoproject.com/en/dev/ref/settings/#secure-hsts-preload SECURE_HSTS_PRELOAD = env.bool("DJANGO_SECURE_HSTS_PRELOAD", default=True) # https://docs.djangoproject.com/en/dev/ref/middleware/#x-content-type-options-nosniff SECURE_CONTENT_TYPE_NOSNIFF = env.bool( "DJANGO_SECURE_CONTENT_TYPE_NOSNIFF", default=True, ) {% if cookiecutter.cloud_provider == 'AWS' %} # https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#settings AWS_ACCESS_KEY_ID = env("DJANGO_AWS_ACCESS_KEY_ID") # https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#settings AWS_SECRET_ACCESS_KEY = env("DJANGO_AWS_SECRET_ACCESS_KEY") # https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#settings AWS_STORAGE_BUCKET_NAME = env("DJANGO_AWS_STORAGE_BUCKET_NAME") # https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#settings AWS_QUERYSTRING_AUTH = False # DO NOT change these unless you know what you're doing. _AWS_EXPIRY = 60 * 60 * 24 * 7 # https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#settings AWS_S3_OBJECT_PARAMETERS = { "CacheControl": f"max-age={_AWS_EXPIRY}, s-maxage={_AWS_EXPIRY}, must-revalidate", } # https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#settings AWS_S3_MAX_MEMORY_SIZE = env.int( "DJANGO_AWS_S3_MAX_MEMORY_SIZE", default=100_000_000, # 100MB ) # https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#settings AWS_S3_REGION_NAME = env("DJANGO_AWS_S3_REGION_NAME", default=None) # https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#cloudfront AWS_S3_CUSTOM_DOMAIN = env("DJANGO_AWS_S3_CUSTOM_DOMAIN", default=None) aws_s3_domain = AWS_S3_CUSTOM_DOMAIN or f"{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com" {% elif cookiecutter.cloud_provider == 'GCP' %} GS_BUCKET_NAME = env("DJANGO_GCP_STORAGE_BUCKET_NAME") GS_DEFAULT_ACL = "publicRead" {% elif cookiecutter.cloud_provider == 'Azure' %} AZURE_ACCOUNT_KEY = env("DJANGO_AZURE_ACCOUNT_KEY") AZURE_ACCOUNT_NAME = env("DJANGO_AZURE_ACCOUNT_NAME") AZURE_CONTAINER = env("DJANGO_AZURE_CONTAINER_NAME") {% endif -%} {% if cookiecutter.cloud_provider != 'None' or cookiecutter.use_whitenoise == 'y' -%} # STATIC & MEDIA # ------------------------ STORAGES = { {%- if cookiecutter.use_whitenoise == 'y' and cookiecutter.cloud_provider == 'None' %} "default": { "BACKEND": "django.core.files.storage.FileSystemStorage", }, "staticfiles": { "BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage", }, {%- elif cookiecutter.cloud_provider == 'AWS' %} "default": { "BACKEND": "storages.backends.s3.S3Storage", "OPTIONS": { "location": "media", "file_overwrite": False, }, }, {%- if cookiecutter.use_whitenoise == 'y' %} "staticfiles": { "BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage", }, {%- else %} "staticfiles": { "BACKEND": "storages.backends.s3.S3Storage", "OPTIONS": { "location": "static", "default_acl": "public-read", }, }, {%- endif %} {%- elif cookiecutter.cloud_provider == 'GCP' %} "default": { "BACKEND": "storages.backends.gcloud.GoogleCloudStorage", "OPTIONS": { "location": "media", "file_overwrite": False, }, }, {%- if cookiecutter.use_whitenoise == 'y' %} "staticfiles": { "BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage", }, {%- else %} "staticfiles": { "BACKEND": "storages.backends.gcloud.GoogleCloudStorage", "OPTIONS": { "location": "static", "default_acl": "publicRead", }, }, {%- endif %} {%- elif cookiecutter.cloud_provider == 'Azure' %} "default": { "BACKEND": "storages.backends.azure_storage.AzureStorage", "OPTIONS": { "location": "media", "overwrite_files": False, }, }, {%- if cookiecutter.use_whitenoise == 'y' %} "staticfiles": { "BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage", }, {%- else %} "staticfiles": { "BACKEND": "storages.backends.azure_storage.AzureStorage", "OPTIONS": { "location": "static", }, }, {%- endif %} {%- endif %} } {%- endif %} {%- if cookiecutter.cloud_provider == 'AWS' %} MEDIA_URL = f"https://{aws_s3_domain}/media/" {%- if cookiecutter.use_whitenoise == 'n' %} COLLECTFASTA_STRATEGY = "collectfasta.strategies.boto3.Boto3Strategy" STATIC_URL = f"https://{aws_s3_domain}/static/" {%- endif %} {%- elif cookiecutter.cloud_provider == 'GCP' %} MEDIA_URL = f"https://storage.googleapis.com/{GS_BUCKET_NAME}/media/" {%- if cookiecutter.use_whitenoise == 'n' %} COLLECTFASTA_STRATEGY = "collectfasta.strategies.gcloud.GoogleCloudStrategy" STATIC_URL = f"https://storage.googleapis.com/{GS_BUCKET_NAME}/static/" {%- endif %} {%- elif cookiecutter.cloud_provider == 'Azure' %} MEDIA_URL = f"https://{AZURE_ACCOUNT_NAME}.blob.core.windows.net/media/" {%- if cookiecutter.use_whitenoise == 'n' %} COLLECTFASTA_STRATEGY = "collectfasta.strategies.azure.AzureBlobStrategy" STATIC_URL = f"https://{AZURE_ACCOUNT_NAME}.blob.core.windows.net/static/" {%- endif %} {%- endif %} # EMAIL # ------------------------------------------------------------------------------ # https://docs.djangoproject.com/en/dev/ref/settings/#default-from-email DEFAULT_FROM_EMAIL = env( "DJANGO_DEFAULT_FROM_EMAIL", default="{{cookiecutter.project_name}} ", ) # https://docs.djangoproject.com/en/dev/ref/settings/#server-email SERVER_EMAIL = env("DJANGO_SERVER_EMAIL", default=DEFAULT_FROM_EMAIL) # https://docs.djangoproject.com/en/dev/ref/settings/#email-subject-prefix EMAIL_SUBJECT_PREFIX = env( "DJANGO_EMAIL_SUBJECT_PREFIX", default="[{{cookiecutter.project_name}}] ", ) ACCOUNT_EMAIL_SUBJECT_PREFIX = EMAIL_SUBJECT_PREFIX # ADMIN # ------------------------------------------------------------------------------ # Django Admin URL regex. ADMIN_URL = env("DJANGO_ADMIN_URL") # Anymail # ------------------------------------------------------------------------------ # https://anymail.readthedocs.io/en/stable/installation/#installing-anymail INSTALLED_APPS += ["anymail"] # https://docs.djangoproject.com/en/dev/ref/settings/#email-backend # https://anymail.readthedocs.io/en/stable/installation/#anymail-settings-reference {%- if cookiecutter.mail_service == 'Mailgun' %} # https://anymail.readthedocs.io/en/stable/esps/mailgun/ EMAIL_BACKEND = "anymail.backends.mailgun.EmailBackend" ANYMAIL = { "MAILGUN_API_KEY": env("MAILGUN_API_KEY"), "MAILGUN_SENDER_DOMAIN": env("MAILGUN_DOMAIN"), "MAILGUN_API_URL": env("MAILGUN_API_URL", default="https://api.mailgun.net/v3"), } {%- elif cookiecutter.mail_service == 'Amazon SES' %} # https://anymail.readthedocs.io/en/stable/esps/amazon_ses/ EMAIL_BACKEND = "anymail.backends.amazon_ses.EmailBackend" ANYMAIL = {} {%- elif cookiecutter.mail_service == 'Mailjet' %} # https://anymail.readthedocs.io/en/stable/esps/mailjet/ EMAIL_BACKEND = "anymail.backends.mailjet.EmailBackend" ANYMAIL = { "MAILJET_API_KEY": env("MAILJET_API_KEY"), "MAILJET_SECRET_KEY": env("MAILJET_SECRET_KEY"), } {%- elif cookiecutter.mail_service == 'Mandrill' %} # https://anymail.readthedocs.io/en/stable/esps/mandrill/ EMAIL_BACKEND = "anymail.backends.mandrill.EmailBackend" ANYMAIL = { "MANDRILL_API_KEY": env("MANDRILL_API_KEY"), "MANDRILL_API_URL": env("MANDRILL_API_URL", default="https://mandrillapp.com/api/1.0"), } {%- elif cookiecutter.mail_service == 'Postmark' %} # https://anymail.readthedocs.io/en/stable/esps/postmark/ EMAIL_BACKEND = "anymail.backends.postmark.EmailBackend" ANYMAIL = { "POSTMARK_SERVER_TOKEN": env("POSTMARK_SERVER_TOKEN"), "POSTMARK_API_URL": env("POSTMARK_API_URL", default="https://api.postmarkapp.com/"), } {%- elif cookiecutter.mail_service == 'Sendgrid' %} # https://anymail.readthedocs.io/en/stable/esps/sendgrid/ EMAIL_BACKEND = "anymail.backends.sendgrid.EmailBackend" ANYMAIL = { "SENDGRID_API_KEY": env("SENDGRID_API_KEY"), "SENDGRID_API_URL": env("SENDGRID_API_URL", default="https://api.sendgrid.com/v3/"), } {%- elif cookiecutter.mail_service == 'Brevo' %} # https://anymail.readthedocs.io/en/stable/esps/brevo/ EMAIL_BACKEND = "anymail.backends.brevo.EmailBackend" ANYMAIL = { "BREVO_API_KEY": env("BREVO_API_KEY"), "BREVO_API_URL": env("BREVO_API_URL", default="https://api.brevo.com/v3/"), } {%- elif cookiecutter.mail_service == 'SparkPost' %} # https://anymail.readthedocs.io/en/stable/esps/sparkpost/ EMAIL_BACKEND = "anymail.backends.sparkpost.EmailBackend" ANYMAIL = { "SPARKPOST_API_KEY": env("SPARKPOST_API_KEY"), "SPARKPOST_API_URL": env("SPARKPOST_API_URL", default="https://api.sparkpost.com/api/v1"), } {%- elif cookiecutter.mail_service == 'Other SMTP' %} # https://anymail.readthedocs.io/en/stable/esps EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend" ANYMAIL = {} {%- endif %} {% if cookiecutter.frontend_pipeline == 'Django Compressor' -%} # django-compressor # ------------------------------------------------------------------------------ # https://django-compressor.readthedocs.io/en/latest/settings/#django.conf.settings.COMPRESS_ENABLED COMPRESS_ENABLED = env.bool("COMPRESS_ENABLED", default=True) {%- if cookiecutter.cloud_provider == 'None' %} # https://django-compressor.readthedocs.io/en/latest/settings/#django.conf.settings.COMPRESS_STORAGE COMPRESS_STORAGE = "compressor.storage.GzipCompressorFileStorage" {%- elif cookiecutter.cloud_provider in ('AWS', 'GCP', 'Azure') and cookiecutter.use_whitenoise == 'n' %} # https://django-compressor.readthedocs.io/en/latest/settings/#django.conf.settings.COMPRESS_STORAGE COMPRESS_STORAGE = STORAGES["staticfiles"]["BACKEND"] {%- endif %} # https://django-compressor.readthedocs.io/en/latest/settings/#django.conf.settings.COMPRESS_URL COMPRESS_URL = STATIC_URL{% if cookiecutter.use_whitenoise == 'y' or cookiecutter.cloud_provider == 'None' %} # noqa: F405 {%- endif -%} {%- if cookiecutter.use_whitenoise == 'y' %} # https://django-compressor.readthedocs.io/en/latest/settings/#django.conf.settings.COMPRESS_OFFLINE COMPRESS_OFFLINE = True # Offline compression is required when using Whitenoise {%- endif %} # https://django-compressor.readthedocs.io/en/latest/settings/#django.conf.settings.COMPRESS_FILTERS COMPRESS_FILTERS = { "css": [ "compressor.filters.css_default.CssAbsoluteFilter", "compressor.filters.cssmin.rCSSMinFilter", ], "js": ["compressor.filters.jsmin.JSMinFilter"], } {% endif %} {%- if cookiecutter.use_whitenoise == 'n' and cookiecutter.cloud_provider in ('AWS', 'GCP', 'Azure') -%} # Collectfasta # ------------------------------------------------------------------------------ # https://github.com/jasongi/collectfasta#installation INSTALLED_APPS = ["collectfasta", *INSTALLED_APPS] {% endif %} # LOGGING # ------------------------------------------------------------------------------ # https://docs.djangoproject.com/en/dev/ref/settings/#logging # See https://docs.djangoproject.com/en/dev/topics/logging for # more details on how to customize your logging configuration. {% if cookiecutter.use_sentry == 'n' -%} # A sample logging configuration. The only tangible logging # performed by this configuration is to send an email to # the site admins on every HTTP 500 error when DEBUG=False. LOGGING = { "version": 1, "disable_existing_loggers": False, "filters": {"require_debug_false": {"()": "django.utils.log.RequireDebugFalse"}}, "formatters": { "verbose": { "format": "%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s", }, }, "handlers": { "mail_admins": { "level": "ERROR", "filters": ["require_debug_false"], "class": "django.utils.log.AdminEmailHandler", }, "console": { "level": "DEBUG", "class": "logging.StreamHandler", "formatter": "verbose", }, }, "root": {"level": "INFO", "handlers": ["console"]}, "loggers": { "django.request": { "handlers": ["mail_admins"], "level": "ERROR", "propagate": True, }, "django.security.DisallowedHost": { "level": "ERROR", "handlers": ["console", "mail_admins"], "propagate": True, }, }, } {% else %} LOGGING = { "version": 1, "disable_existing_loggers": True, "formatters": { "verbose": { "format": "%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s", }, }, "handlers": { "console": { "level": "DEBUG", "class": "logging.StreamHandler", "formatter": "verbose", }, }, "root": {"level": "INFO", "handlers": ["console"]}, "loggers": { "django.db.backends": { "level": "ERROR", "handlers": ["console"], "propagate": False, }, # Errors logged by the SDK itself "sentry_sdk": {"level": "ERROR", "handlers": ["console"], "propagate": False}, "django.security.DisallowedHost": { "level": "ERROR", "handlers": ["console"], "propagate": False, }, }, } # Sentry # ------------------------------------------------------------------------------ SENTRY_DSN = env("SENTRY_DSN") SENTRY_LOG_LEVEL = env.int("DJANGO_SENTRY_LOG_LEVEL", logging.INFO) sentry_logging = LoggingIntegration( level=SENTRY_LOG_LEVEL, # Capture info and above as breadcrumbs event_level=logging.ERROR, # Send errors as events ) {%- if cookiecutter.use_celery == 'y' %} integrations = [ sentry_logging, DjangoIntegration(), CeleryIntegration(), RedisIntegration(), ] {% else %} integrations = [sentry_logging, DjangoIntegration(), RedisIntegration()] {% endif -%} sentry_sdk.init( dsn=SENTRY_DSN, integrations=integrations, environment=env("SENTRY_ENVIRONMENT", default="production"), traces_sample_rate=env.float("SENTRY_TRACES_SAMPLE_RATE", default=0.0), ) {% endif %} {% if cookiecutter.rest_api == 'DRF' -%} # django-rest-framework # ------------------------------------------------------------------------------- # Tools that generate code samples can use SERVERS to point to the correct domain SPECTACULAR_SETTINGS["SERVERS"] = [ {"url": "https://{{ cookiecutter.domain_name }}", "description": "Production server"}, ] {%- endif %} # Your stuff... # ------------------------------------------------------------------------------ ================================================ FILE: {{cookiecutter.project_slug}}/config/settings/test.py ================================================ """ With these settings, tests run faster. """ from .base import * # noqa: F403 from .base import TEMPLATES from .base import env # GENERAL # ------------------------------------------------------------------------------ # https://docs.djangoproject.com/en/dev/ref/settings/#secret-key SECRET_KEY = env( "DJANGO_SECRET_KEY", default="!!!SET DJANGO_SECRET_KEY!!!", ) # https://docs.djangoproject.com/en/dev/ref/settings/#test-runner TEST_RUNNER = "django.test.runner.DiscoverRunner" # PASSWORDS # ------------------------------------------------------------------------------ # https://docs.djangoproject.com/en/dev/ref/settings/#password-hashers PASSWORD_HASHERS = ["django.contrib.auth.hashers.MD5PasswordHasher"] # EMAIL # ------------------------------------------------------------------------------ # https://docs.djangoproject.com/en/dev/ref/settings/#email-backend EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend" # DEBUGGING FOR TEMPLATES # ------------------------------------------------------------------------------ TEMPLATES[0]["OPTIONS"]["debug"] = True # type: ignore[index] # MEDIA # ------------------------------------------------------------------------------ # https://docs.djangoproject.com/en/dev/ref/settings/#media-url MEDIA_URL = "http://media.testserver/" {%- if cookiecutter.frontend_pipeline == 'Webpack' %} # django-webpack-loader # ------------------------------------------------------------------------------ WEBPACK_LOADER["DEFAULT"]["LOADER_CLASS"] = "webpack_loader.loaders.FakeWebpackLoader" # noqa: F405 {%- endif %} # Your stuff... # ------------------------------------------------------------------------------ ================================================ FILE: {{cookiecutter.project_slug}}/config/urls.py ================================================ from django.conf import settings from django.conf.urls.static import static from django.contrib import admin {%- if cookiecutter.use_async == 'y' %} from django.contrib.staticfiles.urls import staticfiles_urlpatterns {%- endif %} from django.urls import include from django.urls import path from django.views import defaults as default_views from django.views.generic import TemplateView {%- if cookiecutter.rest_api == 'DRF' %} from drf_spectacular.views import SpectacularAPIView from drf_spectacular.views import SpectacularSwaggerView from rest_framework.authtoken.views import obtain_auth_token {%- elif cookiecutter.rest_api == 'Django Ninja' %} from .api import api {%- endif %} urlpatterns = [ path("", TemplateView.as_view(template_name="pages/home.html"), name="home"), path( "about/", TemplateView.as_view(template_name="pages/about.html"), name="about", ), # Django Admin, use {% raw %}{% url 'admin:index' %}{% endraw %} path(settings.ADMIN_URL, admin.site.urls), # User management path("users/", include("{{ cookiecutter.project_slug }}.users.urls", namespace="users")), path("accounts/", include("allauth.urls")), # Your stuff: custom urls includes go here # ... # Media files *static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT), ] {%- if cookiecutter.use_async == 'y' %} if settings.DEBUG: # Static file serving when using Gunicorn + Uvicorn for local web socket development urlpatterns += staticfiles_urlpatterns() {%- endif %} {% if cookiecutter.rest_api == 'DRF' %} # API URLS urlpatterns += [ # API base url path("api/", include("config.api_router")), # DRF auth token path("api/auth-token/", obtain_auth_token, name="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", ), ] {%- elif cookiecutter.rest_api == 'Django Ninja' %} # API URLS urlpatterns += [ # API base url path("api/", api.urls), ] {%- endif %} if settings.DEBUG: # This allows the error pages to be debugged during development, just visit # these url in browser to see how these error pages look like. urlpatterns += [ path( "400/", default_views.bad_request, kwargs={"exception": Exception("Bad Request!")}, ), path( "403/", default_views.permission_denied, kwargs={"exception": Exception("Permission Denied")}, ), path( "404/", default_views.page_not_found, kwargs={"exception": Exception("Page not Found")}, ), path("500/", default_views.server_error), ] if "debug_toolbar" in settings.INSTALLED_APPS: import debug_toolbar urlpatterns = [ path("__debug__/", include(debug_toolbar.urls)), *urlpatterns, ] ================================================ FILE: {{cookiecutter.project_slug}}/config/websocket.py ================================================ async def websocket_application(scope, receive, send): while True: event = await receive() if event["type"] == "websocket.connect": await send({"type": "websocket.accept"}) if event["type"] == "websocket.disconnect": break if event["type"] == "websocket.receive": if event["text"] == "ping": await send({"type": "websocket.send", "text": "pong!"}) ================================================ FILE: {{cookiecutter.project_slug}}/config/wsgi.py ================================================ """ WSGI config for {{ cookiecutter.project_name }} project. This module contains the WSGI application used by Django's development server and any production WSGI deployments. It should expose a module-level variable named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover this application via the ``WSGI_APPLICATION`` setting. Usually you will have the standard Django WSGI application here, but it also might make sense to replace the whole Django WSGI application with a custom one that later delegates to the Django one. For example, you could introduce WSGI middleware here, or combine a Django application with an application of another framework. """ import os import sys from pathlib import Path from django.core.wsgi import get_wsgi_application # This allows easy placement of apps within the interior # {{ cookiecutter.project_slug }} directory. BASE_DIR = Path(__file__).resolve(strict=True).parent.parent sys.path.append(str(BASE_DIR / "{{ cookiecutter.project_slug }}")) os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.production") # This application object is used by any WSGI server configured to use this # file. This includes Django's development server, if the WSGI_APPLICATION # setting points here. application = get_wsgi_application() ================================================ FILE: {{cookiecutter.project_slug}}/docker-compose.docs.yml ================================================ services: docs: image: {{ cookiecutter.project_slug }}_local_docs container_name: {{ cookiecutter.project_slug }}_local_docs build: context: . dockerfile: ./compose/local/docs/Dockerfile env_file: - ./.envs/.local/.django volumes: - /app/.venv - ./docs:/docs:z - ./config:/app/config:z - ./{{ cookiecutter.project_slug }}:/app/{{ cookiecutter.project_slug }}:z ports: - '9000:9000' command: /start-docs ================================================ FILE: {{cookiecutter.project_slug}}/docker-compose.local.yml ================================================ volumes: {{ cookiecutter.project_slug }}_local_postgres_data: {} {{ cookiecutter.project_slug }}_local_postgres_data_backups: {} {% if cookiecutter.use_celery == 'y' %}{{ cookiecutter.project_slug }}_local_redis_data: {}{% endif %} services: django:{% if cookiecutter.use_celery == 'y' %} &django{% endif %} build: context: . dockerfile: ./compose/local/django/Dockerfile image: {{ cookiecutter.project_slug }}_local_django container_name: {{ cookiecutter.project_slug }}_local_django depends_on: - postgres {%- if cookiecutter.use_celery == 'y' %} - redis {%- endif %} {%- if cookiecutter.use_mailpit == 'y' %} - mailpit {%- endif %} volumes: - /app/.venv - .:/app:z env_file: - ./.envs/.local/.django - ./.envs/.local/.postgres ports: - '8000:8000' command: /start postgres: build: context: . dockerfile: ./compose/production/postgres/Dockerfile image: {{ cookiecutter.project_slug }}_production_postgres container_name: {{ cookiecutter.project_slug }}_local_postgres volumes: {%- if cookiecutter.postgresql_version|int >= 18 %} - {{ cookiecutter.project_slug }}_local_postgres_data:/var/lib/postgresql/{{ cookiecutter.postgresql_version }}/docker {%- else %} - {{ cookiecutter.project_slug }}_local_postgres_data:/var/lib/postgresql/data {%- endif %} - {{ cookiecutter.project_slug }}_local_postgres_data_backups:/backups env_file: - ./.envs/.local/.postgres {%- if cookiecutter.use_mailpit == 'y' %} mailpit: image: docker.io/axllent/mailpit:latest container_name: {{ cookiecutter.project_slug }}_local_mailpit ports: - "8025:8025" {%- endif %} {%- if cookiecutter.use_celery == 'y' %} redis: image: docker.io/redis:7.2 container_name: {{ cookiecutter.project_slug }}_local_redis volumes: - {{ cookiecutter.project_slug }}_local_redis_data:/data celeryworker: <<: *django image: {{ cookiecutter.project_slug }}_local_celeryworker container_name: {{ cookiecutter.project_slug }}_local_celeryworker depends_on: - redis - postgres {%- if cookiecutter.use_mailpit == 'y' %} - mailpit {%- endif %} ports: [] command: /start-celeryworker celerybeat: <<: *django image: {{ cookiecutter.project_slug }}_local_celerybeat container_name: {{ cookiecutter.project_slug }}_local_celerybeat depends_on: - redis - postgres {%- if cookiecutter.use_mailpit == 'y' %} - mailpit {%- endif %} ports: [] command: /start-celerybeat flower: <<: *django image: {{ cookiecutter.project_slug }}_local_flower container_name: {{ cookiecutter.project_slug }}_local_flower ports: - '5555:5555' command: /start-flower {%- endif %} {%- if cookiecutter.frontend_pipeline in ['Gulp', 'Webpack'] %} node: build: context: . dockerfile: ./compose/local/node/Dockerfile image: {{ cookiecutter.project_slug }}_local_node container_name: {{ cookiecutter.project_slug }}_local_node depends_on: - django volumes: - .:/app:z # http://jdlm.info/articles/2016/03/06/lessons-building-node-app-docker.html - /app/node_modules command: npm run dev ports: - '3000:3000' {%- if cookiecutter.frontend_pipeline == 'Gulp' %} # Expose browsersync UI: https://www.browsersync.io/docs/options/#option-ui - '3001:3001' {%- endif %} {%- endif %} ================================================ FILE: {{cookiecutter.project_slug}}/docker-compose.production.yml ================================================ volumes: production_postgres_data: {} production_postgres_data_backups: {} production_traefik: {} {%- if cookiecutter.cloud_provider == 'None' %} production_django_media: {} {%- endif %} {% if cookiecutter.use_celery == 'y' %} production_redis_data: {} {% endif %} services: django:{% if cookiecutter.use_celery == 'y' %} &django{% endif %} build: context: . dockerfile: ./compose/production/django/Dockerfile {%- if cookiecutter.frontend_pipeline == 'Webpack' and cookiecutter.use_whitenoise == 'n' %} args: # These variable can be defined in an .env file in the root of the repo {%- if cookiecutter.cloud_provider == 'AWS' %} DJANGO_AWS_STORAGE_BUCKET_NAME: ${DJANGO_AWS_STORAGE_BUCKET_NAME} DJANGO_AWS_S3_CUSTOM_DOMAIN: ${DJANGO_AWS_S3_CUSTOM_DOMAIN} {%- elif cookiecutter.cloud_provider == 'GCP' %} DJANGO_GCP_STORAGE_BUCKET_NAME: ${DJANGO_GCP_STORAGE_BUCKET_NAME} {%- elif cookiecutter.cloud_provider == 'Azure' %} DJANGO_AZURE_ACCOUNT_NAME: ${DJANGO_AZURE_ACCOUNT_NAME} {%- endif %} {%- endif %} image: {{ cookiecutter.project_slug }}_production_django {%- if cookiecutter.cloud_provider == 'None' %} volumes: - production_django_media:/app/{{ cookiecutter.project_slug }}/media {%- endif %} depends_on: - postgres - redis env_file: - ./.envs/.production/.django - ./.envs/.production/.postgres command: /start postgres: build: context: . dockerfile: ./compose/production/postgres/Dockerfile image: {{ cookiecutter.project_slug }}_production_postgres volumes: {%- if cookiecutter.postgresql_version|int >= 18 %} - production_postgres_data:/var/lib/postgresql/{{ cookiecutter.postgresql_version }}/docker {%- else %} - production_postgres_data:/var/lib/postgresql/data {%- endif %} - production_postgres_data_backups:/backups env_file: - ./.envs/.production/.postgres traefik: build: context: . dockerfile: ./compose/production/traefik/Dockerfile image: {{ cookiecutter.project_slug }}_production_traefik depends_on: - django volumes: - production_traefik:/etc/traefik/acme ports: - '0.0.0.0:80:80' - '0.0.0.0:443:443' {%- if cookiecutter.use_celery == 'y' %} - '0.0.0.0:5555:5555' {%- endif %} redis: image: docker.io/redis:7.2 {% if cookiecutter.use_celery == 'y' %} volumes: - production_redis_data:/data {% endif %} {%- if cookiecutter.use_celery == 'y' %} celeryworker: <<: *django image: {{ cookiecutter.project_slug }}_production_celeryworker command: /start-celeryworker celerybeat: <<: *django image: {{ cookiecutter.project_slug }}_production_celerybeat command: /start-celerybeat flower: <<: *django image: {{ cookiecutter.project_slug }}_production_flower command: /start-flower {%- endif %} {%- if cookiecutter.cloud_provider == 'AWS' %} awscli: build: context: . dockerfile: ./compose/production/aws/Dockerfile env_file: - ./.envs/.production/.django volumes: - production_postgres_data_backups:/backups:z {%- endif %} {%- if cookiecutter.cloud_provider == 'None' %} nginx: build: context: . dockerfile: ./compose/production/nginx/Dockerfile image: {{ cookiecutter.project_slug }}_production_nginx depends_on: - django volumes: - production_django_media:/usr/share/nginx/media:ro {%- endif %} ================================================ FILE: {{cookiecutter.project_slug}}/docs/Makefile ================================================ # Minimal makefile for Sphinx documentation # # You can set these variables from the command line, and also # from the environment for the first two. SPHINXOPTS ?= SPHINXBUILD ?= sphinx-build SOURCEDIR = . BUILDDIR = ./_build {%- if cookiecutter.use_docker == 'y' %} APP = /app {%- else %} APP = ../{{cookiecutter.project_slug}} {% endif %} .PHONY: help livehtml apidocs Makefile # Put it first so that "make" without argument is like "make help". help: @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -c . # Build, watch and serve docs with live reload livehtml: sphinx-autobuild -b html {%- if cookiecutter.use_docker == 'y' %} --host 0.0.0.0 {%- else %} --open-browser {%- endif %} --port 9000 --watch $(APP) -c . $(SOURCEDIR) $(BUILDDIR)/html # Outputs rst files from django application code apidocs: 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) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -c . ================================================ FILE: {{cookiecutter.project_slug}}/docs/__init__.py ================================================ # Included so that Django's startproject comment runs against the docs directory ================================================ FILE: {{cookiecutter.project_slug}}/docs/conf.py ================================================ # ruff: noqa: ERA001, PTH100 # Configuration file for the Sphinx documentation builder. # # This file only contains a selection of the most common options. For a full # list see the documentation: # https://www.sphinx-doc.org/en/master/usage/configuration.html # -- Path setup -------------------------------------------------------------- # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. import os import sys import django if os.getenv("READTHEDOCS", default="False") == "True": sys.path.insert(0, os.path.abspath("..")) os.environ["DJANGO_READ_DOT_ENV_FILE"] = "True" os.environ["USE_DOCKER"] = "no" else: {%- if cookiecutter.use_docker == 'y' %} sys.path.insert(0, os.path.abspath("/app")) {%- else %} sys.path.insert(0, os.path.abspath("..")) {%- endif %} os.environ["DATABASE_URL"] = "sqlite:///readthedocs.db" os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.local") django.setup() # -- Project information ----------------------------------------------------- project = "{{ cookiecutter.project_name }}" copyright = """{% now 'utc', '%Y' %}, {{ cookiecutter.author_name }}""" # noqa: A001 author = "{{ cookiecutter.author_name }}" # -- General configuration --------------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ "sphinx.ext.autodoc", "sphinx.ext.napoleon", ] # Add any paths that contain templates here, relative to this directory. # templates_path = ["_templates"] # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] # -- Options for HTML output ------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # html_theme = "alabaster" # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". # html_static_path = ["_static"] ================================================ FILE: {{cookiecutter.project_slug}}/docs/howto.rst ================================================ How To - Project Documentation ====================================================================== Get Started ---------------------------------------------------------------------- Documentation can be written as rst files in `{{cookiecutter.project_slug}}/docs`. {% if cookiecutter.use_docker == 'n' %} To build and serve docs, use the command:: uv run make livehtml from inside the `{{cookiecutter.project_slug}}/docs` directory. {% else %} To build and serve docs, use the commands:: docker compose -f docker-compose.docs.yml up {% endif %} Changes to files in `docs/_source` will be picked up and reloaded automatically. `Sphinx `_ is the tool used to build documentation. Docstrings to Documentation ---------------------------------------------------------------------- The sphinx extension `apidoc `_ is used to automatically document code using signatures and docstrings. Numpy or Google style docstrings will be picked up from project files and available for documentation. See the `Napoleon `_ extension for details. For an in-use example, see the `page source <_sources/users.rst.txt>`_ for :ref:`users`. To compile all docstrings automatically into documentation source files, use the command: :: uv run make apidocs {% if cookiecutter.use_docker == 'y' %} This can be done in the docker container: :: docker run --rm docs make apidocs {% endif -%} ================================================ FILE: {{cookiecutter.project_slug}}/docs/index.rst ================================================ .. {{ cookiecutter.project_name }} documentation master file, created by sphinx-quickstart. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. Welcome to {{ cookiecutter.project_name }}'s documentation! ====================================================================== .. toctree:: :maxdepth: 2 :caption: Contents: howto{% if cookiecutter.editor == 'PyCharm' %} pycharm/configuration{% endif %} users Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` ================================================ FILE: {{cookiecutter.project_slug}}/docs/make.bat ================================================ @ECHO OFF pushd %~dp0 REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build -c . ) set SOURCEDIR=_source set BUILDDIR=_build set APP=..\{{cookiecutter.project_slug}} if "%1" == "" goto help %SPHINXBUILD% >NUL 2>NUL if errorlevel 9009 ( echo. echo.The 'sphinx-build' command was not found. Make sure you have Sphinx echo.installed, then set the SPHINXBUILD environment variable to point echo.to the full path of the 'sphinx-build' executable. Alternatively you echo.may add the Sphinx directory to PATH. echo. echo.Install sphinx-autobuild for live serving. echo.If you don't have Sphinx installed, grab it from echo.http://sphinx-doc.org/ exit /b 1 ) %SPHINXBUILD% -b %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% goto end :livehtml sphinx-autobuild -b html --open-browser -p 9000 --watch %APP% -c . %SOURCEDIR% %BUILDDIR%/html GOTO :EOF :apidocs sphinx-apidoc -o %SOURCEDIR%/api %APP% GOTO :EOF :help %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% :end popd ================================================ FILE: {{cookiecutter.project_slug}}/docs/pycharm/configuration.rst ================================================ Docker Remote Debugging ======================= To connect to python remote interpreter inside docker, you have to make sure first, that Pycharm is aware of your docker. Go to *Settings > Build, Execution, Deployment > Docker*. If you are on linux, you can use docker directly using its socket `unix:///var/run/docker.sock`, if you are on Windows or Mac, make sure that you have docker-machine installed, then you can simply *Import credentials from Docker Machine*. .. image:: images/1.png Configure Remote Python Interpreter ----------------------------------- This repository comes with already prepared "Run/Debug Configurations" for docker. .. image:: images/2.png But as you can see, at the beginning there is something wrong with them. They have red X on django icon, and they cannot be used, without configuring remote python interpreter. To do that, you have to go to *Settings > Build, Execution, Deployment* first. Next, you have to add new remote python interpreter, based on already tested deployment settings. Go to *Settings > Project > Project Interpreter*. Click on the cog icon, and click *Add Remote*. .. image:: images/3.png Switch to *Docker Compose* and select `docker-compose.local.yml` file from directory of your project, next set *Service name* to `django` .. image:: images/4.png Having that, click *OK*. Close *Settings* panel, and wait few seconds... .. image:: images/7.png After few seconds, all *Run/Debug Configurations* should be ready to use. .. image:: images/8.png **Things you can do with provided configuration**: * run and debug python code .. image:: images/f1.png * run and debug tests .. image:: images/f2.png .. image:: images/f3.png * run and debug migrations or different django management commands .. image:: images/f4.png * and many others.. Known issues ------------ * Pycharm hangs on "Connecting to Debugger" .. image:: images/issue1.png This might be fault of your firewall. Take a look on this ticket - https://youtrack.jetbrains.com/issue/PY-18913 * Modified files in `.idea` directory Most of the files from `.idea/` were added to `.gitignore` with a few exceptions, which were made, to provide "ready to go" configuration. After adding remote interpreter some of these files are altered by PyCharm: .. image:: images/issue2.png In theory you can remove them from repository, but then, other people will lose a ability to initialize a project from provided configurations as you did. To get rid of this annoying state, you can run command:: $ git update-index --assume-unchanged {{cookiecutter.project_slug}}.iml ================================================ FILE: {{cookiecutter.project_slug}}/docs/users.rst ================================================ .. _users: Users ====================================================================== Starting a new project, it’s highly recommended to set up a custom user model, even if the default User model is sufficient for you. This model behaves identically to the default user model, but you’ll be able to customize it in the future if the need arises. .. automodule:: {{cookiecutter.project_slug}}.users.models :members: :noindex: ================================================ FILE: {{cookiecutter.project_slug}}/gulpfile.mjs ================================================ //////////////////////////////// // Setup //////////////////////////////// // Gulp and package import { src, dest, parallel, series, task, watch } from 'gulp'; import pjson from './package.json' with {type: 'json'}; // Plugins import autoprefixer from 'autoprefixer'; import browserSyncLib from 'browser-sync'; import concat from 'gulp-concat'; import tildeImporter from 'node-sass-tilde-importer'; import cssnano from 'cssnano'; import pixrem from 'pixrem'; import plumber from 'gulp-plumber'; import postcss from 'gulp-postcss'; import rename from 'gulp-rename'; import gulpSass from 'gulp-sass'; import * as dartSass from 'sass'; import gulUglifyES from 'gulp-uglify-es'; import { spawn } from 'node:child_process'; const browserSync = browserSyncLib.create(); const reload = browserSync.reload; const sass = gulpSass(dartSass); const uglify = gulUglifyES.default; // Relative paths function function pathsConfig() { const appName = `./${pjson.name}`; const vendorsRoot = 'node_modules'; return { vendorsJs: [ `${vendorsRoot}/@popperjs/core/dist/umd/popper.js`, `${vendorsRoot}/bootstrap/dist/js/bootstrap.js`, ], app: appName, templates: `${appName}/templates`, css: `${appName}/static/css`, sass: `${appName}/static/sass`, fonts: `${appName}/static/fonts`, images: `${appName}/static/images`, js: `${appName}/static/js`, }; } const paths = pathsConfig(); //////////////////////////////// // Tasks //////////////////////////////// // Styles autoprefixing and minification function styles() { const processCss = [ autoprefixer(), // adds vendor prefixes pixrem(), // add fallbacks for rem units ]; const minifyCss = [ cssnano({ preset: 'default' }), // minify result ]; return src(`${paths.sass}/project.scss`) .pipe( sass({ importer: tildeImporter, includePaths: [paths.sass], }).on('error', sass.logError), ) .pipe(plumber()) // Checks for errors .pipe(postcss(processCss)) .pipe(dest(paths.css)) .pipe(rename({ suffix: '.min' })) .pipe(postcss(minifyCss)) // Minifies the result .pipe(dest(paths.css)); } // Javascript minification function scripts() { return src(`${paths.js}/project.js`) .pipe(plumber()) // Checks for errors .pipe(uglify()) // Minifies the js .pipe(rename({ suffix: '.min' })) .pipe(dest(paths.js)); } // Vendor Javascript minification function vendorScripts() { return src(paths.vendorsJs, { sourcemaps: true }) .pipe(concat('vendors.js')) .pipe(dest(paths.js)) .pipe(plumber()) // Checks for errors .pipe(uglify()) // Minifies the js .pipe(rename({ suffix: '.min' })) .pipe(dest(paths.js, { sourcemaps: '.' })); } // Image compression async function imgCompression() { const imagemin = (await import("gulp-imagemin")).default; return src(`${paths.images}/*`, { encoding: false }) .pipe(imagemin()) // Compresses PNG, JPEG, GIF and SVG images .pipe(dest(paths.images)); } {%- if cookiecutter.use_async == 'y' -%} // Run django server function asyncRunServer() { const cmd = spawn( 'gunicorn', ['config.asgi', '-k', 'uvicorn_worker.UvicornWorker', '--reload'], {stdio: 'inherit'}, ); cmd.on('close', function (code) { console.log('gunicorn exited with code ' + code); }) } {%- else %} // Run django server function runServer(cb) { const cmd = spawn('python', ['manage.py', 'runserver'], { stdio: 'inherit' }); cmd.on('close', function (code) { console.log('runServer exited with code ' + code); cb(code); }); } {%- endif %} // Browser sync server for live reload function initBrowserSync() { browserSync.init( [`${paths.css}/*.css`, `${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 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); }, ], }, }, ); } // Watch function watchPaths() { watch(`${paths.sass}/*.scss`{% if cookiecutter.windows == 'y' %}, { usePolling: true }{% endif %}, styles); watch(`${paths.templates}/**/*.html`{% if cookiecutter.windows == 'y' %}, { usePolling: true }{% endif %}).on('change', reload); watch([`${paths.js}/*.js`, `!${paths.js}/*.min.js`]{% if cookiecutter.windows == 'y' %}, { usePolling: true }{% endif %}, scripts).on( 'change', reload, ); } // Generate all assets const build = parallel(styles, scripts, vendorScripts, imgCompression); // Set up dev environment {%- if cookiecutter.use_docker == 'n' %} {%- if cookiecutter.use_async == 'y' %} const dev = parallel(asyncRunServer, initBrowserSync, watchPaths); {%- else %} const dev = parallel(runServer, initBrowserSync, watchPaths); {%- endif %} {%- else %} const dev = parallel(initBrowserSync, watchPaths); {%- endif %} task('default', series(build, dev)); task('build', build); task('dev', dev); ================================================ FILE: {{cookiecutter.project_slug}}/justfile ================================================ export COMPOSE_FILE := "docker-compose.local.yml" ## Just does not yet manage signals for subprocesses reliably, which can lead to unexpected behavior. ## Exercise caution before expanding its usage in production environments. ## For more information, see https://github.com/casey/just/issues/2473 . # Default command to list all available commands. default: @just --list # build: Build python image. build *args: @echo "Building python image..." @docker compose build {{ "{{args}}" }} # up: Start up containers. up: @echo "Starting up containers..." @docker compose up -d --remove-orphans # down: Stop containers. down: @echo "Stopping containers..." @docker compose down # prune: Remove containers and their volumes. prune *args: @echo "Killing containers and removing volumes..." @docker compose down -v {{ "{{args}}" }} # logs: View container logs logs *args: @docker compose logs -f {{ "{{args}}" }} # manage: Executes `manage.py` command. manage +args: @docker compose run --rm django python ./manage.py {{ "{{args}}" }} ================================================ FILE: {{cookiecutter.project_slug}}/locale/README.md ================================================ # Translations Start by configuring the `LANGUAGES` settings in `base.py`, by uncommenting languages you are willing to support. Then, translation strings will be placed in this folder when running: ```bash {% if cookiecutter.use_docker == 'y' %}docker compose -f docker-compose.local.yml run --rm django {% endif %}python manage.py makemessages --all --no-location ``` This should generate `django.po` (stands for Portable Object) files under each locale `/LC_MESSAGES/django.po`. Each translatable string in the codebase is collected with its `msgid` and need to be translated as `msgstr`, for example: ```po msgid "users" msgstr "utilisateurs" ``` Once all translations are done, they need to be compiled into `.mo` files (stands for Machine Object), which are the actual binary files used by the application: ```bash {% if cookiecutter.use_docker == 'y' %}docker compose -f docker-compose.local.yml run --rm django {% endif %}python manage.py compilemessages ``` Note that the `.po` files are NOT used by the application directly, so if the `.mo` files are out of date, the content won't appear as translated even if the `.po` files are up-to-date. ## Production The production image runs `compilemessages` automatically at build time, so as long as your translated source files (PO) are up-to-date, you're good to go. ## Add a new language 1. Update the [`LANGUAGES` setting](https://docs.djangoproject.com/en/stable/ref/settings/#std-setting-LANGUAGES) to your project's base settings. 2. Create the locale folder for the language next to this file, e.g. `fr_FR` for French. Make sure the case is correct. 3. Run `makemessages` (as instructed above) to generate the PO files for the new language. ================================================ FILE: {{cookiecutter.project_slug}}/locale/en_US/LC_MESSAGES/django.po ================================================ # Translations for the {{ cookiecutter.project_name }} project # Copyright (C) {% now 'utc', '%Y' %} {{ cookiecutter.author_name }} # {{ cookiecutter.author_name }} <{{ cookiecutter.email }}>, {% now 'utc', '%Y' %}. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: {{ cookiecutter.version }}\n" "Language: en-US\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" ================================================ FILE: {{cookiecutter.project_slug}}/locale/fr_FR/LC_MESSAGES/django.po ================================================ # Translations for the {{ cookiecutter.project_name }} project # Copyright (C) {% now 'utc', '%Y' %} {{ cookiecutter.author_name }} # {{ cookiecutter.author_name }} <{{ cookiecutter.email }}>, {% now 'utc', '%Y' %}. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: {{ cookiecutter.version }}\n" "Language: fr-FR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" #: {{cookiecutter.project_slug}}/templates/account/account_inactive.html:5 #: {{cookiecutter.project_slug}}/templates/account/account_inactive.html:8 msgid "Account Inactive" msgstr "Compte inactif" #: {{cookiecutter.project_slug}}/templates/account/account_inactive.html:10 msgid "This account is inactive." msgstr "Ce compte est inactif." #: {{cookiecutter.project_slug}}/templates/account/email.html:7 msgid "Account" msgstr "Compte" #: {{cookiecutter.project_slug}}/templates/account/email.html:10 msgid "E-mail Addresses" msgstr "Adresses e-mail" #: {{cookiecutter.project_slug}}/templates/account/email.html:13 msgid "The following e-mail addresses are associated with your account:" msgstr "Les adresses e-mail suivantes sont associées à votre compte :" #: {{cookiecutter.project_slug}}/templates/account/email.html:27 msgid "Verified" msgstr "Vérifié" #: {{cookiecutter.project_slug}}/templates/account/email.html:29 msgid "Unverified" msgstr "Non vérifié" #: {{cookiecutter.project_slug}}/templates/account/email.html:31 msgid "Primary" msgstr "Primaire" #: {{cookiecutter.project_slug}}/templates/account/email.html:37 msgid "Make Primary" msgstr "Changer Primaire" #: {{cookiecutter.project_slug}}/templates/account/email.html:38 msgid "Re-send Verification" msgstr "Renvoyer vérification" #: {{cookiecutter.project_slug}}/templates/account/email.html:39 msgid "Remove" msgstr "Supprimer" #: {{cookiecutter.project_slug}}/templates/account/email.html:46 msgid "Warning:" msgstr "Avertissement:" #: {{cookiecutter.project_slug}}/templates/account/email.html:46 msgid "" "You currently do not have any e-mail address set up. You should really add " "an e-mail address so you can receive notifications, reset your password, etc." msgstr "" "Vous n'avez actuellement aucune adresse e-mail configurée. Vous devriez ajouter " "une adresse e-mail pour reçevoir des notifications, réinitialiser votre mot " "de passe, etc." #: {{cookiecutter.project_slug}}/templates/account/email.html:51 msgid "Add E-mail Address" msgstr "Ajouter une adresse e-mail" #: {{cookiecutter.project_slug}}/templates/account/email.html:56 msgid "Add E-mail" msgstr "Ajouter e-mail" #: {{cookiecutter.project_slug}}/templates/account/email.html:66 msgid "Do you really want to remove the selected e-mail address?" msgstr "Voulez-vous vraiment supprimer l'adresse e-mail sélectionnée ?" #: {{cookiecutter.project_slug}}/templates/account/email_confirm.html:6 #: {{cookiecutter.project_slug}}/templates/account/email_confirm.html:10 msgid "Confirm E-mail Address" msgstr "Confirmez votre adresse email" #: {{cookiecutter.project_slug}}/templates/account/email_confirm.html:16 #, python-format msgid "" "Please confirm that %(email)s is an e-mail " "address for user %(user_display)s." msgstr "" "Veuillez confirmer que %(email)s est un e-mail " "adresse de l'utilisateur %(user_display)s." #: {{cookiecutter.project_slug}}/templates/account/email_confirm.html:20 msgid "Confirm" msgstr "Confirm" #: {{cookiecutter.project_slug}}/templates/account/email_confirm.html:27 #, python-format msgid "" "This e-mail confirmation link expired or is invalid. Please issue a new e-mail confirmation request." msgstr "" "Ce lien de confirmation par e-mail a expiré ou n'est pas valide. Veuillez" "émettre une nouvelle demande de confirmation " "par e-mail." #: {{cookiecutter.project_slug}}/templates/account/login.html:7 #: {{cookiecutter.project_slug}}/templates/account/login.html:11 #: {{cookiecutter.project_slug}}/templates/account/login.html:56 #: {{cookiecutter.project_slug}}/templates/base.html:72 msgid "Sign In" msgstr "S'identifier" #: {{cookiecutter.project_slug}}/templates/account/login.html:17 msgid "Please sign in with one of your existing third party accounts:" msgstr "Veuillez vous connecter avec l'un de vos comptes tiers existants :" #: {{cookiecutter.project_slug}}/templates/account/login.html:19 #, python-format msgid "" "Or, sign up for a %(site_name)s account and " "sign in below:" msgstr "" "Ou, créez un compte %(site_name)s et " "connectez-vous ci-dessous :" #: {{cookiecutter.project_slug}}/templates/account/login.html:32 msgid "or" msgstr "ou" #: {{cookiecutter.project_slug}}/templates/account/login.html:41 #, python-format msgid "" "If you have not created an account yet, then please sign up first." msgstr "" "Si vous n'avez pas encore créé de compte, veuillez d'abord vous inscrire." #: {{cookiecutter.project_slug}}/templates/account/login.html:55 msgid "Forgot Password?" msgstr "Mot de passe oublié?" #: {{cookiecutter.project_slug}}/templates/account/logout.html:5 #: {{cookiecutter.project_slug}}/templates/account/logout.html:8 #: {{cookiecutter.project_slug}}/templates/account/logout.html:17 #: {{cookiecutter.project_slug}}/templates/base.html:61 msgid "Sign Out" msgstr "Se déconnecter" #: {{cookiecutter.project_slug}}/templates/account/logout.html:10 msgid "Are you sure you want to sign out?" msgstr "Êtes-vous certain de vouloir vous déconnecter?" #: {{cookiecutter.project_slug}}/templates/account/password_change.html:6 #: {{cookiecutter.project_slug}}/templates/account/password_change.html:9 #: {{cookiecutter.project_slug}}/templates/account/password_change.html:14 #: {{cookiecutter.project_slug}}/templates/account/password_reset_from_key.html:5 #: {{cookiecutter.project_slug}}/templates/account/password_reset_from_key.html:8 #: {{cookiecutter.project_slug}}/templates/account/password_reset_from_key_done.html:4 #: {{cookiecutter.project_slug}}/templates/account/password_reset_from_key_done.html:7 msgid "Change Password" msgstr "Changer le mot de passe" #: {{cookiecutter.project_slug}}/templates/account/password_reset.html:7 #: {{cookiecutter.project_slug}}/templates/account/password_reset.html:11 #: {{cookiecutter.project_slug}}/templates/account/password_reset_done.html:6 #: {{cookiecutter.project_slug}}/templates/account/password_reset_done.html:9 msgid "Password Reset" msgstr "Réinitialisation du mot de passe" #: {{cookiecutter.project_slug}}/templates/account/password_reset.html:16 msgid "" "Forgotten your password? Enter your e-mail address below, and we'll send you " "an e-mail allowing you to reset it." msgstr "" "Mot de passe oublié? Entrez votre adresse e-mail ci-dessous, et nous vous " "enverrons un e-mail vous permettant de le réinitialiser." #: {{cookiecutter.project_slug}}/templates/account/password_reset.html:21 msgid "Reset My Password" msgstr "Réinitialiser mon mot de passe" #: {{cookiecutter.project_slug}}/templates/account/password_reset.html:24 msgid "Please contact us if you have any trouble resetting your password." msgstr "" "Veuillez nous contacter si vous rencontrez des difficultés pour réinitialiser" "votre mot de passe." #: {{cookiecutter.project_slug}}/templates/account/password_reset_done.html:15 msgid "" "We have sent you an e-mail. Please contact us if you do not receive it " "within a few minutes." msgstr "" "Nous vous avons envoyé un e-mail. Veuillez nous contacter si vous ne le " "recevez pas d'ici quelques minutes." #: {{cookiecutter.project_slug}}/templates/account/password_reset_from_key.html:8 msgid "Bad Token" msgstr "Token Invalide" #: {{cookiecutter.project_slug}}/templates/account/password_reset_from_key.html:12 #, python-format msgid "" "The password reset link was invalid, possibly because it has already been " "used. Please request a new password reset." msgstr "" "Le lien de réinitialisation du mot de passe n'était pas valide, peut-être parce " "qu'il a déjà été utilisé. Veuillez faire une " "nouvelle demande de réinitialisation de mot de passe." #: {{cookiecutter.project_slug}}/templates/account/password_reset_from_key.html:18 msgid "change password" msgstr "changer le mot de passe" #: {{cookiecutter.project_slug}}/templates/account/password_reset_from_key.html:21 #: {{cookiecutter.project_slug}}/templates/account/password_reset_from_key_done.html:8 msgid "Your password is now changed." msgstr "Votre mot de passe est maintenant modifié." #: {{cookiecutter.project_slug}}/templates/account/password_set.html:6 #: {{cookiecutter.project_slug}}/templates/account/password_set.html:9 #: {{cookiecutter.project_slug}}/templates/account/password_set.html:14 msgid "Set Password" msgstr "Définir le mot de passe" #: {{cookiecutter.project_slug}}/templates/account/signup.html:6 msgid "Signup" msgstr "S'inscrire" #: {{cookiecutter.project_slug}}/templates/account/signup.html:9 #: {{cookiecutter.project_slug}}/templates/account/signup.html:19 #: {{cookiecutter.project_slug}}/templates/base.html:67 msgid "Sign Up" msgstr "S'inscrire" #: {{cookiecutter.project_slug}}/templates/account/signup.html:11 #, python-format msgid "" "Already have an account? Then please sign in." msgstr "" "Vous avez déjà un compte? Alors veuillez vous connecter." #: {{cookiecutter.project_slug}}/templates/account/signup_closed.html:5 #: {{cookiecutter.project_slug}}/templates/account/signup_closed.html:8 msgid "Sign Up Closed" msgstr "Inscriptions closes" #: {{cookiecutter.project_slug}}/templates/account/signup_closed.html:10 msgid "We are sorry, but the sign up is currently closed." msgstr "Désolé, mais l'inscription est actuellement fermée." #: {{cookiecutter.project_slug}}/templates/account/verification_sent.html:5 #: {{cookiecutter.project_slug}}/templates/account/verification_sent.html:8 #: {{cookiecutter.project_slug}}/templates/account/verified_email_required.html:5 #: {{cookiecutter.project_slug}}/templates/account/verified_email_required.html:8 msgid "Verify Your E-mail Address" msgstr "Vérifiez votre adresse e-mail" #: {{cookiecutter.project_slug}}/templates/account/verification_sent.html:10 msgid "" "We have sent an e-mail to you for verification. Follow the link provided to " "finalize the signup process. Please contact us if you do not receive it " "within a few minutes." msgstr "Nous vous avons envoyé un e-mail pour vérification. Suivez le lien fourni " "pour finalisez le processus d'inscription. Veuillez nous contacter si vous ne le " "recevez pas d'ici quelques minutes." #: {{cookiecutter.project_slug}}/templates/account/verified_email_required.html:12 msgid "" "This part of the site requires us to verify that\n" "you are who you claim to be. For this purpose, we require that you\n" "verify ownership of your e-mail address. " msgstr "" "Cette partie du site nous oblige à vérifier que\n" "vous êtes qui vous prétendez être. Nous vous demandons donc de\n" "vérifier la propriété de votre adresse e-mail." #: {{cookiecutter.project_slug}}/templates/account/verified_email_required.html:16 msgid "" "We have sent an e-mail to you for\n" "verification. Please click on the link inside this e-mail. Please\n" "contact us if you do not receive it within a few minutes." msgstr "" "Nous vous avons envoyé un e-mail pour\n" "vérification. Veuillez cliquer sur le lien contenu dans cet e-mail. Veuillez nous\n" "contacter si vous ne le recevez pas d'ici quelques minutes." #: {{cookiecutter.project_slug}}/templates/account/verified_email_required.html:20 #, python-format msgid "" "Note: you can still change your e-" "mail address." msgstr "" "Remarque : vous pouvez toujours changer votre e-" "adresse e-mail." #: {{cookiecutter.project_slug}}/templates/base.html:57 msgid "My Profile" msgstr "Mon Profil" #: {{cookiecutter.project_slug}}/users/admin.py:17 msgid "Personal info" msgstr "Personal info" #: {{cookiecutter.project_slug}}/users/admin.py:19 msgid "Permissions" msgstr "Permissions" #: {{cookiecutter.project_slug}}/users/admin.py:30 msgid "Important dates" msgstr "Dates importantes" #: {{cookiecutter.project_slug}}/users/apps.py:7 msgid "Users" msgstr "Utilisateurs" #: {{cookiecutter.project_slug}}/users/forms.py:24 #: {{cookiecutter.project_slug}}/users/tests/test_forms.py:36 msgid "This username has already been taken." msgstr "Ce nom d'utilisateur est déjà pris." #: {{cookiecutter.project_slug}}/users/models.py:15 msgid "Name of User" msgstr "Nom de l'utilisateur" #: {{cookiecutter.project_slug}}/users/views.py:23 msgid "Information successfully updated" msgstr "Informations mises à jour avec succès" ================================================ FILE: {{cookiecutter.project_slug}}/locale/pt_BR/LC_MESSAGES/django.po ================================================ # Translations for the {{ cookiecutter.project_name }} project # Copyright (C) {% now 'utc', '%Y' %} {{ cookiecutter.author_name }} # {{ cookiecutter.author_name }} <{{ cookiecutter.email }}>, {% now 'utc', '%Y' %}. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: {{ cookiecutter.version }}\n" "Language: pt-BR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" #: {{cookiecutter.project_slug}}/templates/account/account_inactive.html:5 #: {{cookiecutter.project_slug}}/templates/account/account_inactive.html:8 msgid "Account Inactive" msgstr "Conta Inativa" #: {{cookiecutter.project_slug}}/templates/account/account_inactive.html:10 msgid "This account is inactive." msgstr "Esta conta está inativa." #: {{cookiecutter.project_slug}}/templates/account/email.html:7 msgid "Account" msgstr "Conta" #: {{cookiecutter.project_slug}}/templates/account/email.html:10 msgid "E-mail Addresses" msgstr "Endereços de E-mail" #: {{cookiecutter.project_slug}}/templates/account/email.html:13 msgid "The following e-mail addresses are associated with your account:" msgstr "Os seguintes endereços de e-mail estão associados à sua conta:" #: {{cookiecutter.project_slug}}/templates/account/email.html:27 msgid "Verified" msgstr "Verificado" #: {{cookiecutter.project_slug}}/templates/account/email.html:29 msgid "Unverified" msgstr "Não verificado" #: {{cookiecutter.project_slug}}/templates/account/email.html:31 msgid "Primary" msgstr "Primário" #: {{cookiecutter.project_slug}}/templates/account/email.html:37 msgid "Make Primary" msgstr "Tornar Primário" #: {{cookiecutter.project_slug}}/templates/account/email.html:38 msgid "Re-send Verification" msgstr "Reenviar verificação" #: {{cookiecutter.project_slug}}/templates/account/email.html:39 msgid "Remove" msgstr "Remover" #: {{cookiecutter.project_slug}}/templates/account/email.html:46 msgid "Warning:" msgstr "Aviso:" #: {{cookiecutter.project_slug}}/templates/account/email.html:46 msgid "" "You currently do not have any e-mail address set up. You should really add " "an e-mail address so you can receive notifications, reset your password, etc." msgstr "" "No momento, você não tem nenhum endereço de e-mail configurado. Você " "realmente deve adicionar um endereço de e-mail para receber notificações, " "redefinir sua senha etc." #: {{cookiecutter.project_slug}}/templates/account/email.html:51 msgid "Add E-mail Address" msgstr "Adicionar Endereço de E-mail" #: {{cookiecutter.project_slug}}/templates/account/email.html:56 msgid "Add E-mail" msgstr "Adicionar E-mail" #: {{cookiecutter.project_slug}}/templates/account/email.html:66 msgid "Do you really want to remove the selected e-mail address?" msgstr "Você realmente deseja remover o endereço de e-mail selecionado?" #: {{cookiecutter.project_slug}}/templates/account/email_confirm.html:6 #: {{cookiecutter.project_slug}}/templates/account/email_confirm.html:10 msgid "Confirm E-mail Address" msgstr "Confirme o endereço de e-mail" #: {{cookiecutter.project_slug}}/templates/account/email_confirm.html:16 #, python-format msgid "" "Please confirm that %(email)s is an e-mail " "address for user %(user_display)s." msgstr "" "Confirme se %(email)s é um endereço de " "e-mail do usuário %(user_display)s." #: {{cookiecutter.project_slug}}/templates/account/email_confirm.html:20 msgid "Confirm" msgstr "Confirmar" #: {{cookiecutter.project_slug}}/templates/account/email_confirm.html:27 #, python-format msgid "" "This e-mail confirmation link expired or is invalid. Please issue a new e-mail confirmation request." msgstr "Este link de confirmação de e-mail expirou ou é inválido. " "Por favor, emita um novo pedido de confirmação por e-mail." #: {{cookiecutter.project_slug}}/templates/account/login.html:7 #: {{cookiecutter.project_slug}}/templates/account/login.html:11 #: {{cookiecutter.project_slug}}/templates/account/login.html:56 #: {{cookiecutter.project_slug}}/templates/base.html:72 msgid "Sign In" msgstr "Entrar" #: {{cookiecutter.project_slug}}/templates/account/login.html:17 msgid "Please sign in with one of your existing third party accounts:" msgstr "Faça login com uma de suas contas de terceiros existentes:" #: {{cookiecutter.project_slug}}/templates/account/login.html:19 #, python-format msgid "" "Or, sign up for a %(site_name)s account and " "sign in below:" msgstr "Ou, cadastre-se para uma conta em %(site_name)s e entre abaixo:" #: {{cookiecutter.project_slug}}/templates/account/login.html:32 msgid "or" msgstr "ou" #: {{cookiecutter.project_slug}}/templates/account/login.html:41 #, python-format msgid "" "If you have not created an account yet, then please sign up first." msgstr "Se você ainda não criou uma conta, registre-se primeiro." #: {{cookiecutter.project_slug}}/templates/account/login.html:55 msgid "Forgot Password?" msgstr "Esqueceu sua senha?" #: {{cookiecutter.project_slug}}/templates/account/logout.html:5 #: {{cookiecutter.project_slug}}/templates/account/logout.html:8 #: {{cookiecutter.project_slug}}/templates/account/logout.html:17 #: {{cookiecutter.project_slug}}/templates/base.html:61 msgid "Sign Out" msgstr "Sair" #: {{cookiecutter.project_slug}}/templates/account/logout.html:10 msgid "Are you sure you want to sign out?" msgstr "Você tem certeza que deseja sair?" #: {{cookiecutter.project_slug}}/templates/account/password_change.html:6 #: {{cookiecutter.project_slug}}/templates/account/password_change.html:9 #: {{cookiecutter.project_slug}}/templates/account/password_change.html:14 #: {{cookiecutter.project_slug}}/templates/account/password_reset_from_key.html:5 #: {{cookiecutter.project_slug}}/templates/account/password_reset_from_key.html:8 #: {{cookiecutter.project_slug}}/templates/account/password_reset_from_key_done.html:4 #: {{cookiecutter.project_slug}}/templates/account/password_reset_from_key_done.html:7 msgid "Change Password" msgstr "Alterar Senha" #: {{cookiecutter.project_slug}}/templates/account/password_reset.html:7 #: {{cookiecutter.project_slug}}/templates/account/password_reset.html:11 #: {{cookiecutter.project_slug}}/templates/account/password_reset_done.html:6 #: {{cookiecutter.project_slug}}/templates/account/password_reset_done.html:9 msgid "Password Reset" msgstr "Redefinição de senha" #: {{cookiecutter.project_slug}}/templates/account/password_reset.html:16 msgid "" "Forgotten your password? Enter your e-mail address below, and we'll send you " "an e-mail allowing you to reset it." msgstr "Esqueceu sua senha? Digite seu endereço de e-mail abaixo e enviaremos um e-mail permitindo que você o redefina." #: {{cookiecutter.project_slug}}/templates/account/password_reset.html:21 msgid "Reset My Password" msgstr "Redefinir minha senha" #: {{cookiecutter.project_slug}}/templates/account/password_reset.html:24 msgid "Please contact us if you have any trouble resetting your password." msgstr "Entre em contato conosco se tiver algum problema para redefinir sua senha." #: {{cookiecutter.project_slug}}/templates/account/password_reset_done.html:15 msgid "" "We have sent you an e-mail. Please contact us if you do not receive it " "within a few minutes." msgstr "Enviamos um e-mail para você. Entre em contato conosco se você não recebê-lo dentro de alguns minutos." #: {{cookiecutter.project_slug}}/templates/account/password_reset_from_key.html:8 msgid "Bad Token" msgstr "Token Inválido" #: {{cookiecutter.project_slug}}/templates/account/password_reset_from_key.html:12 #, python-format msgid "" "The password reset link was invalid, possibly because it has already been " "used. Please request a new password reset." msgstr "O link de redefinição de senha era inválido, possivelmente porque já foi usado. " "Solicite uma nova redefinição de senha." #: {{cookiecutter.project_slug}}/templates/account/password_reset_from_key.html:18 msgid "change password" msgstr "alterar senha" #: {{cookiecutter.project_slug}}/templates/account/password_reset_from_key.html:21 #: {{cookiecutter.project_slug}}/templates/account/password_reset_from_key_done.html:8 msgid "Your password is now changed." msgstr "Sua senha agora foi alterada." #: {{cookiecutter.project_slug}}/templates/account/password_set.html:6 #: {{cookiecutter.project_slug}}/templates/account/password_set.html:9 #: {{cookiecutter.project_slug}}/templates/account/password_set.html:14 msgid "Set Password" msgstr "Definir Senha" #: {{cookiecutter.project_slug}}/templates/account/signup.html:6 msgid "Signup" msgstr "Cadastro" #: {{cookiecutter.project_slug}}/templates/account/signup.html:9 #: {{cookiecutter.project_slug}}/templates/account/signup.html:19 #: {{cookiecutter.project_slug}}/templates/base.html:67 msgid "Sign Up" msgstr "Cadastro" #: {{cookiecutter.project_slug}}/templates/account/signup.html:11 #, python-format msgid "" "Already have an account? Then please sign in." msgstr "já tem uma conta? Então, por favor, faça login." #: {{cookiecutter.project_slug}}/templates/account/signup_closed.html:5 #: {{cookiecutter.project_slug}}/templates/account/signup_closed.html:8 msgid "Sign Up Closed" msgstr "Inscrições encerradas" #: {{cookiecutter.project_slug}}/templates/account/signup_closed.html:10 msgid "We are sorry, but the sign up is currently closed." msgstr "Lamentamos, mas as inscrições estão encerradas no momento." #: {{cookiecutter.project_slug}}/templates/account/verification_sent.html:5 #: {{cookiecutter.project_slug}}/templates/account/verification_sent.html:8 #: {{cookiecutter.project_slug}}/templates/account/verified_email_required.html:5 #: {{cookiecutter.project_slug}}/templates/account/verified_email_required.html:8 msgid "Verify Your E-mail Address" msgstr "Verifique seu endereço de e-mail" #: {{cookiecutter.project_slug}}/templates/account/verification_sent.html:10 msgid "" "We have sent an e-mail to you for verification. Follow the link provided to " "finalize the signup process. Please contact us if you do not receive it " "within a few minutes." msgstr "Enviamos um e-mail para você para verificação. Siga o link fornecido para finalizar o processo de inscrição. Entre em contato conosco se você não recebê-lo dentro de alguns minutos." #: {{cookiecutter.project_slug}}/templates/account/verified_email_required.html:12 msgid "" "This part of the site requires us to verify that\n" "you are who you claim to be. For this purpose, we require that you\n" "verify ownership of your e-mail address. " msgstr "Esta parte do site exige que verifiquemos se você é quem afirma ser.\n" "Para esse fim, exigimos que você verifique a propriedade\n" "do seu endereço de e-mail." #: {{cookiecutter.project_slug}}/templates/account/verified_email_required.html:16 msgid "" "We have sent an e-mail to you for\n" "verification. Please click on the link inside this e-mail. Please\n" "contact us if you do not receive it within a few minutes." msgstr "Enviamos um e-mail para você para verificação.\n" "Por favor, clique no link dentro deste e-mail.\n" "Entre em contato conosco se você não recebê-lo dentro de alguns minutos." #: {{cookiecutter.project_slug}}/templates/account/verified_email_required.html:20 #, python-format msgid "" "Note: you can still change your e-" "mail address." msgstr "Nota: você ainda pode alterar seu endereço de e-mail." #: {{cookiecutter.project_slug}}/templates/base.html:57 msgid "My Profile" msgstr "Meu perfil" #: {{cookiecutter.project_slug}}/users/admin.py:17 msgid "Personal info" msgstr "Informação pessoal" #: {{cookiecutter.project_slug}}/users/admin.py:19 msgid "Permissions" msgstr "Permissões" #: {{cookiecutter.project_slug}}/users/admin.py:30 msgid "Important dates" msgstr "Datas importantes" #: {{cookiecutter.project_slug}}/users/apps.py:7 msgid "Users" msgstr "Usuários" #: {{cookiecutter.project_slug}}/users/forms.py:24 #: {{cookiecutter.project_slug}}/users/tests/test_forms.py:36 msgid "This username has already been taken." msgstr "Este nome de usuário já foi usado." #: {{cookiecutter.project_slug}}/users/models.py:15 msgid "Name of User" msgstr "Nome do Usuário" #: {{cookiecutter.project_slug}}/users/views.py:23 msgid "Information successfully updated" msgstr "Informação atualizada com sucesso" ================================================ FILE: {{cookiecutter.project_slug}}/manage.py ================================================ #!/usr/bin/env python """Django's command-line utility for administrative tasks.""" import os import sys from pathlib import Path def main(): """Run administrative tasks.""" os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.local") try: from django.core.management import execute_from_command_line # noqa: PLC0415 except ImportError as exc: raise ImportError( # noqa: TRY003 "Couldn't import Django. Are you sure it's installed and " # noqa: EM101 "available on your PYTHONPATH environment variable? Did you " "forget to activate a virtual environment?", ) from exc # This allows easy placement of apps within the interior # {{ cookiecutter.project_slug }} directory. current_path = Path(__file__).parent.resolve() sys.path.append(str(current_path / "{{ cookiecutter.project_slug }}")) execute_from_command_line(sys.argv) if __name__ == "__main__": main() ================================================ FILE: {{cookiecutter.project_slug}}/merge_production_dotenvs_in_dotenv.py ================================================ from collections.abc import Sequence from pathlib import Path BASE_DIR = Path(__file__).parent.resolve() PRODUCTION_DOTENVS_DIR = BASE_DIR / ".envs" / ".production" PRODUCTION_DOTENV_FILES = [ PRODUCTION_DOTENVS_DIR / ".django", PRODUCTION_DOTENVS_DIR / ".postgres", ] DOTENV_FILE = BASE_DIR / ".env" def merge( output_file: Path, files_to_merge: Sequence[Path], ) -> None: merged_content = "" for merge_file in files_to_merge: merged_content += merge_file.read_text() merged_content += "\n" output_file.write_text(merged_content) if __name__ == "__main__": merge(DOTENV_FILE, PRODUCTION_DOTENV_FILES) ================================================ FILE: {{cookiecutter.project_slug}}/package.json ================================================ { "name": "{{cookiecutter.project_slug}}", "version": "{{ cookiecutter.version }}", "devDependencies": { "@babel/core": "^7.16.5", "@babel/preset-env": "^7.16.5", "@popperjs/core": "^2.10.2", "autoprefixer": "^10.4.0", "babel-loader": "^10.0.0", "bootstrap": "^5.2.3", "browser-sync": "^3.0.2", "css-loader": "^7.1.2", "gulp-concat": "^2.6.1", "concurrently": "^9.0.0", "cssnano": "^7.0.0", "gulp": "^5.0.0", "gulp-imagemin": "^9.1.0", "gulp-plumber": "^1.2.1", "gulp-postcss": "^10.0.0", "gulp-rename": "^2.0.0", "gulp-sass": "^5.0.0", "gulp-uglify-es": "^3.0.0", "mini-css-extract-plugin": "^2.4.5", "node-sass-tilde-importer": "^1.0.2", "pixrem": "^5.0.0", "postcss": "^8.3.11", "postcss-loader": "^8.0.0", "postcss-preset-env": "^10.0.3", "sass": "^1.93.1", "sass-loader": "^16.0.1", "webpack": "^5.82.0", "webpack-bundle-tracker": "^3.0.1", "webpack-cli": "^6.0.1", "webpack-dev-server": "^5.0.2", "webpack-merge": "^6.0.1" }, "engines": { "node": "24.14" }, "browserslist": [ "last 2 versions" ], "babel": { "presets": ["@babel/preset-env"] }, "scripts": { "dev": "", "build": "" } } ================================================ FILE: {{cookiecutter.project_slug}}/pyproject.toml ================================================ [project] name = "{{ cookiecutter.project_slug }}" version = "{{ cookiecutter.version }}" description = "{{ cookiecutter.description }}" readme = "README.md" license = { text = "{{ cookiecutter.open_source_license }}" } authors = [ { name = "{{ cookiecutter.author_name }}", email = "{{ cookiecutter.email }}" }, ] requires-python = "==3.13.*" classifiers = [ "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.13", ] dependencies = [ {# set the an initial indentation for uv to follow #} "django", ] [dependency-groups] dev = [ {# set the an initial indentation for uv to follow #} "pytest", ] [tool.ruff] # Exclude a variety of commonly ignored directories. extend-exclude = [ "*/migrations/*.py", "staticfiles/*", ] lint.select = [ "A", "ASYNC", "B", "BLE", "C4", "C90", "COM", "DJ", "DTZ", "E", "EM", "ERA", "EXE", "F", "FA", "FBT", "FLY", "G", "I", "ICN", "INP", "INT", "ISC", "N", "PD", "PERF", "PGH", "PIE", "PL", "PT", "PTH", "PYI", "Q", "RET", "RSE", "RUF", "S", "SIM", "SLF", "SLOT", "T10", "T20", "TC", "TID", "TRY", "UP", "W", "YTT", ] lint.ignore = [ "RUF012", # Mutable class attributes should be annotated with `typing.ClassVar` "S101", # Use of assert detected https://docs.astral.sh/ruff/rules/assert/ "SIM102", # sometimes it's better to nest # of types for comparison. # Deactivated because it can make the code slow: # https://github.com/astral-sh/ruff/issues/7871 ] lint.isort.force-single-line = true [tool.pyproject-fmt] keep_full_version = true # ==== pytest ==== [tool.pytest.ini_options] minversion = "6.0" addopts = "--ds=config.settings.test --reuse-db --import-mode=importlib" python_files = [ "tests.py", "test_*.py", ] {%- if cookiecutter.frontend_pipeline == 'Gulp' %} norecursedirs = [ "node_modules" ] {%- endif %} # ==== Coverage ==== [tool.coverage.run] include = [ "{{cookiecutter.project_slug}}/**" ] omit = [ "*/migrations/*", "*/tests/*" ] plugins = [ "django_coverage_plugin" ] # ==== mypy ==== [tool.mypy] python_version = "3.13" check_untyped_defs = true ignore_missing_imports = true warn_unused_ignores = true warn_redundant_casts = true warn_unused_configs = true plugins = [ "mypy_django_plugin.main", {%- if cookiecutter.rest_api == 'DRF' %} "mypy_drf_plugin.main", {%- endif %} ] [[tool.mypy.overrides]] # Django migrations should not produce any errors: module = "*.migrations.*" ignore_errors = true [tool.django-stubs] django_settings_module = "config.settings.test" # ==== djLint ==== [tool.djlint] blank_line_after_tag = "load,extends" close_void_tags = true format_css = true format_js = true # TODO: remove T002 when fixed https://github.com/djlint/djLint/issues/687 ignore = "H006,H030,H031,T002" include = "H017,H035" indent = 2 max_line_length = 119 profile = "django" [tool.djlint.css] indent_size = 2 [tool.djlint.js] indent_size = 2 ================================================ FILE: {{cookiecutter.project_slug}}/requirements/base.txt ================================================ python-slugify==8.0.4 # https://github.com/un33k/python-slugify Pillow==12.1.1 # https://github.com/python-pillow/Pillow {%- if cookiecutter.frontend_pipeline == 'Django Compressor' %} {%- if cookiecutter.windows == 'y' and cookiecutter.use_docker == 'n' %} rcssmin==1.2.2 --install-option="--without-c-extensions" # https://github.com/ndparker/rcssmin {%- else %} rcssmin==1.2.2 # https://github.com/ndparker/rcssmin {%- endif %} {%- endif %} argon2-cffi==25.1.0 # https://github.com/hynek/argon2_cffi {%- if cookiecutter.use_whitenoise == 'y' %} whitenoise==6.12.0 # https://github.com/evansd/whitenoise {%- endif %} redis==7.3.0 # https://github.com/redis/redis-py {%- if cookiecutter.use_docker == "y" or cookiecutter.windows == "n" %} hiredis==3.3.1 # https://github.com/redis/hiredis-py {%- endif %} {%- if cookiecutter.use_celery == "y" %} celery==5.6.2 # pyup: < 6.0 # https://github.com/celery/celery django-celery-beat==2.9.0 # https://github.com/celery/django-celery-beat {%- if cookiecutter.use_docker == 'y' %} flower==2.0.1 # https://github.com/mher/flower {%- endif %} {%- endif %} {%- if cookiecutter.use_async == 'y' %} uvicorn[standard]==0.42.0 # https://github.com/Kludex/uvicorn uvicorn-worker==0.4.0 # https://github.com/Kludex/uvicorn-worker {%- endif %} # Django # ------------------------------------------------------------------------------ django==6.0.3 # pyup: < 6.1 # https://www.djangoproject.com/ django-environ==0.13.0 # https://github.com/joke2k/django-environ django-model-utils==5.0.0 # https://github.com/jazzband/django-model-utils django-allauth[mfa]==65.15.0 # https://github.com/pennersr/django-allauth django-crispy-forms==2.6 # https://github.com/django-crispy-forms/django-crispy-forms crispy-bootstrap5==2026.3 # https://github.com/django-crispy-forms/crispy-bootstrap5 {%- if cookiecutter.frontend_pipeline == 'Django Compressor' %} django-compressor==4.6.0 # https://github.com/django-compressor/django-compressor {%- endif %} django-redis==6.0.0 # https://github.com/jazzband/django-redis {%- if cookiecutter.rest_api == 'DRF' %} # Django REST Framework djangorestframework==3.17.0 # https://github.com/encode/django-rest-framework django-cors-headers==4.9.0 # https://github.com/adamchainz/django-cors-headers # DRF-spectacular for api documentation drf-spectacular==0.29.0 # https://github.com/tfranzel/drf-spectacular {%- elif cookiecutter.rest_api == 'Django Ninja' %} # Django Ninja django-ninja==1.6.2 # https://github.com/vitalik/django-ninja django-cors-headers==4.9.0 # https://github.com/adamchainz/django-cors-headers {%- endif %} {%- if cookiecutter.frontend_pipeline == 'Webpack' %} django-webpack-loader==3.2.3 # https://github.com/django-webpack/django-webpack-loader {%- endif %} ================================================ FILE: {{cookiecutter.project_slug}}/requirements/local.txt ================================================ Werkzeug[watchdog]==3.1.6 # https://github.com/pallets/werkzeug ipdb==0.13.13 # https://github.com/gotcha/ipdb {%- if cookiecutter.use_docker == 'y' %} psycopg[c]==3.3.3 # https://github.com/psycopg/psycopg {%- else %} psycopg[binary]==3.3.3 # https://github.com/psycopg/psycopg {%- endif %} {%- if cookiecutter.use_async == 'y' or cookiecutter.use_celery == 'y' %} watchfiles==1.1.1 # https://github.com/samuelcolvin/watchfiles {%- endif %} # Testing # ------------------------------------------------------------------------------ mypy==1.19.1 # https://github.com/python/mypy django-stubs[compatible-mypy]==6.0.1 # https://github.com/typeddjango/django-stubs pytest==9.0.2 # https://github.com/pytest-dev/pytest pytest-sugar==1.1.1 # https://github.com/Teemu/pytest-sugar {%- if cookiecutter.rest_api == 'DRF' %} djangorestframework-stubs==3.16.8 # https://github.com/typeddjango/djangorestframework-stubs {%- endif %} # Documentation # ------------------------------------------------------------------------------ sphinx==9.1.0 # https://github.com/sphinx-doc/sphinx sphinx-autobuild==2025.8.25 # https://github.com/GaretJax/sphinx-autobuild # Code quality # ------------------------------------------------------------------------------ ruff==0.15.7 # https://github.com/astral-sh/ruff coverage==7.13.5 # https://github.com/nedbat/coveragepy djlint==1.36.4 # https://github.com/Riverside-Healthcare/djLint pre-commit==4.5.1 # https://github.com/pre-commit/pre-commit # Django # ------------------------------------------------------------------------------ factory-boy==3.3.3 # https://github.com/FactoryBoy/factory_boy django-debug-toolbar==6.2.0 # https://github.com/jazzband/django-debug-toolbar django-extensions==4.1 # https://github.com/django-extensions/django-extensions django-coverage-plugin==3.2.0 # https://github.com/nedbat/django_coverage_plugin pytest-django==4.12.0 # https://github.com/pytest-dev/pytest-django ================================================ FILE: {{cookiecutter.project_slug}}/requirements/production.txt ================================================ # PRECAUTION: avoid production dependencies that aren't in development -r base.txt gunicorn==25.1.0 # https://github.com/benoitc/gunicorn psycopg[c]==3.3.3 # https://github.com/psycopg/psycopg {%- if cookiecutter.use_whitenoise == 'n'and cookiecutter.cloud_provider in ('AWS', 'GCP', 'Azure') %} Collectfasta==3.3.3 # https://github.com/jasongi/collectfasta {%- endif %} {%- if cookiecutter.use_sentry == "y" %} sentry-sdk==2.55.0 # https://github.com/getsentry/sentry-python {%- endif %} {%- if cookiecutter.use_docker == "n" and cookiecutter.windows == "y" %} hiredis==3.3.1 # https://github.com/redis/hiredis-py {%- endif %} # Django # ------------------------------------------------------------------------------ {%- if cookiecutter.cloud_provider == 'AWS' %} django-storages[s3]==1.14.6 # https://github.com/jschneier/django-storages {%- elif cookiecutter.cloud_provider == 'GCP' %} django-storages[google]==1.14.6 # https://github.com/jschneier/django-storages {%- elif cookiecutter.cloud_provider == 'Azure' %} django-storages[azure]==1.14.6 # https://github.com/jschneier/django-storages {%- endif %} {%- if cookiecutter.mail_service == 'Mailgun' %} django-anymail[mailgun]==14.0 # https://github.com/anymail/django-anymail {%- elif cookiecutter.mail_service == 'Amazon SES' %} django-anymail[amazon-ses]==14.0 # https://github.com/anymail/django-anymail {%- elif cookiecutter.mail_service == 'Mailjet' %} django-anymail[mailjet]==14.0 # https://github.com/anymail/django-anymail {%- elif cookiecutter.mail_service == 'Mandrill' %} django-anymail[mandrill]==14.0 # https://github.com/anymail/django-anymail {%- elif cookiecutter.mail_service == 'Postmark' %} django-anymail[postmark]==14.0 # https://github.com/anymail/django-anymail {%- elif cookiecutter.mail_service == 'Sendgrid' %} django-anymail[sendgrid]==14.0 # https://github.com/anymail/django-anymail {%- elif cookiecutter.mail_service == 'Brevo' %} django-anymail[brevo]==14.0 # https://github.com/anymail/django-anymail {%- elif cookiecutter.mail_service == 'SparkPost' %} django-anymail[sparkpost]==14.0 # https://github.com/anymail/django-anymail {%- elif cookiecutter.mail_service == 'Other SMTP' %} django-anymail==14.0 # https://github.com/anymail/django-anymail {%- endif %} ================================================ FILE: {{cookiecutter.project_slug}}/tests/__init__.py ================================================ ================================================ FILE: {{cookiecutter.project_slug}}/tests/test_merge_production_dotenvs_in_dotenv.py ================================================ from pathlib import Path import pytest from merge_production_dotenvs_in_dotenv import merge @pytest.mark.parametrize( ("input_contents", "expected_output"), [ ([], ""), ([""], "\n"), (["JANE=doe"], "JANE=doe\n"), (["SEP=true", "AR=ator"], "SEP=true\nAR=ator\n"), (["A=0", "B=1", "C=2"], "A=0\nB=1\nC=2\n"), (["X=x\n", "Y=y", "Z=z\n"], "X=x\n\nY=y\nZ=z\n\n"), ], ) def test_merge( tmp_path: Path, input_contents: list[str], expected_output: str, ): output_file = tmp_path / ".env" files_to_merge = [] for num, input_content in enumerate(input_contents, start=1): merge_file = tmp_path / f".service{num}" merge_file.write_text(input_content) files_to_merge.append(merge_file) merge(output_file, files_to_merge) assert output_file.read_text() == expected_output ================================================ FILE: {{cookiecutter.project_slug}}/utility/install_os_dependencies.sh ================================================ #!/bin/bash WORK_DIR="$(dirname "$0")" DISTRO_NAME=$(lsb_release -sc) OS_REQUIREMENTS_FILENAME="requirements-$DISTRO_NAME.apt" cd $WORK_DIR # Check if a requirements file exist for the current distribution. if [ ! -r "$OS_REQUIREMENTS_FILENAME" ]; then cat <<-EOF >&2 There is no requirements file for your distribution. You can see one of the files listed below to help search the equivalent package in your system: $(find ./ -name "requirements-*.apt" -printf " - %f\n") EOF exit 1; fi # Handle call with wrong command function wrong_command() { echo "${0##*/} - unknown command: '${1}'" >&2 usage_message } # Print help / script usage function usage_message() { cat <<-EOF Usage: $WORK_DIR/${0##*/} Available commands are: list Print a list of all packages defined on ${OS_REQUIREMENTS_FILENAME} file help Print this help Commands that require superuser permission: install Install packages defined on ${OS_REQUIREMENTS_FILENAME} file. Note: This does not upgrade the packages already installed for new versions, even if new version is available in the repository. upgrade Same that install, but upgrade the already installed packages, if new version is available. EOF } # Read the requirements.apt file, and remove comments and blank lines function list_packages(){ grep -v "#" "${OS_REQUIREMENTS_FILENAME}" | grep -v "^$"; } function install_packages() { list_packages | xargs apt-get --no-upgrade install -y; } function upgrade_packages() { list_packages | xargs apt-get install -y; } function install_or_upgrade() { P=${1} PARAN=${P:-"install"} if [[ $EUID -ne 0 ]]; then cat <<-EOF >&2 You must run this script with root privilege Please do: sudo $WORK_DIR/${0##*/} $PARAN EOF exit 1 else apt-get update # Install the basic compilation dependencies and other required libraries of this project if [ "$PARAN" == "install" ]; then install_packages; else upgrade_packages; fi # cleaning downloaded packages from apt-get cache apt-get clean exit 0 fi } # Handle command argument case "$1" in install) install_or_upgrade;; upgrade) install_or_upgrade "upgrade";; list) list_packages;; help|"") usage_message;; *) wrong_command "$1";; esac ================================================ FILE: {{cookiecutter.project_slug}}/utility/install_python_dependencies.sh ================================================ #!/bin/bash WORK_DIR="$(dirname "$0")" PROJECT_DIR="$(dirname "$WORK_DIR")" uv --version >/dev/null 2>&1 || { echo >&2 -e "\nuv is required but it's not installed." echo >&2 -e "You can install it by following the instructions at https://github.com/astral-sh/uv#installation" exit 1; } uv sync --locked ================================================ FILE: {{cookiecutter.project_slug}}/utility/requirements-bionic.apt ================================================ ##basic build dependencies of various Django apps for Ubuntu Bionic 18.04 #build-essential metapackage install: make, gcc, g++, build-essential #required to translate gettext python3-dev ##shared dependencies of: ##Pillow, pylibmc zlib1g-dev ##Postgresql and psycopg dependencies libpq-dev ##Pillow dependencies libtiff5-dev libjpeg8-dev libfreetype6-dev liblcms2-dev libwebp-dev ##django-extensions libgraphviz-dev ================================================ FILE: {{cookiecutter.project_slug}}/utility/requirements-bookworm.apt ================================================ ##basic build dependencies of various Django apps for Debian Bookworm 12.x #build-essential metapackage install: make, gcc, g++, build-essential #required to translate gettext python3-dev ##shared dependencies of: ##Pillow, pylibmc zlib1g-dev ##Postgresql and psycopg dependencies libpq-dev ##Pillow dependencies libtiff5-dev libjpeg62-turbo-dev libfreetype6-dev liblcms2-dev libwebp-dev ##django-extensions libgraphviz-dev ================================================ FILE: {{cookiecutter.project_slug}}/utility/requirements-bullseye.apt ================================================ ##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 psycopg dependencies libpq-dev ##Pillow dependencies libtiff5-dev libjpeg62-turbo-dev libfreetype6-dev liblcms2-dev libwebp-dev ##django-extensions libgraphviz-dev ================================================ FILE: {{cookiecutter.project_slug}}/utility/requirements-buster.apt ================================================ ##basic build dependencies of various Django apps for Debian Jessie 10.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 psycopg dependencies libpq-dev ##Pillow dependencies libtiff5-dev libjpeg62-turbo-dev libfreetype6-dev liblcms2-dev libwebp-dev ##django-extensions libgraphviz-dev ================================================ FILE: {{cookiecutter.project_slug}}/utility/requirements-focal.apt ================================================ ##basic build dependencies of various Django apps for Ubuntu Focal 20.04 #build-essential metapackage install: make, gcc, g++, build-essential #required to translate gettext python3-dev ##shared dependencies of: ##Pillow, pylibmc zlib1g-dev ##Postgresql and psycopg dependencies libpq-dev ##Pillow dependencies libtiff5-dev libjpeg8-dev libfreetype6-dev liblcms2-dev libwebp-dev ##django-extensions graphviz-dev ================================================ FILE: {{cookiecutter.project_slug}}/utility/requirements-jammy.apt ================================================ ##basic build dependencies of various Django apps for Ubuntu Jammy 22.04 #build-essential metapackage install: make, gcc, g++, build-essential #required to translate gettext python3-dev ##shared dependencies of: ##Pillow, pylibmc zlib1g-dev ##Postgresql and psycopg dependencies libpq-dev ##Pillow dependencies libtiff5-dev libjpeg8-dev libfreetype6-dev liblcms2-dev libwebp-dev ##django-extensions graphviz-dev ================================================ FILE: {{cookiecutter.project_slug}}/utility/requirements-jessie.apt ================================================ ##basic build dependencies of various Django apps for Debian Jessie 8.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 psycopg dependencies libpq-dev ##Pillow dependencies libtiff5-dev libjpeg62-turbo-dev libfreetype6-dev liblcms2-dev libwebp-dev ##django-extensions graphviz-dev ================================================ FILE: {{cookiecutter.project_slug}}/utility/requirements-noble.apt ================================================ ##basic build dependencies of various Django apps for Debian Bookworm 12.x #build-essential metapackage install: make, gcc, g++, build-essential #required to translate gettext python3-dev ##shared dependencies of: ##Pillow, pylibmc zlib1g-dev ##Postgresql and psycopg dependencies libpq-dev ##Pillow dependencies libtiff5-dev libjpeg62-turbo-dev libfreetype6-dev liblcms2-dev libwebp-dev ##django-extensions libgraphviz-dev ================================================ FILE: {{cookiecutter.project_slug}}/utility/requirements-stretch.apt ================================================ ##basic build dependencies of various Django apps for Debian Jessie 9.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 psycopg dependencies libpq-dev ##Pillow dependencies libtiff5-dev libjpeg62-turbo-dev libfreetype6-dev liblcms2-dev libwebp-dev ##django-extensions graphviz-dev ================================================ FILE: {{cookiecutter.project_slug}}/utility/requirements-trusty.apt ================================================ ##basic build dependencies of various Django apps for Ubuntu Trusty 14.04 #build-essential metapackage install: make, gcc, g++, build-essential #required to translate gettext python3-dev ##shared dependencies of: ##Pillow, pylibmc zlib1g-dev ##Postgresql and psycopg dependencies libpq-dev ##Pillow dependencies libtiff4-dev libjpeg8-dev libfreetype6-dev liblcms1-dev libwebp-dev ##django-extensions graphviz-dev ================================================ FILE: {{cookiecutter.project_slug}}/utility/requirements-xenial.apt ================================================ ##basic build dependencies of various Django apps for Ubuntu Xenial 16.04 #build-essential metapackage install: make, gcc, g++, build-essential #required to translate gettext python3-dev ##shared dependencies of: ##Pillow, pylibmc zlib1g-dev ##Postgresql and psycopg dependencies libpq-dev ##Pillow dependencies libtiff5-dev libjpeg8-dev libfreetype6-dev liblcms2-dev libwebp-dev ##django-extensions graphviz-dev ================================================ FILE: {{cookiecutter.project_slug}}/webpack/common.config.js ================================================ const path = require('path'); const BundleTracker = require('webpack-bundle-tracker'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); module.exports = { target: 'web', context: path.join(__dirname, '../'), entry: { project: path.resolve(__dirname, '../{{cookiecutter.project_slug}}/static/js/project'), vendors: path.resolve(__dirname, '../{{cookiecutter.project_slug}}/static/js/vendors'), }, output: { path: path.resolve( __dirname, '../{{cookiecutter.project_slug}}/static/webpack_bundles/', ), publicPath: '/static/webpack_bundles/', filename: 'js/[name]-[fullhash].js', chunkFilename: 'js/[name]-[hash].js', }, plugins: [ new BundleTracker({ path: path.resolve(path.join(__dirname, '../')), filename: 'webpack-stats.json', }), new MiniCssExtractPlugin({ filename: 'css/[name].[contenthash].css' }), ], module: { rules: [ // we pass the output from babel loader to react-hot loader { test: /\.js$/, loader: 'babel-loader', }, { test: /\.s?css$/i, use: [ MiniCssExtractPlugin.loader, 'css-loader', { loader: 'postcss-loader', options: { postcssOptions: { plugins: ['postcss-preset-env', 'autoprefixer', 'pixrem'], }, }, }, 'sass-loader', ], }, ], }, resolve: { modules: ['node_modules'], extensions: ['.js', '.jsx'], }, }; ================================================ FILE: {{cookiecutter.project_slug}}/webpack/dev.config.js ================================================ const { merge } = require('webpack-merge'); const commonConfig = require('./common.config'); module.exports = merge(commonConfig, { mode: 'development', devtool: 'inline-source-map', devServer: { port: 3000, proxy: [ { context: ['/'], {%- if cookiecutter.use_docker == 'n' %} target: 'http://0.0.0.0:8000', {%- else %} target: 'http://django:8000', {%- endif %} }, ], client: { overlay: { errors: true, warnings: false, runtimeErrors: true, }, }, // We need hot=false (Disable HMR) to set liveReload=true hot: false, liveReload: true, }, }); ================================================ FILE: {{cookiecutter.project_slug}}/webpack/prod.config.js ================================================ const { merge } = require('webpack-merge'); const commonConfig = require('./common.config'); // This variable should mirror the one from config/settings/production.py {%- if cookiecutter.use_whitenoise == 'n' %} {%- if cookiecutter.cloud_provider == 'AWS' %} const s3BucketName = process.env.DJANGO_AWS_STORAGE_BUCKET_NAME; const awsS3Domain = process.env.DJANGO_AWS_S3_CUSTOM_DOMAIN ? process.env.DJANGO_AWS_S3_CUSTOM_DOMAIN : `${s3BucketName}.s3.amazonaws.com`; const staticUrl = `https://${awsS3Domain}/static/`; {%- elif cookiecutter.cloud_provider == 'GCP' %} const staticUrl = `https://storage.googleapis.com/${process.env.DJANGO_GCP_STORAGE_BUCKET_NAME}/static/`; {%- elif cookiecutter.cloud_provider == 'Azure' %} const staticUrl = `https://${process.env.DJANGO_AZURE_ACCOUNT_NAME}.blob.core.windows.net/static/`; {%- endif %} {%- else %} const staticUrl = '/static/'; {%- endif %} module.exports = merge(commonConfig, { mode: 'production', devtool: 'source-map', bail: true, output: { publicPath: `${staticUrl}webpack_bundles/`, }, }); ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/__init__.py ================================================ __version__ = "{{ cookiecutter.version }}" __version_info__ = tuple( int(num) if num.isdigit() else num for num in __version__.replace("-", ".", 1).split(".") ) ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/conftest.py ================================================ import pytest from {{ cookiecutter.project_slug }}.users.models import User from {{ cookiecutter.project_slug }}.users.tests.factories import UserFactory @pytest.fixture(autouse=True) def _media_storage(settings, tmpdir) -> None: settings.MEDIA_ROOT = tmpdir.strpath @pytest.fixture def user(db) -> User: return UserFactory.create() ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/contrib/__init__.py ================================================ """ To understand why this file is here, please read: https://cookiecutter-django.readthedocs.io/en/latest/5-help/faq.html#why-is-there-a-django-contrib-sites-directory-in-cookiecutter-django """ ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/contrib/sites/__init__.py ================================================ """ To understand why this file is here, please read: https://cookiecutter-django.readthedocs.io/en/latest/5-help/faq.html#why-is-there-a-django-contrib-sites-directory-in-cookiecutter-django """ ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/contrib/sites/migrations/0001_initial.py ================================================ import django.contrib.sites.models from django.contrib.sites.models import _simple_domain_name_validator from django.db import migrations from django.db import models class Migration(migrations.Migration): dependencies = [] operations = [ migrations.CreateModel( name="Site", fields=[ ( "id", models.AutoField( verbose_name="ID", serialize=False, auto_created=True, primary_key=True, ), ), ( "domain", models.CharField( max_length=100, verbose_name="domain name", validators=[_simple_domain_name_validator], ), ), ("name", models.CharField(max_length=50, verbose_name="display name")), ], options={ "ordering": ("domain",), "db_table": "django_site", "verbose_name": "site", "verbose_name_plural": "sites", }, bases=(models.Model,), managers=[("objects", django.contrib.sites.models.SiteManager())], ), ] ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/contrib/sites/migrations/0002_alter_domain_unique.py ================================================ import django.contrib.sites.models from django.db import migrations from django.db import models class Migration(migrations.Migration): dependencies = [("sites", "0001_initial")] operations = [ migrations.AlterField( model_name="site", name="domain", field=models.CharField( max_length=100, unique=True, validators=[django.contrib.sites.models._simple_domain_name_validator], verbose_name="domain name", ), ) ] ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/contrib/sites/migrations/0003_set_site_domain_and_name.py ================================================ """ To understand why this file is here, please read: https://cookiecutter-django.readthedocs.io/en/latest/5-help/faq.html#why-is-there-a-django-contrib-sites-directory-in-cookiecutter-django """ 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") _update_or_create_site_with_sequence( Site, schema_editor.connection, "{{ cookiecutter.domain_name }}", "{{ cookiecutter.project_name[:50] }}", ) def update_site_backward(apps, schema_editor): """Revert site domain and name to default.""" Site = apps.get_model("sites", "Site") _update_or_create_site_with_sequence( Site, schema_editor.connection, "example.com", "example.com", ) class Migration(migrations.Migration): dependencies = [("sites", "0002_alter_domain_unique")] operations = [migrations.RunPython(update_site_forward, update_site_backward)] ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/contrib/sites/migrations/0004_alter_options_ordering_domain.py ================================================ # Generated by Django 3.1.7 on 2021-02-04 14:49 from django.db import migrations class Migration(migrations.Migration): dependencies = [ ("sites", "0003_set_site_domain_and_name"), ] operations = [ migrations.AlterModelOptions( name="site", options={ "ordering": ["domain"], "verbose_name": "site", "verbose_name_plural": "sites", }, ), ] ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/contrib/sites/migrations/__init__.py ================================================ """ To understand why this file is here, please read: https://cookiecutter-django.readthedocs.io/en/latest/5-help/faq.html#why-is-there-a-django-contrib-sites-directory-in-cookiecutter-django """ ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/static/fonts/.gitkeep ================================================ ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/static/js/project.js ================================================ {%- if cookiecutter.frontend_pipeline == 'Webpack' -%} import '../sass/project.scss'; {% endif -%} /* Project specific Javascript goes here. */ ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/static/sass/custom_bootstrap_vars.scss ================================================ ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/static/sass/project.scss ================================================ @import 'custom_bootstrap_vars'; @import '~bootstrap/scss/bootstrap'; // project specific CSS goes here /////////////// // Variables // /////////////// // Alert colors $white: #fff; $mint-green: #d6e9c6; $black: #000; $pink: #f2dede; $dark-pink: #eed3d7; $red: #b94a48; //////////// // Alerts // //////////// // bootstrap alert CSS, translated to the django-standard levels of // debug, info, success, warning, error .alert-debug { background-color: $white; border-color: $mint-green; color: $black; } .alert-error { background-color: $pink; border-color: $dark-pink; color: $red; } ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/403.html ================================================ {% raw %}{% extends "base.html" %} {% block title %}Forbidden (403){% endblock title %} {% block content %}

Forbidden (403)

{% if exception %} {{ exception }} {% else %} You're not allowed to access this page. {% endif %}

{% endblock content %} {%- endraw %} ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/403_csrf.html ================================================ {% raw %}{% extends "base.html" %} {% block title %}Forbidden (403){% endblock title %} {% block content %}

Forbidden (403)

{% if exception %} {{ exception }} {% else %} You're not allowed to access this page. {% endif %}

{% endblock content %} {%- endraw %} ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/404.html ================================================ {% raw %}{% extends "base.html" %} {% block title %}Page not found{% endblock title %} {% block content %}

Page not found

{% if exception %} {{ exception }} {% else %} This is not the page you were looking for. {% endif %}

{% endblock content %} {%- endraw %} ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/500.html ================================================ {% raw %}{% extends "base.html" %} {% block title %}Server Error{% endblock title %} {% block content %}

Ooops!!! 500

Looks like something went wrong!

We track these errors automatically, but if the problem persists feel free to contact us. In the meantime, try refreshing.

{% endblock content %} {%- endraw %} ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/account/base_manage_password.html ================================================ {% raw %}{% extends "account/base_manage.html" %} {% block main %}
{% block content %} {% endblock content %}
{% endblock main %}{% endraw %} ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/allauth/elements/alert.html ================================================ {% raw %}{% load i18n %} {% load allauth %}
{% slot message %} {% endslot %}
{% endraw %} ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/allauth/elements/badge.html ================================================ {% raw %}{% load allauth %} {% slot %} {% endslot %} {% endraw %} ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/allauth/elements/button.html ================================================ {% raw %}{% load allauth %} {% comment %} djlint:off {% endcomment %} <{% if attrs.href %}a href="{{ attrs.href }}"{% else %}button{% endif %} {% if attrs.form %}form="{{ attrs.form }}"{% endif %} {% if attrs.id %}id="{{ attrs.id }}"{% endif %} {% if attrs.name %}name="{{ attrs.name }}"{% endif %} {% if attrs.type %}type="{{ attrs.type }}"{% endif %} class="btn {% if 'success' in attrs.tags %}btn-success {% elif 'warning' in attrs.tags %}btn-warning {% elif 'secondary' in attrs.tags %}btn-secondary {% elif 'danger' in attrs.tags %}btn-danger {% elif 'primary' in attrs.tags %}btn-primary {% else %}btn-primary {% endif %}" > {% slot %} {% endslot %} {% endraw %} ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/allauth/elements/field.html ================================================ {% raw %}{% load allauth %} {% load crispy_forms_tags %} {% if attrs.type == "textarea" %}
{% elif attrs.type == "radio" %}
{% else %}
{% endif %} {% if slots.help_text %}
{% slot help_text %}{% endslot %}
{% endif %}{% endraw %} ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/allauth/elements/fields.html ================================================ {% raw %}{% load crispy_forms_tags %} {{ attrs.form|crispy }}{% endraw %} ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/allauth/elements/panel.html ================================================ {% raw %}{% load allauth %}

{% slot title %} {% endslot %}

{% slot body %} {% endslot %} {% if slots.actions %}
    {% for action in slots.actions %}
  • {{ action }}
  • {% endfor %}
{% endif %}
{% endraw %} ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/allauth/elements/table.html ================================================ {% raw %}{% load allauth %} {% slot %} {% endslot %}
{% endraw %} ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/allauth/layouts/entrance.html ================================================ {% raw %}{% extends "base.html" %} {% load i18n %} {% block bodyclass %}bg-light{% endblock bodyclass %} {% block css %}{{ block.super }}{% endblock css %} {% block title %} {% block head_title %} {% trans "Sign In" %} {% endblock head_title %} {% endblock title %} {% block body %}
{% if messages %} {% for message in messages %}
{{ message }}
{% endfor %} {% endif %} {% block content %} {% endblock content %} {% block extra_body %} {% endblock extra_body %}
{% endblock body %}{% endraw %} ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/allauth/layouts/manage.html ================================================ {% raw %}{% extends "base.html" %} {% block main %} {% block content %} {% endblock content %} {% endblock main %}{% endraw %} ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/base.html ================================================ {% raw %} {% load static i18n {% endraw %} {%- if cookiecutter.frontend_pipeline == 'Django Compressor' %}compress{%- endif %}{% raw %}%}{% endraw %} {%- if cookiecutter.frontend_pipeline == 'Webpack' %}{% raw %} {% load render_bundle from webpack_loader %} {% endraw %} {%- endif %}{% raw %} {% get_current_language as LANGUAGE_CODE %} {% block title %} {% endraw %}{{ cookiecutter.project_name }}{% raw %} {% endblock title %} {% block css %} {%- endraw %} {%- if cookiecutter.frontend_pipeline in ['None', 'Django Compressor'] %} {%- raw %} {%- endraw %} {%- endif %} {%- raw %} {%- endraw %} {% if cookiecutter.frontend_pipeline == 'None' %} {% raw %} {%- endraw %} {% elif cookiecutter.frontend_pipeline == 'Django Compressor' %} {% raw %} {% compress css %} {% endcompress %} {%- endraw %} {% elif cookiecutter.frontend_pipeline == 'Gulp' %} {% raw %} {%- endraw %} {% elif cookiecutter.frontend_pipeline == "Webpack" %} {% raw %} {% render_bundle 'project' 'css' %} {%- endraw %} {% endif %} {% raw %} {% endblock css %} {# Placed at the top of the document so pages load faster with defer #} {% block javascript %} {%- endraw %} {% if cookiecutter.frontend_pipeline == 'Gulp' %} {% raw %} {%- endraw %} {% elif cookiecutter.frontend_pipeline == "Webpack" %} {% raw %} {% render_bundle 'vendors' 'js' attrs='defer' %} {%- endraw %} {% else %} {% raw %} {%- endraw %} {% endif %} {% raw %} {%- endraw %} {% if cookiecutter.frontend_pipeline == 'None' %} {% raw %} {%- endraw %} {% elif cookiecutter.frontend_pipeline == 'Django Compressor' %} {% raw %} {% compress js %} {% endcompress %} {%- endraw %} {% elif cookiecutter.frontend_pipeline == 'Gulp' %} {% raw %} {%- endraw %} {% elif cookiecutter.frontend_pipeline == "Webpack" %} {% raw %} {% render_bundle 'project' 'js' attrs='defer' %} {%- endraw %} {% endif %} {% raw %} {% endblock javascript %} {% block body %}
{% if messages %} {% for message in messages %}
{{ message }}
{% endfor %} {% endif %} {% block main %} {% block content %}

Use this document as a way to quick start any new project.

{% endblock content %} {% endblock main %}
{% endblock body %} {% block modal %} {% endblock modal %} {% block inline_javascript %} {% comment %} Script tags with only code, no src (defer by default). To run with a "defer" so that you run inline code: {% endcomment %} {% endblock inline_javascript %} {%- endraw %} ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/pages/about.html ================================================ {% raw %}{% extends "base.html" %} {% endraw %} ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/pages/home.html ================================================ {% raw %}{% extends "base.html" %} {% endraw %} ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/users/user_detail.html ================================================ {% raw %}{% extends "base.html" %} {% load static %} {% block title %} User: {% endraw %} {% if cookiecutter.username_type == "email" %} {% raw %}{{ object.name }}{% endraw %} {% else %} {% raw %}{{ object.username }}{% endraw %} {% endif %} {% raw %} {% endblock title %} {% block content %}

{% endraw %} {% if cookiecutter.username_type == "email" %} {% raw %}{{ object.name }}{% endraw %} {% else %} {% raw %}{{ object.username }}{% endraw %} {% endif %}

{%- if cookiecutter.username_type == "username" %} {%- raw %} {% if object.name %}

{{ object.name }}

{% endif %} {%- endraw %} {%- endif %}
{%- raw %} {% if object == request.user %} {% endif %}
{% endblock content %} {%- endraw %} ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/users/user_form.html ================================================ {% raw %}{% extends "base.html" %} {% load crispy_forms_tags %} {% block title %} {% endraw %} {% if cookiecutter.username_type == "email" %} {% raw %}{{ user.name }}{% endraw %} {% else %} {% raw %}{{ user.username }}{% endraw %} {% endif %} {% raw %} {% endblock title %} {% block content %}

{% endraw %} {% if cookiecutter.username_type == "email" %} {% raw %}{{ user.name }}{% endraw %} {% else %} {% raw %}{{ user.username }}{% endraw %} {% endif %} {% raw %}

{% csrf_token %} {{ form|crispy }}
{% endblock content %} {%- endraw %} ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/__init__.py ================================================ ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/adapters.py ================================================ from __future__ import annotations import typing from allauth.account.adapter import DefaultAccountAdapter from allauth.socialaccount.adapter import DefaultSocialAccountAdapter from django.conf import settings if typing.TYPE_CHECKING: from allauth.socialaccount.models import SocialLogin from django.http import HttpRequest from {{cookiecutter.project_slug}}.users.models import User class AccountAdapter(DefaultAccountAdapter): def is_open_for_signup(self, request: HttpRequest) -> bool: return getattr(settings, "ACCOUNT_ALLOW_REGISTRATION", True) class SocialAccountAdapter(DefaultSocialAccountAdapter): def is_open_for_signup( self, request: HttpRequest, sociallogin: SocialLogin, ) -> bool: return getattr(settings, "ACCOUNT_ALLOW_REGISTRATION", True) def populate_user( self, request: HttpRequest, sociallogin: SocialLogin, data: dict[str, typing.Any], ) -> User: """ Populates user information from social provider info. See: https://docs.allauth.org/en/latest/socialaccount/advanced.html#creating-and-populating-user-instances """ user = super().populate_user(request, sociallogin, data) if not user.name: if name := data.get("name"): user.name = name elif first_name := data.get("first_name"): user.name = first_name if last_name := data.get("last_name"): user.name += f" {last_name}" return user ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/admin.py ================================================ from allauth.account.decorators import secure_admin_login from django.conf import settings from django.contrib import admin from django.contrib.auth import admin as auth_admin from django.utils.translation import gettext_lazy as _ from .forms import UserAdminChangeForm from .forms import UserAdminCreationForm from .models import User if settings.DJANGO_ADMIN_FORCE_ALLAUTH: # Force the `admin` sign in process to go through the `django-allauth` workflow: # https://docs.allauth.org/en/latest/common/admin.html#admin admin.autodiscover() admin.site.login = secure_admin_login(admin.site.login) # type: ignore[method-assign] @admin.register(User) class UserAdmin(auth_admin.UserAdmin): form = UserAdminChangeForm add_form = UserAdminCreationForm fieldsets = ( {%- if cookiecutter.username_type == "email" %} (None, {"fields": ("email", "password")}), (_("Personal info"), {"fields": ("name",)}), {%- else %} (None, {"fields": ("username", "password")}), (_("Personal info"), {"fields": ("name", "email")}), {%- endif %} ( _("Permissions"), { "fields": ( "is_active", "is_staff", "is_superuser", "groups", "user_permissions", ), }, ), (_("Important dates"), {"fields": ("last_login", "date_joined")}), ) list_display = ["{{cookiecutter.username_type}}", "name", "is_superuser"] search_fields = ["name"] {%- if cookiecutter.username_type == "email" %} ordering = ["id"] add_fieldsets = ( ( None, { "classes": ("wide",), "fields": ("email", "password1", "password2"), }, ), ) {%- endif %} ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/api/__init__.py ================================================ ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/api/schema.py ================================================ from django.urls import reverse from ninja import ModelSchema from {{ cookiecutter.project_slug }}.users.models import User class UpdateUserSchema(ModelSchema): class Meta: model = User {%- if cookiecutter.username_type == "email" %} fields = ["name"] {%- else %} fields = ["username", "name"] {%- endif %} class UserSchema(ModelSchema): url: str class Meta: model = User {%- if cookiecutter.username_type == "email" %} fields = ["email", "name"] {%- else %} fields = ["username", "email", "name"] {%- endif %} @staticmethod def resolve_url(obj: User): {%- if cookiecutter.username_type == "email" %} return reverse("api:retrieve_user", kwargs={"pk": obj.pk}) {%- else %} return reverse("api:retrieve_user", kwargs={"username": obj.username}) {%- endif %} ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/api/serializers.py ================================================ from rest_framework import serializers from {{ cookiecutter.project_slug }}.users.models import User class UserSerializer(serializers.ModelSerializer[User]): class Meta: model = User {%- if cookiecutter.username_type == "email" %} fields = ["name", "url"] extra_kwargs = { "url": {"view_name": "api:user-detail", "lookup_field": "pk"}, } {%- else %} fields = ["username", "name", "url"] extra_kwargs = { "url": {"view_name": "api:user-detail", "lookup_field": "username"}, } {%- endif %} ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/api/views.py ================================================ {% if cookiecutter.rest_api == 'DRF' -%} from rest_framework import status from rest_framework.decorators import action from rest_framework.mixins import ListModelMixin from rest_framework.mixins import RetrieveModelMixin from rest_framework.mixins import UpdateModelMixin from rest_framework.response import Response from rest_framework.viewsets import GenericViewSet from {{ cookiecutter.project_slug }}.users.models import User from .serializers import UserSerializer class UserViewSet(RetrieveModelMixin, ListModelMixin, UpdateModelMixin, GenericViewSet): serializer_class = UserSerializer queryset = User.objects.all() {%- if cookiecutter.username_type == "email" %} lookup_field = "pk" {%- else %} lookup_field = "username" {%- endif %} 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) def me(self, request): serializer = UserSerializer(request.user, context={"request": request}) return Response(status=status.HTTP_200_OK, data=serializer.data) {%- elif cookiecutter.rest_api == 'Django Ninja' -%} from django.db.models import QuerySet from django.shortcuts import get_object_or_404 from ninja import Router from {{ cookiecutter.project_slug }}.users.api.schema import UpdateUserSchema from {{ cookiecutter.project_slug }}.users.api.schema import UserSchema from {{ cookiecutter.project_slug }}.users.models import User router = Router(tags=["users"]) def _get_users_queryset(request) -> QuerySet[User]: return User.objects.filter(pk=request.user.pk) @router.get("/", response=list[UserSchema]) def list_users(request): return _get_users_queryset(request) {%- if cookiecutter.username_type == "email" %} @router.get("/me/", response=UserSchema) def retrieve_current_user(request): return request.user @router.get("/{pk}/", response=UserSchema) def retrieve_user(request, pk: int): users_qs = _get_users_queryset(request) return get_object_or_404(users_qs, pk=pk) {%- else %} @router.get("/me/", response=UserSchema) def retrieve_current_user(request): return request.user @router.get("/{username}/", response=UserSchema) def retrieve_user(request, username: str): users_qs = _get_users_queryset(request) return get_object_or_404(users_qs, username=username) {%- endif %} @router.patch("/me/", response=UserSchema) def update_current_user(request, data: UpdateUserSchema): user = request.user user.name = data.name {%- if cookiecutter.username_type == "username" %} user.username = data.username {%- endif %} user.save() return user {%- if cookiecutter.username_type == "email" %} @router.patch("/{pk}/", response=UserSchema) def update_user(request, pk: int, data: UpdateUserSchema): users_qs = _get_users_queryset(request) user = get_object_or_404(users_qs, pk=pk) user.name = data.name user.save() return user {%- else %} @router.patch("/{username}/", response=UserSchema) def update_user(request, username: str, data: UpdateUserSchema): users_qs = _get_users_queryset(request) user = get_object_or_404(users_qs, username=username) user.name = data.name user.username = data.username user.save() return user {%- endif %} {%- endif %} ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/apps.py ================================================ from django.apps import AppConfig from django.utils.translation import gettext_lazy as _ class UsersConfig(AppConfig): name = "{{ cookiecutter.project_slug }}.users" verbose_name = _("Users") def ready(self): """ Override this method in subclasses to run code when Django starts. """ ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/context_processors.py ================================================ 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, } ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/forms.py ================================================ from allauth.account.forms import SignupForm from allauth.socialaccount.forms import SignupForm as SocialSignupForm from django.contrib.auth import forms as admin_forms {%- if cookiecutter.username_type == "email" %} from django.forms import EmailField {%- endif %} from django.utils.translation import gettext_lazy as _ from .models import User class UserAdminChangeForm(admin_forms.UserChangeForm): class Meta(admin_forms.UserChangeForm.Meta): model = User {%- if cookiecutter.username_type == "email" %} field_classes = {"email": EmailField} {%- endif %} class UserAdminCreationForm(admin_forms.AdminUserCreationForm): """ Form for User Creation in the Admin Area. To change user signup, see UserSignupForm and UserSocialSignupForm. """ class Meta(admin_forms.UserCreationForm.Meta): model = User {%- if cookiecutter.username_type == "email" %} fields = ("email",) field_classes = {"email": EmailField} error_messages = { "email": {"unique": _("This email has already been taken.")}, } {%- else %} error_messages = { "username": {"unique": _("This username has already been taken.")}, } {%- endif %} 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. """ ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/managers.py ================================================ from typing import TYPE_CHECKING from django.contrib.auth.hashers import make_password from django.contrib.auth.models import UserManager as DjangoUserManager if TYPE_CHECKING: from .models import User # noqa: F401 class UserManager(DjangoUserManager["User"]): """Custom manager for the User model.""" def _create_user(self, email: str, password: str | None, **extra_fields): """ Create and save a user with the given email and password. """ if not email: msg = "The given email must be set" raise ValueError(msg) email = self.normalize_email(email) user = self.model(email=email, **extra_fields) user.password = make_password(password) user.save(using=self._db) return user def create_user(self, email: str, password: str | None = None, **extra_fields): # type: ignore[override] extra_fields.setdefault("is_staff", False) extra_fields.setdefault("is_superuser", False) return self._create_user(email, password, **extra_fields) def create_superuser(self, email: str, password: str | None = None, **extra_fields): # type: ignore[override] extra_fields.setdefault("is_staff", True) extra_fields.setdefault("is_superuser", True) if extra_fields.get("is_staff") is not True: msg = "Superuser must have is_staff=True." raise ValueError(msg) if extra_fields.get("is_superuser") is not True: msg = "Superuser must have is_superuser=True." raise ValueError(msg) return self._create_user(email, password, **extra_fields) ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/migrations/0001_initial.py ================================================ import django.contrib.auth.models import django.contrib.auth.validators import django.utils.timezone from django.db import migrations from django.db import models import {{cookiecutter.project_slug}}.users.models class Migration(migrations.Migration): initial = True dependencies = [ ("auth", "0012_alter_user_first_name_max_length"), ] operations = [ migrations.CreateModel( name="User", fields=[ ( "id", models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ("password", models.CharField(max_length=128, verbose_name="password")), ( "last_login", models.DateTimeField( blank=True, null=True, verbose_name="last login", ), ), ( "is_superuser", models.BooleanField( default=False, help_text="Designates that this user has all permissions without explicitly assigning them.", verbose_name="superuser status", ), ), {%- if cookiecutter.username_type == "username" -%} ( "username", models.CharField( error_messages={ "unique": "A user with that username already exists." }, help_text="Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.", max_length=150, unique=True, validators=[ django.contrib.auth.validators.UnicodeUsernameValidator() ], verbose_name="username", ), ), ( "email", models.EmailField( blank=True, max_length=254, verbose_name="email address", ), ), {%- else %} ( "email", models.EmailField( unique=True, max_length=254, verbose_name="email address", ), ), {%- endif %} ( "is_staff", models.BooleanField( default=False, help_text="Designates whether the user can log into this admin site.", verbose_name="staff status", ), ), ( "is_active", models.BooleanField( default=True, help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.", verbose_name="active", ), ), ( "date_joined", models.DateTimeField( default=django.utils.timezone.now, verbose_name="date joined", ), ), ( "name", models.CharField( blank=True, max_length=255, verbose_name="Name of User", ), ), ( "groups", models.ManyToManyField( blank=True, help_text="The groups this user belongs to. A user will get all permissions granted to each of their groups.", related_name="user_set", related_query_name="user", to="auth.Group", verbose_name="groups", ), ), ( "user_permissions", models.ManyToManyField( blank=True, help_text="Specific permissions for this user.", related_name="user_set", related_query_name="user", to="auth.Permission", verbose_name="user permissions", ), ), ], options={ "verbose_name": "user", "verbose_name_plural": "users", "abstract": False, }, managers=[ {%- if cookiecutter.username_type == "email" %} ("objects", {{cookiecutter.project_slug}}.users.models.UserManager()), {%- else %} ("objects", django.contrib.auth.models.UserManager()), {%- endif %} ], ), ] ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/migrations/__init__.py ================================================ ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/models.py ================================================ {%- if cookiecutter.username_type == "email" %} from typing import ClassVar {% endif -%} from django.contrib.auth.models import AbstractUser from django.db.models import CharField {%- if cookiecutter.username_type == "email" %} from django.db.models import EmailField {%- endif %} from django.urls import reverse from django.utils.translation import gettext_lazy as _ {%- if cookiecutter.username_type == "email" %} from .managers import UserManager {%- endif %} class User(AbstractUser): """ 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) first_name = None # type: ignore[assignment] last_name = None # type: ignore[assignment] {%- if cookiecutter.username_type == "email" %} email = EmailField(_("email address"), unique=True) username = None # type: ignore[assignment] USERNAME_FIELD = "email" REQUIRED_FIELDS = [] objects: ClassVar[UserManager] = UserManager() {%- endif %} def get_absolute_url(self) -> str: """Get URL for user's detail view. Returns: str: URL for user detail. """ {%- if cookiecutter.username_type == "email" %} return reverse("users:detail", kwargs={"pk": self.id}) {%- else %} return reverse("users:detail", kwargs={"username": self.username}) {%- endif %} ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tasks.py ================================================ from celery import shared_task from .models import User @shared_task() def get_users_count(): """A pointless Celery task to demonstrate usage.""" return User.objects.count() ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/__init__.py ================================================ ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/api/__init__.py ================================================ ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/api/test_openapi.py ================================================ from http import HTTPStatus import pytest from django.urls import reverse def test_api_docs_accessible_by_admin(admin_client): {%- if cookiecutter.rest_api == 'DRF' %} url = reverse("api-docs") {%- elif cookiecutter.rest_api == 'Django Ninja' %} url = reverse("api:openapi-view") {%- endif %} response = admin_client.get(url) assert response.status_code == HTTPStatus.OK @pytest.mark.django_db def test_api_docs_not_accessible_by_anonymous_users(client): {%- if cookiecutter.rest_api == 'DRF' %} url = reverse("api-docs") response = client.get(url) assert response.status_code == HTTPStatus.FORBIDDEN {%- elif cookiecutter.rest_api == 'Django Ninja' %} url = reverse("api:openapi-view") response = client.get(url) assert response.status_code == HTTPStatus.FOUND assert response.url == "/admin/login/?next=/api/docs" {%- endif %} def test_api_schema_generated_successfully(admin_client): {%- if cookiecutter.rest_api == 'DRF' %} url = reverse("api-schema") {%- elif cookiecutter.rest_api == 'Django Ninja' %} url = reverse("api:openapi-json") {%- endif %} response = admin_client.get(url) assert response.status_code == HTTPStatus.OK ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/api/test_urls.py ================================================ from django.urls import resolve from django.urls import reverse from {{ cookiecutter.project_slug }}.users.models import User {%- if cookiecutter.rest_api == 'DRF' %} def test_user_detail(user: User): {%- if cookiecutter.username_type == "email" %} assert ( reverse("api:user-detail", kwargs={"pk": user.pk}) == f"/api/users/{user.pk}/" ) assert resolve(f"/api/users/{user.pk}/").view_name == "api:user-detail" {%- else %} assert ( reverse("api:user-detail", kwargs={"username": user.username}) == f"/api/users/{user.username}/" ) assert resolve(f"/api/users/{user.username}/").view_name == "api:user-detail" {%- endif %} def test_user_list(): assert reverse("api:user-list") == "/api/users/" assert resolve("/api/users/").view_name == "api:user-list" def test_user_me(): assert reverse("api:user-me") == "/api/users/me/" assert resolve("/api/users/me/").view_name == "api:user-me" {%- elif cookiecutter.rest_api == 'Django Ninja' %} def test_user_detail(user: User): {%- if cookiecutter.username_type == "email" %} assert ( reverse("api:retrieve_user", kwargs={"pk": user.pk}) == f"/api/users/{user.pk}/" ) assert resolve(f"/api/users/{user.pk}/").view_name == "api:retrieve_user" {%- else %} assert ( reverse("api:retrieve_user", kwargs={"username": user.username}) == f"/api/users/{user.username}/" ) assert resolve(f"/api/users/{user.username}/").view_name == "api:retrieve_user" {%- endif %} def test_user_list(): assert reverse("api:list_users") == "/api/users/" assert resolve("/api/users/").view_name == "api:list_users" def test_current_user(): assert reverse("api:retrieve_current_user") == "/api/users/me/" assert resolve("/api/users/me/").view_name == "api:retrieve_current_user" def test_update_user(): {%- if cookiecutter.username_type == "email" %} assert reverse("api:update_user", kwargs={"pk": 123}) == "/api/users/123/" assert resolve("/api/users/123/").view_name == "api:retrieve_user" {%- else %} assert reverse("api:update_user", kwargs={"username": "john"}) == "/api/users/john/" assert resolve("/api/users/john/").view_name == "api:retrieve_user" {%- endif %} {%- endif %} ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/api/test_views.py ================================================ {% if cookiecutter.rest_api == 'DRF' -%} import pytest from rest_framework.test import APIRequestFactory from {{ cookiecutter.project_slug }}.users.api.views import UserViewSet from {{ cookiecutter.project_slug }}.users.models import User class TestUserViewSet: @pytest.fixture def api_rf(self) -> APIRequestFactory: return APIRequestFactory() def test_get_queryset(self, user: User, api_rf: APIRequestFactory): view = UserViewSet() request = api_rf.get("/fake-url/") request.user = user view.request = request assert user in view.get_queryset() def test_me(self, user: User, api_rf: APIRequestFactory): view = UserViewSet() request = api_rf.get("/fake-url/") request.user = user view.request = request response = view.me(request) # type: ignore[call-arg, arg-type, misc] assert response.data == { {%- if cookiecutter.username_type == "email" %} "url": f"http://testserver/api/users/{user.pk}/", {%- else %} "username": user.username, "url": f"http://testserver/api/users/{user.username}/", {%- endif %} "name": user.name, } {%- elif cookiecutter.rest_api == 'Django Ninja' -%} from http import HTTPStatus import pytest from django.test import Client from django.urls import reverse from {{ cookiecutter.project_slug }}.users.models import User from {{ cookiecutter.project_slug }}.users.tests.factories import UserFactory pytestmark = pytest.mark.django_db @pytest.fixture def user(): return UserFactory.create() def test_list_users_as_anonymous_user(client: Client): response = client.get(reverse("api:list_users")) assert response.status_code == HTTPStatus.UNAUTHORIZED def test_list_users_as_authenticated_user(client: Client, user: User): client.force_login(user) # Another user, excluded from the response UserFactory.create() response = client.get(reverse("api:list_users")) assert response.status_code == HTTPStatus.OK assert response.json() == [ { "email": user.email, "name": user.name, {%- if cookiecutter.username_type == "email" %} "url": f"/api/users/{user.pk}/", {%- else %} "url": f"/api/users/{user.username}/", "username": user.username, {%- endif %} }, ] {%- if cookiecutter.username_type == "email" %} def test_retrieve_current_user(client: Client, user: User): client.force_login(user) response = client.get( reverse("api:retrieve_current_user"), ) assert response.status_code == HTTPStatus.OK assert response.json() == { "email": user.email, "name": user.name, "url": f"/api/users/{user.pk}/", } def test_retrieve_user(client: Client, user: User): client.force_login(user) response = client.get( reverse("api:retrieve_user", kwargs={"pk": user.pk}), ) assert response.status_code == HTTPStatus.OK assert response.json() == { "email": user.email, "name": user.name, "url": f"/api/users/{user.pk}/", } {%- else %} def test_retrieve_current_user(client: Client, user: User): client.force_login(user) response = client.get( reverse("api:retrieve_current_user"), ) assert response.status_code == HTTPStatus.OK assert response.json() == { "email": user.email, "name": user.name, "url": f"/api/users/{user.username}/", "username": user.username, } def test_retrieve_user(client: Client, user: User): client.force_login(user) response = client.get( reverse("api:retrieve_user", kwargs={"username": user.username}), ) assert response.status_code == HTTPStatus.OK assert response.json() == { "email": user.email, "name": user.name, "url": f"/api/users/{user.username}/", "username": user.username, } {%- endif %} def test_retrieve_another_user(client: Client, user: User): client.force_login(user) user_2 = UserFactory.create() response = client.get( {%- if cookiecutter.username_type == "email" %} reverse("api:retrieve_user", kwargs={"pk": user_2.pk}), {%- else %} reverse("api:retrieve_user", kwargs={"username": user_2.username}), {%- endif %} ) assert response.status_code == HTTPStatus.NOT_FOUND assert response.json() == {"detail": "Not Found"} def test_update_current_user(client: Client): user = UserFactory.create(name="Old") client.force_login(user) response = client.patch( reverse("api:update_current_user"), {%- if cookiecutter.username_type == "email" %} data='{"name": "New Name"}', {%- else %} data='{"name": "New Name", "username": "old"}', {%- endif %} content_type="application/json", ) assert response.status_code == HTTPStatus.OK, response.json() assert response.json() == { "email": user.email, "name": "New Name", {%- if cookiecutter.username_type == "email" %} "url": f"/api/users/{user.pk}/", {%- else %} "username": "old", "url": "/api/users/old/", {%- endif %} } {%- if cookiecutter.username_type == "email" %} def test_update_user(client: Client): user = UserFactory.create(name="Old") client.force_login(user) response = client.patch( reverse("api:update_user", kwargs={"pk": user.pk}), data='{"name": "New Name"}', content_type="application/json", ) assert response.status_code == HTTPStatus.OK, response.json() assert response.json() == { "email": user.email, "name": "New Name", "url": f"/api/users/{user.pk}/", } {%- else %} def test_update_user(client: Client): user = UserFactory.create(name="Old", username="old") client.force_login(user) response = client.patch( reverse("api:update_user", kwargs={"username": "old"}), data='{"name": "New Name", "username": "old"}', content_type="application/json", ) assert response.status_code == HTTPStatus.OK, response.json() assert response.json() == { "email": user.email, "name": "New Name", "url": "/api/users/old/", "username": "old", } {%- endif %} {%- endif %} ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/factories.py ================================================ from __future__ import annotations from factory import Faker from factory import post_generation from factory.django import DjangoModelFactory from {{ cookiecutter.project_slug }}.users.models import User class UserFactory(DjangoModelFactory[User]): {%- if cookiecutter.username_type == "username" %} username = Faker("user_name") {%- endif %} email = Faker("email") name = Faker("name") @post_generation def password(self: User, create: bool, extracted: str | None, **kwargs): # noqa: FBT001 password = ( extracted if extracted else Faker( "password", length=42, special_chars=True, digits=True, upper_case=True, lower_case=True, ).evaluate(None, None, extra={"locale": None}) ) self.set_password(password) if create: self.save() class Meta: model = User django_get_or_create = ["{{cookiecutter.username_type}}"] skip_postgeneration_save = True ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_admin.py ================================================ import contextlib from http import HTTPStatus from importlib import reload import pytest from django.contrib import admin from django.contrib.auth.models import AnonymousUser from django.urls import reverse from pytest_django.asserts import assertRedirects from {{ cookiecutter.project_slug }}.users.models import User class TestUserAdmin: def test_changelist(self, admin_client): url = reverse("admin:users_user_changelist") response = admin_client.get(url) assert response.status_code == HTTPStatus.OK def test_search(self, admin_client): url = reverse("admin:users_user_changelist") response = admin_client.get(url, data={"q": "test"}) assert response.status_code == HTTPStatus.OK def test_add(self, admin_client): url = reverse("admin:users_user_add") response = admin_client.get(url) assert response.status_code == HTTPStatus.OK response = admin_client.post( url, data={ {%- if cookiecutter.username_type == "email" %} "email": "new-admin@example.com", {%- else %} "username": "test", {%- endif %} "password1": "My_R@ndom-P@ssw0rd", "password2": "My_R@ndom-P@ssw0rd", }, ) assert response.status_code == HTTPStatus.FOUND {%- if cookiecutter.username_type == "email" %} assert User.objects.filter(email="new-admin@example.com").exists() {%- else %} assert User.objects.filter(username="test").exists() {%- endif %} def test_view_user(self, admin_client): {%- if cookiecutter.username_type == "email" %} user = User.objects.get(email="admin@example.com") {%- else %} user = User.objects.get(username="admin") {%- endif %} url = reverse("admin:users_user_change", kwargs={"object_id": user.pk}) response = admin_client.get(url) assert response.status_code == HTTPStatus.OK @pytest.fixture def _force_allauth(self, settings): settings.DJANGO_ADMIN_FORCE_ALLAUTH = True # Reload the admin module to apply the setting change import {{ cookiecutter.project_slug }}.users.admin as users_admin # noqa: PLC0415 with contextlib.suppress(admin.sites.AlreadyRegistered): # type: ignore[attr-defined] reload(users_admin) @pytest.mark.django_db @pytest.mark.usefixtures("_force_allauth") def test_allauth_login(self, rf, settings): request = rf.get("/fake-url") request.user = AnonymousUser() response = admin.site.login(request) # The `admin` login view should redirect to the `allauth` login view target_url = reverse(settings.LOGIN_URL) + "?next=" + request.path assertRedirects(response, target_url, fetch_redirect_response=False) ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_forms.py ================================================ """Module for all Form Tests.""" from django.utils.translation import gettext_lazy as _ from {{ cookiecutter.project_slug }}.users.forms import UserAdminCreationForm from {{ cookiecutter.project_slug }}.users.models import User class TestUserAdminCreationForm: """ Test class for all tests related to the UserAdminCreationForm """ def test_username_validation_error_msg(self, user: User): """ 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 """ # The user already exists, # hence cannot be created. form = UserAdminCreationForm( { {%- if cookiecutter.username_type == "email" %} "email": user.email, {%- else %} "username": user.username, {%- endif %} "password1": user.password, "password2": user.password, }, ) assert not form.is_valid() assert len(form.errors) == 1 {%- if cookiecutter.username_type == "email" %} assert "email" in form.errors assert form.errors["email"][0] == _("This email has already been taken.") {%- else %} assert "username" in form.errors assert form.errors["username"][0] == _("This username has already been taken.") {%- endif %} ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_managers.py ================================================ from io import StringIO import pytest from django.core.management import call_command from {{ cookiecutter.project_slug }}.users.models import User @pytest.mark.django_db class TestUserManager: def test_create_user(self): user = User.objects.create_user( email="john@example.com", password="something-r@nd0m!", # noqa: S106 ) assert user.email == "john@example.com" assert not user.is_staff assert not user.is_superuser assert user.check_password("something-r@nd0m!") assert user.username is None def test_create_superuser(self): user = User.objects.create_superuser( email="admin@example.com", password="something-r@nd0m!", # noqa: S106 ) assert user.email == "admin@example.com" assert user.is_staff assert user.is_superuser assert user.username is None def test_create_superuser_username_ignored(self): user = User.objects.create_superuser( email="test@example.com", password="something-r@nd0m!", # noqa: S106 ) assert user.username is None @pytest.mark.django_db def test_createsuperuser_command(): """Ensure createsuperuser command works with our custom manager.""" out = StringIO() command_result = call_command( "createsuperuser", "--email", "henry@example.com", interactive=False, stdout=out, ) assert command_result is None assert out.getvalue() == "Superuser created successfully.\n" user = User.objects.get(email="henry@example.com") assert not user.has_usable_password() ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_models.py ================================================ from {{ cookiecutter.project_slug }}.users.models import User def test_user_get_absolute_url(user: User): {%- if cookiecutter.username_type == "email" %} assert user.get_absolute_url() == f"/users/{user.pk}/" {%- else %} assert user.get_absolute_url() == f"/users/{user.username}/" {%- endif %} ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_tasks.py ================================================ import pytest from celery.result import EagerResult from {{ cookiecutter.project_slug }}.users.tasks import get_users_count from {{ cookiecutter.project_slug }}.users.tests.factories import UserFactory pytestmark = pytest.mark.django_db def test_user_count(settings): """A basic test to execute the get_users_count Celery task.""" batch_size = 3 UserFactory.create_batch(batch_size) settings.CELERY_TASK_ALWAYS_EAGER = True task_result = get_users_count.delay() assert isinstance(task_result, EagerResult) assert task_result.result == batch_size ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_urls.py ================================================ from django.urls import resolve from django.urls import reverse from {{ cookiecutter.project_slug }}.users.models import User def test_detail(user: User): {%- if cookiecutter.username_type == "email" %} assert reverse("users:detail", kwargs={"pk": user.pk}) == f"/users/{user.pk}/" assert resolve(f"/users/{user.pk}/").view_name == "users:detail" {%- else %} assert ( reverse("users:detail", kwargs={"username": user.username}) == f"/users/{user.username}/" ) assert resolve(f"/users/{user.username}/").view_name == "users:detail" {%- endif %} def test_update(): assert reverse("users:update") == "/users/~update/" assert resolve("/users/~update/").view_name == "users:update" def test_redirect(): assert reverse("users:redirect") == "/users/~redirect/" assert resolve("/users/~redirect/").view_name == "users:redirect" ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_views.py ================================================ from http import HTTPStatus import pytest from django.conf import settings from django.contrib import messages from django.contrib.auth.models import AnonymousUser from django.contrib.messages.middleware import MessageMiddleware from django.contrib.sessions.middleware import SessionMiddleware from django.http import HttpRequest from django.http import HttpResponseRedirect from django.test import RequestFactory from django.urls import reverse from django.utils.translation import gettext_lazy as _ from {{ cookiecutter.project_slug }}.users.forms import UserAdminChangeForm from {{ cookiecutter.project_slug }}.users.models import User from {{ cookiecutter.project_slug }}.users.tests.factories import UserFactory from {{ cookiecutter.project_slug }}.users.views import UserRedirectView from {{ cookiecutter.project_slug }}.users.views import UserUpdateView from {{ cookiecutter.project_slug }}.users.views import user_detail_view pytestmark = pytest.mark.django_db class TestUserUpdateView: """ TODO: extracting view initialization code as class-scoped fixture would be great if only pytest-django supported non-function-scoped fixture db access -- this is a work-in-progress for now: https://github.com/pytest-dev/pytest-django/pull/258 """ def dummy_get_response(self, request: HttpRequest): return None def test_get_success_url(self, user: User, rf: RequestFactory): view = UserUpdateView() request = rf.get("/fake-url/") request.user = user view.request = request {%- if cookiecutter.username_type == "email" %} assert view.get_success_url() == f"/users/{user.pk}/" {%- else %} assert view.get_success_url() == f"/users/{user.username}/" {%- endif %} def test_get_object(self, user: User, rf: RequestFactory): view = UserUpdateView() request = rf.get("/fake-url/") request.user = user view.request = request assert view.get_object() == user def test_form_valid(self, user: User, rf: RequestFactory): view = UserUpdateView() request = rf.get("/fake-url/") # Add the session/message middleware to the request SessionMiddleware(self.dummy_get_response).process_request(request) MessageMiddleware(self.dummy_get_response).process_request(request) request.user = user view.request = request # Initialize the form form = UserAdminChangeForm() form.cleaned_data = {} form.instance = user view.form_valid(form) messages_sent = [m.message for m in messages.get_messages(request)] assert messages_sent == [_("Information successfully updated")] class TestUserRedirectView: def test_get_redirect_url(self, user: User, rf: RequestFactory): view = UserRedirectView() request = rf.get("/fake-url") request.user = user view.request = request {%- if cookiecutter.username_type == "email" %} assert view.get_redirect_url() == f"/users/{user.pk}/" {%- else %} assert view.get_redirect_url() == f"/users/{user.username}/" {%- endif %} class TestUserDetailView: def test_authenticated(self, user: User, rf: RequestFactory): request = rf.get("/fake-url/") request.user = UserFactory.create() {%- if cookiecutter.username_type == "email" %} response = user_detail_view(request, pk=user.pk) {%- else %} response = user_detail_view(request, username=user.username) {%- endif %} assert response.status_code == HTTPStatus.OK def test_not_authenticated(self, user: User, rf: RequestFactory): request = rf.get("/fake-url/") request.user = AnonymousUser() {%- if cookiecutter.username_type == "email" %} response = user_detail_view(request, pk=user.pk) {%- else %} response = user_detail_view(request, username=user.username) {%- endif %} login_url = reverse(settings.LOGIN_URL) assert isinstance(response, HttpResponseRedirect) assert response.status_code == HTTPStatus.FOUND assert response.url == f"{login_url}?next=/fake-url/" ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/urls.py ================================================ from django.urls import path from .views import user_detail_view from .views import user_redirect_view from .views import user_update_view app_name = "users" urlpatterns = [ path("~redirect/", view=user_redirect_view, name="redirect"), path("~update/", view=user_update_view, name="update"), {%- if cookiecutter.username_type == "email" %} path("/", view=user_detail_view, name="detail"), {%- else %} path("/", view=user_detail_view, name="detail"), {%- endif %} ] ================================================ FILE: {{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/views.py ================================================ from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.messages.views import SuccessMessageMixin from django.db.models import QuerySet from django.urls import reverse from django.utils.translation import gettext_lazy as _ from django.views.generic import DetailView from django.views.generic import RedirectView from django.views.generic import UpdateView from {{ cookiecutter.project_slug }}.users.models import User class UserDetailView(LoginRequiredMixin, DetailView): model = User {%- if cookiecutter.username_type == "email" %} slug_field = "id" slug_url_kwarg = "id" {%- else %} slug_field = "username" slug_url_kwarg = "username" {%- endif %} user_detail_view = UserDetailView.as_view() class UserUpdateView(LoginRequiredMixin, SuccessMessageMixin, UpdateView): model = User fields = ["name"] success_message = _("Information successfully updated") def get_success_url(self) -> str: assert self.request.user.is_authenticated # type guard return self.request.user.get_absolute_url() def get_object(self, queryset: QuerySet | None = None) -> User: assert self.request.user.is_authenticated # type guard return self.request.user user_update_view = UserUpdateView.as_view() class UserRedirectView(LoginRequiredMixin, RedirectView): permanent = False def get_redirect_url(self) -> str: {%- if cookiecutter.username_type == "email" %} return reverse("users:detail", kwargs={"pk": self.request.user.pk}) {%- else %} return reverse("users:detail", kwargs={"username": self.request.user.username}) {%- endif %} user_redirect_view = UserRedirectView.as_view()