diff --git a/README.md b/README.md index fc79887..12d25d8 100644 --- a/README.md +++ b/README.md @@ -292,6 +292,30 @@ to keep things seperate `django-distill` will also check `settings.LANGUAGES` fo language codes. +### Sitemaps + +You may need to generate a list of all the URLs registered with `django-distill`. +For example, you have a statically generated blog with a few hundred pages and +you want to list all of the URLs easily in a `sitemap.xml` or other similar list +of all URLs. You could wrap your sitemap view in `distill_path` then replicate +all of your URL generation logic by importing your views `distill_func`s from +your `urls.py` and generating these all manually, but given this is quite a hassle +there's a built-in helper to generate all your URLs that will be distilled for you. + +```python +from django_distill import distilled_urls + +for uri, file_name in distilled_urls(): + # URI is the generated, complete URI for the page + print(uri) # for example: /blog/my-post-123/ + # file_name is the actual file name on disk, this may be None or a string + print(file_name) # for example: /blog/my-post-123/index.html +``` + +**Note** that `distilled_urls()` will only return URLs after all of your URLs +in `urls.py` have been loaded with `distill_path(...)`. + + # The `distill-local` command Once you have wrapped the URLs you want to generate statically you can now diff --git a/django_distill/__init__.py b/django_distill/__init__.py index 828bb50..3b8d34c 100644 --- a/django_distill/__init__.py +++ b/django_distill/__init__.py @@ -3,6 +3,8 @@ from django import __version__ as django_version from django_distill.errors import DistillError +from django_distill.distill import urls_to_distill +from django_distill.renderer import generate_urls try: @@ -31,3 +33,7 @@ def distill_path(*args, **kwargs): err = ('Your installed version of Django ({}) does not supprt ' 'django.urls.path, please upgrade') raise DistillError(err.format(django_version)) + + +def distilled_urls(): + return generate_urls(urls_to_distill) diff --git a/django_distill/renderer.py b/django_distill/renderer.py index 2ab90a6..8af84b8 100644 --- a/django_distill/renderer.py +++ b/django_distill/renderer.py @@ -184,15 +184,18 @@ def render_file(self, view_name, status_codes, view_args, view_kwargs): file_name = self._get_filename(file_name, uri, args) return uri, file_name, render - def render_all_urls(self): + def render_all_urls(self, do_render=True): def _render(item): rtn = [] for lang in self.get_langs(): activate_lang(lang) - url, view_name, param_set, status_codes, file_name_base, a, k = item + url, view_name, param_set, status_codes, file_name_base, a, k, do_render = item uri = self.generate_uri(url, view_name, param_set) - render = self.render_view(uri, status_codes, param_set, a, k) + if do_render: + render = self.render_view(uri, status_codes, param_set, a, k) + else: + render = None file_name = self._get_filename(file_name_base, uri, param_set) rtn.append((uri, file_name, render)) return rtn @@ -204,7 +207,7 @@ def _render(item): param_set = () elif self._is_str(param_set): param_set = (param_set,) - to_render.append((url, view_name, param_set, status_codes, file_name_base, a, k)) + to_render.append((url, view_name, param_set, status_codes, file_name_base, a, k, do_render)) with ThreadPoolExecutor(max_workers=self.parallel_render) as executor: results = executor.map(_render, to_render) for i18n_result in results: @@ -223,6 +226,10 @@ def render(self, view_name=None, status_codes=None, view_args=None, view_kwargs= else: return self.render_all_urls() + def urls(self): + for (uri, file_name, _) in self.render_all_urls(do_render=False): + yield uri, file_name + def get_langs(self): langs = [] LANGUAGE_CODE = str(getattr(settings, 'LANGUAGE_CODE', 'en')) @@ -475,6 +482,12 @@ def render_single_file(output_dir, view_name, *args, **kwargs): return True +def generate_urls(urls_to_distill): + load_urls() + renderer = get_renderer(urls_to_distill) + return renderer.urls() + + def render_static_redirect(destination_url): redir = [] redir.append(f'') diff --git a/tests/test_renderer.py b/tests/test_renderer.py index b3635c0..b619068 100644 --- a/tests/test_renderer.py +++ b/tests/test_renderer.py @@ -12,6 +12,7 @@ from django_distill.distill import urls_to_distill from django_distill.renderer import DistillRender, render_to_dir, render_single_file, get_renderer from django_distill.errors import DistillError +from django_distill import distilled_urls class CustomRender(DistillRender): @@ -489,3 +490,46 @@ def _blackhole(_): for expected_file in expected_files: filepath = os.path.join(tmpdirname, *expected_file) self.assertIn(filepath, written_files) + + def test_generate_urls(self): + urls = distilled_urls() + generated_urls = [] + for url, file_name in urls: + generated_urls.append(url) + expected_urls = ( + '/path/namespace1/sub-url-in-namespace', + '/path/namespace1/path/sub-namespace/sub-url-in-sub-namespace', + '/path/no-namespace/sub-url-in-no-namespace', + '/en/path/i18n/sub-url-with-i18n-prefix', + '/re_path/', + '/re_path-no-func/', + '/re_path/12345', + '/re_path/67890', + '/re_path/x/12345', + '/re_path/x/67890', + '/re_path/test', + '/re_path/x/test', + '/re_path/broken', + '/re_path/ignore-sessions', + '/re_path/404', + '/re_path/flatpage/flat/page1.html', + '/re_path/flatpage/flat/page2.html', + '/path/', + '/path-no-func/', + '/path/12345', + '/path/67890', + '/path/x/12345', + '/path/x/67890', + '/path/test', + '/path/x/test', + '/path/broken', + '/path/ignore-sessions', + '/path/404', + '/path/flatpage/flat/page1.html', + '/path/flatpage/flat/page2.html', + '/path/test-sitemap', + '/path/kwargs', + '/path/humanize', + '/path/has-resolver-match' + ) + self.assertEqual(sorted(generated_urls), sorted(expected_urls))