Skip to main content
Version: 3.0

Medication Administration

MedicationAdministration records that a medication was given to a patient — or that giving it was attempted — fulfilling a MedicationRequest. You write one each time a dose is administered against an order. The Django model is the storage layer; several columns are opaque JSONFields whose structure comes from the Pydantic resource specs in care/emr/resources/medication/administration/. Both layers are documented below.

Source:

Models

ModelPurpose
MedicationAdministrationThe administration event that fulfils a MedicationRequest

MedicationAdministration extends EMRBaseModel, the shared Care EMR base that provides external_id, audit fields, and soft-delete semantics (see Base model). It maps to the FHIR MedicationAdministration resource.

MedicationAdministration fields

Each row lists the storage column type and, where the column is a JSONField, the structured shape the resource spec enforces.

Status & classification

FieldStorageSpec shapeNotes
statusCharField(100)MedicationAdministrationStatus enumRequired. Administration event status — see enum values
status_reasonJSONField (null)Coding bound to system-medication value setOptional. Coded reason for the status. The spec binds this to the medication value set, not the "not given" reason set you might expect
categoryCharField(100) (null)MedicationAdministrationCategory enumOptional. Administration setting — see enum values

Medication & product

FieldStorageSpec shapeNotes
medicationJSONField (default {})Coding bound to system-medication value setOptional in spec. { system, version?, code, display? }. Mutually exclusive with administered_product (model validator)
administered_productFK → ProductKnowledge (null, CASCADE)UUID4 (write) / nested ProductKnowledgeReadSpec (read)Optional. The specific catalog product administered. Cannot be set together with medication
dosageJSONField (null)Dosage nested specOptional. Dose, rate, route, site, and method actually administered — see Dosage

Subject & context

FieldStorageSpec shapeNotes
patientFK → Patient (CASCADE)not in spec (server-derived)The patient who received the medication. Set server-side from the encounter's patient on create — never accepted from the client
encounterFK → Encounter (null, CASCADE)UUID4 (required, write)The encounter during which the medication was administered. Validated to exist; read schema returns the encounter's external_id
requestFK → MedicationRequest (null, CASCADE)UUID4 (required, write)The order this administration fulfils. Validated to exist; read schema returns the request's external_id

Timing & attribution

FieldStorageSpec shapeNotes
authored_onDateTimeField (null)datetimeOptional. When the record was authored, distinct from when the dose was given
occurrence_period_startDateTimeField (default datetime.now)datetime (required)When the administration began. Required on create; defaults to now at the model level
occurrence_period_endDateTimeField (null)datetimeOptional. End of the administration, for infusions and extended doses. Updatable via MedicationAdministrationUpdateSpec
recordedDateTimeField (null)datetimeOptional. When the event was entered into the system, distinct from occurrence_period_start
performerJSONField (default [])list[MedicationAdministrationPerformer]Optional. Actors who performed the administration and their function — see MedicationAdministrationPerformer
noteTextField (null)strOptional. Free-text annotation. Updatable via MedicationAdministrationUpdateSpec

Enum values

MedicationAdministrationStatus values

str enum (care/emr/resources/medication/administration/spec.py). These use underscores (e.g. not_done), not the FHIR hyphenated forms.

Value
completed
not_done
entered_in_error
stopped
in_progress
on_hold
unknown
cancelled

MedicationAdministrationCategory values

Value
inpatient
outpatient
community
discharge

MedicationAdministrationPerformerFunction values

Value
performer
verifier
witness

Nested specs (JSON-field shapes)

Dosage (nested spec)

Structured shape of the dosage JSONField. Every field is optional.

FieldTypeNotes
textstr | NoneFree-text dosage instructions
siteCoding | NoneBound to system-body-site value set (SNOMED CT << 91723000)
routeCoding | NoneBound to system-route value set (SNOMED CT << 284009009)
methodCoding | NoneBound to system-administration-method value set (SNOMED CT << 736665006)
doseQuantity | NoneThe amount of medication administered
rateQuantity | NoneThe speed of administration

Quantity shape (care/emr/resources/common/quantity.py, extra="forbid"): { value: Decimal? (max_digits 20, decimal_places 6), unit: Coding?, code: Coding?, meta: dict? }.

Coding shape (care/emr/resources/common/coding.py, extra="forbid"): { system: str?, version: str?, code: str (required), display: str? }.

MedicationAdministrationPerformer (nested spec)

Element shape of the performer JSONField list.

FieldTypeNotes
actorUUID4 (required)The user who performed the administration. Validated server-side to reference an existing User (field_validator raises "User not found")
functionMedicationAdministrationPerformerFunction | NoneThe performer's function — see enum values

Bound value sets

Coded fields bind to Care system value sets (SNOMED CT). ValueSetBoundCoding rejects any code outside the bound set.

FieldValue setSlugSNOMED CT constraint
medication, status_reasonMedicationsystem-medication<< 763158003 (Medicinal product)
dosage.siteBody Sitesystem-body-siteis-a 91723000
dosage.routeRoutesystem-routeis-a 284009009
dosage.methodAdministration Methodsystem-administration-methodis-a 736665006

Three more medication value sets are defined alongside these but go unreferenced by this resource's specs: Medication Not Given Reason (system-medication-not-given, is-a 242990004 + is-a 182895007), Additional Instruction (system-additional-instruction, is-a 419492006), and As Needed (system-as-needed-reason, is-a 404684003).

Resource specs (API schema)

All specs build on EMRResource (care/emr/resources/base.py), which provides serialize (DB object → read schema) and de_serialize (write schema → DB object), each with a perform_extra_serialization / perform_extra_deserialization hook. __exclude__ lists the fields those hooks handle manually rather than copying field-for-field.

Spec classRoleKey fields / behaviour
BaseMedicationAdministrationSpecshared baseAll common fields: status, status_reason, category, medication, authored_on, occurrence_period_start, occurrence_period_end, recorded, encounter, request, performer, dosage, note. __exclude__ = ["patient", "encounter", "request", "administered_product"]
MedicationAdministrationSpecwrite · createExtends base; adds administered_product: UUID4 | None. Validates encounter and request exist; rejects medication + administered_product set together
MedicationAdministrationUpdateSpecwrite · updateNarrow update schema: only status, note, occurrence_period_end. __exclude__ = ["patient", "encounter", "request"] — those are immutable after create
MedicationAdministrationReadSpecread · detail/listExtends base; adds audit fields created_by, updated_by, created_date, modified_date, and nested administered_product: dict
DosagenestedShape of the dosage JSON field (see above)
MedicationAdministrationPerformernestedElement of the performer JSON list (see above)

Validation rules

  • Mutual exclusion (MedicationAdministrationSpec.validate_administered_product, model_validator(mode="after")): medication and administered_product cannot both be set.
  • Existence checks (field validators, create): encounter must reference an existing Encounter; request must reference an existing MedicationRequest; each performer.actor must reference an existing User.
  • Bound codings: medication, status_reason, and dosage.{site,route,method} are validated against their bound value sets; unknown codes raise.
  • Required on create: status, occurrence_period_start, encounter, request.

Server-maintained behaviour

MedicationAdministrationSpec.perform_extra_deserialization (create only, is_update == False):

  • Resolves encounter from the supplied external_id and sets obj.encounter.
  • Derives obj.patient from obj.encounter.patientpatient is never taken from the client.
  • Resolves request from its external_id and sets obj.request.
  • If administered_product is supplied, resolves the ProductKnowledge and sets obj.administered_product.

MedicationAdministrationReadSpec.perform_extra_serialization:

  • Sets id to external_id; flattens encounter and request to their external_ids.
  • Serializes administered_product (when present) via ProductKnowledgeReadSpec.
  • Adds created_by / updated_by via serialize_audit_users.

administered_product references the supply-side catalog rather than carrying a nested record:

administered_product → FK ProductKnowledge (nullable, CASCADE)
patient → FK Patient (CASCADE)
encounter → FK Encounter (nullable, CASCADE)
request → FK MedicationRequest (nullable, CASCADE)

medication, dosage, status_reason, and performer are stored inline as JSONFields rather than in separate tables, mirroring the FHIR MedicationAdministration structure; their real shape comes from the resource specs above.

Methods & save behaviour

  • de_serialize(obj?) dumps the write schema with model_dump(exclude_defaults=True), so unset fields never overwrite existing values — the same path handles both create and update.
  • Audit and soft-delete fields (external_id, created_by, created_date, modified_date, deleted, etc.) are inherited from EMRBaseModel and maintained by the platform; clients never set them.

API integration notes

  • Write requests use MedicationAdministrationSpec (create) and MedicationAdministrationUpdateSpec (update); reads return MedicationAdministrationReadSpec. Field names mostly match the model; occurrence_period_start / occurrence_period_end map to the FHIR occurence[x] period.
  • Send coded fields (medication, status_reason, dosage.site/route/method) as Coding objects (system / code / display) drawn from the bound value sets — free strings and out-of-set codes are rejected.
  • status values use underscores (in_progress, not_done, on_hold, entered_in_error), not the FHIR hyphenated spellings.
  • Provide encounter and request as external_id UUIDs; patient is derived server-side from the encounter and must not be sent.
  • Set either medication or administered_product, never both. Use administered_product when a specific catalogued product was given, so the administration reconciles against inventory; use medication for a coded drug with no catalog product.
  • After create, only status, note, and occurrence_period_end are updatable; encounter, request, and patient are immutable.