Skip to main content
Version: 3.0

Service Request

A ServiceRequest is an order or proposal to perform an action — clinical or otherwise — for a patient (FHIR ServiceRequest). It drives the creation of specimens, diagnostic reports, observations, and procedures, each of which links back to the originating request. Care implements a minimal subset of the FHIR spec.

Source:

The Django model is only storage: several columns are opaque JSONFields and free-text CharFields. Their real structure, enums, bound value sets, and read/write API schemas live in the Pydantic resource specs (care/emr/resources/service_request/spec.py). Both layers are covered below.

Models

ModelPurpose
ServiceRequestAn order or proposal to perform an action for a patient

ServiceRequest extends EMRBaseModel, the shared Care EMR base that supplies external_id, audit fields created_by/updated_by, created_date/modified_date, meta, and soft-delete semantics — see Base model.

ServiceRequest fields

Request definition

FieldModel typeSpec type / shapeNotes
titleCharField(1024)strHuman-readable summary. Required on create, optional on update.
categoryCharField(255)ActivityDefinitionCategoryOptions enumCoded category. Required on create. See category values.
statusCharField(255)ServiceRequestStatusChoices enumLifecycle status. Required on create. See status values.
intentCharField(255)ServiceRequestIntentChoices enumRequired on create. See intent values.
priorityCharField(255)ServiceRequestPriorityChoices enumRequired on create. See priority values.
do_not_performBooleanFieldbool | NoneTrue flags the service/procedure as explicitly not to be performed. Model default False; spec default None, so it's omitted from writes unless set.
codeJSONField (nullable)Coding bound to activity-definition-procedure-codeThe requested service/procedure. Required on create. A single Coding, not a CodeableConcept, validated against the bound value set.
body_siteJSONField (nullable)Coding bound to system-body-site-observation, optionalCoded location on the body. A single Coding, validated against the bound value set.

A bound Coding (ValueSetBoundCoding) has the shape:

{
"system": "<uri | null>",
"version": "<str | null>",
"code": "<str>", // required; must resolve in the bound value set
"display": "<str | null>"
}

Clinical detail

FieldModel typeSpec typeNotes
noteTextField (nullable)str | NoneFree-text comments.
patient_instructionTextField (nullable)str | NoneInstructions surfaced to the patient.
occuranceDateTimeField (nullable)datetime | NoneWhen the request should take place. Spelled occurance in both model and spec — the typo is intentional, match it.

Relationships

FieldModel typeSpec typeNotes
facilityFK → facility.Facility(not in write spec)Owning facility. PROTECT. Set server-side from request context.
patientFK → emr.Patient(derived)Subject of the request. CASCADE. Not accepted from clients — set server-side from encounter.patient on create.
encounterFK → emr.Encounter (nullable)UUID4 (create only)Encounter the request was created in. CASCADE. Required as a UUID on Create; resolved via get_object_or_404. Read back as a serialized encounter dict.
healthcare_serviceFK → emr.HealthcareService (nullable)UUID4 | NoneService fulfilling the request. PROTECT. Write accepts external_id; resolved server-side. Excluded from base serialize; returned only on Retrieve.
activity_definitionFK → emr.ActivityDefinition (nullable)(read only)Template the request was created from. PROTECT. Serialized only on Retrieve.
requesterFK → users.User (nullable)UUID4 | None (write) / dict | None (read)User who placed the request. CASCADE. Write accepts external_id; read returns a cached UserSpec dict.
locationsArrayField[int]list[UUID4] (write) / list[dict] (read)Facility-location IDs the request applies to. Model default []. Write accepts location external_ids, stored on obj._locations for the manager to persist; serialized as FacilityLocationListSpec dicts only on Retrieve.
tagsArrayField[int]list[dict] (read)Tag IDs. Model default []. Rendered via SingleFacilityTagManager().render_tags(obj) on read; not set directly from the write spec.

Enums

Status values

ServiceRequestStatusChoices values are snake_case, not the hyphenated FHIR codes.

ValueMeaning
draftRequest is being drafted, not yet actionable
activeRequest is active
on_holdRequest is paused
entered_in_errorRequest was entered in error
endedRequest has ended
completedRequest has been fulfilled
revokedRequest was revoked/cancelled

spec.py derives two groupings from these:

  • SERVICE_REQUEST_COMPLETED_CHOICES = completed, revoked, ended, entered_in_error (terminal states).
  • SERVICE_REQUEST_CANCELLED_CHOICES = revoked, entered_in_error.

There is no unknown status.

Intent values

ServiceRequestIntentChoices

Value
proposal
plan
directive
order

Priority values

ServiceRequestPriorityChoices

Value
routine
urgent
asap
stat

Category values

category reuses ActivityDefinitionCategoryOptions from care/emr/resources/activity_definition/spec.py.

Value
laboratory
imaging
counselling
surgical_procedure
education

Bound value sets

Each coded Coding field validates its code against a registered Care value set (ValueSetBoundCoding[...]).

FieldValue set slugComposition
codeactivity-definition-procedure-codeSNOMED CT is-a 71388002 (Procedure). See activity_definition/valueset.py.
body_sitesystem-body-site-observationSNOMED CT — explicit limb/joint concepts plus is-a 442083009. See observation/valueset.py.

Resource specs (API schema)

Every spec subclasses EMRResource (serialize / de_serialize, with perform_extra_serialization / perform_extra_deserialization hooks — see Base model). The base sets __model__ = ServiceRequest and __exclude__ = ["encounter", "healthcare_service", "locations"], so those three fields are handled only by the explicit per-spec hooks.

Spec classRoleAdds / overrides
BaseServiceRequestSpecsharedid, title, status, intent, priority, category, do_not_perform, note, code (required), body_site, occurance, patient_instruction
ServiceRequestWriteSpecwrite · sharedAdds healthcare_service: UUID4?, locations: list[UUID4], requester: UUID4?. Resolves healthcare_service and requester from external_id; stashes locations on obj._locations.
ServiceRequestCreateSpecwrite · createAdds required encounter: UUID4. Resolves the encounter and sets obj.patient = obj.encounter.patient server-side.
ServiceRequestUpdateSpecwrite · updateMakes title, status, intent, priority, category, code all optional for partial update.
ServiceRequestReadSpecread · listAdds created_date, modified_date, encounter (serialized via EncounterListSpec), tags (rendered), requester (cached UserSpec). Sets id = external_id.
ServiceRequestRetrieveSpecread · detailExtends Read with locations (FacilityLocationListSpec), healthcare_service (HealthcareServiceReadSpec), activity_definition (ActivityDefinitionReadSpec), specimens (SpecimenReadSpec), diagnostic_reports (DiagnosticReportListSpec), embedded encounter.patient (PatientRetrieveSpec), and audit created_by/updated_by.

Write-side behaviour (perform_extra_deserialization)

  • healthcare_service, when provided, is looked up by external_id and assigned.
  • requester, when provided, is looked up by external_id via get_object_or_404(User, ...).
  • locations: the list of UUIDs is stored on obj._locations; the persisting view/manager translates them to integer IDs for the locations array.
  • On create only, encounter is required, fetched via get_object_or_404(Encounter, ...), and obj.patient is forced to encounter.patient. Clients cannot set patient directly.

Read-side behaviour (perform_extra_serialization)

  • id is set to external_id; encounter is serialized with EncounterListSpec; tags come from SingleFacilityTagManager().render_tags(obj); requester, if set, is a cached UserSpec.
  • On retrieve only: queries FacilityLocation for obj.locations; serializes healthcare_service and activity_definition when present; fetches the related Specimen and DiagnosticReport rows that reference this request; embeds the patient (PatientRetrieveSpec, scoped to obj.facility) under encounter.patient; and attaches audit users.

Methods & save behaviour

  • ServiceRequest inherits save, soft-delete, and audit behaviour from EMRBaseModel (see Base model). The model defines no custom save override.
  • The Pydantic write specs enforce all write validation — enums, required code, bound value sets, encounter requirement — during de_serialize, not Django field choices. The DB columns are plain CharField/JSONField.
  • patient is never accepted from the client; it is derived from encounter.patient on create.
  • Related Specimen and DiagnosticReport records reference the request via their own service_request FK. The detail view (Retrieve) reads them back rather than storing them on the request.

API integration notes

Things that trip up integrators:

  • Spellings follow Care conventions, not FHIR: status/intent/priority are snake_case enum values, and occurance keeps its model typo.
  • code is required and body_site optional; both are single Coding objects validated against their bound value sets — not CodeableConcept.
  • category, status, intent, and priority are validated as enums by the spec even though the columns are free CharFields.
  • Write healthcare_service, requester, and locations as external_id/UUIDs and let the server resolve them. encounter (UUID) is required on create and determines the patient.
  • locations and tags store ID arrays for fast filtering — drive them through the location/tag managers rather than setting the raw arrays from clients.
  • Activity Definition — template a request can be created from; supplies the category enum and code value set
  • Encounter — required context on create; supplies the patient
  • Patient — subject, derived from the encounter
  • Specimen — specimens collected for a request
  • Diagnostic Report — reports produced for a request
  • Observation — shares the body-site value set
  • Healthcare Service — service fulfilling the request
  • Location — facility locations the request applies to
  • User — requester / audit users