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:
- Model:
care/emr/models/medication_administration.py - Spec:
care/emr/resources/medication/administration/spec.py - Value sets:
care/emr/resources/medication/valueset/
Models
| Model | Purpose |
|---|---|
MedicationAdministration | The 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
| Field | Storage | Spec shape | Notes |
|---|---|---|---|
status | CharField(100) | MedicationAdministrationStatus enum | Required. Administration event status — see enum values |
status_reason | JSONField (null) | Coding bound to system-medication value set | Optional. Coded reason for the status. The spec binds this to the medication value set, not the "not given" reason set you might expect |
category | CharField(100) (null) | MedicationAdministrationCategory enum | Optional. Administration setting — see enum values |
Medication & product
| Field | Storage | Spec shape | Notes |
|---|---|---|---|
medication | JSONField (default {}) | Coding bound to system-medication value set | Optional in spec. { system, version?, code, display? }. Mutually exclusive with administered_product (model validator) |
administered_product | FK → ProductKnowledge (null, CASCADE) | UUID4 (write) / nested ProductKnowledgeReadSpec (read) | Optional. The specific catalog product administered. Cannot be set together with medication |
dosage | JSONField (null) | Dosage nested spec | Optional. Dose, rate, route, site, and method actually administered — see Dosage |
Subject & context
| Field | Storage | Spec shape | Notes |
|---|---|---|---|
patient | FK → 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 |
encounter | FK → 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 |
request | FK → MedicationRequest (null, CASCADE) | UUID4 (required, write) | The order this administration fulfils. Validated to exist; read schema returns the request's external_id |
Timing & attribution
| Field | Storage | Spec shape | Notes |
|---|---|---|---|
authored_on | DateTimeField (null) | datetime | Optional. When the record was authored, distinct from when the dose was given |
occurrence_period_start | DateTimeField (default datetime.now) | datetime (required) | When the administration began. Required on create; defaults to now at the model level |
occurrence_period_end | DateTimeField (null) | datetime | Optional. End of the administration, for infusions and extended doses. Updatable via MedicationAdministrationUpdateSpec |
recorded | DateTimeField (null) | datetime | Optional. When the event was entered into the system, distinct from occurrence_period_start |
performer | JSONField (default []) | list[MedicationAdministrationPerformer] | Optional. Actors who performed the administration and their function — see MedicationAdministrationPerformer |
note | TextField (null) | str | Optional. 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.
| Field | Type | Notes |
|---|---|---|
text | str | None | Free-text dosage instructions |
site | Coding | None | Bound to system-body-site value set (SNOMED CT << 91723000) |
route | Coding | None | Bound to system-route value set (SNOMED CT << 284009009) |
method | Coding | None | Bound to system-administration-method value set (SNOMED CT << 736665006) |
dose | Quantity | None | The amount of medication administered |
rate | Quantity | None | The 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.
| Field | Type | Notes |
|---|---|---|
actor | UUID4 (required) | The user who performed the administration. Validated server-side to reference an existing User (field_validator raises "User not found") |
function | MedicationAdministrationPerformerFunction | None | The 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.
| Field | Value set | Slug | SNOMED CT constraint |
|---|---|---|---|
medication, status_reason | Medication | system-medication | << 763158003 (Medicinal product) |
dosage.site | Body Site | system-body-site | is-a 91723000 |
dosage.route | Route | system-route | is-a 284009009 |
dosage.method | Administration Method | system-administration-method | is-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 class | Role | Key fields / behaviour |
|---|---|---|
BaseMedicationAdministrationSpec | shared base | All 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"] |
MedicationAdministrationSpec | write · create | Extends base; adds administered_product: UUID4 | None. Validates encounter and request exist; rejects medication + administered_product set together |
MedicationAdministrationUpdateSpec | write · update | Narrow update schema: only status, note, occurrence_period_end. __exclude__ = ["patient", "encounter", "request"] — those are immutable after create |
MedicationAdministrationReadSpec | read · detail/list | Extends base; adds audit fields created_by, updated_by, created_date, modified_date, and nested administered_product: dict |
Dosage | nested | Shape of the dosage JSON field (see above) |
MedicationAdministrationPerformer | nested | Element of the performer JSON list (see above) |
Validation rules
- Mutual exclusion (
MedicationAdministrationSpec.validate_administered_product,model_validator(mode="after")):medicationandadministered_productcannot both be set. - Existence checks (field validators, create):
encountermust reference an existingEncounter;requestmust reference an existingMedicationRequest; eachperformer.actormust reference an existingUser. - Bound codings:
medication,status_reason, anddosage.{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
encounterfrom the suppliedexternal_idand setsobj.encounter. - Derives
obj.patientfromobj.encounter.patient—patientis never taken from the client. - Resolves
requestfrom itsexternal_idand setsobj.request. - If
administered_productis supplied, resolves theProductKnowledgeand setsobj.administered_product.
MedicationAdministrationReadSpec.perform_extra_serialization:
- Sets
idtoexternal_id; flattensencounterandrequestto theirexternal_ids. - Serializes
administered_product(when present) viaProductKnowledgeReadSpec. - Adds
created_by/updated_byviaserialize_audit_users.
Related models
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 withmodel_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 fromEMRBaseModeland maintained by the platform; clients never set them.
API integration notes
- Write requests use
MedicationAdministrationSpec(create) andMedicationAdministrationUpdateSpec(update); reads returnMedicationAdministrationReadSpec. Field names mostly match the model;occurrence_period_start/occurrence_period_endmap to the FHIRoccurence[x]period. - Send coded fields (
medication,status_reason,dosage.site/route/method) asCodingobjects (system/code/display) drawn from the bound value sets — free strings and out-of-set codes are rejected. statusvalues use underscores (in_progress,not_done,on_hold,entered_in_error), not the FHIR hyphenated spellings.- Provide
encounterandrequestasexternal_idUUIDs;patientis derived server-side from the encounter and must not be sent. - Set either
medicationoradministered_product, never both. Useadministered_productwhen a specific catalogued product was given, so the administration reconciles against inventory; usemedicationfor a coded drug with no catalog product. - After create, only
status,note, andoccurrence_period_endare updatable;encounter,request, andpatientare immutable.
Related
- Reference: Medication Request
- Reference: Medication Dispense
- Reference: Medication Statement
- Reference: Product Knowledge
- Reference: Encounter
- Reference: Patient
- Reference: User
- Reference: Base model
- Source: medication_administration.py on GitHub
- Source: administration/spec.py on GitHub
- Source: medication value sets on GitHub