Toggle menu
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.

References/Questionnaire

From OHC Network Wiki
referencedefinitionsCARE 3.0+

A Questionnaire is a versioned, FHIR-inspired form: a tree of questions answered about a patient or an encounter. You touch it whenever you define a data-collection form, render one for filling, or submit answers — which can flow back out as Observations. It captures both clinical data and arbitrary non-clinical structured data.

The Django model is only the storage layer. The API schema you code against lives in the Pydantic resource specs under care/emr/resources/questionnaire*: enums, the nested shape of the JSON fields, validation, and the split between read and write contracts.

Source (model): [https://github.com/ohcnetwork/care/blob/develop/care/emr/models/questionnaire.py care/emr/models/questionnaire.py]

Source (specs): [https://github.com/ohcnetwork/care/blob/develop/care/emr/resources/questionnaire/spec.py resources/questionnaire/spec.py] · [https://github.com/ohcnetwork/care/blob/develop/care/emr/resources/questionnaire/utils.py resources/questionnaire/utils.py] · [https://github.com/ohcnetwork/care/blob/develop/care/emr/resources/questionnaire/questionnaire_organization.py resources/questionnaire/questionnaire_organization.py] · [https://github.com/ohcnetwork/care/blob/develop/care/emr/resources/questionnaire_response/spec.py resources/questionnaire_response/spec.py] · [https://github.com/ohcnetwork/care/blob/develop/care/emr/resources/questionnaire_response_template/spec.py resources/questionnaire_response_template/spec.py] · [https://github.com/ohcnetwork/care/blob/develop/care/emr/resources/form_submission/spec.py resources/form_submission/spec.py]

Models

Six models back the forms feature. The Questionnaire is the definition; everything else records submissions, answers, organization scope, or reusable prefill.

Model Purpose
Questionnaire A versioned form definition: questions, styling, subject type, and status
FormSubmission A submission of a questionnaire against a patient (and optional encounter)
QuestionnaireResponse A stored set of answers for a subject, optionally tied to a submission
QuestionnaireOrganization Scopes a questionnaire to an instance-level Organization
QuestionnaireFacilityOrganization Scopes a questionnaire to a FacilityOrganization
QuestionnaireResponseTemplate Reusable prefill template for questionnaire responses

All extend EMRBaseModel, which supplies external_id, audit fields, and soft-delete semantics.

Questionnaire fields

Definition

Field Type Req Notes
version CharField(255) yes
slug CharField(255) yes
title CharField(255) yes
description TextField no
subject_type CharField(255) yes
status CharField(255) yes
styling_metadata JSONField no
questions JSONField yes
organization_cache ArrayField[int]
internal_organization_cache ArrayField[int]

The write spec also carries a type: str field (default "custom") that has no backing model column.

Organization scope caches

organization_cache and internal_organization_cache hold flattened organization IDs so access filtering can run without deep joins. The through-models below own them; clients never write them directly.

Field Maintained by
organization_cache QuestionnaireOrganization.sync_questionnaire_cache() — instance Organization IDs plus each org's parent_cache
internal_organization_cache QuestionnaireFacilityOrganization.sync_questionnaire_cache()FacilityOrganization IDs plus each org's parent_cache

Enum values

QuestionnaireStatus values

The lifecycle state of the definition, modeled on FHIR publication-status. Once a questionnaire is active, edit and delete are off the table — move it to retired instead.

Value
active
retired
draft

SubjectType values

What kind of resource the form is about. This drives whether an encounter is required at submit time.

Value
patient
encounter

QuestionType values

The type of each question (Question.type). The commented-out members open_choice, attachment, and reference are not implemented.

Value Notes
group Container; must have ≥1 sub-question
boolean Validated against true/false/1/0 on submit
decimal
integer
string
text Length capped by settings.MAX_QUESTIONNAIRE_TEXT_RESPONSE_SIZE on submit
display Display-only, no answer
date ISO date
dateTime Must include timezone on submit
time %H:%M:%S
choice Requires answer_option or answer_value_set
url Must have scheme + netloc
quantity Requires answer_option or answer_value_set; answers need a unit
structured Skipped by response validation

EnableOperator values

The comparison for an enable_when condition (EnableWhen.operator).

Value
exists
equals
not_equals
greater
less
greater_or_equals
less_or_equals

EnableBehavior values

How multiple enable_when conditions combine (Question.enable_behavior).

Value Meaning
all Enable only if all conditions pass (default on submit)
any Enable if any condition passes

DisabledDisplay values

How a disabled question renders (Question.disabled_display).

Value
hidden
protected

AnswerConstraint values

Whether free input outside the options is allowed (Question.answer_constraint).

Value
required
optional

QuestionnaireResponseStatusChoices values

QuestionnaireResponse.status (model default "completed").

Value
completed
entered_in_error

FormSubmissionStatusChoices values

FormSubmission.status.

Value
draft
submitted
entered_in_error

Question nested shape

Questionnaire.questions is an opaque JSONField, but the API contract is a recursive list of Question (QuestionnaireBaseSpec). Fields, with their real types and validation:

Field Type Req Default Notes
link_id str yes
id UUID4 no
code Coding bound to value set system-observation no
collect_time bool no
collect_performer bool no
text str yes
description str no
type QuestionType yes
structured_type str no
enable_when list[EnableWhen] no
enable_behavior EnableBehavior no
disabled_display DisabledDisplay no
collect_body_site bool no
collect_method bool no
required bool no
repeats bool no
read_only bool no
max_length int no
answer_constraint AnswerConstraint no
answer_option list[AnswerOption] no
answer_value_set str no
is_observation bool no
unit Coding bound to value set system-ucum-units no
questions list[Question] no
formula str no
styling_metadata dict no
templates list[TemplateConfig] no
is_component bool no

A model_validator (mode after) enforces three rules:

  • choice / quantity types must have answer_option or answer_value_set.
  • group types must have at least one sub-question.
  • answer_value_set, when set, must reference an existing ValueSet.

Sub-specs of Question

Spec Shape
EnableWhen { question: str (link_id), operator: EnableOperator, answer: Any }
AnswerOption { value: Any (non-blank, stripped), initial_selected: bool = false }
Performer None, text: str | None }
TemplateConfig None, meta: dict | None }

Resource specs (API schema)

Every spec builds on EMRResource, which provides serialize / de_serialize. Read specs run perform_extra_serialization; write specs run perform_extra_deserialization.

Questionnaire

Spec Role Key fields / behaviour
QuestionnaireBaseSpec shared __model__ = Questionnaire
QuestionnaireWriteSpec write (base) version (frozen "1.0"), slug (SlugType), title, description, type ("custom"), status, subject_type, styling_metadata, questions. Validates slug uniqueness and that it doesn't shadow internal types, a non-empty title, and unique link_ids and ids across the whole tree
QuestionnaireSpec write · create
Pages that link here: