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

References/Condition

From OHC Network Wiki
referenceclinicalFHIR: ConditionCARE 3.0+

A Condition records a clinical problem, diagnosis, or symptom against a patient. It maps to the FHIR Condition resource and shows up in the Care product UI as Symptoms.

Source:

A Condition lives across two layers, and the split matters when you read the code:

  • The Django model (care/emr/models/condition.py) is storage. Its coded and timing fields (code, body_site, onset, abatement) are opaque JSONFields — the model says nothing about their shape.
  • The Pydantic resource specs (care/emr/resources/condition/spec.py) are the API. They define the enums, the structure inside each JSON field, field validation, the value-set binding for code, and the separate read and write schemas.

Models

Model Purpose
Condition A clinical condition, problem, diagnosis, or symptom recorded for a patient

Condition extends EMRBaseModel, the shared Care EMR base that provides external_id, created_date/modified_date, soft-delete via deleted, created_by/updated_by, and history/meta JSON.

Condition fields

Status & classification

Field Type Notes

{{Field|model=Condition|section=Status & classification|name=clinical_status|type=CharField(100), nullable|notes=Clinical state. Spec binds to [[#clinicalstatuschoices-values}} {{Field|model=Condition|section=Status & classification|name=verification_status|type=CharField(100), nullable|notes=Level of certainty. Spec binds to [[#verificationstatuschoices-values}} {{Field|model=Condition|section=Status & classification|name=category|type=CharField(100), nullable|notes=Classification. Spec binds to [[#categorychoices-values}} {{Field|model=Condition|section=Status & classification|name=severity|type=CharField(100), nullable|notes=Subjective severity. Spec binds to [[#severitychoices-values}}

Coded concepts

Field Type Notes

{{Field|model=Condition|section=Coded concepts|name=code|type=JSONField (default=dict, not null/blank)|notes=The condition itself. On write, a single [[#coding-shape}}

body_site JSONField (default=dict, not null/blank) Anatomical location(s). Exists on the model but no current spec exposes it — never written or read through the standard Condition API.

Timing

Field Type Notes

{{Field|model=Condition|section=Timing|name=onset|type=JSONField (default=dict)|notes=Choice-of-type onset, shaped by [[#conditiononsetspec-onset-shape}} {{Field|model=Condition|section=Timing|name=abatement|type=JSONField (default=dict)|notes=When the condition resolved or went into remission. Shaped by [[#conditionabatementspec-abatement-shape}}

recorded_date DateTimeField, nullable When the condition was first recorded. Not exposed by the current specs.

Context & notes

Field Type Notes
patient FK → Patient, on_delete=CASCADE Subject of the condition. Derived server-side from the encounter on create, never read from the client (__exclude__).
encounter FK → Encounter, nullable, on_delete=CASCADE Encounter the condition was recorded in. Set server-side on create (__exclude__); the client supplies a UUID in the spec, which is validated to exist.
note TextField, nullable Free-text clinical note.

Enums

Every enum is a str, Enum in care/emr/resources/condition/spec.py. The value stored and serialized is the string in the table.

ClinicalStatusChoices values

Value
active
recurrence
relapse
inactive
remission
resolved
unknown

VerificationStatusChoices values

Value
unconfirmed
provisional
differential
confirmed
refuted
entered_in_error

CategoryChoices values

Value
problem_list_item
encounter_diagnosis
chronic_condition

SeverityChoices values

Value
mild
moderate
severe

Nested JSON shapes

These spec classes (all extend EMRResource) are the real structure behind the model's JSON fields.

ConditionOnSetSpec (onset shape)

Field Type Default Notes
onset_datetime datetime None
onset_age int None
onset_string str None
note str None

ConditionAbatementSpec (abatement shape)

Field Type Default Notes
abatement_datetime datetime None
abatement_age int None
abatement_string str None
note str None

Coding shape

code is a single [https://github.com/ohcnetwork/care/blob/develop/care/emr/resources/common/coding.py Coding], not a CodeableConcept. extra="forbid".

Field Type Notes
system str Code system URI (e.g. http://snomed.info/sct).
version str Code system version.
code str Required. The code value.
display str Human-readable label.

code value-set binding

On write, code is typed ValueSetBoundCoding[CARE_CODITION_CODE_VALUESET.slug] — a Coding checked against the Condition code value set (care/emr/resources/condition/valueset.py, slug system-condition-code), which covers SNOMED CT concepts that are is-a 404684003 (Clinical finding). Codes outside it are rejected on ConditionSpec, ConditionUpdateSpec, and ChronicConditionUpdateSpec. The read spec falls back to a plain Coding and skips value-set validation, so reads stay cheap.

Resource specs (API schema)

Every spec extends BaseConditionSpecEMRResource and round-trips through serialize (DB → Pydantic) and de_serialize (Pydantic → DB). BaseConditionSpec sets __model__ = Condition, sets __exclude__ = ["patient", "encounter"] (both server-maintained, never trusted from the client), and exposes id: UUID4.

Spec class Role Exposes / behaviour
BaseConditionSpec shared base id; excludes patient and encounter from direct mapping.
ConditionSpec write · create clinical_status?, verification_status (required), severity?, code (value-set bound, required), encounter (UUID4, required), onset (={}), abatement (={}), note?, category (required). Validates that the encounter exists; on create sets obj.encounter and obj.patient = encounter.patient.
ConditionUpdateSpec write · update clinical_status?, verification_status (required), severity?, code (value-set bound, required), onset (={}), abatement (={}), note?. Does not accept encounter, category, or patient.
ChronicConditionUpdateSpec write · update (chronic) Extends ConditionUpdateSpec and adds encounter (UUID4). On deserialize, if encounter is set, resolves it (get_object_or_404) and assigns obj.encounter.
ConditionReadSpec read · detail/list clinical_status, verification_status, category, criticality, severity (all plain str), code (plain Coding), encounter (UUID4), onset, abatement, created_by?, updated_by?, note?, created_date, modified_date.

Validation & server-side behaviour

  • Encounter is required and verified on create. ConditionSpec.validate_encounter_exists rejects unknown encounter UUIDs; perform_extra_deserialization (create only) loads the encounter and derives patient from it. Clients never set patient or encounter directly.
  • verification_status is mandatory on both ConditionSpec and ConditionUpdateSpec; category is mandatory only on create (ConditionSpec).
  • code must belong to the bound value set (SNOMED CT clinical findings) on every write spec.
  • onset_datetime cannot be in the future and is forced timezone-aware; abatement_datetime carries no such constraint.
  • ConditionReadSpec exposes criticality, a string in the read schema with no backing column on the Condition model. The standard serializer never populates it, so it comes back unset.
  • Read serialization (perform_extra_serialization) maps id = external_id, replaces encounter with its external_id, and expands created_by/updated_by via serialize_audit_users (cached UserSpec).
  • body_site and recorded_date exist on the model but no current spec reads or writes them — storage-only, outside the standard Condition API surface.

Condition links to two clinical records:

patient   → FK Patient   (CASCADE, server-derived from encounter)
encounter → FK Encounter (CASCADE, nullable; required on create)

Deleting a Patient or Encounter cascades to its Condition rows. The column allows a null encounter, but the standard create flow always supplies one and derives patient from it.

Methods & save behaviour

  • serialize(obj) and de_serialize(obj) (from EMRResource) convert between the Condition model and the spec. Field mapping uses the model's non-FK column names; __exclude__ (patient, encounter) and id/external_id are skipped during deserialization.
  • ConditionSpec.perform_extra_deserialization(is_update=False, obj) — create path: resolves the encounter and sets obj.patient = obj.encounter.patient.
  • ChronicConditionUpdateSpec.perform_extra_deserialization — resolves and assigns encounter when provided.
  • ConditionReadSpec.perform_extra_serialization — sets id/encounter external ids and serializes audit users.
  • external_id, audit fields, meta/history, and soft-delete (deleted) are platform-maintained via EMRBaseModel.

API integration notes

  • Send code as a structured Coding ({system, code, display}) drawn from the SNOMED CT clinical-finding value set, not as free text. Always include verification_status; add category and encounter when creating.
  • onset and abatement are structured choice-of-type objects (*_datetime, *_age, *_string, note), not arbitrary JSON. onset_datetime must be timezone-aware and not in the future.
  • Don't send patient, external_id, audit fields, or deleted from the client — the server owns them.

Pages that link here:

Wiki: ohcnwiki.tellmey.fyi