Source code for staticpages.loader

"""
Loader is in charge to resolve page item options and to create UrlPattern objects from
a given page registry.

Basically you could use it like this: ::

    staticpages_loader = StaticpagesLoader()
    staticpages_loader.build_urls()

This will return you a list of UrlPattern objects, note than without any argument
the loader will use the settings for default values from settings and especially
the setting ``STATICPAGES``.

In the following sample, you can see a more concrete way that will build
UrlPattern objects directly mounted as urls, something you can use in a Django
``urls.py``: ::

    staticpages_loader = StaticpagesLoader()

    urlpatterns = [
        ...
        # Add pages urls using the same template
        *staticpages_loader.build_urls([
            "index",
            "foo",
            "bar",
        ])
    ]

That will respectively configure pages on urls ``/``, ``/foo/`` and ``/bar/``.

"""
import os

from django.conf import settings
from django.urls import path, re_path

from .exceptions import StaticpagesResolverError
from .views import StaticPageView


[docs] class StaticpagesLoader: """ A ``TemplateView`` inheriter with some more attributes to implement staticpages features. Keyword Arguments: template_basepath (string): Path to prefix a page template path. If empty, default value comes from ``STATICPAGES_DEFAULT_TEMPLATEPATH`` setting. name_base (string): Name to prefix a page url name. If empty, default value comes from ``STATICPAGES_DEFAULT_NAME_BASE`` setting. url_basepath (string): Base url path to prefix a page url path. If empty, default value comes from ``STATICPAGES_DEFAULT_URLPATH`` setting. view_class (object): A Class based view to use instead of the default ``staticpages.views.StaticPageView`` that is an extend of Django class base view ``TemplateView``. Given class must respect expected attributes ``template_name``, ``page_options`` and ``staticpages``. """ def __init__(self, template_basepath=None, name_base=None, url_basepath=None, view_class=None): self.template_basepath = ( template_basepath or settings.STATICPAGES_DEFAULT_TEMPLATEPATH ) self.name_base = name_base or settings.STATICPAGES_DEFAULT_NAME_BASE self.url_basepath = url_basepath or settings.STATICPAGES_DEFAULT_URLPATH self.view_class = view_class or StaticPageView
[docs] def validate_item(self, data): """ Validate item data is correct. Arguments: data (dict): Item options to validate. See ``resolve_item`` for expected data. """ if "template" not in data and "template_path" not in data: raise StaticpagesResolverError(( "Either 'template' or 'template_path' must be defined in a staticpage " "registry item." )) if data.get("template_path") and "name" not in data: raise StaticpagesResolverError(( "When a staticpage registry item defines 'template_path' the 'name' " "option must be defined too." ))
def _is_index(self, data, payload): """ Resolve if item is an index or not. Arguments: data (dict): Given item options to perform resolving. See ``resolve_item`` for expected data. payload (dict): Resolved item options. Returns: bool: True if an index, else False. """ return payload["name"] == settings.STATICPAGES_INDEX_NAME def _is_regex(self, data, payload): """ Resolve if item path is a regex. Arguments: data (dict): Given item options to perform resolving. See ``resolve_item`` for expected data. payload (dict): Resolved item options. Returns: bool: True if a regex, else False. """ return data.get("re_path") not in ("", None) def _resolve_template(self, data, payload): """ Resolve template path from options. Arguments: data (dict): Given item options to perform resolving. See ``resolve_item`` for expected data. payload (dict): Resolved item options. Returns: string: Resolved template path. """ # 'template_path' option have highest priority. if "template_path" in data: resolved_template = data["template_path"] # Else we use 'template' option with HTML extension suffix else: resolved_template = "{}.html".format(data["template"]) # Finally prefix with template basepath if not empty if self.template_basepath: resolved_template = os.path.join( self.template_basepath, resolved_template ) return resolved_template def _resolve_name(self, data, payload): """ Resolve name from options. Arguments: data (dict): Given item options to perform resolving. See ``resolve_item`` for expected data. payload (dict): Resolved item options. Returns: string: Resolved name. """ return data.get("name") or data["template"] def _resolve_urlname(self, data, payload): """ Resolve url name from options. Arguments: data (dict): Given item options to perform resolving. See ``resolve_item`` for expected data. payload (dict): Resolved item options. Returns: string: Resolved url name. """ urlname = payload["name"] if self.name_base: urlname = "{}{}".format(self.name_base, urlname) return urlname def _resolve_path(self, data, payload): """ Resolve url path from options. Arguments: data (dict): Given item options to perform resolving. See ``resolve_item`` for expected data. payload (dict): Resolved item options. Returns: string: Resolved url path. """ if payload["is_index"]: path = "" else: path = ( data.get("re_path") or data.get("path", "{}/".format(payload["name"])) ) if self.url_basepath: path = os.path.join(self.url_basepath, path) return path
[docs] def resolve_item(self, data): """ Resolve a registry item. Expected data may be something like: :: { "path": "foo/", "re_path": r"foo/$", "template": "foo", "template_path": "foo.html", "name": "foo", "extra": "anything anykind", } See :ref:`Option specifications <usage_options_specs>` for more details. Arguments: data (dict): Item options. Returns: dict: A dictionnary of resolved options. See :ref:`usage_template_context` for more details. """ self.validate_item(data) payload = {} payload["template"] = self._resolve_template(data, payload) payload["name"] = self._resolve_name(data, payload) payload["is_index"] = self._is_index(data, payload) payload["urlname"] = self._resolve_urlname(data, payload) payload["is_regex"] = self._is_regex(data, payload) payload["path"] = self._resolve_path(data, payload) # Optional extra context to pass to view payload["extra"] = data.get("extra", None) return payload
[docs] def resolve_registry(self, registry=None): """ From given registry, resolve each registry item to a tuple suitable to build urls. Keyword Arguments: registry (list): List of either string or dict. Dictionnary is the verbose way to define options opposed to a String which is expected to be a template name (without leading path and ending HTML suffix) that will be used to resolve options. If this argument is empty, default value will comes from ``STATICPAGES`` setting. Returns: list: A list of item options as dictionnary. """ resolved = [] registry = registry or settings.STATICPAGES # TODO: An error may be raised if there is duplicate path or url name ? for item in registry: # If a simple string, resolve every options if isinstance(item, str): resolved.append( self.resolve_item({"template": item}) ) # Assume it's a dict with one or more options else: resolved.append( self.resolve_item(item) ) return resolved
[docs] def build_url(self, page, pages): """ Build an url object for given page item. Arguments: page (dict): Page options. pages (list): List of all pages options. Returns: django.urls.resolvers.URLPattern: URLPattern object to mount in urls. """ # Use the right object to define url depending it's a regex path or not path_object = path if page["is_regex"]: path_object = re_path view = self.view_class.as_view( template_name=page["template"], page_options=page, staticpages=pages, ) url_object = path_object(page["path"], view, name=page["urlname"]) return url_object
[docs] def build_urls(self, registry=None): """ Build view url objects for page registry. Keyword Arguments: registry (list): List of page items. Returns: list: List of URLPattern objects. """ resolved = self.resolve_registry(registry=registry) urls = [] for item in resolved: urls.append( self.build_url(item, resolved) ) return urls