Computed View Data (data_method)
By default a view gets its data by querying the model’s records through the
standard data layer (fetchData → filter → records): pagination, sorting,
grouping, the search bar, the Browse panel and inline edit all flow from that one
query.
Some views render data that isn’t a flat list of records — a capacity board
(every resource × time bucket, with a computed load %), a reconciliation grid, a
roll-up. For those, a view declares a data_method in its arch. This is the
standard, blessed way a view sources computed / non-record data: the front end
calls that method on the view’s model — passing the view’s live params — and
renders the result, instead of running the record query.
It replaces the older pattern of building a bespoke client action per computed
board (each of which bypassed the view system and hand-rolled its own header).
With data_method, computed data flows through the view system, so the view
inherits the standard chrome: the title bar, view switching, full-bleed layout.
What it is — and isn’t
Section titled “What it is — and isn’t”- Read-only. A method returns a computed projection. The generic record affordances (inline edit, record selection, export, form drill-down, pagination, the Browse panel) only apply if the method itself honours the params it is handed. A purely computed board declares those off (see Gating the chrome below).
- The return contract is per view type, not universal. There is no single
magic shape. Each view type documents what its
data_methodmust return — e.g.Listwants record-shaped rows,Calendarwants dated records,TimelineHeatmapwants a{ buckets, rows }matrix. Any view type can opt in, with its own documented shape.
Declaring it
Section titled “Declaring it”Put data_method in the view arch instead of (or alongside, where a view type
allows a fallback) field mappings:
- data_type: UiView name: wc_load_heatmap_view identifier: wc_load_heatmap_view type: TimelineHeatmap model: WorkCenterLoad arch: - data_method: ui_loadThe action points at the same (often transient) model:
- data_type: WindowAction name: Capacity Load identifier: mrp_capacity_load_action model: WorkCenterLoad default_view: wc_load_heatmap_view modes: TimelineHeatmap action_ctx: data_method: ui_load # mirror — see "Gating the chrome" views: - - R - - wc_load_heatmap_viewImplementing the method
Section titled “Implementing the method”The method lives on the view’s model. For computed boards this is usually a
transient read model (_transient = True) — it stores nothing; it just
exposes the method. Because the /api/execute/<model>/<method> path instantiates
an in-memory instance and calls method(instance, **kwargs), the method MUST
be an instance method (self), not a cls method. The view’s live params
arrive as keyword arguments matched by name.
class WorkCenterLoad(Model): _transient = True _verbose_name = "Work Center Load"
async def ui_load(self, bucket="Day", anchor=None): # `bucket` and `anchor` are the TimelineHeatmap's live params. ... return {"buckets": [...], "rows": [...]} # the view type's shape
self, notcls. Acls-first method is auto-promoted to a classmethod and the execute path’s positional instance collides with its first real argument (got multiple values for argument ...). Everydata_methodis aselfinstance method.
Live params
Section titled “Live params”The front end passes the view’s current state as the method kwargs, so navigating (changing the period, paging the window) re-queries:
| View type | Params passed |
|---|---|
| TimelineHeatmap | bucket (Day/Week/Month), anchor (YYYY-MM-DD) |
(Other view types add their own as they adopt the mechanism — e.g. a calendar window, a pivot groupby.)
The front-end hook
Section titled “The front-end hook”A single shared hook implements the mechanism for every view type:
app/src/hooks/useViewDataMethod.js. It calls executeMethod(model, method, [], params), returns { data, isLoading, isFetching, error }, keeps previous data
while refetching, and background-polls. A view component branches on whether its
arch declares data_method:
const computed = useViewDataMethod({ model: actionData.model, method: arch.data_method, params: { bucket, anchor }, enabled: !!arch.data_method,});Adopting data_method in a new view type is therefore three things: branch the
component on arch.data_method, call useViewDataMethod with that view’s live
params, and render the returned shape. No new plumbing per view.
Gating the chrome
Section titled “Gating the chrome”A computed view has no records, so the search bar and Browse panel are
meaningless. The action mirrors data_method into action_ctx; the shell
reads actionData.ctx.data_method and drops both for that action only:
AppHeader/SecondaryHeader— no search bar.ShellContent— no BrowseFilterPanel.
This is gated per action, not per view type — so the generic record-sourced use of the same view type (e.g. a TimelineHeatmap over real records) keeps full search + Browse. Only the computed action loses them.