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:

StandaloneDashboardWidgetMixin

Makes 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

ConfigSchemaWidgetMixin

Allows 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

WidgetPermissionsMixin

Allows implementing widgets to specify permissions required to use the widget. If user does not have the required permissions, the widget will not display.

ActionMenuMixin

Adds menu options to the widget. This is included by default in BaseDashboardWidget.

TimeGranularityWidgetMixin

For time-scale / over-time widgets, allows user to specify time granularity (defined in SUPPORTED_GRANULARITIES) and exposes granularity property 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 BaseDashboardWidget that 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 with action_

get_menu_options() Iterator[WidgetMenuOption]

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

ID used to create cookie to persist frozen/unfrozen table header. A widget configs pk is used if availible as it is stable.

Expiry for widgets cookie in days. If using a fixed id (widget_config_id) set to a long expiry otherwise short

get_menu_options() Iterator[WidgetMenuOption]

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_form is True, this is expected to hold exactly one form

property audit_form: AuditForm

Gets single form instance if is_single_form is 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 reloadWithDynamicFieldSet js 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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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_config instance 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 None is 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., None otherwise

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_defaults ensure that values in it are valid values for the respective config field type. For instance, for a list field, a valid empty value is [], but not None.

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 PermissionRequiredMixin view 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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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
get_table_rows() Iterator[TableRow]

Yields values as table rows to be rendered underneath the chart in full-size view

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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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

get_table_rows() Iterator[TableRow]

Yields values as table rows to be rendered underneath the chart in full-size view

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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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

get_table_rows() Iterator[TableRow]

Yields values as table rows to be rendered underneath the chart in full-size view

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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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

static from_dataframe(df: DataFrame) Iterator[TableRow]

Converts rows in the dataframe to table rows index is ignored.

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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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

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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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

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_rate option 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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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.Issue objects with most common ‘comment’ value.

Parameters:
  • widget_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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 dataframe property.

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_time and end_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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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_table is True.

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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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.

generate_rows(page: int | None = None, page_size: int | None = None) Iterator[TableRow]

Returns generator of row items

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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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 dataframe property.

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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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 Ward

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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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 Accreditation config specified in the config. Implemented in Task #26592, only supports customn observations.

Parameters:
  • widget_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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:
  1. Retrieves observation data with timestamps

  2. Filters for the configured subform

  3. Collects compliance data for matching observations

  4. Orders field by order and swaps field names for labels then joins datasets

  5. Applies time grouping based on configured granularity

  6. Calculates mean compliance scores and observation counts

  7. 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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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_name and field_name_top) And represents compliance for each combination of values in those fields. The selected fields are wrapped in HeatmapField that 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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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, and show_count_on_audit_form properties.

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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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 if answer_to_count is not set.

stat_format

Formatter function to format the value for display. Possible values are: seconds_to_time_string to use seconds_to_time_string(). If not provided, uses humanize_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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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_time and end_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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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_names config, 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_configWidgetConfig instance 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 None when under test.

  • forms – current form, or multiple forms. If left blank, forms can still be inferred from filters if supplied.

  • observations – optional qs of observations pre-filter. If not specified, AuditForm.entries is 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