mirror of
https://github.com/cookiecutter/cookiecutter-django.git
synced 2025-08-19 03:14:52 +03:00
Merge branch 'master' into feature/mysql-support
This commit is contained in:
commit
9f99400b92
15
.github/contributors.json
vendored
15
.github/contributors.json
vendored
|
@ -1202,5 +1202,20 @@
|
||||||
"name": "Bogdan Mateescu",
|
"name": "Bogdan Mateescu",
|
||||||
"github_login": "mateesville93",
|
"github_login": "mateesville93",
|
||||||
"twitter_username": ""
|
"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": ""
|
||||||
}
|
}
|
||||||
]
|
]
|
2
.github/workflows/update-contributors.yml
vendored
2
.github/workflows/update-contributors.yml
vendored
|
@ -26,7 +26,7 @@ jobs:
|
||||||
run: python scripts/update_contributors.py
|
run: python scripts/update_contributors.py
|
||||||
|
|
||||||
- name: Commit changes
|
- name: Commit changes
|
||||||
uses: stefanzweifel/git-auto-commit-action@v4.12.0
|
uses: stefanzweifel/git-auto-commit-action@v4.13.1
|
||||||
with:
|
with:
|
||||||
commit_message: Update Contributors
|
commit_message: Update Contributors
|
||||||
file_pattern: CONTRIBUTORS.md .github/contributors.json
|
file_pattern: CONTRIBUTORS.md .github/contributors.json
|
||||||
|
|
31
CHANGELOG.md
31
CHANGELOG.md
|
@ -3,6 +3,37 @@ All enhancements and patches to Cookiecutter Django will be documented in this f
|
||||||
|
|
||||||
<!-- GENERATOR_PLACEHOLDER -->
|
<!-- GENERATOR_PLACEHOLDER -->
|
||||||
|
|
||||||
|
## 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
|
## 2022.01.07
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
|
@ -733,6 +733,13 @@ Listed in alphabetical order.
|
||||||
</td>
|
</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Fuzzwah</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://github.com/Fuzzwah">Fuzzwah</a>
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Gabriel Mejia</td>
|
<td>Gabriel Mejia</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -1342,6 +1349,13 @@ Listed in alphabetical order.
|
||||||
</td>
|
</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Pedro Campos</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://github.com/pcampos119104">pcampos119104</a>
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Peter Bittner</td>
|
<td>Peter Bittner</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -1531,6 +1545,13 @@ Listed in alphabetical order.
|
||||||
</td>
|
</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Thibault J.</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://github.com/thibault">thibault</a>
|
||||||
|
</td>
|
||||||
|
<td>thibault</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Théo Segonds</td>
|
<td>Théo Segonds</td>
|
||||||
<td>
|
<td>
|
||||||
|
|
|
@ -63,13 +63,17 @@ Projects that provide financial support to the maintainers:
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
[{#Two Scoops of Django 3.x .align-center}](https://www.feldroy.com/products//two-scoops-of-django-3-x)
|
<p align="center">
|
||||||
|
<a href="https://www.feldroy.com/products//two-scoops-of-django-3-x"><img src="https://cdn.shopify.com/s/files/1/0304/6901/products/Two-Scoops-of-Django-3-Alpha-Cover_540x_26507b15-e489-470b-8a97-02773dd498d1_1080x.jpg"></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
Two Scoops of Django 3.x is the best ice cream-themed Django reference in the universe!
|
Two Scoops of Django 3.x is the best ice cream-themed Django reference in the universe!
|
||||||
|
|
||||||
### PyUp
|
### PyUp
|
||||||
|
|
||||||
[{#pyup .align-center}](https://pyup.io/)
|
<p align="center">
|
||||||
|
<a href="https://pyup.io/"><img src="https://pyup.io/static/images/logo.png"></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
PyUp brings you automated security and dependency updates used by Google and other organizations. Free for open source projects!
|
PyUp brings you automated security and dependency updates used by Google and other organizations. Free for open source projects!
|
||||||
|
|
||||||
|
|
|
@ -191,16 +191,18 @@ docker
|
||||||
|
|
||||||
The ``container_name`` from the yml file can be used to check on containers with docker commands, for example: ::
|
The ``container_name`` from the yml file can be used to check on containers with docker commands, for example: ::
|
||||||
|
|
||||||
$ docker logs worker
|
$ docker logs <project_slug>_local_celeryworker
|
||||||
$ docker top worker
|
$ docker top <project_slug>_local_celeryworker
|
||||||
|
|
||||||
|
|
||||||
|
Notice that the ``container_name`` is generated dynamically using your project slug as a prefix
|
||||||
|
|
||||||
Mailhog
|
Mailhog
|
||||||
~~~~~~~
|
~~~~~~~
|
||||||
|
|
||||||
When developing locally you can go with MailHog_ for email testing provided ``use_mailhog`` was set to ``y`` on setup. To proceed,
|
When developing locally you can go with MailHog_ for email testing provided ``use_mailhog`` was set to ``y`` on setup. To proceed,
|
||||||
|
|
||||||
#. make sure ``mailhog`` container is up and running;
|
#. make sure ``<project_slug>_local_mailhog`` container is up and running;
|
||||||
|
|
||||||
#. open up ``http://127.0.0.1:8025``.
|
#. open up ``http://127.0.0.1:8025``.
|
||||||
|
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
sphinx==4.3.2
|
sphinx==4.4.0
|
||||||
sphinx-rtd-theme==1.0.0
|
sphinx-rtd-theme==1.0.0
|
||||||
|
|
|
@ -21,6 +21,6 @@ pyyaml==6.0
|
||||||
# Scripting
|
# Scripting
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
PyGithub==1.55
|
PyGithub==1.55
|
||||||
gitpython==3.1.25
|
gitpython==3.1.26
|
||||||
jinja2==3.0.3
|
jinja2==3.0.3
|
||||||
requests==2.27.1
|
requests==2.27.1
|
||||||
|
|
2
setup.py
2
setup.py
|
@ -5,7 +5,7 @@ except ImportError:
|
||||||
from distutils.core import setup
|
from distutils.core import setup
|
||||||
|
|
||||||
# We use calendar versioning
|
# We use calendar versioning
|
||||||
version = "2022.01.07"
|
version = "2022.01.14"
|
||||||
|
|
||||||
with open("README.rst") as readme_file:
|
with open("README.rst") as readme_file:
|
||||||
long_description = readme_file.read()
|
long_description = readme_file.read()
|
||||||
|
|
|
@ -312,8 +312,12 @@ ACCOUNT_EMAIL_REQUIRED = True
|
||||||
ACCOUNT_EMAIL_VERIFICATION = "mandatory"
|
ACCOUNT_EMAIL_VERIFICATION = "mandatory"
|
||||||
# https://django-allauth.readthedocs.io/en/latest/configuration.html
|
# https://django-allauth.readthedocs.io/en/latest/configuration.html
|
||||||
ACCOUNT_ADAPTER = "{{cookiecutter.project_slug}}.users.adapters.AccountAdapter"
|
ACCOUNT_ADAPTER = "{{cookiecutter.project_slug}}.users.adapters.AccountAdapter"
|
||||||
|
# https://django-allauth.readthedocs.io/en/latest/forms.html
|
||||||
|
ACCOUNT_FORMS = {"signup": "{{cookiecutter.project_slug}}.users.forms.UserSignupForm"}
|
||||||
# https://django-allauth.readthedocs.io/en/latest/configuration.html
|
# https://django-allauth.readthedocs.io/en/latest/configuration.html
|
||||||
SOCIALACCOUNT_ADAPTER = "{{cookiecutter.project_slug}}.users.adapters.SocialAccountAdapter"
|
SOCIALACCOUNT_ADAPTER = "{{cookiecutter.project_slug}}.users.adapters.SocialAccountAdapter"
|
||||||
|
# https://django-allauth.readthedocs.io/en/latest/forms.html
|
||||||
|
SOCIALACCOUNT_FORMS = {"signup": "{{cookiecutter.project_slug}}.users.forms.UserSocialSignupForm"}
|
||||||
{% if cookiecutter.use_compressor == 'y' -%}
|
{% if cookiecutter.use_compressor == 'y' -%}
|
||||||
# django-compressor
|
# django-compressor
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
|
@ -9,14 +9,14 @@ volumes:
|
||||||
{{ cookiecutter.project_slug }}_local_mysql_data: {}
|
{{ cookiecutter.project_slug }}_local_mysql_data: {}
|
||||||
{{ cookiecutter.project_slug }}_local_mysql_data_backups: {}
|
{{ cookiecutter.project_slug }}_local_mysql_data_backups: {}
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
||||||
services:
|
services:
|
||||||
django:{% if cookiecutter.use_celery == 'y' %} &django{% endif %}
|
django:{% if cookiecutter.use_celery == 'y' %} &django{% endif %}
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: ./compose/local/django/Dockerfile
|
dockerfile: ./compose/local/django/Dockerfile
|
||||||
image: {{ cookiecutter.project_slug }}_local_django
|
image: {{ cookiecutter.project_slug }}_local_django
|
||||||
container_name: django
|
container_name: {{ cookiecutter.project_slug }}_local_django
|
||||||
depends_on:
|
depends_on:
|
||||||
{%- if cookiecutter.database_engine == 'postgresql' %}
|
{%- if cookiecutter.database_engine == 'postgresql' %}
|
||||||
- postgres
|
- postgres
|
||||||
|
@ -50,10 +50,10 @@ services:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: ./compose/production/postgres/Dockerfile
|
dockerfile: ./compose/production/postgres/Dockerfile
|
||||||
image: {{ cookiecutter.project_slug }}_production_postgres
|
image: {{ cookiecutter.project_slug }}_production_postgres
|
||||||
container_name: postgres
|
container_name: {{ cookiecutter.project_slug }}_local_postgres
|
||||||
volumes:
|
volumes:
|
||||||
- local_postgres_data:/var/lib/postgresql/data:Z
|
- {{ cookiecutter.project_slug }}_local_postgres_data:/var/lib/postgresql/data:Z
|
||||||
- local_postgres_data_backups:/backups:z
|
- {{ cookiecutter.project_slug }}_local_postgres_data_backups:/backups:z
|
||||||
env_file:
|
env_file:
|
||||||
- ./.envs/.local/.postgres
|
- ./.envs/.local/.postgres
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
@ -73,7 +73,7 @@ services:
|
||||||
|
|
||||||
docs:
|
docs:
|
||||||
image: {{ cookiecutter.project_slug }}_local_docs
|
image: {{ cookiecutter.project_slug }}_local_docs
|
||||||
container_name: docs
|
container_name: {{ cookiecutter.project_slug }}_local_docs
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: ./compose/local/docs/Dockerfile
|
dockerfile: ./compose/local/docs/Dockerfile
|
||||||
|
@ -90,7 +90,7 @@ services:
|
||||||
|
|
||||||
mailhog:
|
mailhog:
|
||||||
image: mailhog/mailhog:v1.0.0
|
image: mailhog/mailhog:v1.0.0
|
||||||
container_name: mailhog
|
container_name: {{ cookiecutter.project_slug }}_local_mailhog
|
||||||
ports:
|
ports:
|
||||||
- "8025:8025"
|
- "8025:8025"
|
||||||
|
|
||||||
|
@ -99,12 +99,12 @@ services:
|
||||||
|
|
||||||
redis:
|
redis:
|
||||||
image: redis:6
|
image: redis:6
|
||||||
container_name: redis
|
container_name: {{ cookiecutter.project_slug }}_local_redis
|
||||||
|
|
||||||
celeryworker:
|
celeryworker:
|
||||||
<<: *django
|
<<: *django
|
||||||
image: {{ cookiecutter.project_slug }}_local_celeryworker
|
image: {{ cookiecutter.project_slug }}_local_celeryworker
|
||||||
container_name: celeryworker
|
container_name: {{ cookiecutter.project_slug }}_local_celeryworker
|
||||||
depends_on:
|
depends_on:
|
||||||
- redis
|
- redis
|
||||||
{%- if cookiecutter.database_engine == 'postgresql' %}
|
{%- if cookiecutter.database_engine == 'postgresql' %}
|
||||||
|
@ -122,7 +122,7 @@ services:
|
||||||
celerybeat:
|
celerybeat:
|
||||||
<<: *django
|
<<: *django
|
||||||
image: {{ cookiecutter.project_slug }}_local_celerybeat
|
image: {{ cookiecutter.project_slug }}_local_celerybeat
|
||||||
container_name: celerybeat
|
container_name: {{ cookiecutter.project_slug }}_local_celerybeat
|
||||||
depends_on:
|
depends_on:
|
||||||
- redis
|
- redis
|
||||||
{%- if cookiecutter.database_engine == 'postgresql' %}
|
{%- if cookiecutter.database_engine == 'postgresql' %}
|
||||||
|
@ -140,7 +140,7 @@ services:
|
||||||
flower:
|
flower:
|
||||||
<<: *django
|
<<: *django
|
||||||
image: {{ cookiecutter.project_slug }}_local_flower
|
image: {{ cookiecutter.project_slug }}_local_flower
|
||||||
container_name: flower
|
container_name: {{ cookiecutter.project_slug }}_local_flower
|
||||||
ports:
|
ports:
|
||||||
- "5555:5555"
|
- "5555:5555"
|
||||||
command: /start-flower
|
command: /start-flower
|
||||||
|
@ -153,7 +153,7 @@ services:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: ./compose/local/node/Dockerfile
|
dockerfile: ./compose/local/node/Dockerfile
|
||||||
image: {{ cookiecutter.project_slug }}_local_node
|
image: {{ cookiecutter.project_slug }}_local_node
|
||||||
container_name: node
|
container_name: {{ cookiecutter.project_slug }}_local_node
|
||||||
depends_on:
|
depends_on:
|
||||||
- django
|
- django
|
||||||
volumes:
|
volumes:
|
||||||
|
|
|
@ -24,7 +24,7 @@ flower==1.0.0 # https://github.com/mher/flower
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{%- if cookiecutter.use_async == 'y' %}
|
{%- if cookiecutter.use_async == 'y' %}
|
||||||
uvicorn[standard]==0.16.0 # https://github.com/encode/uvicorn
|
uvicorn[standard]==0.17.0 # https://github.com/encode/uvicorn
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
||||||
# Django
|
# Django
|
||||||
|
@ -42,5 +42,5 @@ django-redis==5.2.0 # https://github.com/jazzband/django-redis
|
||||||
{%- if cookiecutter.use_drf == "y" %}
|
{%- if cookiecutter.use_drf == "y" %}
|
||||||
# Django REST Framework
|
# Django REST Framework
|
||||||
djangorestframework==3.13.1 # https://github.com/encode/django-rest-framework
|
djangorestframework==3.13.1 # https://github.com/encode/django-rest-framework
|
||||||
django-cors-headers==3.10.1 # https://github.com/adamchainz/django-cors-headers
|
django-cors-headers==3.11.0 # https://github.com/adamchainz/django-cors-headers
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
-r base.txt
|
-r base.txt
|
||||||
|
|
||||||
Werkzeug==2.0.2 # https://github.com/pallets/werkzeug
|
Werkzeug[watchdog]==2.0.2 # https://github.com/pallets/werkzeug
|
||||||
ipdb==0.13.9 # https://github.com/gotcha/ipdb
|
ipdb==0.13.9 # https://github.com/gotcha/ipdb
|
||||||
{%- if cookiecutter.database_engine == "postgresql" %}
|
{%- if cookiecutter.database_engine == "postgresql" %}
|
||||||
{%- if cookiecutter.use_docker == 'y' %}
|
{%- if cookiecutter.use_docker == 'y' %}
|
||||||
|
@ -28,7 +28,7 @@ djangorestframework-stubs==1.4.0 # https://github.com/typeddjango/djangorestfra
|
||||||
|
|
||||||
# Documentation
|
# Documentation
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
sphinx==4.3.2 # https://github.com/sphinx-doc/sphinx
|
sphinx==4.4.0 # https://github.com/sphinx-doc/sphinx
|
||||||
sphinx-autobuild==2021.3.14 # https://github.com/GaretJax/sphinx-autobuild
|
sphinx-autobuild==2021.3.14 # https://github.com/GaretJax/sphinx-autobuild
|
||||||
|
|
||||||
# Code quality
|
# Code quality
|
||||||
|
|
|
@ -12,7 +12,7 @@ mysqlclient==2.1.0 # https://github.com/PyMySQL/mysqlclient
|
||||||
Collectfast==2.2.0 # https://github.com/antonagestam/collectfast
|
Collectfast==2.2.0 # https://github.com/antonagestam/collectfast
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{%- if cookiecutter.use_sentry == "y" %}
|
{%- if cookiecutter.use_sentry == "y" %}
|
||||||
sentry-sdk==1.5.1 # https://github.com/getsentry/sentry-python
|
sentry-sdk==1.5.2 # https://github.com/getsentry/sentry-python
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{%- if cookiecutter.use_docker == "n" and cookiecutter.windows == "y" %}
|
{%- if cookiecutter.use_docker == "n" and cookiecutter.windows == "y" %}
|
||||||
hiredis==2.0.0 # https://github.com/redis/hiredis-py
|
hiredis==2.0.0 # https://github.com/redis/hiredis-py
|
||||||
|
|
|
@ -7,23 +7,52 @@ from django.conf import settings
|
||||||
from django.db import migrations
|
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):
|
def update_site_forward(apps, schema_editor):
|
||||||
"""Set site domain and name."""
|
"""Set site domain and name."""
|
||||||
Site = apps.get_model("sites", "Site")
|
Site = apps.get_model("sites", "Site")
|
||||||
Site.objects.update_or_create(
|
_update_or_create_site_with_sequence(
|
||||||
id=settings.SITE_ID,
|
Site,
|
||||||
defaults={
|
schema_editor.connection,
|
||||||
"domain": "{{cookiecutter.domain_name}}",
|
"{{cookiecutter.domain_name}}",
|
||||||
"name": "{{cookiecutter.project_name}}",
|
"{{cookiecutter.project_name}}",
|
||||||
},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def update_site_backward(apps, schema_editor):
|
def update_site_backward(apps, schema_editor):
|
||||||
"""Revert site domain and name to default."""
|
"""Revert site domain and name to default."""
|
||||||
Site = apps.get_model("sites", "Site")
|
Site = apps.get_model("sites", "Site")
|
||||||
Site.objects.update_or_create(
|
_update_or_create_site_with_sequence(
|
||||||
id=settings.SITE_ID, defaults={"domain": "example.com", "name": "example.com"}
|
Site,
|
||||||
|
schema_editor.connection,
|
||||||
|
"example.com",
|
||||||
|
"example.com",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ from django.contrib.auth import admin as auth_admin
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from {{ cookiecutter.project_slug }}.users.forms import UserChangeForm, UserCreationForm
|
from {{ cookiecutter.project_slug }}.users.forms import UserAdminChangeForm, UserAdminCreationForm
|
||||||
|
|
||||||
User = get_user_model()
|
User = get_user_model()
|
||||||
|
|
||||||
|
@ -11,8 +11,8 @@ User = get_user_model()
|
||||||
@admin.register(User)
|
@admin.register(User)
|
||||||
class UserAdmin(auth_admin.UserAdmin):
|
class UserAdmin(auth_admin.UserAdmin):
|
||||||
|
|
||||||
form = UserChangeForm
|
form = UserAdminChangeForm
|
||||||
add_form = UserCreationForm
|
add_form = UserAdminCreationForm
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, {"fields": ("username", "password")}),
|
(None, {"fields": ("username", "password")}),
|
||||||
(_("Personal info"), {"fields": ("name", "email")}),
|
(_("Personal info"), {"fields": ("name", "email")}),
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from allauth.account.forms import SignupForm
|
||||||
|
from allauth.socialaccount.forms import SignupForm as SocialSignupForm
|
||||||
from django.contrib.auth import forms as admin_forms
|
from django.contrib.auth import forms as admin_forms
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
@ -5,15 +7,36 @@ from django.utils.translation import gettext_lazy as _
|
||||||
User = get_user_model()
|
User = get_user_model()
|
||||||
|
|
||||||
|
|
||||||
class UserChangeForm(admin_forms.UserChangeForm):
|
class UserAdminChangeForm(admin_forms.UserChangeForm):
|
||||||
class Meta(admin_forms.UserChangeForm.Meta):
|
class Meta(admin_forms.UserChangeForm.Meta):
|
||||||
model = User
|
model = User
|
||||||
|
|
||||||
|
|
||||||
class UserCreationForm(admin_forms.UserCreationForm):
|
class UserAdminCreationForm(admin_forms.UserCreationForm):
|
||||||
|
"""
|
||||||
|
Form for User Creation in the Admin Area.
|
||||||
|
To change user signup, see UserSignupForm and UserSocialSignupForm.
|
||||||
|
"""
|
||||||
|
|
||||||
class Meta(admin_forms.UserCreationForm.Meta):
|
class Meta(admin_forms.UserCreationForm.Meta):
|
||||||
model = User
|
model = User
|
||||||
|
|
||||||
error_messages = {
|
error_messages = {
|
||||||
"username": {"unique": _("This username has already been taken.")}
|
"username": {"unique": _("This username has already been taken.")}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class UserSignupForm(SignupForm):
|
||||||
|
"""
|
||||||
|
Form that will be rendered on a user sign up section/screen.
|
||||||
|
Default fields will be added automatically.
|
||||||
|
Check UserSocialSignupForm for accounts created from social.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class UserSocialSignupForm(SocialSignupForm):
|
||||||
|
"""
|
||||||
|
Renders the form when user has signed up using social accounts.
|
||||||
|
Default fields will be added automatically.
|
||||||
|
See UserSignupForm otherwise.
|
||||||
|
"""
|
||||||
|
|
|
@ -5,7 +5,11 @@ from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class User(AbstractUser):
|
class User(AbstractUser):
|
||||||
"""Default user for {{cookiecutter.project_name}}."""
|
"""
|
||||||
|
Default custom user model for {{cookiecutter.project_name}}.
|
||||||
|
If adding fields that need to be filled at user signup,
|
||||||
|
check forms.SignupForm and forms.SocialSignupForms accordingly.
|
||||||
|
"""
|
||||||
|
|
||||||
#: First and last name do not cover name patterns around the globe
|
#: First and last name do not cover name patterns around the globe
|
||||||
name = CharField(_("Name of User"), blank=True, max_length=255)
|
name = CharField(_("Name of User"), blank=True, max_length=255)
|
||||||
|
|
|
@ -4,20 +4,20 @@ Module for all Form Tests.
|
||||||
import pytest
|
import pytest
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from {{ cookiecutter.project_slug }}.users.forms import UserCreationForm
|
from {{ cookiecutter.project_slug }}.users.forms import UserAdminCreationForm
|
||||||
from {{ cookiecutter.project_slug }}.users.models import User
|
from {{ cookiecutter.project_slug }}.users.models import User
|
||||||
|
|
||||||
pytestmark = pytest.mark.django_db
|
pytestmark = pytest.mark.django_db
|
||||||
|
|
||||||
|
|
||||||
class TestUserCreationForm:
|
class TestUserAdminCreationForm:
|
||||||
"""
|
"""
|
||||||
Test class for all tests related to the UserCreationForm
|
Test class for all tests related to the UserAdminCreationForm
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def test_username_validation_error_msg(self, user: User):
|
def test_username_validation_error_msg(self, user: User):
|
||||||
"""
|
"""
|
||||||
Tests UserCreation Form's unique validator functions correctly by testing:
|
Tests UserAdminCreation Form's unique validator functions correctly by testing:
|
||||||
1) A new user with an existing username cannot be added.
|
1) A new user with an existing username cannot be added.
|
||||||
2) Only 1 error is raised by the UserCreation Form
|
2) Only 1 error is raised by the UserCreation Form
|
||||||
3) The desired error message is raised
|
3) The desired error message is raised
|
||||||
|
@ -25,7 +25,7 @@ class TestUserCreationForm:
|
||||||
|
|
||||||
# The user already exists,
|
# The user already exists,
|
||||||
# hence cannot be created.
|
# hence cannot be created.
|
||||||
form = UserCreationForm(
|
form = UserAdminCreationForm(
|
||||||
{
|
{
|
||||||
"username": user.username,
|
"username": user.username,
|
||||||
"password1": user.password,
|
"password1": user.password,
|
||||||
|
|
|
@ -8,7 +8,7 @@ from django.http import HttpRequest, HttpResponseRedirect
|
||||||
from django.test import RequestFactory
|
from django.test import RequestFactory
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
|
||||||
from {{ cookiecutter.project_slug }}.users.forms import UserChangeForm
|
from {{ cookiecutter.project_slug }}.users.forms import UserAdminChangeForm
|
||||||
from {{ cookiecutter.project_slug }}.users.models import User
|
from {{ cookiecutter.project_slug }}.users.models import User
|
||||||
from {{ cookiecutter.project_slug }}.users.tests.factories import UserFactory
|
from {{ cookiecutter.project_slug }}.users.tests.factories import UserFactory
|
||||||
from {{ cookiecutter.project_slug }}.users.views import (
|
from {{ cookiecutter.project_slug }}.users.views import (
|
||||||
|
@ -62,7 +62,7 @@ class TestUserUpdateView:
|
||||||
view.request = request
|
view.request = request
|
||||||
|
|
||||||
# Initialize the form
|
# Initialize the form
|
||||||
form = UserChangeForm()
|
form = UserAdminChangeForm()
|
||||||
form.cleaned_data = []
|
form.cleaned_data = []
|
||||||
view.form_valid(form)
|
view.form_valid(form)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user