← Knowledge library

Pharmacy

Medication Request

A MedicationRequest records a prescriber's intent to supply or administer a medication to a patient — the FHIR MedicationRequest resource. You create one whenever a drug is ordered during an encounter; it carries the medication, dosage…

3.1 · versioned documentation · 10 min read

A MedicationRequest records a prescriber's intent to supply or administer a medication to a patient — the FHIR MedicationRequest resource. You create one whenever a drug is ordered during an encounter; it carries the medication, dosage instructions, timing, and route as structured JSON, grouped under a prescription.

Source:

Several fields are opaque JSONFields whose structure the Django model never declares. The contract lives in the Pydantic resource specs under care/emr/resources/medication/request/: the enums, the nested shape of those JSON fields, validation rules, the read/write schema split, and the server-side side effects. The tables below merge both layers.

Models

Model Purpose
MedicationRequestPrescription Groups medication requests authored together for an encounter (a prescription)
MedicationRequest A single medication order/request for a patient within an encounter

Both extend EMRBaseModel, which supplies external_id, created_date/modified_date, soft-delete via deleted, created_by/updated_by, and history/meta JSON.

MedicationRequest fields

Order status & intent

Field Type Required Notes
status CharField(100) → MedicationRequestStatus Yes (spec) Nullable on the model, required by the spec; defaults to active. See status values
status_reason CharField(100) → StatusReason | None No Why the request was discontinued or changed. See status reason values
intent CharField(100) → MedicationRequestIntent Yes (spec) Nullable on the model, required by the spec. See intent values
category CharField(100) → MedicationRequestCategory Yes (spec) Nullable on the model, required by the spec. See category values
priority CharField(100) → MedicationRequestPriority Yes (spec) Nullable on the model, required by the spec. See priority values
do_not_perform BooleanField → bool Yes Set True to record that the medication must explicitly not be given
dispense_status CharField(100) → MedicationRequestDispenseStatus | None No Defaults to None. Tracks dispense progress. See dispense status values

Medication & dosage

Field Type Required Notes
medication JSONField → ValueSetBoundCoding[system-medication] | None Conditional Model default {}. A single Coding { system, code, display } bound to the Medication value set (SNOMED CT medicinal products). Set exactly one of medication / requested_product
method JSONField n/a Model default {}. Stored but not exposed by any current spec — administration method travels per dosage line via dosage_instruction[].method
dosage_instruction JSONField → list[DosageInstruction] Yes Model default []. The structured dosage lines. See DosageInstruction shape
note TextField → str | None No Free-text note

Subject & provenance

Field Type Required Notes
patient FK → Patient server-set CASCADE. Ignored if sent by the client — derived from encounter.patient
encounter FK → Encounter Yes (create) CASCADE. Write spec takes encounter as a UUID and validates that it exists
authored_on DateTimeField → datetime Yes (spec) Must be tz-aware. Model default timezone.now when omitted
requester FK → users.User No SET_NULL. The prescriber; write spec takes a requester UUID
requested_product FK → ProductKnowledge Conditional SET_NULL, default None. Write spec takes a requested_product UUID. Set exactly one of medication / requested_product
prescription FK → MedicationRequestPrescription No SET_NULL, default None. Set via a prescription UUID or create_prescription (see validation)

Enum values

Spec enums use underscored member values (on_hold, entered_in_error, original_order), not the hyphenated FHIR spellings. These are the exact strings the API accepts and returns.

MedicationRequestStatus values

Value
active
on_hold
ended
stopped
completed
cancelled
entered_in_error
draft
unknown

StatusReason values

Value Meaning (FHIR)
altchoice Alternative choice
clarif Prescription requires clarification
drughigh Drug level too high
hospadm Admission to hospital
labint Lab interference issues
non_avail Patient not available
preg Patient is pregnant or breastfeeding
salg Allergy
sddi Drug interaction
sdupther Duplicate therapy
sintol Suspected intolerance
surg Patient scheduled for surgery
washout Washout

MedicationRequestIntent values

Value
proposal
plan
order
original_order
reflex_order
filler_order
instance_order

MedicationRequestPriority values

Value
routine
urgent
asap
stat

MedicationRequestCategory values

Value
inpatient
outpatient
community
discharge

MedicationRequestDispenseStatus values

Value
complete
partial
incomplete
declined

TimingUnit values

UCUM time units used by Timing.repeat.period_unit and bounds_duration.unit.

Value Unit
s second
min minute
h hour
d day
wk week
mo month
a year

DoseType values

Used by DoseAndRate.type.

Value
ordered
calculated

DosageInstruction nested spec

Each entry in the dosage_instruction JSON list deserializes to a DosageInstruction (Pydantic, snake_case keys) — the structure hiding behind the opaque JSONField.

Field Type Required Notes
sequence int | None No Order of the instruction
text str | None No Free-text dosage instruction (SIG)
additional_instruction list[Coding] | None No Bound to the Additional Instruction value set
patient_instruction str | None No Patient-facing instructions
timing Timing | None No See Timing below
as_needed_boolean bool Yes Set True for PRN orders
as_needed_for Coding | None No Reason for PRN; bound to the As Needed value set
site Coding | None No Bound to the Body Site value set
route Coding | None No Bound to the Route value set
method Coding | None No Bound to the Administration Method value set
dose_and_rate DoseAndRate | None No See DoseAndRate below
max_dose_per_period DoseRange | None No Upper dose limit per period

Sub-types under DosageInstruction

Timing {
  repeat: TimingRepeat        # required
  code: Coding | None         # e.g. BID/TID/QID timing abbreviation
}

TimingRepeat {
  frequency: int              # required — repetitions per period
  period: Decimal(20,0)       # required — duration the frequency applies to
  period_unit: TimingUnit     # required — s|min|h|d|wk|mo|a
  bounds_duration: TimingQuantity  # required — total span
}

TimingQuantity {              # integer-valued time amount
  value: Decimal(20,0)        # required
  unit: TimingUnit            # required
}

DoseAndRate {
  type: DoseType              # required — ordered | calculated
  dose_range: DoseRange | None      # for titrated doses
  dose_quantity: DosageQuantity | None  # for regular doses
}

DoseRange {
  low: DosageQuantity         # required
  high: DosageQuantity        # required
}

DosageQuantity {              # measured dose amount
  value: Decimal(20,6)        # required
  unit: Coding                # required
}

The Pydantic specs define these JSON keys as snake_case (as_needed_boolean, period_unit, dose_and_rate, max_dose_per_period, bounds_duration), so that is how they sit in storage — not the camelCase FHIR wire format.

Bound value sets

Coded fields bind to MANSOQ value sets through ValueSetBoundCoding[<slug>]. On write, the supplied Coding.code is validated against the value set; a code outside it is rejected. All draw from SNOMED CT (http://snomed.info/sct).

Field Value set slug SNOMED CT scope
medication system-medication << 763158003 Medicinal product
dosage_instruction[].route system-route is-a 284009009 Route of administration
dosage_instruction[].site system-body-site is-a 91723000 Anatomical structure
dosage_instruction[].method system-administration-method is-a 736665006
dosage_instruction[].as_needed_for system-as-needed-reason is-a 404684003 Clinical finding
dosage_instruction[].additional_instruction system-additional-instruction is-a 419492006

system-medication-not-given lives in this directory too, but it binds on Medication Administration, not on the request.

Resource specs (API schema)

Every spec extends EMRResource, which provides serialize / de_serialize plus the perform_extra_serialization / perform_extra_deserialization hooks. MedicationRequestResource sets __exclude__ = [patient, encounter, requester, requested_product, prescription], so those relations are wired up by hand instead of auto-mapped.

Spec class Role Notes
MedicationRequestAbstractSpec shared (fields) Plain BaseModel holding the clinical fields: status, status_reason, intent, category, priority, do_not_perform, medication, dosage_instruction, authored_on, note, dispense_status
MedicationRequestResource shared (binding) Binds the spec to the MedicationRequest model and declares __exclude__
BaseMedicationRequestSpec shared MedicationRequestResource + MedicationRequestAbstractSpec + id: UUID4
MedicationRequestSpec write · create Adds encounter (UUID, required), requester, requested_product, prescription (UUIDs), and create_prescription. Carries the validators and perform_extra_deserialization
MedicationRequestUpdateSpec write · update Narrow — only status, note, dispense_status are mutable after create
MedicationRequestReadWithoutPrescriptionSpec read · embedded Full read minus prescription; expands requested_product (ProductKnowledgeReadSpec), requester/created_by/updated_by (UserSpec), plus created_date/modified_date
MedicationRequestReadSpec read · detail/list Adds expanded prescription (MedicationRequestPrescriptionReadSpec) and the encounter external id
CreatePrescription write · nested { name?, note?, alternate_identifier (required) } — inline prescription creation

Validation (create — MedicationRequestSpec)

Server-side side effects (perform_extra_deserialization)

Serialization (read)

perform_extra_serialization sets id = external_id and expands requested_product, requester, and the audit users (created_by/updated_by) from cache. MedicationRequestReadSpec goes further, expanding prescription and emitting encounter as its external id.

Related models

MedicationRequestPrescription

The container that groups every medication request authored together for an encounter into one prescription. Each request points back via MedicationRequest.prescription.

encounter            → FK Encounter (CASCADE)
patient              → FK Patient (CASCADE)
name                 → CharField(100), nullable
note                 → TextField, nullable
prescribed_by        → FK users.User (CASCADE, nullable)
status               → CharField(100), nullable  → MedicationRequestPrescriptionStatus
approval_status      → CharField(100), nullable
alternate_identifier → CharField(100), nullable
tags                 → ArrayField[int], default []

A UniqueConstraint (unique_alternate_identifier_encounter) keeps alternate_identifier unique per encounter.

MedicationRequestPrescriptionStatus values

active, on_hold, ended, stopped, completed, cancelled, entered_in_error, draft.

A pharmacist may only move a prescription between active, on_hold, completed (MEDICATION_PRESCRIPTION_PHARMACIST_ALLOWED_STATUS).

Prescription specs

Spec class Role Notes
BaseMedicationRequestPrescriptionSpec shared id, status (MedicationRequestPrescriptionStatus), note, name
MedicationRequestPrescriptionWriteSpec write · create Adds encounter (UUID), prescribed_by (UUID); resolves encounter→patient and prescribed_by server-side
MedicationRequestPrescriptionUpdateSpec write · update Same shared fields, no new FKs
MedicationRequestPrescriptionReadSpec read · list Adds created_date, modified_date, expanded prescribed_by (UserSpec), tags (rendered via SingleFacilityTagManager)
MedicationRequestPrescriptionRetrieveSpec read · detail Adds audit created_by/updated_by
MedicationRequestPrescriptionRetrieveMedicationsSpec read · detail+children Adds medications (each via MedicationRequestReadWithoutPrescriptionSpec) and full encounter (EncounterRetrieveSpec)
MedicationRequestPrescriptionRetrieveDetailedSpec read · detail Adds encounter via EncounterListSpec

Methods & save behaviour

API integration notes

Related

Source evidence

References are pinned to the private MANSOQ source repository. Repository access is required to open these links.