References/Medication Statement
More languages
More actions
A MedicationStatement records a medication the patient is taking, has taken, or intends to take, as reported by the patient, a relative, or a clinician rather than actively prescribed or dispensed. Reach for it when you're capturing a medication history rather than driving an order. It aligns with the FHIR MedicationStatement resource.
The Django model stores medication and effective_period as opaque JSONFields. Their real structure comes from the Pydantic resource specs in care/emr/resources/medication/statement/, which define the enums, nested JSON shapes, validation, the value-set binding on medication, and the read/write API schemas. This page covers both layers.
Source:
- Model: [https://github.com/ohcnetwork/care/blob/develop/care/emr/models/medication_statement.py
care/emr/models/medication_statement.py] - Spec: [https://github.com/ohcnetwork/care/blob/develop/care/emr/resources/medication/statement/spec.py
care/emr/resources/medication/statement/spec.py] - Value set: [https://github.com/ohcnetwork/care/blob/develop/care/emr/resources/medication/valueset/medication.py
care/emr/resources/medication/valueset/medication.py]
Models
| Model | Purpose |
|---|---|
MedicationStatement
|
A record of a medication the patient is taking, has taken, or intends to take — as reported rather than actively prescribed |
MedicationStatement extends EMRBaseModel, the shared Care EMR base that supplies external_id, audit fields created_by/updated_by, created_date/modified_date, history/meta JSON, and soft-delete semantics.
MedicationStatement fields
Type is the Django storage type. Spec shape is the structured shape the Pydantic resource spec enforces when reading and writing over the API.
Statement details
| Field | Type | Spec shape | Notes |
|---|---|---|---|
status |
CharField(100) |
MedicationStatementStatus enum
| |
reason |
CharField(100) |
str
| |
medication |
JSONField (default=dict) |
Coding bound to the system-medication value set
| |
information_source |
CharField(100) |
MedicationStatementInformationSourceType enum
| |
effective_period |
JSONField (default=dict) |
PeriodSpec
| |
dosage_text |
TextField |
str
| |
note |
TextField |
str
|
Relationships
| Field | Type | Notes |
|---|---|---|
patient |
FK → Patient |
on_delete=CASCADE. The patient the statement is about. Derived server-side from the encounter — never accepted from clients.
|
encounter |
FK → Encounter |
on_delete=CASCADE. The encounter the statement was recorded in. Supplied as a UUID on create.
|
patient → FK Patient (CASCADE)
encounter → FK Encounter (CASCADE)
Deleting a patient or encounter deletes its medication statements.
Enum values
MedicationStatementStatus values
MedicationStatementStatus(str, Enum) in spec.py, bound to status.
| Value | Meaning |
|---|---|
active
|
The medication is being taken |
on_hold
|
Taking has been paused |
completed
|
The course has finished |
stopped
|
The medication was stopped |
unknown
|
Status is not known |
entered_in_error
|
The record was entered in error |
not_taken
|
The patient is not taking the medication |
intended
|
The patient intends to take the medication |
MedicationStatementInformationSourceType values
MedicationStatementInformationSourceType(str, Enum) in spec.py, bound to information_source.
| Value | Meaning |
|---|---|
related_person
|
A relative or related person reported it |
practitioner
|
A clinician reported it |
patient
|
The patient self-reported it |
Nested JSON shapes
Coding shape
medication is stored as JSON but typed as a single Coding (from care/emr/resources/common/coding.py), not a CodeableConcept. The spec sets extra="forbid", so unrecognized keys are rejected.
| Field | Type | Notes |
|---|---|---|
system |
str |
Code system URI (e.g. http://snomed.info/sct)
|
version |
str |
Code-system version |
code |
str |
Required. Validated against the bound value set |
display |
str |
Human-readable label |
Bound value set
medication is declared as ValueSetBoundCoding[CARE_MEDICATION_VALUESET.slug]. On write, code is validated against the system-medication value set ([https://github.com/ohcnetwork/care/blob/develop/care/emr/resources/medication/valueset/medication.py medication.py]), which includes SNOMED CT concepts under the constraint << 763158003 |Medicinal product|. Any code outside the set is rejected.
The
care/emr/resources/medication/valueset/directory holds further value sets for other medication resources (route, body site, administration method, additional instruction, as-needed reason, medication-not-given reason).MedicationStatementbinds onlymedication→system-medication.
PeriodSpec shape
effective_period is stored as JSON but typed as PeriodSpec (from care/emr/resources/base.py).
| Field | Type | Notes |
|---|---|---|
start |
datetime |
Must be timezone-aware if present; naive datetimes are rejected |
end |
datetime |
Must be timezone-aware if present |
validate_period (mode after) rejects a naive start/end and requires start to be no greater than end.
Resource specs (API schema)
Every spec subclasses EMRResource (care/emr/resources/base.py), which provides serialize (DB object → pydantic) and de_serialize (pydantic → DB object). __model__ = MedicationStatement, and __exclude__ = ["patient", "encounter"] holds those two fields out of the generic field copy so the extra hooks set them instead.
| Spec class | Role | Fields exposed |
|---|---|---|
BaseMedicationStatementSpec
|
shared base | id, status, reason, medication, dosage_text, effective_period, encounter, information_source, note
|
MedicationStatementSpec
|
write · create | Inherits BaseMedicationStatementSpec; adds encounter existence validation + extra deserialization
|
MedicationStatementUpdateSpec
|
write · update | status, effective_period, note only
|
MedicationStatementReadSpec
|
read · list & detail | Inherits base; adds created_by, updated_by (UserSpec), created_date, modified_date
|
What the specs validate and maintain on your behalf:
encountermust exist —MedicationStatementSpec.validate_encounter_exists, afield_validatoronencounter, raises"Encounter not found"unless anEncounterwith thatexternal_idexists.patientis derived server-side —MedicationStatementSpec.perform_extra_deserializationruns only on create (is_updatefalse): it resolves theEncounterfrom the supplied UUID and setsobj.patient = obj.encounter.patient. Clients never sendpatient.- Updates are narrow —
MedicationStatementUpdateSpecaccepts onlystatus,effective_period, andnote.medication,reason,dosage_text,information_source, andencountercan't be changed through it. - Read serialization —
MedicationStatementReadSpec.perform_extra_serializationsetsid = obj.external_id,encounter = obj.encounter.external_id, and serializes audit users viaserialize_audit_users(created_by/updated_byasUserSpec). medicationvalue-set check — runs at validation time againstCoding.code(see Bound value set).effective_periodtz-awareness and ordering — enforced byPeriodSpec(seePeriodSpecshape).
There is no status_history. status is a single current value, not an appended log.
Methods & save behaviour
- From
EMRBaseModel:external_id(UUID), audit fields, soft delete. Deletes are soft — a removed statement stays in the table withdeleted=Trueand is hidden by the default manager. - Create flow: client sends
MedicationStatementSpec→de_serializecopies scalar/JSON fields →perform_extra_deserializationresolvesencounterand back-fillspatient→ model saved. - Read flow:
MedicationStatementReadSpec.serialize(obj)copies fields, thenperform_extra_serializationinjectsid,encounter(as UUIDs), and audit users.
API integration notes
- Exposed through Care's REST API, aligned with FHIR
MedicationStatement. Use the spec field names above for payloads. medicationis a single SNOMED CTCodingobject whosecodemust be in thesystem-medicationvalue set — not a free CodeableConcept, and not a scalar string.effective_perioddatetimes must be timezone-aware and ordered (start ≤ end).encountergoes in as a UUID;patientis derived from it server-side and must not be sent.- Updates flow through
MedicationStatementUpdateSpecand can touch onlystatus,effective_period, andnote. information_sourceis what separates a self-reported or third-party statement from an actively managed prescription (MedicationRequest).external_id(UUID),created_by/updated_by,created_date/modified_date,history, andmetaare platform-maintained — don't set them from clients.
Related
Pages that link here:
- Reference: References/Base models & conventions