Caching

The routing library provides simple caching mechanisms for forms and data. By default, the routing library will NOT cache any forms or data.

Form Caching

To override the default behaviour, you can set the Route.cache_form attribute to True. This will cause the routing library to cache all forms.

from routing.router import Route

Route.cache_form = True

You can also set this attribute on specific routes.

class IndexRoute(Route):
    path = "/"
    form = "Pages.Index"
    cache_form = True

Data Caching

The routing library can cache data loaded by the load_data method. If you are not using the load_data method, you can skip this section. For more details, see the Data Loading section.

Set cache_data=True to reuse loaded data until it is invalidated or garbage-collected. The default is False, which does not retain data for later navigation. Initial data sent by the server is still used once. The exported constants CACHE_FIRST and NO_CACHE are aliases for True and False respectively.

gc_time defaults to 30 minutes and controls when navigation can remove old cached data and any form with the same cache key. stale_time does not expire data cached with cache_data=True.

Caching

If you are using the load_data method and cache_form is set to True, then the load_data method will not be called if there is an existing cached form.

Caching Keys

The routing library will cache forms and data using a cache key. The key combines the concrete URL path, such as /articles/123, and the dictionary returned by cache_deps. By default, the cache_deps method returns the query dictionary.

Clearing Cache

To clear all cached content, you can call the clear_cache function.

from routing import router

router.clear_cache()

Invalidating Cache

If you want to invalidate the cache for a specific path, you can call the invalidate function. Invalidation removes matching cached forms. It also removes matching data, except for STALE_WHILE_REVALIDATE data, which is kept and marked stale for the next load. Invalidation alone does not navigate or refresh the displayed form. Use the current routing context's refetch() to reload its data immediately.

from routing import router

router.invalidate(path="/articles")

The call signature for invalidate is:

invalidate(*, path=None, deps=None, exact=False)
invalidate(path, **kws)
invalidate(routing_context, **kws)
path
The path to invalidate.
deps
The dependencies to invalidate. These are the same dependencies that are returned by the cache_deps method.
exact
If True, then the path and deps must match exactly. If False (the default), the path matches itself and its descendants. Cached dependencies must contain all entries supplied in deps; omitted dependencies do not restrict the match.

Partial Invalidation

from routing.router import Route


class ArticlesRoute(Route):
    path = "/articles"
    form = "Pages.Articles"


class ArticleRoute(Route):
    path = "/articles/:id"
    form = "Pages.Article"

In the above example, if you call invalidate("/articles", exact=True), then data and forms associated with the ArticlesRoute will be invalidated. If you call invalidate("/articles", exact=False), then data and forms associated with the ArticlesRoute and all cached ArticleRoute instances will be invalidated, because concrete paths such as /articles/123 are descendants of /articles.

from routing.router import Route


class ArticlesRoute(Route):
    path = "/articles"
    form = "Pages.Articles"

    def cache_deps(self, **loader_args):
        return {"page": loader_args["query"]["page"]}

    def parse_query(self, query):
        return {**query, "page": int(query.get("page", 1))}

In the above example, the data is cached depending on the page query parameter. If you call invalidate("/articles"), then all data associated with all pages will be invalidated. Omitting deps imposes no dependency filter. If you call invalidate("/articles", exact=True), then no data will be invalidated, since there is no exact match. Calling invalidate("/articles", deps={"page": 1}) will invalidate only the data for the first page.

Invalidating Contexts

A routing context also has an invalidate method for convenience.

from routing import router


class ArticleForm(ArticleFormTemplate):
    def __init__(self, routing_context: router.RoutingContext, **properties):
        self.routing_context = routing_context
        super().__init__(**properties)

    def delete_button_click(self, **event_args):
        self.remove_from_parent()
        self.routing_context.invalidate(exact=True)