Dependency resolver#
This page covers how the dependency resolver inspects a callable, picks providers, fills parameters, and caches results across a request.
Overview#
The resolver is a singleton instance of DependencyResolver.
Every page context function, every page render, and every component context function is invoked through the resolver.
The form dispatch adds its own call sites.
These are the form-class factory, get_initial, the @action handler, on_valid, and wizard.done.
Pipeline#
flowchart TB
Callable[Decorated callable] --> Sig[Inspect signature]
Sig --> Providers[Providers in priority order]
Providers --> Resolution[ResolutionContext]
Resolution --> Cache{Cache hit}
Cache -- yes --> Value[Cached value]
Cache -- no --> Provider[Provider.resolve]
Provider --> Value
Value --> Inject[Inject parameter]
Providers -- Depends --> NamedDep[Named dependency]
Providers -- Context --> CtxByKey[Context by key]
Providers -- DUrl --> UrlProv[URL provider]
Providers -- DQuery --> QueryProv[Query provider]
Providers -- form or DForm or class --> FormProv[Form provider]
Providers -- name match --> NameProv[Context or URL kwargs by name]
Modules#
next.deps.resolver.DependencyResolverplus the singletonresolverinstance. Exposesresolve,resolve_dependencies, andresolve_with_template_contextto run a callable with resolved parameters.resolve_with_template_contextis the component entry point. It stripsEXPLICIT_RESOLVE_KEYSfrom the template context it injects, so a context key cannot shadow a dedicated provider such asrequestorform.next.deps.providers.The
ParameterProviderprotocol and theRegisteredParameterProviderbase class. The resolver reads the auto-registry onRegisteredParameterProvider._registryto instantiate the built-in providers on first use.next.deps.cache.DependencyCacheaccumulator, theREQUEST_DEP_CACHE_ATTRconstant, theDependencyCycleErrorexception, and theget_request_dep_cacheaccessor.next.deps.context.ResolutionContextvalue object passed to every provider, plus theRESERVED_KEYSfrozenset of names excluded from name-based resolution.next.deps.markers.Depends,DDependencyBase, and theDependsProviderthat resolvesDependsmarkers.
Provider order#
The resolver iterates providers in ascending priority order.
Each provider declares whether it can handle a parameter through can_handle.
The first provider that returns True produces the value.
Every RegisteredParameterProvider subclass carries a priority class attribute, and the resolver sorts the registry by it.
The nine built-in providers pin the values 10 through 80, which yields
DependsProvider, ContextByDefaultProvider, ContextByNameProvider, FormProvider,
CleanedDataProvider, HttpRequestProvider, UrlByAnnotationProvider, UrlKwargsProvider, and QueryParamProvider.
FormProvider and CleanedDataProvider share priority 40.
See Dependency injection for the single source of truth on this order and what each provider matches.
Custom providers register through RegisteredParameterProvider.
A subclass that does not set priority inherits the default 100, so it is consulted after every built-in provider.
The resolver sorts the registry by priority as the primary key and by subclass definition order as the stable tie-break.
Depends forms#
DependsProvider handles a parameter whose default is a Depends marker, see Dependency injection for the four marker forms.
ResolutionContext#
Each call builds a fresh ResolutionContext.
It carries the current request, the captured URL kwargs, the template scope as context_data, the bound form when one exists, the dependency cache, and the resolution stack.
Query-string values are read off the request by the query provider.
Providers read what they need and never mutate the context.
The names in RESERVED_KEYS (request, form, cleaned_data, _cache, _stack, _context_data) are stripped from name-based resolution.
A context key called request cannot shadow the HttpRequest provider, and the other five names stay reserved for the resolver’s own inputs.
Cache#
Each resolution pass owns a DependencyCache.
It lives on the ResolutionContext for that pass and holds named dependency values.
The cache key is the dependency name string alone, with no type component.
FormActionDispatch.dispatch creates a fresh dispatch cache dict on every POST and attaches it to the request under the attribute named REQUEST_DEP_CACHE_ATTR.
The cache is shared across each stage of the dispatch, from get_initial and the factory resolution to the handler call and any re-render after validation failure.
On a re-render the page context and component context renderers read it back through get_request_dep_cache and rejoin the same cache.
An ordinary page request that does not pass through the form dispatcher never sees this attribute.
Two consequences flow from the cache.
- Provider results are never cached.
The framework cache memoises only named
Depends("name")values. A provider that must return one value per request keeps its own request-scoped store.- Shared across the dispatch.
The dispatch cache attaches on every form-dispatch POST and is consumed on the validation-failure re-render to keep the second pass cheap.
Cycle detection#
DependencyCycleError is raised when a named dependency re-enters a name already being resolved, directly or through a longer Depends chain.
The error message lists the chain of named dependencies that closed the loop, read left to right.
Signals#
provider_registered fires once per provider when the subclass enters the RegisteredParameterProvider registry.
Subscribe to track custom providers across reloads.
Extension points#
Subclass
DDependencyBaseto introduce a typed marker.Subclass
RegisteredParameterProviderto handle a custom marker or a custom annotation.Use
resolver.dependency("name")to register a callable forDepends("name").Call
resolver.current_callable()from a provider that has to answer for the whole call rather than for the parameter in isolation. Resolving a named dependency nests one resolve inside another, so the innermost callable is the one returned.
See also#
See also
Dependency injection for the topic guide. Request lifecycle for the surrounding request pipeline.