diff --git a/README.rst b/README.rst index 0c1fa04c..d334f1c1 100644 --- a/README.rst +++ b/README.rst @@ -145,6 +145,20 @@ Communication .. _Read the Docs: https://readthedocs.org/ .. _Repository Status Badges: https://www.repostatus.org/#concept +Dynamic Settings +~~~~~~~~~~~~~~~~ + +Choose to add `django-constance`_ for dynamic Django settings, which allows +you to: + +#. Easily migrate your static settings to dynamic settings. +#. Edit dynamic settings in the Django Admin interface. + +See our `django-constance How-to`_ for more information. + +.. _django-constance: https://django-constance.readthedocs.io/en/latest/index.html +.. _django-constance How-to: https://django-cookiecutter.readthedocs.io/en/latest/how-tos/how-to-constance.html + Contributing ------------ diff --git a/cookiecutter.json b/cookiecutter.json index 497e5911..ffe65fd0 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -18,6 +18,10 @@ "False" ], "SITE_ID": "1", + "use_constance": [ + "n", + "y" + ], "deploy_with_docker": [ "n", "y", diff --git a/docs/source/_static/imgs/how-tos/admin-constance-setting.png b/docs/source/_static/imgs/how-tos/admin-constance-setting.png new file mode 100644 index 00000000..09bc71b1 Binary files /dev/null and b/docs/source/_static/imgs/how-tos/admin-constance-setting.png differ diff --git a/docs/source/_static/imgs/how-tos/admin-constance.png b/docs/source/_static/imgs/how-tos/admin-constance.png new file mode 100644 index 00000000..f58b4cb7 Binary files /dev/null and b/docs/source/_static/imgs/how-tos/admin-constance.png differ diff --git a/docs/source/how-tos/how-to-constance.rst b/docs/source/how-tos/how-to-constance.rst new file mode 100644 index 00000000..64acd1f9 --- /dev/null +++ b/docs/source/how-tos/how-to-constance.rst @@ -0,0 +1,97 @@ +.. include:: /extras.rst.txt +.. highlight:: rst +.. index:: how-to-constance ; Index + +.. _how-to-constance: + +========= +Constance +========= + + +django-constance provides the convenience of dynamic site settings, +accessible in the Admin panel. + +There are many configuration options available; for more, see further +reading below. + +django-cookiecutter employs the django-constance database configuration option. + +Adding dynamic settings is done in `config/settings/base.py`. + + +.. code-block:: python + :linenos: + + CONSTANCE_CONFIG = { + 'THE_ANSWER': (42, 'Answer to the Ultimate Question of Life, ' + 'The Universe, and Everything', int), + } + +In the example above, provided in `config/settings/base.py`, + +`THE_ANSWER`: is the dynamic settings key. + +`42`: is the default value if `THE_ANSWER` is not found in the backend. + +`Help` text displayed in the Admin panel. + 'Answer to the Ultimate Question of Life, ' + 'The Universe, and Everything' + +`int`: optional indicates the value type. + +The supported types are: + + - bool + - int + - float + - Decimal + - str + - datetime + - date + - time + + +Changing Settings +_________________ + +Settings you have provided in `base.py`, shown above, can be changed in the +Admin panel. + +**Select** `Config` in the Constance section. + +.. image:: ../_static/imgs/how-tos/admin-constance.png + :alt: Django Admin Constance + + +| + +**Change** the setting. + +The example dynamic setting provided with django-cookiecutter is below. + +.. image:: ../_static/imgs/how-tos/admin-constance-setting.png + :alt: Django Admin Constance + +| + +Further Reading +--------------- + +For additional Constance and custom configurations. + +`Constance config quickstart`_. + +Constance provides several backend options to store configuration values. +By default, it uses the `Redis` backend. django-cookiecutter uses `database`. + +`Constance backends`_. + +Use `override_config` class for testing how your app behaves with different config values. + +`Constance config for testing`_. + + +.. _Constance config quickstart: https://django-constance.readthedocs.io/en/latest/index.html +.. _Constance backends: +.. _Constance config for testing: https://django-constance.readthedocs.io/en/latest/testing.html diff --git a/docs/source/how-tos/index-how-to.rst b/docs/source/how-tos/index-how-to.rst index 622169e7..14f3471b 100644 --- a/docs/source/how-tos/index-how-to.rst +++ b/docs/source/how-tos/index-how-to.rst @@ -15,10 +15,11 @@ See below for a list of How-To for Django Cookiecutter. :titlesonly: how-to-quickstart + how-to-constance how-to-custom-user + how-to-docker-linux-cheatsheet how-to-htmx how-to-logging how-to-tailwind how-to-test-env-settings - how-to-docker-linux-cheatsheet how-to-contribute diff --git a/docs/source/reference/reference-project-inputs.rst b/docs/source/reference/reference-project-inputs.rst index 32a6a99f..768c3827 100644 --- a/docs/source/reference/reference-project-inputs.rst +++ b/docs/source/reference/reference-project-inputs.rst @@ -66,10 +66,10 @@ version The first version number. The version number appears in the documentation and semantic version release. -Django Settings ---------------- +Django Static Settings +---------------------- -"ALLOWED_HOSTS": "www.example.com", +"ALLOWED_HOSTS": "", "INTERNAL_IPS": "127.0.0.1", @@ -89,6 +89,17 @@ See `Django Settings`_ for more information. Options ------- +Django Dynamic Settings +----------------------- + +"use_constance": ["n", "y"] +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Use django-constance for Dynamic Django settings. + +#. Easily migrate your static settings to dynamic settings. +#. Edit dynamic settings in the Django Admin interface. + The following Django Cookiecutter configuration options are grouped logically. Where options are in a list, the first item is the default setting. @@ -235,6 +246,8 @@ Requires a `Pyup.io`_ account linked to your GitHub project repository. "open_source_license": ~~~~~~~~~~~~~~~~~~~~~~ +Let people know about this project license arrangements. + [ 1. MIT License, 2. BSD license, @@ -244,8 +257,6 @@ Requires a `Pyup.io`_ account linked to your GitHub project repository. 6. Not open source ] -Let people know about this project license arrangements. - .. _Pyup.io: https://github.com/pyupio/pyup .. _Conventional Commits: https://www.conventionalcommits.org/en/v1.0.0/ .. _Django Settings: https://docs.djangoproject.com/en/4.0/ref/settings/ diff --git a/tests/test_bake_django.py b/tests/test_bake_django.py index 45dc6cb9..834b0733 100644 --- a/tests/test_bake_django.py +++ b/tests/test_bake_django.py @@ -189,6 +189,59 @@ def test_baked_django_without_commit_message_file(cookies): non_default_django.project_path / ".github" ) +def test_baked_django_without_constance_config_in_base_py(cookies): + """Test django-constance not installed.""" + default_django = cookies.bake() + + list_path = default_django.project_path / "config/settings/base.py" + list_file = str(list_path.read_text().splitlines()) + + assert "constance" not in list_file + assert "constance.backends.database" not in list_file + assert "# Constance Configuration" not in list_file + + + +def test_baked_django_with_constance_config_in_base_py(cookies): + """Test django-constance installed correctly.""" + non_default_django = cookies.bake( + extra_context={ + "use_constance": "y", + } + ) + + list_path = non_default_django.project_path / "config/settings/base.py" + list_file = str(list_path.read_text().splitlines()) + + assert "constance" in list_file + assert "constance.backends.database" in list_file + assert "# Constance Configuration" in list_file + + + + +def test_baked_django_without_constance_config_in_base_txt(cookies): + """Test django-constance not installed.""" + default_django = cookies.bake() + + list_path = default_django.project_path / "config/requirements/base.txt" + list_file = str(list_path.read_text().splitlines()) + + assert 'django-constance[database]==' not in list_file + + +def test_baked_django_with_constance_config_in_base_txt(cookies): + """Test django-constance installed correctly.""" + non_default_django = cookies.bake( + extra_context={ + "use_constance": "y", + } + ) + + list_path = non_default_django.project_path / "config/requirements/base.txt" + list_file = str(list_path.read_text().splitlines()) + + assert 'django-constance[database]==' in list_file def test_baked_django_with_custom_issue_template_files(cookies): """Test Django project has custom ISSUE templates generated correctly. diff --git a/{{cookiecutter.git_project_name}}/config/requirements/base.txt b/{{cookiecutter.git_project_name}}/config/requirements/base.txt index 606d7ef3..487bf095 100644 --- a/{{cookiecutter.git_project_name}}/config/requirements/base.txt +++ b/{{cookiecutter.git_project_name}}/config/requirements/base.txt @@ -1,5 +1,6 @@ Django==4.0.3 -django-allauth==0.49.0 +django-allauth==0.49.0{% if cookiecutter.use_constance != "n" %} +django-constance[database]==2.8.0{% endif %} django-environ==0.8.1 django-htmx==1.9.0 django-tailwind==3.1.1 diff --git a/{{cookiecutter.git_project_name}}/config/settings/base.py b/{{cookiecutter.git_project_name}}/config/settings/base.py index 9e361f22..4660a536 100644 --- a/{{cookiecutter.git_project_name}}/config/settings/base.py +++ b/{{cookiecutter.git_project_name}}/config/settings/base.py @@ -62,7 +62,9 @@ # Application definition -INSTALLED_APPS = [ +INSTALLED_APPS = [{% if cookiecutter.use_constance != "n" %} + "constance", + "constance.backends.database",{% endif %} "users", "django.contrib.admin", "django.contrib.auth", @@ -142,7 +144,22 @@ "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", }, ] +{% if cookiecutter.use_constance != "n" %} +# Constance Configuration +CONSTANCE_BACKEND = "constance.backends.database.DatabaseBackend" + +CONSTANCE_CONFIG = { + "THE_ANSWER": ( + 42, + "Answer to the Ultimate Question of Life, The Universe, and Everything", + int, + ), +} +CONSTANCE_CONFIG_FIELDSETS = { + "The Answer": ("THE_ANSWER",), +} +{% endif %} # Internationalization # https://docs.djangoproject.com/en/4.0/topics/i18n/ {%- set language_labels = ({