mirror of
https://github.com/django-components/django-components.git
synced 2025-08-15 11:40:14 +00:00
Resolve media and template files relative to component class dir (#395), thanks @JuroOravec
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Emil Stenström <emil@emilstenstrom.se>
This commit is contained in:
parent
1de859bd34
commit
37fd901908
21 changed files with 477 additions and 43 deletions
|
@ -2,34 +2,84 @@
|
|||
Template loader that loads templates from each Django app's "components" directory.
|
||||
"""
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import Set
|
||||
|
||||
from django.apps import apps
|
||||
from django.conf import settings
|
||||
from django.template.loaders.filesystem import Loader as FilesystemLoader
|
||||
from django.template.utils import get_app_template_dirs
|
||||
|
||||
from django_components.logger import logger
|
||||
|
||||
|
||||
# Same as `Path.is_relative_to`, defined as standalone function because `Path.is_relative_to`
|
||||
# is marked for deprecation.
|
||||
def path_is_relative_to(child_path: str, parent_path: str):
|
||||
# If the relative path doesn't start with `..`, then child is descendant of parent
|
||||
# See https://stackoverflow.com/a/7288073/9788634
|
||||
rel_path = os.path.relpath(child_path, parent_path)
|
||||
return not rel_path.startswith("..")
|
||||
|
||||
|
||||
class Loader(FilesystemLoader):
|
||||
def get_dirs(self):
|
||||
component_dir = "components"
|
||||
directories = set(get_app_template_dirs(component_dir))
|
||||
# Allow to configure from settings which dirs should be checked for components
|
||||
if hasattr(settings, "STATICFILES_DIRS") and len(settings.STATICFILES_DIRS):
|
||||
component_dirs = settings.STATICFILES_DIRS
|
||||
else:
|
||||
component_dirs = ["components"]
|
||||
|
||||
if hasattr(settings, "BASE_DIR"):
|
||||
path = (Path(settings.BASE_DIR) / component_dir).resolve()
|
||||
if path.is_dir():
|
||||
directories.add(path)
|
||||
logger.debug(
|
||||
"Template loader will search for valid template dirs from following options:\n"
|
||||
+ "\n".join([f" - {str(d)}" for d in component_dirs])
|
||||
)
|
||||
|
||||
if settings.SETTINGS_MODULE:
|
||||
module_parts = settings.SETTINGS_MODULE.split(".")
|
||||
module_path = Path(*module_parts)
|
||||
directories: Set[Path] = set()
|
||||
for component_dir in component_dirs:
|
||||
curr_directories: Set[Path] = set()
|
||||
|
||||
if len(module_parts) > 2:
|
||||
module_path = Path(*module_parts[:-1])
|
||||
# For each dir in `settings.STATICFILES_DIRS`, we go over all Django apps
|
||||
# and, for each app, check if the STATICFILES_DIRS dir is within that app dir.
|
||||
# If so, we add the dir as a valid source.
|
||||
# The for loop is based on Django's `get_app_template_dirs`.
|
||||
for app_config in apps.get_app_configs():
|
||||
if not app_config.path:
|
||||
continue
|
||||
if not Path(component_dir).is_dir():
|
||||
continue
|
||||
|
||||
# Use list() for < Python 3.9
|
||||
for parent in list(module_path.parents)[:2]:
|
||||
path = (parent / component_dir).resolve()
|
||||
if path_is_relative_to(component_dir, app_config.path):
|
||||
curr_directories.add(Path(component_dir).resolve())
|
||||
|
||||
if hasattr(settings, "BASE_DIR"):
|
||||
path = (Path(settings.BASE_DIR) / component_dir).resolve()
|
||||
if path.is_dir():
|
||||
directories.add(path)
|
||||
curr_directories.add(path)
|
||||
|
||||
# Add the directory that holds the settings file
|
||||
if settings.SETTINGS_MODULE:
|
||||
module_parts = settings.SETTINGS_MODULE.split(".")
|
||||
module_path = Path(*module_parts)
|
||||
|
||||
# - If len() == 2, then path to settings file is <app_name>/<settings_file>.py
|
||||
# - If len() > 2, then we assume that settings file is in a settings directory,
|
||||
# e.g. <app_name>/settings/<settings_file>.py
|
||||
if len(module_parts) > 2:
|
||||
module_path = Path(*module_parts[:-1])
|
||||
|
||||
# Get the paths for the nested settings dir like `<app_name>/settings`,
|
||||
# or for non-nested dir like `<app_name>`
|
||||
#
|
||||
# NOTE: Use list() for < Python 3.9
|
||||
for parent in list(module_path.parents)[:2]:
|
||||
path = (parent / component_dir).resolve()
|
||||
if path.is_dir():
|
||||
curr_directories.add(path)
|
||||
|
||||
directories.update(curr_directories)
|
||||
|
||||
logger.debug(
|
||||
"Template loader matched following template dirs:\n" + "\n".join([f" - {str(d)}" for d in directories])
|
||||
)
|
||||
return list(directories)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue