Dashboard widgets
Base & mixin classes
All widgets should extend BaseDashboardWidget.
In addition StandaloneDashboardWidgetMixin should be used
with some exceptions of hardcoded-only widgets.
Notable mixins:
StandaloneDashboardWidgetMixinMakes widget “Standalone” (widget can calculate its own data) by standardizing its constructor arguments and providing common methods and properties for filtering and working with audit forms, QIP issues, observations, etc.
Note
All new widgets must include this mixin unless already included by its subclass
ConfigSchemaWidgetMixinAllows widget to define its own configuration schema using django-jsonform library to present configuration options to the user in a form style rather than ras json.
Tip
Add this mixin to make it more user-friendly and enable it to be edited by end users in the new edit pop-up
WidgetPermissionsMixinAllows implementing widgets to specify permissions required to use the widget. If user does not have the required permissions, the widget will not display.
ActionMenuMixinAdds menu options to the widget. This is included by default in
BaseDashboardWidget.TimeGranularityWidgetMixinFor time-scale / over-time widgets, allows user to specify time granularity (defined in
SUPPORTED_GRANULARITIES) and exposesgranularityproperty to the widget.
Base classes
- dashboard_widgets.widgets.base.widget_action(label: str, target: str = '_self', show_in_menu: bool = True)
A Widget Action method that will appear in the widget’s menu.
- Parameters:
label – label displayed to the user
target – if widget returns a http response, whether the address to be opened in a new tab
show_in_menu – whether this action should appear in the widget menu (default: True)
Example:
>>> @widget_action(label=_('Test Action')) >>> def action_download_csv(self, request, **kwargs): >>> return HttpResponse("Test complete")
- class dashboard_widgets.widgets.base.ActionMenuMixin
Mixin class for
BaseDashboardWidgetthat provides dropdown menu with actions to the widget- allow_download = True
whether this widget should have “download as image” option
- get_actions() Iterator[Callable[[], HttpResponseBase | None]]
Yields widget actions defined as widget methods. Such actions should be decorated with
widget_action()and their names should be prefixed withaction_
Iterates all the menu options available in this widget
- Yield:
widget menu options
- class dashboard_widgets.widgets.base.FreezeWidgetHeaderMixin
A mixin designed for table widgets which gives the user a new widget menu/action item to freeze the widgets table header. Freezing makes the header sticky which means it stays visible when scrolling down the table.
- property widget_config_id: int | None
Attemps to find a fixed widget ID by looking for the the widget’s config as its id is fixed
- property widget_cookie_id: str
ID used to create cookie to persist frozen/unfrozen table header. A widget configs pk is used if availible as it is stable.
- property widget_cookie_expiry_days: int
Expiry for widgets cookie in days. If using a fixed id (widget_config_id) set to a long expiry otherwise short
Adds freeze header menu option to widget. Includes onclick function defined in JS which adds / removes ‘freeze-table-header’ class
- class dashboard_widgets.widgets.base.BaseDashboardWidget(**kwargs)
- full_size: bool = False
Should this widget take up full width and display more detail
- widget_config: WidgetConfig | None = None
For custom dashboards, this field holds instance of the widget model
- widget_id: int | None = None
if this widget is displayed in a group, this is widget’s order number within the group
- show_comment_box: bool = True
Whether comment box should be shown in print view underneath this widget
- allow_lazy: bool = True
Whether this widget can be lazy-loaded can be set to false for widgets that don’t do any expensive computations
- property html_selector: str
css/jquery selector for the base html element of this widget; E.g. #widget-12345
- render_content() str
Render contents inside the widget :return: html safe string
- get_size() int
Gets size of this widget in terms of bootstrap grid system sizing (1-12)
- is_empty() bool
Tells whether this widget has data to display To be overridden by subclasses to decide whether No Data placeholder should show
- is_compact() bool
Returns wheter this widget will be compact or standard. Compact widgets have a minimum height which is half of a standard widget
- get_context_data() Dict[str, Any]
Context data for rendered widget template
- validate() None
Validates widget configuration before rendering.
- Raises:
ConfigurationError – when the widget configuration is invalid.
- render() str
Renders widget’s html and js content in-line
- Returns:
rendered html as text
- add_selected_filters_breadcrumb() None
Adds a Sentry breadcrumb with the selected dashboard filters.
- render_error(error: ConfigurationError) str
Renders error widget in place of this widget to report config error to the user.
- dashboard_widgets.widgets.base.CustomDataSet(**kwargs) dict
A wrapper for jchart’s DataSet which accept a meta dict. Meta data can be used when scripting chart configuration on the frontend: https://chartjs-plugin-datalabels.netlify.app/guide/options.html#scriptable-options
Widget mix-ins
- exception dashboard_widgets.widgets.mixin.WidgetHasManyForms
Exception raised when trying to get form in a widget that has more than one form
- class dashboard_widgets.widgets.mixin.FormWidgetMixin
Mixin providing form tools to the widget. Essential to working with issues and observations
- support_multi_form = True
Subclasses can override this to disable support for more than 1 audit form or no audit forms. Set this to false if the widget supports only exactly one form at a time.
- audit_forms: tuple[AuditForm]
forms passed to this widget. Can be empty or any number of forms if
support_multi_formis True, this is expected to hold exactly one form
- property audit_form: AuditForm
Gets single form instance if
is_single_formis set.- Returns:
single form instance
- Raises:
WidgetHasManyForms – if this widget supports multiple forms
- property form_config: AuditFormConfig
Gets current form’s configuration. If there’s no single form, defaults to a blank form config with model-level defaults.
- property forms_grouped: Iterator[tuple[ObservationModel, Iterable[AuditForm]]]
Generates tuples of observation model class and iterable of forms with that observation model
- property is_using_custom_date_filter_field: bool
Returns true if the current widget has just one form, with a custom date filter field.
- property date_filter_field_name: str
Gets the correct date field name for the current audit form. For multi form widgets, returns the default session end time field name.
- property date_filter_field: CustomField | Field | None
Gets the correct date field name for the current audit form. For multi form widgets, returns the default session end time field name.
- class dashboard_widgets.widgets.mixin.ObservationWidgetMixin
Mix-in for widgets working with observations
- include_own: bool = False
when True, includes the auditor’s own submissions regardless of ward ringfencing
- property base_observations_qs: ObservationQuerySet
Returns the base, permission-filtered ObservationQuerySet for the widget.
This queryset is filtered by: - The widget’s selected audit form(s). - The current user’s permissions (wards, forms via .for_auditor_forms). - A pre-set ._observations queryset, if provided.
It does not include widget-specific filters (see .apply_observation_filters). :raises TypeError: if widget does not show single form and some of the forms use non-custom observation model
- property observations_qs: ObservationQuerySet
Single filtered queryset containing all observations within selected form and filters. Note that with multi-form widgets, all forms must use CustomObservation model. To get all observations of any type, use observations_iter instead.
- Raises:
TypeError – if widget does not show single form and some of the forms use non-custom observation model
- property using_counter_logic: bool
Property which defines if a widget has counter_logic in the schema config
- Returns:
True if the widget configuration contains the counter logic setting, False otherwise.
- property counter_logic: Literal['audits', 'observations']
Property which defines the counter_logic selected in the widget by the user
- Returns:
True if the widget configuration contains the counter logic setting, False otherwise.
- property num_observations: int
Returns a count of either audit sessions or observations depending on counter logic
- Returns:
The total count of observations or audit sessions, based on the configured counter logic.
- property observations_iter: Iterator[Observation]
Iterate observations without caching
- class dashboard_widgets.widgets.mixin.TargetActionMixin
Adds the target action property to target widgets that use counter logic. Converts the counter logic configuration into the equivalent target action.
- class dashboard_widgets.widgets.mixin.DynamicFieldWidgetMixin
Mixin for widget methods used when a widget allows dynamically switching the field name without changing the widget config.
- active_fields_override: list[str] | None = None
The dynamic choice(s) selected by a user, set in an AJAX request
- dynamic_field_target: str | None = None
Key of the field in the widgets config which is to be used for dynamic fields
- get_dynamic_field_name() str | None
Gets field name passed globally via GET argument from
reloadWithDynamicFieldSetjs function. This value is validated by ensuring it is one of the field choices- Returns:
field name if a valid one was passed, or null if no field was passed, or the field is not one of the valid choices
- property dynamic_field_id: int | None
Dynamic ID used to find this widget in the dashboard for rerendering. Using an id which doesnt change the widgets widget_config ID.
- property using_dynamic_filtering: bool
Determines if this widget is using dynamic filtering. Even if widget includes DynamicFieldWidgetMixin, the particular subclass may not support it. The widget needs to have dynamic_filtering enabled and field_names in the widgets schema to use dynamic filtering. Also, the widget needs to allow lazy rendering
- Returns:
True if the widget configuration contains the dynamic filtering setting, False otherwise.
- property field_name_choices: list[ChoiceSchema]
Gets fields (choices) shown in dynamic field dropdown in dashboard for this widget. If compliance is enabled it filters choices by fields used to calculate compliance. If subforms are select it filters choices by fields in them subformsIt also filters choices by compatible widget types using DYNAMIC_FIELD_COMPATIBALE_WIDGETS
- property dynamic_filtering: bool
Property which defines the dynamic_filtering selected in the widget by the user. Throws an error if the choice is not a bool.
- Returns:
dynamic_filtering choice selected in the widgets config
- property field_names: list[str] | None
Determines the list of currently active fields names.
It prioritizes dynamic override fields from a possible AJAX request, otherwise it falls back to the default fields
- property field_name: str | None
Determines the currently active field name.
If any override fields are present the first is selected.
- property active_fields: list[str] | None
Returns the currently selected fields for display in dynamic field dropdown.
- class dashboard_widgets.widgets.mixin.QipDateFilterWidgetMixin
Mixin to override the time_range filter for the observation queryset in widgets that focus on QIP issues. This is for when the observation queryset is used to filter the Issues, and the time_range filter is intended to filter the Issues. e.g. QIP Issues - Ordinarily a time_filter of ‘today’ would exclude an issue created today if the linked observation was dated yesterday (session end date).
- class dashboard_widgets.widgets.mixin.QipWidgetMixin
Mixin for widgets working with QIP issues
- filter_issues_by_observations: bool
Whether to filter issues by observations in this widget. this requires that the class also extends
ObservationWidgetMixin.
- class dashboard_widgets.widgets.mixin.StandaloneDashboardWidgetMixin(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
Mixin for widget classes that provides all parameters for the widget to calculate its data and render itself.
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- widget_config: 'WidgetConfig' | None
If created off widget config model, the model instance is referenced by the widget_config field
- user_config: dict[str, Any]
user config holds all variable configuration for this widget coming either from
widget_configinstance or passed from the dashboard
- validate() None
- Raises:
DashboardConfigError – when widget requires a single form but multiple are provided.
- get_config_value(key: str, default=None) Any
gets a single config value. If value is not set (or is null), returns the default value.
- property user: User | None
Current user instance if request was passed and user is authenticated
- Returns:
user instance, or
Noneis user is not authenticated
- property institution: Institution | None
Gets institution instance if only one.
- Returns:
Institution instance if the widget shows data from exactly one institution.,
Noneotherwise
- property widget_editable: bool
Whether current user can edit this widget. Checks that user has the permission and current dashboard can be edited by user
- class dashboard_widgets.widgets.mixin.ConfigSchemaWidgetMixin
Allows widget to define schema for its config json If schema is defined, a form will be rendered using django-jsonform inside the model form to configure the widget options instead of the raw json field.
Warning
When overriding
config_defaultsensure that values in it are valid values for the respective config field type. For instance, for alistfield, a valid empty value is[], but notNone.Example:
>>> class ExampleWidget(ConfigSchemaWidgetMixin, BaseDashboard): >>> config_schema = SchemaDict(type='dict', keys={ >>> 'label': SchemaDict(type='string', title=_('Label')), >>> 'items': SchemaDict(type='list', items=ListItemSchema(type='string'), title=_('List of strings')), >>> 'number': SchemaDict(type='integer', title=_('Number')), >>> 'checkbox': SchemaDict(type='boolean', title=_("Checkbox")), >>> 'dropdown': SchemaDict(type='string', title=_("Dropdown"), choices=[ >>> ChoiceSchema(value='1', label=_("Option 1")), >>> ChoiceSchema(value='2', label=_("Option 2")), >>> ]), >>> config_defaults = { >>> 'items': [], >>> 'checkbox': True, >>> } >>> })
- config_defaults: dict[str, str | int | list | bool] = {}
default values to be set in widget model’s config when initially created.
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
Gets config schema for the specified custom dashboard widget. Override this method to further configure the schema per widget config if needed.
- class dashboard_widgets.widgets.mixin.WidgetPermissionsMixin
Allows widget to define permissions required to view it. Analogous to django
PermissionRequiredMixinview mixin.Example:
>>> class ExampleWidget(WidgetPermissionsMixin, BaseDashboard): >>> permissions = 'megforms.view_auditform', 'qip.view_issue',
- permissions: tuple[str]
Tuple of django permissions required by this widget
- class dashboard_widgets.widgets.mixin.SingleStatMixin
Mixin that provides common single stat widget variables & answers to custom fields
- get_answers_for_field(field_name: str) QuerySet
Queryset of observations or subobservations annotated with value, containing value of the field passed in
field_name`- Parameters:
field_name – name of a custom field
- Returns:
queryset of the (sub)observation with added annotation of the given field’s value
- class dashboard_widgets.widgets.mixins.TimeGranularityWidgetMixin
Mixin for widget classes that provides granularity configuration and property for accessing it.
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
if widget extends ConfigSchemaWidgetMixin, add granularity dropdown. To work, this mixin must be added before ConfigSchemaWidgetMixin.
- get_date_range_for_dataframe(column_name: str, dataframe: DataFrame) DatetimeIndex
Given the currently selected granularity and a dataframe, return the date range as an index.
- Parameters:
column_name – The column name of the date field in the dataframe.
dataframe – Optionally provide the dataframe as an argument. If not specified self.dataframe will be used.
- class dashboard_widgets.widgets.mixins.DocumentWidgetMixin
Define documents and versions querysets
- property megdocs_config: MegDocsConfig
Get MegDocsConfig for the widget’s institutions
- class dashboard_widgets.widgets.mixins.TimeTrackingWidgetConfigMixin
Schema config shared by time tracking widgets.
Chart Widgets
All widgets rendering some sort of a graph or chart, primarily using ChartJS library.
These widgets all inherit from dashboard_widgets.widgets.chart.BaseChartWidget.
- class dashboard_widgets.widgets.chart.JchartDataset
Represents dict returned by DataSet() jchart func
- class dashboard_widgets.widgets.chart.ChartType(*values)
Chart types supported by ChartJS More available: https://www.chartjs.org/docs/latest/charts/
- property js_value
Value for rendering chartjs
- class dashboard_widgets.widgets.chart.BaseChartWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- property value_format
str(object=’’) -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to ‘strict’.
- limit_values(chart_data: Iterable[Tuple[int | float | None, str | date]]) list[Tuple[int | float | None, str | date]]
limits values to ‘limit_number_of_entries_to’ Sums all other entries if show_all_others is set to True
:param chart_data :param show_all_others
- Returns:
chart_data limited to ‘limit_number_of_entries_to’
- property values: list[Tuple[int | float | None, str | date]]
Override in sub-classes if widget self-calculates data
- property name: str
unique widget name, used as id for js
- generate_color() Iterator[Tuple[int, int, int]]
Generates new colour from the palette Yields: tuples of (R, G, B) values Rules: - If exactly one institution is selected, use that institution’s effective palette. - If multiple institutions are selected and they all belong to the same group, use that group’s palette - Otherwise (different groups or ungrouped mix), fall back to the widget’s default palette.
- generate_colors(number: int) List[Tuple[int, int, int]]
generates number of colours (RGB tuples) and returns them as a tuple
- get_dataset_label() str
Override this method to change the default label
- get_contrasted_dataset_styles() dict
Increase line thickness (borderWidth)
Ensure a strong borderColor is applied
Increase point radius and hover radius for better visibility
Harmonise point colours with the line colour
- Returns:
- get_datasets(*args, **kwargs) list[JchartDataset]
Returns list of dataset dictionaries https://github.com/matthisk/django-jchart#docs-get-datasets
- property flattened_values: Tuple[int | float | None]
Override this method in multi series charts. Used in min_value, max_value & is_empty methods.
- get_dataset_colors() List[Tuple[int, int, int]]
Generates colour (R, G, B) tuple for each item in the dataset
- get_labels(*args, **kwargs) Sequence[str]
Returns categorical axis labels https://github.com/matthisk/django-jchart#docs-get-labels
- is_empty() bool
Tells whether this widget has data to display To be overridden by subclasses to decide whether No Data placeholder should show
- get_js_data() dict
Data available as javascript dict js_data in the widget
- get_context_data() Dict[str, Any]
Context data for rendered widget template
- class dashboard_widgets.widgets.chart.TargetValue(label: 'str', actual: 'int', target: 'int')
- class dashboard_widgets.widgets.pie_chart.PieChartWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- dynamic_field_target: str | None = 'field_name'
Key of the field in the widgets config which is to be used for dynamic fields
- config_defaults: dict[str, str | int | list | bool] = {'counter_logic': 'observations', 'dynamic_filtering': False, 'field_name': None, 'limit_number_of_entries_to': None, 'show_all_others': False, 'value_color_map': None}
default values to be set in widget model’s config when initially created.
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
Gets config schema for the specified custom dashboard widget. Override this method to further configure the schema per widget config if needed.
- get_table_rows() Iterator[TableRow]
Yields values as table rows to be rendered underneath the pie chart in full-size view
- get_dataset_colors() List[Tuple[int, int, int]]
Generates colour (R, G, B) tuple for each item in the dataset
- property table_percentage_label
Encapsulate a function call and act as a proxy for methods that are called on the result of that function. The function is not evaluated until one of the methods on the result is called.
- get_labels(*args, **kwargs)
Returns categorical axis labels https://github.com/matthisk/django-jchart#docs-get-labels
- class dashboard_widgets.widgets.pie_chart.RingChartWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- config_defaults: dict[str, str | int | list | bool] = {'counter_logic': 'observations', 'field_name': None, 'limit_number_of_entries_to': None, 'show_all_others': None, 'value_color_map': None}
default values to be set in widget model’s config when initially created.
- class dashboard_widgets.widgets.pie_chart.DetailPieChartWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
gives different values depending on full_size
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- property values: list[Tuple[int | float | None, str | date]]
Override in sub-classes if widget self-calculates data
- class dashboard_widgets.widgets.pie_chart.QipStatusWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- dynamic_field_target: str | None = None
Key of the field in the widgets config which is to be used for dynamic fields
- config_defaults: dict[str, str | int | list | bool] = {'issue_level': 'all'}
default values to be set in widget model’s config when initially created.
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
Gets config schema for the specified custom dashboard widget. Override this method to further configure the schema per widget config if needed.
- property values: list[Tuple[int | float | None, str | date]]
Override in sub-classes if widget self-calculates data
- get_dataset_colors() list[Tuple[int, int, int]]
Generates colour (R, G, B) tuple for each item in the dataset
- class dashboard_widgets.widgets.pie_chart.QipClosureStatisticsWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
Pie chart widget showing QIP issues closed on time vs closed late. - Closed on time: completed date <= due date - Closed late: completed date > due date
Only shows closed issues (qipstatus.closed = True)
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- dynamic_field_target: str | None = None
Key of the field in the widgets config which is to be used for dynamic fields
- config_defaults: dict[str, str | int | list | bool] = {'issue_level': 'all'}
default values to be set in widget model’s config when initially created.
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
Gets config schema for the specified custom dashboard widget. Override this method to further configure the schema per widget config if needed.
- generate_timeliness_data() Iterator[Tuple[int | float | None, str | date]]
Generates data showing count of issues closed on time vs closed late. Only includes closed issues (qipstatus.closed = True) with both completed date and due date set.
- property colors: list
Define colors for the chart segments
- property values: list[Tuple[int | float | None, str | date]]
Override in sub-classes if widget self-calculates data
- get_dataset_colors() list[Tuple[int, int, int]]
Generates colour (R, G, B) tuple for each item in the dataset
- class dashboard_widgets.widgets.bar_chart.BarChartWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
A horizontal bar chart widget that displays count of different values of the specified “field_name”. field_name can be a hardcoded audit form field, or a custom field or a related form custom field.
Examples:
Hardcoded field:
{ "field_name": "ward" }
Custom field:
{ "field_name": "test_select" }
Related form Custom field:
{ "field_name": "27_patient_name" }
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- config_defaults: dict[str, str | int | list | bool] = {'compliance': False, 'compliance_threshold': None, 'custom_compliance_levels': [], 'max_label_length': 70, 'show_sample_size': False}
default values to be set in widget model’s config when initially created.
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
Gets config schema for the specified custom dashboard widget. Override this method to further configure the schema per widget config if needed.
- is_empty() bool
Tells whether this widget has data to display To be overridden by subclasses to decide whether No Data placeholder should show
- property table_percentage_label: str
Encapsulate a function call and act as a proxy for methods that are called on the result of that function. The function is not evaluated until one of the methods on the result is called.
- get_dataset_colors()
Generates colour (R, G, B) tuple for each item in the dataset
- values
- get_labels(*args, **kwargs) Sequence[str]
Returns categorical axis labels https://github.com/matthisk/django-jchart#docs-get-labels
- class dashboard_widgets.widgets.bar_chart.VerticalBarChartWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
A vertical bar chart widget that displays count of different values of the specified “field_name”. Has the same functionality as the horizontal bar chart.
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- class dashboard_widgets.widgets.bar_chart.DetailBarChartWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
gives different values depending on full_size
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
Gets config schema for the specified custom dashboard widget. Override this method to further configure the schema per widget config if needed.
- values
- class dashboard_widgets.widgets.bar_chart.SubformBarChartWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
Bar chart showing compliance/number of entries in each subform
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- support_multi_form = False
Subclasses can override this to disable support for more than 1 audit form or no audit forms. Set this to false if the widget supports only exactly one form at a time.
- config_defaults: dict[str, str | int | list | bool] = {'compliance': True}
default values to be set in widget model’s config when initially created.
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
Gets config schema for the specified custom dashboard widget. Override this method to further configure the schema per widget config if needed.
- values
- is_empty()
Tells whether this widget has data to display To be overridden by subclasses to decide whether No Data placeholder should show
- table_percentage_label
- class dashboard_widgets.widgets.bar_chart.FieldBarChartWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
Bar-chart showing compliance numbers for each field in the audit
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- support_multi_form = False
Subclasses can override this to disable support for more than 1 audit form or no audit forms. Set this to false if the widget supports only exactly one form at a time.
- config_defaults: dict[str, str | int | list | bool] = {'compliance': True, 'counter_logic': 'observations', 'sort_order': None}
default values to be set in widget model’s config when initially created.
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
Gets config schema for the specified custom dashboard widget. Override this method to further configure the schema per widget config if needed.
- calculate_field_count(field: CustomField | Field) int | None
Calculates field compliance or count for the field across observations
- property table_percentage_label
Encapsulate a function call and act as a proxy for methods that are called on the result of that function. The function is not evaluated until one of the methods on the result is called.
- values
- class dashboard_widgets.widgets.bar_chart.OverTimeBarChartMixin
A mixin for line chart to convert it into a bar chart. - changes chart type to bar - fixes scaling so the bars are uniform size - handles bar colors - formats dates
- class dashboard_widgets.widgets.bar_chart.ValueOverTimeBarWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
if widget extends ConfigSchemaWidgetMixin, add granularity dropdown. To work, this mixin must be added before ConfigSchemaWidgetMixin.
- class dashboard_widgets.widgets.bar_chart.ComplianceOverTimeBarWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
A Bar chart widget inheriting characteristics of a line chart to allow showing over-time trend.
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- dynamic_field_target: str | None = 'field_names'
Key of the field in the widgets config which is to be used for dynamic fields
- config_defaults: dict[str, str | int | list | bool] = {'counter_logic': 'observations', 'dynamic_filtering': False}
default values to be set in widget model’s config when initially created.
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
if widget extends ConfigSchemaWidgetMixin, add granularity dropdown. To work, this mixin must be added before ConfigSchemaWidgetMixin.
- property table_percentage_label
Encapsulate a function call and act as a proxy for methods that are called on the result of that function. The function is not evaluated until one of the methods on the result is called.
- get_datasets(*args, **kwargs) list[dict[str, Any]]
Returns list of dataset dictionaries https://github.com/matthisk/django-jchart#docs-get-datasets
- get_dataset_colors() Iterator[Tuple[int, int, int]]
Generates colour (R, G, B) tuple for each item in the dataset
- class dashboard_widgets.widgets.bar_chart.MultiTeamBarChartWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- config_defaults: dict[str, str | int | list | bool] = {'data_label_compliance_none': '0', 'data_label_compliance_none_desc': 'N/A', 'data_label_compliance_zero': '0', 'data_label_compliance_zero_desc': 'zero compliance', 'data_label_entries_none': '0', 'data_label_entries_none_desc': 'no data', 'filter_teams_with_no_compliance': True, 'zero_none_compliance': False}
default values to be set in widget model’s config when initially created.
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
Gets config schema for the specified custom dashboard widget. Override this method to further configure the schema per widget config if needed.
- property data_label_compliance_none: str
Label for categories that have data but no compliance
- property data_label_compliance_none_desc: str
Description for label for categories that have data but no compliance
- property data_label_compliance_none_colour: str
Colour for label for categories that have data but no compliance
- property data_label_entries_none: str
Data label for categories where data is missing
- property data_label_entries_none_desc: str
Description for label for categories where data is missing
- property data_label_entries_none_colour: str
Colour for label for categories where data is missing
- property data_label_compliance_zero: str
Data label for categories where compliance score is zero
- property data_label_compliance_zero_desc: str
Description for label for categories where compliance score is zero
- property data_label_compliance_zero_colour: str
Colour for label for categories where compliance score is zero
- zero_none_compliance
Show all wards, even if they have no data
- wards
Wards mapped by their id
- populate_wards(chart_values: Iterable[Tuple[int | float | None, str | date, int]]) Iterable[Tuple[int | float | None, str | date, int]]
Replaces ward ids with ward names in the chart data, and fills in missing wards if necessary
- create_chart_data_with_for_teams() Iterable[tuple[str, list[Tuple[int | float | None, str | date, int]]]]
Builds chart data for teams
- Returns:
tuples containing team and tuples with compliance/count
- get_datasets(*args, **kwargs) list[dict[str, Any]]
Returns list of dataset dictionaries https://github.com/matthisk/django-jchart#docs-get-datasets
- get_labels() List[str]
Returns categorical axis labels https://github.com/matthisk/django-jchart#docs-get-labels
- values
Iterates over each serie in the dataset instead of returning the first available
- is_empty() bool
Tells whether this widget has data to display To be overridden by subclasses to decide whether No Data placeholder should show
- get_series_meta(series: Iterable[Tuple[int | float | None, str | date, int]]) dict[str, list[str]]
Meta data to be used by frontend JS to configure chart appearance.
- get_series_data(series: Iterable[Tuple[int | float | None, str | date, int]]) tuple[int | float | None]
Maps value for each series to the correct label, and initialising as zero if no value
- get_custom_legend() dict
Get dictionary details to populate a custom additional legend in the jchart html template.
- class dashboard_widgets.widgets.bar_chart.StackedBarWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- support_multi_form = False
Subclasses can override this to disable support for more than 1 audit form or no audit forms. Set this to false if the widget supports only exactly one form at a time.
- config_defaults: dict[str, str | int | list | bool] = {'granularity': 'month'}
default values to be set in widget model’s config when initially created.
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
Gets config schema for the specified custom dashboard widget. Override this method to further configure the schema per widget config if needed.
- build_dataframe(field_name1: str, field_name2: str) DataFrame
Builds an aggregated DataFrame with columns [field_name1, field_name2, ‘count’] using SQL-level aggregation instead of fetching all observation rows.
- create_stacked_chart_data(field_name1: str, field_name2: str, granularity: Granularity) dict | None
Creates data for a stacked bar chart Args: field_name1: name of the field that represent x axis field_name2: name of the field that should be represented as stacked along with y axis (count) granularity: date granularity for x-axis when field_name1 has date value qip_flag: a flag to specify if calculations for issues or not
- get_field(name: str) CustomField | Field
Gets field by name
- Returns:
Hardcoded or custom field
- Raises:
KeyError – if the field does not exist
- render_content() str
Render contents inside the widget :return: html safe string
- get_table_rows(key: str) Iterator[TableRow]
Yields values as table rows to be rendered underneath the pie chart in full-size view
- render_table()
Render table with values used in the pie chart
- is_empty() bool
Tells whether this widget has data to display To be overridden by subclasses to decide whether No Data placeholder should show
- get_datasets(*args, **kwargs) List[Dict[str, Any]]
Returns list of datasets dictionaries https://github.com/matthisk/django-jchart#docs-get-datasets
- class dashboard_widgets.widgets.bar_chart.CalculatedFieldBarChartWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
Bar-chart showing calculated custom field data over time.
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- config_defaults: Dict[str, Any] = {'operator': 'sum'}
default values to be set in widget model’s config when initially created.
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
if widget extends ConfigSchemaWidgetMixin, add granularity dropdown. To work, this mixin must be added before ConfigSchemaWidgetMixin.
- property table_percentage_label: str | None
Encapsulate a function call and act as a proxy for methods that are called on the result of that function. The function is not evaluated until one of the methods on the result is called.
- class dashboard_widgets.widgets.bar_chart.TargetsBarChartWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- config_defaults: dict = {'counter_logic': 'observations', 'target_breakdown': 'ward'}
default values to be set in widget model’s config when initially created.
- dynamic_field_target: str | None = None
Key of the field in the widgets config which is to be used for dynamic fields
- classmethod get_target_breakdowns(institution: Institution) Dict[str, str]
Get target breakdown options with dynamic labels.
- classmethod get_target_breakdown_choices(institution: Institution) list[ChoiceSchema]
Generate choices for target breakdown with ward first.
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
if widget extends ConfigSchemaWidgetMixin, add granularity dropdown. To work, this mixin must be added before ConfigSchemaWidgetMixin.
- property table_value_label: str
Encapsulate a function call and act as a proxy for methods that are called on the result of that function. The function is not evaluated until one of the methods on the result is called.
- property table_percentage_label: str
Encapsulate a function call and act as a proxy for methods that are called on the result of that function. The function is not evaluated until one of the methods on the result is called.
- values
- get_datasets(*args, **kwargs) list[JchartDataset]
Returns list of dataset dictionaries https://github.com/matthisk/django-jchart#docs-get-datasets
- get_dataset_colors() Iterator[Tuple[int, int, int]]
Colors the bars based on % of target met. >= 100% = green >= 50% = orange < 50% = red
- get_dataset_label() str
Override this method to change the default label
- class dashboard_widgets.widgets.line_chart.LineChartWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- config_defaults: dict[str, str | int | list | bool] = {'compliance': False, 'extra_dataset': None, 'show_events': False}
default values to be set in widget model’s config when initially created.
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
if widget extends ConfigSchemaWidgetMixin, add granularity dropdown. To work, this mixin must be added before ConfigSchemaWidgetMixin.
- field_weights
maps field names to their compliance weights
- property subform_weights: dict[str, float]
Maps subform names to their compliance weights. Returns empty dict by default. Override in subclasses that support subforms.
- property calculation_type: Literal['compliance', 'count', 'session-count']
Determine what to calculate from the dataset: number of sessions, observations, or compliance; depending on wiget config
- values
- get_annotation_options() dict
Options for the annotation plugin https://github.com/chartjs/chartjs-plugin-annotation#configuration
- get_labels(*args, **kwargs) list[str | date]
Returns categorical axis labels https://github.com/matthisk/django-jchart#docs-get-labels
- get_dataset_colors()
Generates colour (R, G, B) tuple for each item in the dataset
- get_datasets(*args, **kwargs) list[dict[str, Any]]
Returns list of dataset dictionaries https://github.com/matthisk/django-jchart#docs-get-datasets
- class dashboard_widgets.widgets.line_chart.MultiSeriesLineChart(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
if widget extends ConfigSchemaWidgetMixin, add granularity dropdown. To work, this mixin must be added before ConfigSchemaWidgetMixin.
- property subform_weights: dict[str, float]
Maps subform names to their compliance weights. Returns empty dict by default. Override in subclasses that support subforms.
- subforms
Queryset of subforms, if subform names were designated in widget config
- values
- get_datasets(*args, **kwargs) List[Dict[str, Any]]
Returns list of dataset dictionaries https://github.com/matthisk/django-jchart#docs-get-datasets
- get_labels(*args, **kwargs) List[str | date]
Returns categorical axis labels https://github.com/matthisk/django-jchart#docs-get-labels
- get_multi_series_labels() Sequence[datetime]
Gets labels for multi series chart: sorts and removes duplicates. This method shouldn’t overridden by any method which changes the label format.
- flattened_values
- class dashboard_widgets.widgets.line_chart.ComplianceOverTimeWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
Alias to line chart to allow custom dashboards distinguish it from the regular line chart
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- dynamic_field_target: str | None = 'field_names'
Key of the field in the widgets config which is to be used for dynamic fields
- config_defaults: dict[str, str | int | list | bool] = {'compliance': False, 'counter_logic': 'observations', 'dynamic_filtering': False, 'extra_dataset': None, 'show_events': False}
default values to be set in widget model’s config when initially created.
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
if widget extends ConfigSchemaWidgetMixin, add granularity dropdown. To work, this mixin must be added before ConfigSchemaWidgetMixin.
- class dashboard_widgets.widgets.line_chart.ValueOverTimeLineChartWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
Alias to line chart to allow custom dashboards distinguish it from the regular line chart. Shows integer value changes over time
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- config_defaults: Dict[str, Any] = {'average': False, 'extra_dataset': None, 'granularity': 'month', 'group_data_by': None, 'show_events': False, 'static_lines': []}
default values to be set in widget model’s config when initially created.
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
if widget extends ConfigSchemaWidgetMixin, add granularity dropdown. To work, this mixin must be added before ConfigSchemaWidgetMixin.
- values
- labels
Extracts and deduplicates time period labels across all grouped series.
When data is grouped (e.g., by ward), each group may have different time periods. This method collects all unique labels from all groups, sorts them, and deduplicates them while preserving sort order. This ensures the chart displays all time periods consistently across all series, with None values filling gaps where a series has no data for a particular time period.
- Returns:
Sorted list of unique time period labels
- flattened_values
- get_labels(*args, **kwargs) List[str | date]
Returns categorical axis labels https://github.com/matthisk/django-jchart#docs-get-labels
- get_datasets(*args, **kwargs) List[Dict[str, Any]]
Returns list of dataset dictionaries https://github.com/matthisk/django-jchart#docs-get-datasets
- class dashboard_widgets.widgets.line_chart.ControlChartWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
Widget for rendering control charts. a control chart is a statistical tool used to monitor a process and detect any unusual variations or trends. It helps ensure that a process remains within the specified limits of variation and maintains its stability.
This Chart will display the provided data along with the mean, upper and lower limits as fixed lines calculated based on the current data.
Accepts compliance, granularity and field names for specific form and renders the chart
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- support_multi_form = False
Subclasses can override this to disable support for more than 1 audit form or no audit forms. Set this to false if the widget supports only exactly one form at a time.
- config_defaults: Dict[str, Any] = {'compliance': True, 'field_name': None, 'granularity': 'month'}
default values to be set in widget model’s config when initially created.
- dynamic_field_target: str | None = None
Key of the field in the widgets config which is to be used for dynamic fields
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
if widget extends ConfigSchemaWidgetMixin, add granularity dropdown. To work, this mixin must be added before ConfigSchemaWidgetMixin.
- get_datasets(*args, **kwargs) List[Dict[str, Any]]
Returns list of dataset dictionaries https://github.com/matthisk/django-jchart#docs-get-datasets
- class dashboard_widgets.widgets.line_chart.TrendMetricVisualizerWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
Used to either show a real trend metric & alert in action or to create / optimize a trend metric & alert. Default is not to use a real trend metric & alert & to instead use the many options below. If using a real alert ‘value’ & ‘alert_operator’ are ignored. If using a real trend metric ‘field’ to ‘smoothing’ will be ignored.
Very useful to find good values to use for trend metric & alert given your specific data.
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- support_multi_form = False
Subclasses can override this to disable support for more than 1 audit form or no audit forms. Set this to false if the widget supports only exactly one form at a time.
- config_defaults: Dict[str, Any] = {'alert': None, 'alert_operator': '>', 'fast_window': None, 'field': '_count', 'granularity': 'day', 'series_start_date': None, 'slow_window': None, 'smoothing': 3, 'trend_metric': None, 'trigger_as_switch': True, 'use_dashboard_wards': False, 'value': 0.1, 'wards': None}
default values to be set in widget model’s config when initially created.
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
if widget extends ConfigSchemaWidgetMixin, add granularity dropdown. To work, this mixin must be added before ConfigSchemaWidgetMixin.
- get_alert_data() tuple[Callable[[float, float], bool], float]
Gets real alert if one is specified or creates a temp one for the chart
- timeseries_and_alert
Creates timeseries which is used for plotting. Uses a real metric or metric options if None. Uses a real alert or alert options to find where threshold is crossed.
- events
Adds triggers as lines indicating approximately where the alert would first be triggered. Used if trigger isn’t a switch (shaded area).
- values
Gets timeseries dataframe as GroupedChartValues
- get_datasets(*args, **kwargs) List[Dict[str, Any]]
Returns list of dataset dictionaries https://github.com/matthisk/django-jchart#docs-get-datasets
- class dashboard_widgets.widgets.pareto_chart.ParetoChartWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- config_defaults: dict[str, str | int | list | bool] = {'field_name': None, 'non_compliance': False}
default values to be set in widget model’s config when initially created.
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
Gets config schema for the specified custom dashboard widget. Override this method to further configure the schema per widget config if needed.
- property values: list[Tuple[int | float | None, str | date]]
Override in sub-classes if widget self-calculates data
- get_datasets(*args, **kwargs) List[Dict[str, Any]]
Returns list of dataset dictionaries https://github.com/matthisk/django-jchart#docs-get-datasets
- class dashboard_widgets.widgets.takeda.PatientTrackerBarChart(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
Shows number of active / discontinued patients based on number of enrolled (added) minus discontinued entries.
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- support_multi_form = False
Subclasses can override this to disable support for more than 1 audit form or no audit forms. Set this to false if the widget supports only exactly one form at a time.
- dynamic_field_target: str | None = None
Key of the field in the widgets config which is to be used for dynamic fields
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
Gets config schema for the specified custom dashboard widget. Override this method to further configure the schema per widget config if needed.
- num_discontinued
Number of discontinued patients
- property num_active_patients: int
Number of active patients (= added - discontinued)
- values
- class dashboard_widgets.widgets.benchmark.BenchmarkOverTimeLineChart(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- config_defaults: dict[str, str | int | list | bool] = {'average': True, 'field_names': []}
default values to be set in widget model’s config when initially created.
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
if widget extends ConfigSchemaWidgetMixin, add granularity dropdown. To work, this mixin must be added before ConfigSchemaWidgetMixin.
- get_datasets(*args, **kwargs) list[JchartDataset]
Returns list of dataset dictionaries https://github.com/matthisk/django-jchart#docs-get-datasets
- get_labels(*args, **kwargs)
Returns categorical axis labels https://github.com/matthisk/django-jchart#docs-get-labels
- is_empty() bool
Tells whether this widget has data to display To be overridden by subclasses to decide whether No Data placeholder should show
Table Widgets
- class dashboard_widgets.widgets.table.TableCellValue(value, value_txt)
Create new instance of TableCellValue(value, value_txt)
- value
Alias for field number 0
- value_txt
Alias for field number 1
- class dashboard_widgets.widgets.table.TableField(name: str, label: str)
Represents a table column for a field that is neither a model field, nor a custom field
Create new instance of TableField(name, label)
- name: str
Alias for field number 0
- label: str
Alias for field number 1
- class dashboard_widgets.widgets.table.Ordering(field, reversed)
Create new instance of Ordering(field, reversed)
- field: CustomField | Field
Alias for field number 0
- reversed: bool
Alias for field number 1
- class dashboard_widgets.widgets.table.TableMixin
Adds table to widget
- get_table_rows() Iterator[TableRow]
Yields values as table rows to be rendered underneath the pie chart in full-size view
- render_table() str
Render table with values used in the pie chart
- class dashboard_widgets.widgets.table.TableItem(*, classes: Sequence[str] = ())
Base class representing an element rendered in table widget
- class dashboard_widgets.widgets.table.TableRow(cells: Iterable[TableCell] = None, **kwargs)
Represents table widget row, contains cells stored in a tuple
- class dashboard_widgets.widgets.table.TableCell(plain_text: str = None, html_text: str | None = None, value: Any = None, style: str = '', **kwargs)
Represents table cell. Contains its value and methods of rendering the value to html or plain text
- Parameters:
plain_text – value of the cell expressed as plain text
html_text – rich text representation of the value (in safe html string format)
value – raw python value stored in this cell
style – arbitrary css style of the cell
kwargs – any additional args for the base class
- property html: str
Html contents of this cell or fall back to plain text if it has not html representation. Use this to render cell contents into html documents.
- property text: str
Plain text contents of this cell. If cell has no text, return string representation of its value. Use this to render cell contents as plain text into csv or other non-html documents.
- class dashboard_widgets.widgets.table.TableWidgetHighlightMixin
Adds text search highlighting widgets. Only works with table widget. Highlghting is done in javascript using mark.js. This mixin adds the needed js and adds logic to determine which columns to highlight. Text should be highlighted if the answers for a searchable custom field are shown (use_for_filtering set to exact / partial search)
- should_highlight: bool = True
set if widget should highlight text on search
- single_field_widget: bool = False
set if the widgets data is derived from one field / question
- highlight_column_names: bool = False
set if search result filters columns
- class dashboard_widgets.widgets.table.TableWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- property show_numbering: bool
Whether columns in this table should be numbered (starting at 1)
- property urlize_text: bool
Whether links in the text should be clickable
- should_truncate_text(text: str) bool
Determine if cell content should be truncated. Returns True for text content longer than truncation_char_limit.
- is_empty() bool
Tells whether this widget has data to display To be overridden by subclasses to decide whether No Data placeholder should show
- property column_styles: dict[str, list[str]]
Extra styles added to cells in columns, mapped by column name to list of specific column styles
- render_cell(col: int, cell: TableCell, column_name: str | None = None) SafeString
Renders HTML for table cell
- Parameters:
col – table column index
cell – cell to be rendered
column_name – name of column cell is rendered in
- is_confidential
Check if the form type has confidential label configured
- generate_filename(base_name: str, extension: str) str
Generate filename with confidential suffix if needed
- Parameters:
base_name – base name for the file
extension – file extension (e.g., ‘csv’, ‘xls’)
- Returns:
filename with confidential suffix if applicable
- get_limit_message() str
Message to be appended to the table if number of rows exceeds the hard limit
- render_content() str
Render contents inside the widget :return: html safe string
- add_confidential_header(sheet: Worksheet) int
Add confidential header to the first row of Excel sheet.
- Parameters:
sheet – xlwt worksheet object
- Returns:
Row offset (1 if header was added, 0 if not) for subsequent content positioning
- class dashboard_widgets.widgets.table.AnswerTableWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
A table widget which displays answers to questions in this Form in a table.
Supported types of columns (definde in
field_names): * form fields:hardcoded fields (ward, auditor, etc)
hardcoded questions (e.g. hand hygiene form fields)
custom fields
- computed fields (represented by
dashboard_widgets.widgets.table.TableField) compliance
- computed fields (represented by
Additional columns can be added by enabling various options: *
show_numbering- prepends first column with sequence number *edit_link- appends a column with Edit button for each row- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- support_multi_form = False
Subclasses can override this to disable support for more than 1 audit form or no audit forms. Set this to false if the widget supports only exactly one form at a time.
- config_defaults: dict[str, str | int | list | bool] = {'clickable_links': False, 'compliance_rate': '', 'edit_link': False, 'field_names': None, 'highlight_compliance': False, 'javascript_searchbar': False, 'latest_review_date': False, 'max_entries': 500, 'next_review_date': False, 'ordering_field': None, 'show_change_not_viewed_alert': False, 'show_empty_rows': False, 'show_issues': False, 'show_issues_state': False, 'show_numbering': False, 'show_review_count': False, 'sub_observation': None, 'web_request_lookup_value': ''}
default values to be set in widget model’s config when initially created.
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
Gets config schema for the specified custom dashboard widget. Override this method to further configure the schema per widget config if needed.
- classmethod has_web_request_tracking(audit_form: AuditForm) bool
Check if web request tracking exists for this form by looking for workflows with web request operations.
- Parameters:
audit_form – Audit Form
- property javascript_searchbar: bool
Whether the javascript searchbar should be enabled based on the widget config. Automatically False if there is no request object, or the page is not a Public Dashboard.
- web_request_lookup
Returns web_request_lookup value from the widget configuration.
- property urlize_text: bool
Whether links in the table should be clickable
- is_empty() bool
Pre-fetches rows to populate
total_row_countwhen not yet set, avoiding separate COUNT / EXISTS queries.
- render_content() str
Override to render body first, populating total_row_count via the COUNT(*) OVER() window function before is_empty or num_items are evaluated. This eliminates separate COUNT and EXISTS queries.
- get_context_data() Dict[str, Any]
Pre-render content so
total_row_countis populated beforeget_subtitleaccessesnum_items.
- answer_issues
Maps field name and observation id to the number of QIP issues raised. count will also be 0 if show_issues config is False
- ordering
If ordering field is specified, returns a tuple of: * ordering field instance * boolean determining whether order is reversed (descending)
- property show_numbering: bool
Whether columns in this table should be numbered (starting at 1)
- property use_empty_row_filter: bool
Boolean property to denote whether or not to apply empty row filter
- apply_empty_row_filter() Q
Build Q object to exclude rows with empty field values
- property annotate_compliance: bool
Whether queryset should be annotated with compliance data
- compliance_range
Selected compliance range to filter observations by
- Returns:
a tuple representing lower bound and upped bound (float values between 0.0 and 1.0) if
compliance_rateoption is set on the widget.
- num_items
Total row count from
total_row_count.- Raises:
RuntimeError – if rows have not been evaluated yet.
- get_limit_message() str
Message to be appended to the table if number of rows exceeds the hard limit
- get_fields() Sequence[CustomField | Field | TableField]
List of mixed models.Field and custom Field instances
- field_names_set
Cached set of field names for O(1) lookup in hot paths.
- has_field(field_name: str) bool
Check if field is enabled (O(1) lookup).
- headings
Extract heading texts from heading_field_map
- heading_field_map
Maps each heading text to its corresponding field (or None for extra headings)
- render_head() SafeString
Override to add MEG AI feature indicators to column headers for CustomFields
- observations_qs
- filter_by_latest_web_request(qs: ObservationQuerySet, lookup_value: str, date_range: DateTimeRange | None = None) ObservationQuerySet
Filters latest web requests for answer table using the configured lookup value.
- Parameters:
qs – QuerySet of observations to filter
lookup_value – String value to match against web request payloads
date_range – Optional date range to pre-filter logs (improves performance when available)
- build_review_data_lookup(item_pks: list[int], content_type: ContentType) tuple[dict[int, int], dict[int, datetime]]
Build lookup dicts for review counts and latest dates.
- Returns:
Tuple of (review_counts, latest_review_dates) where review_counts maps observation PK to review count, and latest_review_dates maps PK to most recent review datetime.
- build_issue_counts_lookup(item_pks: list[int], content_type: ContentType, items_model: type) Counter[int]
Build lookup of pending issue counts per observation. Includes issues on sub-observations when the form has subforms. Uses IssueQueryset.for_observations to reuse existing filtering logic.
- build_change_alert_lookup(item_pks: list[int], content_type: ContentType) set[int]
Build a set of item PKs that have unseen changes. Replaces correlated subqueries for show_change_not_viewed_alert with bulk queries.
- Returns:
Set of item PKs where the latest change is newer than the user’s last view/change action.
- attach_bulk_data_to_items(items: list[BaseAuditModel | BaseSubObservation], content_type: ContentType, items_model: type) None
Fetch auxiliary data and attach to items in a single iteration. Only fetches data for columns that are actually enabled.
- items
Items (rows) in this table
- Returns:
a queryset of observations or sub-observations depending on config
- ward_id_institution_slug_map
Maps ward ID to institution slug using single query
- generate_rows(page: int | None = None, page_size: int | None = None) Iterator[TableRow]
Returns generator of row items
- get_rows() Iterable[TableRow]
Returns table rows. Returns pre-fetched rows when available (populated by
is_empty()for non-render paths), otherwise generates rows using infinite scrolling (first page only) unless printing, exporting, infinite scroll is explicitly disabled, or javascript_searchbar is enabled.
- action_load_more_rows(request: HttpRequest, **kwargs) HttpResponse
AJAX endpoint for infinite scrolling - returns HTML rows for the next page.
- compliance_calculator
Provides fall-back compliance calculator for when subform compliance cannot be extracted from observation’s compliance dict.
- class dashboard_widgets.widgets.table.GroupedAnswerTableWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
Table widget showing any the count for any answer grouped by ward, department or institution
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- support_multi_form = False
Subclasses can override this to disable support for more than 1 audit form or no audit forms. Set this to false if the widget supports only exactly one form at a time.
- single_field_widget: bool = True
set if the widgets data is derived from one field / question
- highlight_column_names: bool = True
set if search result filters columns
- config_defaults: dict[str, str | int | list | bool] = {'group_by': 'ward'}
default values to be set in widget model’s config when initially created.
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
Gets config schema for the specified custom dashboard widget. Override this method to further configure the schema per widget config if needed.
- get_group_value_statements() tuple[F, F]
returns an ORM “F” statement pair for value and label for any selected “group by” option
- Returns:
ORM F for group by value, ORM F for group by label
- class dashboard_widgets.widgets.table.IssueTypeMixin
For use in widgets that have the issue_type config option. Filters available issues by the selected issue_type.
- class dashboard_widgets.widgets.table.QipCommonIssuesWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
Table widget showing most common issues by looking at
qip.models.Issueobjects with most common ‘comment’ value.- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
Gets config schema for the specified custom dashboard widget. Override this method to further configure the schema per widget config if needed.
- class dashboard_widgets.widgets.table.QipConfigurableTableWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
Table widget allowing issues to be grouped in columns and rows by any field on the issue model, hardcoded or custom.
Implemented in Task #26468
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- render_pandas_table: bool = False
Whether to render dataframe into html. This overrides TableWidget’s rendering logic.
- config_defaults: dict[str, str | int | list | bool] = {'column_field': 'qipstatus', 'issue_type': 'all', 'row_field': 'ward'}
default values to be set in widget model’s config when initially created.
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
Gets config schema for the specified custom dashboard widget. Override this method to further configure the schema per widget config if needed.
- row_label
Gets the label for a hardcoded field on the Issue model, or custom issue field.
- headings
Get headings with custom labels for both row and column headers.
- build_dataframe() DataFrame
Users of this mixin should override this method to build the dataframe. The method will be called only once.
Do not call this method directly, use the
dataframeproperty.
- class dashboard_widgets.widgets.table.TimeTrackingTableWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
An answer table which only shows observations which have had specific actions performed on them. A column is prepended to the table data to show the time taken for the action to be performed.
Widget implemented in Task #24426
Example configuration:
{ "start_time": {"time_viewed": ""}, "end_time": {"int_field": 20}, "metric_verb": "Updated" }
- start_time
The time that a particular action was performed on an observation. This can be when it was created, updated, viewed, reviewed, or updated with a particular field/answer combination.
- end_time
The time that a particular action was performed on an observation. This can be when it was created, updated, viewed, reviewed, or updated with a particular field/answer combination.
- metric_verb
Used in the widget frontend to describe the activity that’s being tracked. The default is “Viewed” (the time taken to view an observation after creation).
Possible values for
start_timeandend_time:{"time_created": ""}The time that the observation was created.{"time_viewed": ""}The first time the observation was viewed by anybody.{"time_changed": ""}The first time that the observation was changed by anybody.{"time_reviewed": ""}The first time that the observation was reviewed by anybody.{"field_name": "answer"}The first time that the observation was updated with a particular field/answer combination.
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- config_defaults: dict[str, str | int | list | bool] = {'edit_link': False, 'end_time': {'time_viewed': ''}, 'metric_verb': 'Viewed', 'start_time': {'time_created': ''}}
default values to be set in widget model’s config when initially created.
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
Gets config schema for the specified custom dashboard widget. Override this method to further configure the schema per widget config if needed.
- metric_verb: str
- get_fields() Sequence[CustomField | Field | TableField]
List of mixed models.Field and custom Field instances
- actioned_observations() Iterable[tuple[int, timedelta]]
Iterator yielding tuples representing observation id and time difference as tuples for each observation
- observation_times: Dict[int, str] | None
dictionary mapping observation ids to their respective time deltas
- class dashboard_widgets.widgets.table.TargetsTableWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- config_defaults: dict[str, str | int | list | bool] = {'actual_label': 'Actual', 'counter_logic': 'observations', 'target_breakdown': 'ward', 'target_label': 'Target'}
default values to be set in widget model’s config when initially created.
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
Gets config schema for the specified custom dashboard widget. Override this method to further configure the schema per widget config if needed.
- headings_and_column_map
Creates headings for chart and adds a map for each heading from data name to display name
- dataframe
- render_table() str
Render the dataframe as <table>. This is a custom logic invoked when
render_pandas_tableisTrue.
- class dashboard_widgets.widgets.table.LFPSEAnswerTableWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
An implementation of AnswerTableWidget that displays LFPSE specific columns:
lfpse_errors
lfpse_reference
Either or none of the LFPSE specific field_names can be included.
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- class dashboard_widgets.widgets.table.FieldComplianceTableWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
Table widget showing number of observations and compliance for each answer to a given field
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- support_multi_form = False
Subclasses can override this to disable support for more than 1 audit form or no audit forms. Set this to false if the widget supports only exactly one form at a time.
- class dashboard_widgets.widgets.table.ObservationEmailTrackingTableWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- support_multi_form = False
Subclasses can override this to disable support for more than 1 audit form or no audit forms. Set this to false if the widget supports only exactly one form at a time.
- config_defaults: dict[str, str | int | list | bool] = {'max_entries': 500}
default values to be set in widget model’s config when initially created.
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
Gets config schema for the specified custom dashboard widget. Override this method to further configure the schema per widget config if needed.
- property headings: Sequence[str]
Extract heading texts from heading_field_map
- class dashboard_widgets.widgets.table.MetricOvertimeSummary(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
Compares the answer values for a specific field of observations for a specific form over time. Groups observations by a text field. Only supports a single form, but will work in an overview dashboard if filtered by form_id. Does not support subforms.
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- support_multi_form = False
Subclasses can override this to disable support for more than 1 audit form or no audit forms. Set this to false if the widget supports only exactly one form at a time.
- config_defaults: dict[str, str | int | list | bool] = {'granularity': 'month', 'grouper_field_name': '', 'static_color_map': [], 'value_field_name': ''}
default values to be set in widget model’s config when initially created.
- render_pandas_table: bool = False
Whether to render dataframe into html. This overrides TableWidget’s rendering logic.
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
if widget extends ConfigSchemaWidgetMixin, add granularity dropdown. To work, this mixin must be added before ConfigSchemaWidgetMixin.
- fields
Takes the selected value and grouper field names and pulls the fields they belong too. Required for highlighting, real fields need to be checked for searchablility.
- build_dataframe() DataFrame
Users of this mixin should override this method to build the dataframe. The method will be called only once.
Do not call this method directly, use the
dataframeproperty.
- class dashboard_widgets.widgets.ward_compliance.WardCell(ward: Ward | Department, is_best: bool, **kwargs)
- Parameters:
plain_text – value of the cell expressed as plain text
html_text – rich text representation of the value (in safe html string format)
value – raw python value stored in this cell
style – arbitrary css style of the cell
kwargs – any additional args for the base class
- class dashboard_widgets.widgets.ward_compliance.WardComplianceWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- config_defaults: dict[str, str | int | list | bool] = {'counter_logic': 'observations'}
default values to be set in widget model’s config when initially created.
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
Gets config schema for the specified custom dashboard widget. Override this method to further configure the schema per widget config if needed.
- trend_img(trend: float | None) str
Renders arrow image for the trend value
- property compliance_range: tuple[float, float] | None
Selected compliance range to filter observations by
- ward_dataframe
Dataframe holding ward data required for the table
- class dashboard_widgets.widgets.ward_compliance.DepartmentComplianceWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- model
alias of
Department
- class dashboard_widgets.widgets.question_compliance_table.QuestionRow(field, observation, result)
Create new instance of QuestionRow(field, observation, result)
- field
Alias for field number 0
- observation
Alias for field number 1
- result
Alias for field number 2
- class dashboard_widgets.widgets.question_compliance_table.ComplianceData(compliant, total, compliance)
Create new instance of ComplianceData(compliant, total, compliance)
- compliance
Alias for field number 2
- compliant
Alias for field number 0
- total
Alias for field number 1
- class dashboard_widgets.widgets.question_compliance_table.QuestionComplianceTableWidget(*args, **kwargs)
- support_multi_form = False
Subclasses can override this to disable support for more than 1 audit form or no audit forms. Set this to false if the widget supports only exactly one form at a time.
- config_defaults: dict[str, str | int | list | bool] = {'issue_level': 'all'}
default values to be set in widget model’s config when initially created.
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
Gets config schema for the specified custom dashboard widget. Override this method to further configure the schema per widget config if needed.
- is_empty() bool
Tells whether this widget has data to display To be overridden by subclasses to decide whether No Data placeholder should show
- set_question_ignored(field: CustomField, observation: BaseAuditModel | BaseSubObservation) None
Controls if a field has been ignored for compliance calculation for every observation. Ensures that if an observation has not ignored a field, it won’t later be marked as ignored by subsequent observations.
- Parameters:
field – The CustomField.
observation – The observation or sub observation to check.
- render_cell(col: int, value: TableCell, column_name: str | None = None) SafeString
Renders HTML for table cell
- Parameters:
col – table column index
cell – cell to be rendered
column_name – name of column cell is rendered in
- get_context_data()
Context data for rendered widget template
- class dashboard_widgets.widgets.kpi.KpiTableWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
Key Performance Indicators widget. Allows configuration to define target compliance for each field and render table showing field by quarter heatmap representing compliance (or average value of the field) for given quarter and whether target was met.
Implemented in Task #23977
Example config:
{ "granularity": "quarter", "targets": { "desks": 0.8, "phones": 0.5, "ethernet_wiring": 0.2 }, "target_margin": 0.1, "less_than_targets": [ "ethernet_wiring" ] }
- targets
dictionary; maps field name to a target compliance (0.0 - 1.0 range). field name can be any field with compliance data, or a numeric field (int or float).
- target_margin
float; Target will be marked as “met” (in orange) if within this margin. This value should be in 0.0-1.0 range.
- target_margin_per_field
dictionary; maps field name to a target margin.
- less_than_targets
list of field names where the target is to be below specified value.
- use_compliance
If False, then field answer data is used for KPI calculation for all fields. If True and the field has compliance, the compliance data is used. This is the default behavior.
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- support_multi_form = False
Subclasses can override this to disable support for more than 1 audit form or no audit forms. Set this to false if the widget supports only exactly one form at a time.
- config_defaults: dict[str, str | int | list | bool] = {'target_margin': 0.1, 'target_margin_per_field': {}, 'targets': {}, 'use_compliance': True}
default values to be set in widget model’s config when initially created.
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
Gets config schema for the specified custom dashboard widget. Override this method to further configure the schema per widget config if needed.
- property target_margin: dict[str, float]
Value for “close to achieving target”, marked as orange
- class dashboard_widgets.widgets.accreditation.AccreditationLevelCell(level: AccreditationLevel, classes=('accreditation',))
- Parameters:
plain_text – value of the cell expressed as plain text
html_text – rich text representation of the value (in safe html string format)
value – raw python value stored in this cell
style – arbitrary css style of the cell
kwargs – any additional args for the base class
- class dashboard_widgets.widgets.accreditation.WardAccreditationWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
Displays ward accreditation table based off
Accreditationconfig specified in the config. Implemented in Task #26592, only supports customn observations.- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
Gets config schema for the specified custom dashboard widget. Override this method to further configure the schema per widget config if needed.
- generate_form_compliances() Iterator[tuple[int, float]]
Generates tuples containing ward id and its compliance value
- generate_subform_compliances() Iterator[tuple[int, float]]
Generates ward id and subform compliance for each ward and each subform.
- Yields:
tuple containing (ward_id, compliance) where compliance is a non-null float, and ward_id is repeated for each subform.
- property compliances: dict[int, list[float]]
Dictionary mapping ward ids to a list of form (or subform, depending on accreditation) compliances
- class dashboard_widgets.widgets.audit_scores.AuditScoresWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
Implemented in Task #25190, A table widget rendering compliance over time, grouped by a specific field (e.g., Department, Institution, or a Custom Field).
This widget aggregates observation compliance percentages and counts for specified time granularities (Day, Month, Year). It supports optional visualizations such as heatmaps for compliance levels and trend indicators.
Key Features:
Time-Series Aggregation: Groups data by the configured time granularity.
Custom Scoring: Can score by hardcoded fields (Department), custom form fields or subform.
Visual Styling: Optional heatmap coloring and trend arrows (up/down).
Example Output:
July 2025
August 2025
September 2025
October 2025
Department
Compliance
Count
Compliance
Count
Compliance
Count
Compliance
Count
Hand Hygiene Dept
0
82.5%
2
78.7% ↓
2
0
Test Department
77.6%
4
83.1% ↑
4
84.2% ↑
4
78.2% ↓
1
Average Score
77.6%
4
82.8% ↑
6
81.5% ↓
6
78.2% ↓
1
Supported Configuration Options:
- granularity (str)
The time period to group columns by. Options:
'day','month','year'. Defaults to'month'.- score_by (str)
The database field name used to group the rows and calculate compliance scores (e.g., department, institution, or custom field). If form has custom subforms, it’s also possible to score by subform.
Note
when scoring by “subform”, the behaviour changes from grouping observation compliance data, to grouping sub-observation compliance (Subform Compliance)
- score_by_label (str)
A custom user-facing label for the first column header (e.g., “Ward” or “Department”).
- show_count (bool)
If
True, displays a “Count” column next to the “Compliance” column for each time period. Defaults toFalse.- heatmap (bool)
If
True, applies color-coding (CSS classes) to compliance cells based on defined compliance levels.- trend_indicator (bool)
: If
True, displays an arrow (↑ or ↓) indicating if the score has increased or decreased compared to the previous period.- show_total (bool)
If
True, adds a summary row. Defaults toTrue.Note
Totals are recalculated from source data, not column averages.This ensures accuracy when observations overlap (e.g., multi-choice fields). See Retrieving Compliance Data.- counter_logic (str: “observations” | “audits”)
Defines the logic for the count metric (e.g., counting individual observations vs. audit sessions).
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- config_defaults: dict[str, str | int | list | bool] = {'counter_logic': 'observations', 'granularity': 'month', 'show_total': True}
default values to be set in widget model’s config when initially created.
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
Gets config schema for the specified custom dashboard widget. Override this method to further configure the schema per widget config if needed.
- property show_count: bool
Whether to show the ‘Count’ column
- property show_total: bool
Whether to show the final summary row
- property heatmap: bool
Whether to color-code compliance cells
- property score_by: Literal['audit_form', 'department', 'institution', 'subform'] | str
Field to score by. It’ll be one of the pre-determined options or a field name
- property score_by_label: str
Label to display in the first column, describes what field we’re grouping by
- Returns:
string or a lazy string
- property score_by_subform: bool
Tells whether we’re scoring by subform.
- property trend_indicator: bool
Whether to show trending arrow beside compliance figure
- get_custom_field() CustomField | None
Instance of the custom field being scored by
- property multi_institution: bool
Whether showing data from multiple institutions
- property grouper_expr: F | Expression
Query expression used to determine grouper
- property summary_label: Literal['Total Compliance', 'Average Score'] | str
Label used for the summary row - the last row.
- Returns:
Label for summary score; either ‘Total Compliance’, or ‘Average Score’ (or localized translation of it)
- Total Compliance
Means that resulting summary is computed from source. It’s the more accurate count. Task #30860
- Average Score
Means that summary is computed by averaging data in the column, without accounting for number of observations (count column)
- property time_bucket_expr: Expression
Query expression used to assign time bucket. Returned value aligns with the selected granularity
- property subforms: QuerySet
Set of custom subforms to use when score_by=SUBFORM. Returns all subforms in the current audit form(s), but also respects filter form selection and narrows down forms if user has selected subforms.
- Returns:
Queryset of subforms to score by
- property item_order: list[str]
Defines order of rows, including the summary row If the grouper has a predefined order that needs to be respected, this property defines that order.
Returned values must match grouper values exactly. Any items in the dataframe not included in this order, will be placed after the ordered items and before the summary row.
- calculate_average_score(scores: Iterable[tuple[date, str | int | bool | list | float | None, float | None, int]]) Iterator[tuple[date, str, float | None, int]]
Calculate average for each time bucket Returned dataset combines all data for each time bucket in a single data under a new grouper “Average “Score”.
The average score is calculated by averaging all compliance data, and counts are added up (sum).
- Parameters:
scores – an iterable of tuples containing: time bucket (date), grouper, compliance, count. Must be ordered by date.
- Yields:
Summary data (Compliance, count) of all groups for each time bucket
- get_score_data() Iterator[tuple[date, str | int | bool | list | float | None, float | None, int]]
Builds Queryset returning score data and yields the results as tuples. An additional group “Average Score” is yielded at the end if show_total is enabled
- Yields:
tuples: (date, grouper, compliance, count)
- build_dataframe() DataFrame
Builds dataframe to be rendered as the table.
The resulting dataframe has multiindex columns (date / compliance) + (date / count) The index is the name of the grouper.
Example:
Department department
2023-01-01 compliance
2023-01-01 count
Test Department
1.0
5
Average Score
1.0
5
- property index_mapping: dict[str, str]
Maps a value to its display name
- format_index(value: Any, axis: Literal['columns', 'rows']) str
Format a DataFrame index/column label for display.
- Parameters:
value – the value to be formatted
axis – whether this is a column heading (colums), or index value (rows).
- render_content() str
Render contents inside the widget :return: html safe string
- class dashboard_widgets.widgets.audit_scores.SubformFieldScoresWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
A widget designed to display compliance trends for individual questions (fields) within a specific subform over time. Originally implemented in Task #30496.
Shows average compliance of question answers within each subform, and count of answers with compliance.
Average is not weighted, each answer is considered equally across observations
The count shows how many times the question was answered with an answer that has compliance data
The summary row shows “Total Compliance” - it’s a complete re-calculation of the subform’s compliance for the given time period, taking each sub-observation separately and averaging the result. The Count in the summary is the number of observations.
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- config_defaults: dict[str, str | int | list | bool] = {'granularity': 'month', 'subform': ''}
default values to be set in widget model’s config when initially created.
- support_multi_form = False
Subclasses can override this to disable support for more than 1 audit form or no audit forms. Set this to false if the widget supports only exactly one form at a time.
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
Gets config schema for the specified custom dashboard widget. Override this method to further configure the schema per widget config if needed.
- property score_by_label: str
Label to display in the first column, describes what field we’re grouping by
- Returns:
string or a lazy string
- property field_label_mapping: dict[str, str]
Dictionary mapping field names to their display labels.
Used by format_index to resolve unique field_name keys to human-readable labels at render time.
- property item_order: list[str]
Return field names as the category order instead of labels.
- format_index(value: Any, axis: Literal['columns', 'rows']) str
Override to show field labels when available, handling duplicate labels safely.
- Parameters:
value – the index value to be formatted
axis – whether this is a column heading (columns), or index value (rows).
- get_score_data() Iterator[tuple[date, str | int | bool | list | float | None, float | None, int]]
Yield score data tuples for each field in the subform.
Uses field_name as the grouper value to avoid duplicate category errors when multiple fields share the same label. Labels are resolved at render time via format_index.
- class dashboard_widgets.widgets.audit_scores.FormFieldScoresWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
Widget that renders the audit scores of a flat-form in a tabular format Inherits all the regular funtionality from the AuditScoresWidget like granularity, show_count, heatmap & trend_indicatior Also allows the user to specifiy which field names from they form, they would like to include in the scoring A form does not have to be specified in the config, instead the widget will render that form from the widget’s dashboard itself.
The final row shows “Average Score”: average compliance and total count. The average compliance is an average value of all above figures (without accounting for the count). And count is a sum of all the values above.
The Counts represent how many observations have an answer for given question with a value that has compliance data.
Config options:
- field_names
Fields to show in the table
- granularity
Date granularity for data aggregation
- show_count
Whether to show how many times a field was answered with a value that has compliance data (i.e. not null)
- heatmap
Whether to colour-code compliance cells based on its value
- trend_indicator
Whether to show trend arrow comparing each compliance value with one from previous time bucket
Example appearance:
July 2025
August 2025
September 2025
October 2025
Compliance
Count
Compliance
Count
Compliance
Count
Compliance
Count
Compliance Field 1
0
82.5%
2
78.7% ↓
2
0
Compliance Field 2
77.6%
4
83.1% ↑
4
84.2% ↑
4
78.2% ↓
1
Average Score
77.6%
4
82.8% ↑
6
81.5% ↓
6
78.2% ↓
1
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- config_defaults: dict[str, str | int | list | bool] = {'field_names': None, 'form': '', 'granularity': 'month'}
default values to be set in widget model’s config when initially created.
- support_multi_form = False
Subclasses can override this to disable support for more than 1 audit form or no audit forms. Set this to false if the widget supports only exactly one form at a time.
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
Gets config schema for the specified custom dashboard widget. Override this method to further configure the schema per widget config if needed.
- property field_label_mapping: dict[str, str]
Dictionary mapping field names to their display name
- property item_order: list[str]
Defines order of rows, including the summary row If the grouper has a predefined order that needs to be respected, this property defines that order.
Returned values must match grouper values exactly. Any items in the dataframe not included in this order, will be placed after the ordered items and before the summary row.
- property summary_label: str
Label used for the summary row - the last row.
- Returns:
Label for summary score; either ‘Total Compliance’, or ‘Average Score’ (or localized translation of it)
- Total Compliance
Means that resulting summary is computed from source. It’s the more accurate count. Task #30860
- Average Score
Means that summary is computed by averaging data in the column, without accounting for number of observations (count column)
- property score_by_label: str
Label to display in the first column, describes what field we’re grouping by
- Returns:
string or a lazy string
- format_index(value: Any, axis: Literal['columns', 'rows']) str
Override to show custom field labels when available (handles duplicate indices safely) as per task: 32155
- get_score_data() Iterator[tuple[date, str | int | bool | list | float | None, float | None, int]]
Builds Queryset returning score data and yields the results as tuples. An additional group “Average Score” is yielded at the end if show_total is enabled
- Yields:
tuples: (date, grouper, compliance, count)
Heatmap widgets
- dashboard_widgets.widgets.heatmap.HeatmapHeading
Represents a valid value for a heading (vertical or horizontal) value of a heading. It can be any valid answer type, but also a model instance, or a lazy string
__proxy__(Promise)alias of
str|int|bool|list|float|date|time|datetime|None|Model|ObservationFile|HeatmapField
- dashboard_widgets.widgets.heatmap.HeatmapKey
a tuple of headings, identifying a position within the heatmap. Heading order within the tuple: (top, left)
alias of
tuple[str|int|bool|list|float|date|time|datetime|None|Model|ObservationFile|HeatmapField,str|int|bool|list|float|date|time|datetime|None|Model|ObservationFile|HeatmapField]
- class dashboard_widgets.widgets.heatmap.HeatmapCell(key: HeatmapKey = None, label: str | None = '', compliance: Compliance = None, count: int | None = 0, hint: str | None = '', compliance_levels: ComplianceLevels = (0.9, 0.8), classes: str = '')
Holds data for a cell within heatmap
- static get_overall(cells: Iterable[HeatmapCell], **kwargs) HeatmapCell
Builds a summary cell for a number of cells by calculating average compliance (weighted by count)
- property label_display_value: str
The label field formatted correctly for display.
For use with numeric cells formed from a summation or average of values. If the count for the number of values in the cell is 0 / None then we return the null placeholder ‘-‘. If the label is one of the NULL types (e.g. empty string / None) we return ‘-‘. Otherwise it returns the label.
- property field_has_multiple_values: bool
Return true if there is a field in key that has multiple values input
- property field_has_partial_compliance: bool
Return true if there is a field in key that has multiple values input
- dashboard_widgets.widgets.heatmap.HeatmapValues
Maps heatmap position (top, left) to a value
alias of
dict[tuple[str|int|bool|list|float|date|time|datetime|None|Model|ObservationFile|HeatmapField,str|int|bool|list|float|date|time|datetime|None|Model|ObservationFile|HeatmapField],HeatmapCell]
- class dashboard_widgets.widgets.heatmap.HeatmapField(name: str, heatmap: HeatmapWidget)
Represents single field used for either heatmap’s X (left) or Y (top) axis and provides utility methods for handling its values.
- make_key(value: SerializedAnswer) Answer
Convert raw key (serialized value) to a value that will be recognized by heatmap as matching axis values
- get_annotation() F | Func
Provides SQL expression to annotate an observation queryset with a value of this field.
For field that have multiple values (multichoice, m2m relations), this will result in the queryset containing multiple rows for some observations, one for each choice - this is desired behaviour for the heatmap so that the observation can represent all relevant cells, one for each value. This also means that some obsevations will be excluded from the queryset if they don’t have any choices in the m2m relation or no answers in the multichoice field.
- Returns:
SQL Expression
- get_value(observation: BaseAuditModel) str | int | bool | list | float | None
Gets raw field value from observation
- get_answer(observation: Observation) Answer
Gets answer from observation; converts choices to human-readable representation, and for foreign keys gets the referenced object instance
- property choices: dict[SerializedAnswer, Answer]
Mapping of value to display value in this field
- property choices_qs: QuerySet | None
if the field is a foreign key, this property provides a base queryset for the linked model.
- property values: Iterable[Answer]
returns unique values for this field from observations. For choice fields it simply returns all possible choices. For fk fields, it returns all referenced objects as a queryset
- property values_map: dict[SerializedAnswer, Answer]
Dictionary mapping (serialized) values present in this field to their (object) answer / human-readable answer. Note that some answers may not be present in this dict, and the dict will be empty for some types of fields, so you should fall back to the value (key) if corresponding answer is not present.
- class dashboard_widgets.widgets.heatmap.HeatmapFields(left, top)
Create new instance of HeatmapFields(left, top)
- left: HeatmapField
Alias for field number 0
- top: HeatmapField
Alias for field number 1
- make_key(top: SerializedAnswer, left: SerializedAnswer) HeatmapKey
Makes a pair of keys from a pair of raw values
- class dashboard_widgets.widgets.heatmap.HeatmapWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
A heatmap widget that given two fields renders a grid where each cell represents average compliance with the corresponding values.
The base implementation takes two fields as the configuration (configured as
field_nameandfield_name_top) And represents compliance for each combination of values in those fields. The selected fields are wrapped inHeatmapFieldthat represents the field, but subclasses of the heatmap can override the behaviour to represent other non-field concepts or models linked by m2m fields.Configuration options
- field_name
name of the field to use as the left heading (rows)
- field_name_top
name of the field to use as the top heading (columns)
- overall_compliance
whether to add an extra row and column at the ends, summarizing the overall compliance in each serie
- pivoted
whether to swap columns/rows (pivot 90°)
- value_field
use value from a numeric field instead of compliance
Example configuration json{ "pivoted": false, "field_name": "audit_form", "value_field": "", "field_name_top": "ward", "show_empty_rows": false, "overall_compliance": false, "headings_left_label": "" }
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- config_defaults: dict[str, str | int | list | bool] = {'field_name': 'auditor', 'field_name_top': 'ward', 'headings_left_label': '', 'overall_compliance': False, 'show_count': False, 'show_empty_rows': False, 'value_field': ''}
default values to be set in widget model’s config when initially created.
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
Gets config schema for the specified custom dashboard widget. Override this method to further configure the schema per widget config if needed.
- property value_field_aggregation: Literal['sum', 'avg']
Aggregation to use for one cell over its values, either a sum or an average
- property overall_compliance: bool
Whether to show “Overall Compliance” row at the start
- property show_count: bool
Whether to show the entry on row intersections
- property show_empty_rows: bool
whether heatmap rows with no compliance should still render
- property headings_left_label: str
Text displayed in the corner cell between top and left headings
- is_empty() bool
Tells whether this widget has data to display To be overridden by subclasses to decide whether No Data placeholder should show
- get_headings_top(start: int | None = None, max_cols: int | None = None) Iterable[HeatmapHeading]
Gets the column headers. Can limit the columns displayed when printing by specifying both start and max_cols.
- Parameters:
start – Optionally specify the index of the first header to limit the headers returned.
max_cols – Optionally specify the max number of columns to limit the headers returned.
- render_head(start: int | None = None, max_cols: int | None = None) str
Renders the thead html. Can limit the columns displayed when printing by specifying both start and max_cols.
- Parameters:
start – Optionally specify the index of the first header to limit the headers returned.
max_cols – Optionally specify the max number of columns to limit the headers returned.
- generate_row_cells(heading_left: HeatmapHeading, start: int | None = None, max_cols: int | None = None) Iterator[HeatmapCell]
Generates cells for given left heading. Yields tuple of top heading and cell value
- Parameters:
heading_left – The row header to generate the cells for.
start – Optionally specify the index of the first header to limit the headers returned.
max_cols – Optionally specify the max number of columns to limit the headers returned.
- render_body(start: int | None = None, max_cols: int | None = None) SafeString
Renders the tbody html. Can limit the columns displayed when printing by specifying both start and max_cols.
- Parameters:
start – Optionally specify the index of the first header to limit the headers returned.
max_cols – Optionally specify the max number of columns to limit the headers returned.
- get_context_data() Dict[str, Any]
When printing the heatmap is broken into separate tables to allow all the columns to fit into the printable window.
- property compliance_levels_map: dict[AuditForm, ComplianceLevels]
Maps audit form instance to its compliance levels. Only forms that have a config object are mapped Returns empty dict if this heatmap does not use audit form field.
NOTE: It is assumed that Audit forms are located on the left axis.
- calculate_overall(values: HeatmapValues) HeatmapValues
Computes average value and total count for each column and returns a new values dict representing the overall data. Resulting values dict will be keyed with each heading and “Average” string so that it can be merged into the heatmap dict.
- Parameters:
values – heatmap values dict
- Returns:
Overall values dict
- class dashboard_widgets.widgets.heatmap.FieldComparisonCountWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
A field comparison widget that given two fields renders a grid where each cell represents count of each intersecting values from both fields, the background color of each cell can also be customized using static color map attribute
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- config_defaults: dict[str, str | int | list | bool] = {'field_name': 'auditor', 'field_name_top': 'ward', 'headings_left_label': '', 'overall_count': False, 'show_empty_rows': False, 'static_color_map': [], 'value_field': '', 'value_field_aggregator': 'sum'}
default values to be set in widget model’s config when initially created.
- property overall_compliance: bool
Whether to show “Overall Count” row at the start
- property value_field_aggregation: Literal['sum', 'avg']
Determines whether to Sum or Average the data. Required because summing is correct for counts (e.g. “Total Incidents”), but incorrect for rates (e.g. “Compliance %”), which should be averaged.
- render_body(start: int | None = None, max_cols: int | None = None) SafeString
Renders the tbody html. Can limit the columns displayed when printing by specifying both start and max_cols.
- Parameters:
start – Optionally specify the index of the first header to limit the headers returned.
max_cols – Optionally specify the max number of columns to limit the headers returned.
- class dashboard_widgets.widgets.ward_heatmap.RenderLabelMixin
Adds a method for rendering cell label based on the
show_numerator,show_numerator_for_partial_compliance, andshow_count_on_audit_formproperties.These properties can be overriden through config options of the same name, or as properties.
- property show_numerator: bool
Whether the label will show the numerator (x/y) besides the percentage otherwise only the percentage will appear
- property show_numerator_for_partial_compliance: bool
Whether the label will show the numerator (x/y) besides the percentage for fields with partial compliance
- property show_count_on_audit_form: bool
Whether numerator will show as count (y) when field_name is “audit_form” otherwise it will always show as (x/y)
- render_label(cell: HeatmapCell, numerator: int | None = None, denominator: int | None = None) str
Render label as percentage or percentage (denominator) or percentage (numerator/denominator) based on mixin attributes
Don’t show numerator even when enabled when field has multiple values or field has partial compliance setup #31263
- class dashboard_widgets.widgets.ward_heatmap.WardHeatmapWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
A heatmap widget where top headings are hardcoded for wards. The ward heading provides collapsible department/ward hierarchy.
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- config_defaults: dict[str, str | int | list | bool] = {'field_name': 'auditor', 'headings_left_label': '', 'overall_compliance': False, 'pivoted': False, 'show_empty_rows': False, 'value_field': ''}
default values to be set in widget model’s config when initially created.
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
Gets config schema for the specified custom dashboard widget. Override this method to further configure the schema per widget config if needed.
- get_split_dept_colspans(start: int, max_cols: int) Counter
Return the Counter object that records the ‘colspan’ attribute for a Department <td> element when a large table is split into smaller tables (eg. for the Print View). Create and store the Counter object on first query. Update the counter if ‘max_cols’ changes.
- render_heading(value, colspan: int = 1, rowspan: int = 1, classes='', attrs: Sequence[str] = ()) str
Renders the heading as a <th> tag
- Parameters:
value – the heading value or label to render
colspan – add colspan to the tag
rowspan – add rowspan to the tag
classes – classes to add to the HTML tag
attrs – any additiona attributes. Will be inserted directly into the tag, separated by spaces
- Returns:
rendered heading
- generate_row_cells(heading_left: HeatmapHeading, start: int | None = None, max_cols: int | None = None) Iterator[HeatmapCell]
Generates cells for given left heading. Yields tuple of top heading and cell value
- Parameters:
heading_left – The row header to generate the cells for.
start – Optionally specify the index of the first header to limit the headers returned.
max_cols – Optionally specify the max number of columns to limit the headers returned.
- render_head(start: int | None = None, max_cols: int | None = None) str
Renders the thead html. Can limit the columns displayed when printing by specifying both start and max_cols.
- Parameters:
start – Optionally specify the index of the first header to limit the headers returned.
max_cols – Optionally specify the max number of columns to limit the headers returned.
- render_row(heading_left: HeatmapHeading, cells: str, classes: str) SafeString
Renders the <tr> tag with given content
- Parameters:
heading_left – heading representing this row (the first cell)
cells – HTML content of the row
classes – any css classes to be applied to the row
- Returns:
rendered table row
- render_body(start: int | None = None, max_cols: int | None = None) SafeString
Renders the tbody html. Can limit the columns displayed when printing by specifying both start and max_cols.
- Parameters:
start – Optionally specify the index of the first header to limit the headers returned.
max_cols – Optionally specify the max number of columns to limit the headers returned.
- get_context_data() Dict[str, Any]
When printing the heatmap is broken into separate tables to allow all the columns to fit into the printable window.
- class dashboard_widgets.widgets.ward_heatmap.HeatmapTeamField(name: 'str', heatmap: 'HeatmapWidget', team_names: 'list[str]')
- get_value(observation: Observation) SerializedAnswer
Gets raw field value from observation
- get_answer(observation: Observation) Answer
Gets answer from observation; converts choices to human-readable representation, and for foreign keys gets the referenced object instance
- values
- teams_by_userid
maps user ids to their respective teams
- get_annotation() F
Provides SQL expression to annotate an observation queryset with a value of this field.
For field that have multiple values (multichoice, m2m relations), this will result in the queryset containing multiple rows for some observations, one for each choice - this is desired behaviour for the heatmap so that the observation can represent all relevant cells, one for each value. This also means that some obsevations will be excluded from the queryset if they don’t have any choices in the m2m relation or no answers in the multichoice field.
- Returns:
SQL Expression
- class dashboard_widgets.widgets.ward_heatmap.WardTeamHeatmapWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- config_defaults: dict[str, str | int | list | bool] = {'overall_compliance': False, 'pivoted': False, 'show_empty_rows': False, 'team_names': []}
default values to be set in widget model’s config when initially created.
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
Gets config schema for the specified custom dashboard widget. Override this method to further configure the schema per widget config if needed.
- class dashboard_widgets.widgets.ward_heatmap.HeatmapMultiField(name: 'str', heatmap: 'HeatmapWidget', fields: 'tuple[HeatmapField]')
- property values: Iterable[Answer]
returns unique values for this field from observations. For choice fields it simply returns all possible choices. For fk fields, it returns all referenced objects as a queryset
- class dashboard_widgets.widgets.ward_heatmap.WardQuestionHeatmapWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
A heatmap mapping each question against each ward. Each cell shows compliance for the ward in context of just that one question. This widget supports only custom fields since they are the only fields that provide compliance information
Example appearance:
💡 Click on Departments to collapse / expand Wards data [Collapse All] [Expand All]
Overall Compliance
Test Department - meg-staff ^
Test Ward
Overall Compliance
80.3% (404/504)
80.3% (404/504)
Desks
89.9% (107/119)
89.9% (107/119)
Phones
50.9%
50.9%
Ethernet wiring
82.0% (100/122)
82.0% (100/122)
Door locked
93.3% (140/150)
93.3% (140/150)
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- config_defaults: dict[str, str | int | list | bool] = {'field_names': [], 'headings_left_label': '', 'overall_compliance': False, 'pivoted': False, 'select_dynamic_fields': False, 'show_numerator': True, 'sub_observation': ''}
default values to be set in widget model’s config when initially created.
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
Gets config schema for the specified custom dashboard widget. Override this method to further configure the schema per widget config if needed.
- property dynamic_field_selection: bool
Whether to allow the user to click on fields in the heatmap to apply them as dynamic filter on this dahboard
- Returns:
True if the widget setting is enabled, and widget is not currently opened in full-view
- selected_field_name
Name of field selected by clicking a cell (if any)
- render_row(heading_left: HeatmapHeading | HeatmapField, cells: str, classes: str) SafeString
Renders the <tr> tag with given content
- Parameters:
heading_left – heading representing this row (the first cell)
cells – HTML content of the row
classes – any css classes to be applied to the row
- Returns:
rendered table row
- prefetch_subobservations_answer_counts() Dict[int, Counter]
Prefetch sub-observations and calculate field answer counts efficiently.
- get_headings_top(start: int | None = None, max_cols: int | None = None) Iterable[HeatmapHeading]
Gets the column headers. Can limit the columns displayed when printing by specifying both start and max_cols.
- Parameters:
start – Optionally specify the index of the first header to limit the headers returned.
max_cols – Optionally specify the max number of columns to limit the headers returned.
- class dashboard_widgets.widgets.ward_heatmap.HeatmapSubformField(name: 'str', heatmap: 'HeatmapWidget', subforms: 'Sequence[Subform]')
- get_value(observation: Observation) SerializedAnswer
Gets raw field value from observation
- get_answer(observation: Observation) Sequence[Subform]
Gets answer from observation; converts choices to human-readable representation, and for foreign keys gets the referenced object instance
- property subform_field_pairs: Iterator[tuple[Subform, Sequence[str]]]
Iterates subforms paired with a set of field names in that subform
- subforms_by_observation
Dictionary mapping observation ids to set of sub-subforms in that observation
- values
- class dashboard_widgets.widgets.ward_heatmap.WardSubformHeatmapWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
A heatmap mapping each subform against each ward Each cell shows compliance for the ward in context of single subform
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- config_defaults: dict[str, str | int | list | bool] = {'overall_compliance': False, 'pivoted': False, 'show_count_on_audit_form': True}
default values to be set in widget model’s config when initially created.
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
Gets config schema for the specified custom dashboard widget. Override this method to further configure the schema per widget config if needed.
- single_custom_form_with_weighted_compliance
Returns true if the widget is form specific and that form uses observation or subobservation weighted compliance.
Summary widgets
- class dashboard_widgets.widgets.report_summary.PublicReportSummaryWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- is_empty() bool
Tells whether this widget has data to display To be overridden by subclasses to decide whether No Data placeholder should show
- property session_multi_ward_map: set[int]
Set of session ids whose observations span multiple wards.
- property ward_multi_map: dict[int, bool]
Map of ward id -> whether any of its sessions has observations in multiple wards.
- property ward_labels: list[str]
List of ward display labels with a suffix for those that span multiple wards. Example: [“Ward 1 (has multiple wards)”, “Ward 2”]
- get_context_data()
Build the template context for the public report summary widget.
Prepares per-ward multi-ward indicators, ward labels with suffixes where sessions span multiple wards, and aggregate figures for display.
- Note:
Ward IDs are used internally to avoid name collisions across institutions. Ward labels are sorted by name for stable output.
- Returns:
Context dictionary with ward names, auditors, observation/form counts, institution, and time span
- class dashboard_widgets.widgets.report_summary.SingleStatWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
Renders a single value aggregated from observations in the form.
Config options:
- field_name
Custom field to use
- message
Message to show under the value
- operator
Operator used to aggregate data, for example:
sum,mean. This config option is only used ifanswer_to_countis not set.- stat_format
Formatter function to format the value for display. Possible values are:
seconds_to_time_stringto useseconds_to_time_string(). If not provided, useshumanize_number().- stat_formatter_kwargs: dict
Keyword arguments to pass to
stat_format- prefix: str
Text to be prepended to the value
- suffix: str
Suffix to be appended to the value
- answer_to_count: str
Count how many observations have this answer. When provided, instead of using the field’s answer itself as a value, the widget will show how many observations have this value.
Example appearance:
+-------------------------------------------+ | Single stat : | | | | 10 months, 4 weeks | | | | Total Time Difference | | | +-------------------------------------------+
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- property answer_to_count: str | None
Answer the value to count how many observations have this answer.
- property operator: Aggregate | None
Aggregation operator
- property stat_formatter_kwargs: dict
Any keyword arguments that are supported by the chosen stat_formatter method.
- resolve_field_values(field: str | dict | int | float) str | int | bool | list | float | None
Resolves value of a field if input is a string, or using the passed value if its numeric
- Parameters:
field – field name, a value, or calculation expression
- Returns:
calculated value
- get_context_data() Dict[str, Any]
Context data for rendered widget template
- showing_time_string() bool
Provide context that the widget is displaying time. Time displays have a different css class compared to integer values
- class dashboard_widgets.widgets.report_summary.NetPromoterScoreWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
Widget for displaying Net Promoter Score (NPS) in dashboards NPS = Total % of promoters – total % of detractors
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- get_net_promoter_score() tuple[int, bool]
Calculates the net promoter score based on the number of promoter values and detractor values. Also determines if the widget has no data to compute the NPS score (empty).
- Returns:
tuple[int, bool] - NPS, and True if there’s no data
- get_context_data() Dict[str, Any]
Context data for rendered widget template
- class dashboard_widgets.widgets.report_summary.TimeTrackingSummaryWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
Reports on the average time taken to perform specific actions on observations. Widget implemented in Task #24426
For example, show the time taken to view an observation after it has been created. Also allows for tracking time taken to give an observation a particular answer value. This would be useful in the case of an incident where you want to track the time taken to close an incident.
Example configuration:
{ "start_time": {"time_viewed": ""}, "end_time": {"int_field": 20}, "metric_verb": "Updated" }
- start_time
The time that a particular action was performed on an observation. This can be when it was created, updated, viewed, reviewed, or updated with a particular field/answer combination.
- end_time
The time that a particular action was performed on an observation. This can be when it was created, updated, viewed, reviewed, or updated with a particular field/answer combination.
- metric_verb
Used in the widget frontend to describe the activity that’s being tracked. The default is “Viewed” (the time taken to view an observation after creation).
Possible values for
start_timeandend_time:{"time_created": ""}The time that the observation was created.{"time_viewed": ""}The first time the observation was viewed by anybody.{"time_changed": ""}The first time that the observation was changed by anybody.{"time_reviewed": ""}The first time that the observation was reviewed by anybody.{"field_name": "answer"}The first time that the observation was updated with a particular field/answer combination.
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- showing_time_string() bool
Provide context that the widget is displaying time. Time displays have a different css class compared to integer values
- class dashboard_widgets.widgets.report_summary.ObservationCountWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- allow_download = False
whether this widget should have “download as image” option
- is_compact()
Returns wheter this widget will be compact or standard. Compact widgets have a minimum height which is half of a standard widget
QIP widgets
- class dashboard_widgets.widgets.qip_stackedbar_chart.ValueColorMapMixin
Map specific values to use specific colors in chart
- property value_color_map: dict[Any, str]
- Returns:
a dictionary mapping of Value -> Color
- class dashboard_widgets.widgets.qip_stackedbar_chart.QipStackedBarWidget(*, widget_config: 'WidgetConfig' | None = None, request: HttpRequest | None = None, forms: AuditForm | Iterable[AuditForm] | None = None, observations: ObservationQuerySet | None = None, filters: OverviewFilterForm | None = None, user_config: dict[str, Any] | None = None, **kwargs)
A Stacked bar chart widget that renders two dimensions of QIP issues. The two fields are configured using
field_namesconfig, and the bar chart reflects how many issues ain each category.For example, to render a bar chart showing a count of issues per ward and per status with customized colours:
{ "colors": ["green", "orange", "red"], "field_names": [ "ward", "status" ] }
- Parameters:
widget_config –
WidgetConfiginstance if this widget is being instantiated from a custom widget.request – current HTTP request. This is usually passed in if widget is being rendered for dashboard, but can be
Nonewhen under test.forms – current form, or multiple forms. If left blank, forms can still be inferred from
filtersif supplied.observations – optional qs of observations pre-filter. If not specified,
AuditForm.entriesis used. If specified, it is expected that all observations belong to the selected audit form(s)filters – when present, observations will be filtered. This is present for dashboards that have filter. In places without filter (submission report), this will be
Null.user_config – config dictionary, will override options in
widget_config.config.
- config_defaults: dict[str, str | int | list | bool] = {'value_color_map': {}}
default values to be set in widget model’s config when initially created.
- classmethod get_config_schema(widget_config: WidgetConfig) SchemaDict
Gets config schema for the specified custom dashboard widget. Override this method to further configure the schema per widget config if needed.
- property value_color_map: dict[Any, str]
Update the value_colour_map from the widget’s config to be locale agnostic. For each QIP Status, look at each translation of the label and see if there is an entry in the existing value_color_map. If an entry is found for any translation of a QIP Status’ label, copy that entry to the current translation of that QIP Status’ label.
- Returns:
a dictionary mapping of Value -> Color
- build_dataframe(field_name1: str, field_name2: str) DataFrame
Builds an aggregated DataFrame with columns [field_name1, field_name2, ‘count’] using SQL-level aggregation instead of fetching all observation rows.
- get_field(name: str) CustomField | Field
Gets field by name
- Returns:
Hardcoded or custom field
- Raises:
KeyError – if the field does not exist