diff --git a/CHANGELOG.md b/CHANGELOG.md index ae20f2a9..d26c94b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Added - We now officially support Django 3.2, and tentatively Django 4.0 +- Load templates from template engines’ [`DIRS`](https://docs.djangoproject.com/en/3.2/ref/settings/#dirs) as well as apps’ `templates` subdirectories. ### Fixed diff --git a/docs/reference/api.md b/docs/reference/api.md index 6d05a745..57f53eb2 100644 --- a/docs/reference/api.md +++ b/docs/reference/api.md @@ -59,7 +59,7 @@ PATTERN_LIBRARY = { ### `SECTIONS` `SECTIONS` controls the groups of templates that appear in the navigation. -The keys are the group titles and the values are lists of template name prefixes that will be searched to populate the groups. +The keys are the group titles and the values are lists of template name prefixes that will be searched to populate the groups. The pattern library searches for templates both in [`DIRS`](https://docs.djangoproject.com/en/3.2/ref/settings/#dirs) directories for template engines, and in the `templates` subdirectory inside each installed application if using [`APP_DIRS`](https://docs.djangoproject.com/en/3.2/ref/settings/#app-dirs). You can use this to create basic two-folder "includes and pages" hierarchies: diff --git a/pattern_library/utils.py b/pattern_library/utils.py index f16e8ade..d5fc4dcf 100644 --- a/pattern_library/utils.py +++ b/pattern_library/utils.py @@ -2,6 +2,7 @@ import os import re +from django.conf import settings from django.template import TemplateDoesNotExist from django.template.context import Context from django.template.loader import get_template, render_to_string @@ -66,9 +67,16 @@ def order_dict(dictionary, key_sort=None): return dict(values) +def get_template_dirs(): + template_dirs = [d for engines in settings.TEMPLATES for d in engines.get("DIRS", [])] + template_app_dirs = get_app_template_dirs('templates') + template_dirs += template_app_dirs + return template_dirs + + def get_pattern_templates(): templates = base_dict() - template_dirs = get_app_template_dirs('templates') + template_dirs = get_template_dirs() for lookup_dir in template_dirs: for root, dirs, files in os.walk(lookup_dir, topdown=True): diff --git a/tests/tests/test_utils.py b/tests/tests/test_utils.py index 81b937ef..d65f23cd 100644 --- a/tests/tests/test_utils.py +++ b/tests/tests/test_utils.py @@ -1,6 +1,9 @@ -from django.test import SimpleTestCase +import os -from pattern_library.utils import get_template_ancestors +from django.conf import settings +from django.test import SimpleTestCase, override_settings + +from pattern_library.utils import get_template_ancestors, get_template_dirs class TestGetTemplateAncestors(SimpleTestCase): @@ -33,3 +36,40 @@ def test_parent_template_from_variable(self): 'patterns/base.html', ], ) + + @override_settings(TEMPLATES=[ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'APP_DIRS': True, + }, + ]) + def test_get_template_dirs_app_dirs(self): + template_dirs = ['/'.join(d.replace(os.path.dirname(settings.BASE_DIR), 'dpl').split('/')[-4:-1]) for d in get_template_dirs()] + self.assertListEqual(template_dirs, [ + 'django/contrib/auth', + 'dpl/pattern_library', + 'dpl/tests', + ]) + + @override_settings(TEMPLATES=[ + { + 'NAME': 'one', + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [os.path.join(settings.BASE_DIR, "test_one", "templates")], + 'APP_DIRS': True, + }, + { + 'NAME': 'two', + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [os.path.join(settings.BASE_DIR, "test_two", "templates")], + }, + ]) + def test_get_template_dirs_list_dirs(self): + template_dirs = ['/'.join(d.replace(os.path.dirname(settings.BASE_DIR), 'dpl').split('/')[-4:-1]) for d in get_template_dirs()] + self.assertListEqual(template_dirs, [ + 'dpl/tests/test_one', + 'dpl/tests/test_two', + 'django/contrib/auth', + 'dpl/pattern_library', + 'dpl/tests', + ])