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
- render() str
Renders widget’s html and js content in-line
- Returns:
rendered html as text
- render_error(error: Exception) str
Renders error widget in place of this widget
- 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
- 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'] | Literal['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[dashboard_widgets.widgets.types.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
- 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, Union[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(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)
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[Union[int, float, NoneType], Union[str, datetime.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[Union[int, float, NoneType], Union[str, datetime.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[dashboard_widgets.widgets.chart.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[Union[int, float, NoneType], Union[str, datetime.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[Union[int, float, NoneType], Union[str, datetime.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[Union[int, float, NoneType], Union[str, datetime.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.
- property annotate_compliance: bool
Whether to annotate the observation queryset with compliance value
- 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[Union[int, float, NoneType], Union[str, datetime.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[Union[int, float, NoneType]]
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.
- 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
- 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.
- use_average
- 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[dashboard_widgets.widgets.types.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[dashboard_widgets.widgets.chart.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.
- property annotate_compliance: bool
Whether to annotate the observation queryset with compliance value
- field_weights
maps field names to their compliance weights
- compliance_calculator
returns func that takes observation and returns its compliance with respect to the widget’s fields config
- property counter_logic_calculator: Callable[[BaseAuditModel], int | float | None]
Returns a calable which returns observation counts or audit counts depending on counter logic. Audit counts are calculated by counting one on the first session ID then 0 for consecutive calls for observations with the same session ID
- Returns:
A callable function that takes an Observation instance and returns an integer (1 or 0) to be used as a counter.
- property value_calculator: Callable[[BaseAuditModel], int | float | None]
Callable that takes observation and returns value associated with the observation.
- property use_average: bool | str
Whether values for the same index should be summed, or calculated average. For instance, when calculating compliance, we want to take average compliance for the day. But for a value field, user may want to see the sum of values in the day. Other values than true/false are possible (INT_AVERAGE)
- values
- get_annotation_options() dict
Options for the annotation plugin https://github.com/chartjs/chartjs-plugin-annotation#configuration
- get_labels(*args, **kwargs) list[Union[str, datetime.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.
- 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.
- compliance_calculator
- 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.
- property value_calculator: Callable[[BaseAuditModel], int | float | None]
Callable that takes observation and returns value associated with the observation.
- 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[Union[int, float, NoneType], Union[str, datetime.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[dashboard_widgets.widgets.chart.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
Tells whether this widget has data to display To be overridden by subclasses to decide whether No Data placeholder should show
- 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 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.
- 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).
- 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.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[Union[megforms.models.BaseAuditModel, megforms.models.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. Always uses 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[django.db.models.expressions.F, django.db.models.expressions.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, datetime.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.
- 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.
- 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)
A table widget with an optional HeatMap option that displays compliance over time (in columns) per
Department.Example appearance:
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
- 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.
- get_grouper_label(grouper_field_name: str) str
Gets display label for field name (hard coded or custom field).
- property trend_indicator: bool
Whether to show trending arrow beside compliance figure
- property score_by_custom_field: CustomField | None
Validate that score_by custom field exists and valid otherwise raise DashboardConfigError
- compliance_with_summation_aggregator(grouped_df: DataFrame) Series
Computes summed compliance using the formula copied from the backend calculation sum of all compliance * weight / sum of weights
- mean_compliance_aggregator(grouped_df: DataFrame) Series
Averages compliance and adds count by either number of sessions or observations (counter_logic)
- property propagate_weight: bool
Whether field weight should be reflected in observation weight
- observation_sub_obs_compliance_aggregator(grouped_df: DataFrame) Series
Designed to mimic the get_subform_compliance function from
ComplianceGetter. Specifically used to mimic how multipe sub observation of one subform in one observation are aggregated into one value for that subform & observation.A weighted average of the compliance using the field weights is first applied (if multiple). If the subform has weights that weight is propegated for all case bar question level compliance where a weight if 1 is propegated. If the subform has no weights in all cases a sum of the field weights is propegated
- 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 time_grouper: Grouper
Returns a pandas Grouper for time-series aggregation.
The Grouper is configured using the instance’s date filter field and granularity.
- Returns:
A pandas Grouper object ready for use in groupby operations.
- process_time_field(qs_dataframe: DataFrame) DataFrame
Prepares the datetime field for widget rendering.
Converts the primary datetime field to a local, timezone-naive representation. This format is required for rendering the widget. It also handles initial parsing if a custom date field is in use.
- Parameters:
qs_dataframe – The input DataFrame with the datetime field.
- Returns:
The DataFrame with the datetime field formatted for rendering.
- get_average_df_label(label: str, df: DataFrame) MultiIndex
Creates a MultiIndex for the summary row. Places the label in the first level (Level 0) and pads the rest with empty strings.
- apply_average_scores(qs_dataframe: DataFrame) DataFrame
Adds a simple average row to the DataFrame.
- apply_total_compliance(qs_dataframe: DataFrame, total_compliance_row: DataFrame, final_row_name: str | None = None) DataFrame
Adds a precomputed total compliance row to the DataFrame.
- create_total_compliance_row(qs_dataframe: DataFrame, dont_groupby_observation: bool = False) DataFrame
Calculates the final row of the dataframe, for use when using weighted compliance instead of a simple average
- format_index(value: Any) str
Format a DataFrame index/column label for display.
- 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)
- 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.
- 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 dataframe: DataFrame
Creates a DataFrame containing subform field compliance scores & counts.
- The method:
Retrieves observation data with timestamps
Filters for the configured subform
Collects compliance data for matching observations
Orders field by order and swaps field names for labels then joins datasets
Applies time grouping based on configured granularity
Calculates mean compliance scores and observation counts
Generates summary statistics (averages and totals)
For the final row (7) depending we want the row to match the row in Audit Scores for this subform. So Instead of using the question level compliance we need to get the subobservation level compliance. The ObservationCompliance contains this info (‘subform_compliance’) so this is also fetched and aggregated into a simple average or weighted average to construct the final row.
- Returns:
A multi-index DataFrame with: Columns as time periods and metrics (compliance/count), rows as field (question) metrics
- 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
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.
- 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.
- format_index(value: Any) str
Override to show custom field labels when available (handles duplicate indices safely) as per task: 32155
- property dataframe: DataFrame
Creates a DataFrame containing form field compliance scores & counts.
- Returns:
A multi-index DataFrame with: Columns as time periods and metrics (compliance/count), rows as field (question) metrics
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
Union[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[Union[str,int,bool,list,float,date,time,datetime,None,Model,ObservationFile,HeatmapField],Union[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 = ComplianceLevels(pass_first=0.9, pass_second=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 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[Union[str,int,bool,list,float,date,time,datetime,None,Model,ObservationFile,HeatmapField],Union[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 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[megforms.models.AuditForm, megforms.models.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': ''}
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
- 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