Specimen Definition
A SpecimenDefinition is a reusable, facility-scoped template for a kind of specimen: what material to collect, how to prepare the patient, how to collect it, and how it's held in a container for testing. A lab maintains a repository of these, and an Activity Definition or Service Request references one so the same container and handling rules apply every time. When a concrete Specimen is instantiated from a definition, the link is kept and the specimen copies the definition's data for history and integrity.
The Django model is only the storage layer: type_collected, patient_preparation, collection, and type_tested are opaque JSONFields. Their real structure — the enums, value-set bindings, and read/write API schemas — lives in the Pydantic resource specs documented below.
Source:
- Model:
care/emr/models/specimen_definition.py - Resource spec:
care/emr/resources/specimen_definition/spec.py - Value sets:
care/emr/resources/specimen_definition/valueset.py - Conversion helper:
care/emr/resources/specimen_definition/specimen.py - ViewSet:
care/emr/api/viewsets/specimen_definition.py
Models
| Model | Purpose |
|---|---|
SpecimenDefinition | Reusable definition of a kind of specimen: what to collect, how to prepare the patient, how to collect it, and how it is contained and tested |
SpecimenDefinition extends SlugBaseModel: the Care EMR base with FACILITY_SCOPED = True, a facility-scoped slug, external_id, history/meta JSON, audit fields, and soft-delete semantics.
SpecimenDefinition fields
Identity & status
| Field | Type | Required | Notes |
|---|---|---|---|
facility | FK → facility.Facility (PROTECT) | model: optional | null=True, blank=True, default=None. Never client-supplied — the ViewSet sets it from the facility_external_id URL kwarg, so every API-created definition is facility-scoped. Excluded from both spec schemas (__exclude__ = ["facility"]) |
version | IntegerField | default 1 | Definition version. Read-only over the API — exposed by SpecimenDefinitionReadSpec, never accepted on write |
slug | CharField(255) | yes (server-built) | Stored fully-qualified as f-<facility_external_id>-<slug_value> (see Methods & save behaviour). Clients send the bare slug_value instead |
title | CharField(1024) | yes | Human-readable name |
derived_from_uri | TextField | optional | null=True, blank=True. URI of the canonical/external definition this was derived from |
status | CharField(255) | yes | Lifecycle status, constrained by SpecimenDefinitionStatusOptions — see enum |
description | TextField | yes | Natural-language description (markdown) |
Collection & testing detail (JSON fields)
The model stores these as raw JSON; the spec defines their true shape and value-set bindings.
| Field | Model type | Spec type | Notes |
|---|---|---|---|
type_collected | JSONField (null=True) | Coding bound to Specimen Type Code value set | Required on write. The kind of material collected. See value sets |
patient_preparation | JSONField (default=list) | list[Coding] bound to Prepare Patient Prior Specimen Code value set | Defaults to []. Steps the patient follows before collection |
collection | JSONField (null=True) | Coding bound to Specimen Collection Code value set, optional | The specimen collection procedure |
type_tested | JSONField (default=dict) | TypeTestedSpec (nested), optional | Container, handling, and testing detail. See TypeTestedSpec |
Each bound coded field accepts a
Codingobject ({ system, version?, code, display? });ValueSetBoundCodingvalidates thecodeagainst the bound value set at de-serialization time.
Related models
| Type | Where | Shape |
|---|---|---|
Coding | resources/common/coding.py | { system: str?, version: str?, code: str (required), display: str? }, extra="forbid" |
QuantitySpec | spec.py | { value: Decimal (max_digits=20, decimal_places=0), unit: Coding } — decimal_places=0, so integer-valued |
MinimumVolumeSpec | spec.py | { quantity: QuantitySpec?, string: str? }; a validator forbids supplying both |
ContainerSpec | spec.py | { description: str?, capacity: QuantitySpec?, minimum_volume: MinimumVolumeSpec?, cap: Coding? (bound to Container Cap), preparation: str? } |
DurationSpec | spec.py | { value: Decimal (max_digits=20, decimal_places=0), unit: Coding } — unit not yet restricted to datetime units |
RangeSpec | spec.py | { low: QuantitySpec?, high: QuantitySpec? } |
HandlingSpec | spec.py | { temperature_qualifier: HandlingConditionOptions?, temperature_range: RangeSpec?, max_duration: DurationSpec?, instruction: str? } |
TypeTestedSpec | spec.py | see TypeTestedSpec below |
TypeTestedSpec
The structured shape of the type_tested JSON field. A definition holds a single container; for multiple containers per test, repeat the definition in the Activity Definition spec.
| Field | Type | Required | Notes |
|---|---|---|---|
is_derived | bool | yes | false for a primary specimen, true for a secondary/derived one |
preference | PreferenceOptions | yes | preferred / alternate — see enum |
container | ContainerSpec | optional | The specimen's container — description, capacity, minimum volume, cap, preparation |
requirement | str | optional | Delivery requirements / special handling (markdown) |
retention_time | DurationSpec | optional | Usual time this kind of specimen is retained |
single_use | bool | optional | Specimen for single use only |
handling | HandlingSpec | optional | Temperature qualifier/range, max duration, instruction |
Enums
SpecimenDefinitionStatusOptions values
| Value | Meaning |
|---|---|
draft | Being authored, not yet in use |
active | In use |
retired | Withdrawn from use |
PreferenceOptions values
| Value | Meaning |
|---|---|
preferred | Preferred specimen for the test |
alternate | Acceptable alternative specimen |
HandlingConditionOptions values
| Value | Meaning |
|---|---|
room | Room temperature |
refrigerated | Refrigerated |
frozen | Frozen |
Resource specs (API schema)
All specs build on EMRResource (serialize/de_serialize, perform_extra_serialization/perform_extra_deserialization). __exclude__ = ["facility"] keeps facility out of both directions. The ViewSet wires pydantic_model = SpecimenDefinitionWriteSpec for create/update and pydantic_read_model = SpecimenDefinitionReadSpec for list/retrieve.
| Spec class | Role | Fields / behaviour |
|---|---|---|
BaseSpecimenDefinitionSpec | shared base | id, title, derived_from_uri, status, description, type_collected, patient_preparation, collection, type_tested. Holds the coded-field value-set bindings and the nested type_tested shape |
SpecimenDefinitionWriteSpec | write · create & update | Base fields plus slug_value: SlugType. perform_extra_deserialization copies slug_value → obj.slug (the ViewSet then fully-qualifies it). facility, version, and the stored slug are never client-supplied |
SpecimenDefinitionReadSpec | read · list & detail | Base fields plus version: int?, slug: str, slug_config: dict. perform_extra_serialization sets id = obj.external_id and slug_config = obj.parse_slug(obj.slug), decomposing the qualified slug into { facility, slug_value } |
Nested specs used by the schemas: TypeTestedSpec, ContainerSpec, MinimumVolumeSpec, QuantitySpec, DurationSpec, RangeSpec, HandlingSpec (see Related models).
Validation rules
slug_value(SlugType): string, length 5–50, matching^[a-zA-Z0-9][a-zA-Z0-9_-]*[a-zA-Z0-9]$(URL-safe; starts and ends alphanumeric).- Coded fields
type_collected,patient_preparation[*],collection, andcontainer.cap:ValueSetBoundCodingvalidates eachCoding.codeagainst its bound value set during de-serialization and rejects unknown codes. MinimumVolumeSpec:quantityandstringare mutually exclusive — supplying both raises"Only one of quantity or string should be provided".QuantitySpec/DurationSpecvalue:Decimal,max_digits=20,decimal_places=0(integer-valued).- Slug uniqueness (ViewSet
validate_data): the fully-qualifiedf-<facility>-<slug_value>must be unique within the facility (case-insensitive), else"Specimen Definition with this slug already exists."On update, the current record is excluded from the check.
Bound value sets
| Field | Value set | Slug | Source system(s) |
|---|---|---|---|
type_collected | Specimen Type Code | system-specimen_type-code | HL7 v2-0487 (unbounded include) |
patient_preparation[*] | Prepare Patient Prior Specimen Code | system-prepare_patient_prior_specimen_code | SNOMED CT, is-a 703763000 |
collection | Specimen Collection Code | system-specimen_collection_code | SNOMED CT (curated list: aspiration, biopsy, puncture, excision, scraping, clean-catch/timed/catheterized urine, coughed sputum, finger-prick) |
container.cap | Container Cap | system-container_cap-code | HL7 container-cap code system |
Methods & save behaviour
SpecimenDefinition overrides no save()/delete() and defines no custom methods. Slug helpers, audit fields, and soft-delete come from SlugBaseModel. The side effects below live in the resource spec and the ViewSet, not the model:
- Slug qualification (write). Clients send a bare
slug_value.SpecimenDefinitionWriteSpec.perform_extra_deserializationsetsobj.slug = slug_value; then the ViewSet'sperform_create/perform_updaterewrites it viaSpecimenDefinition.calculate_slug_from_facility(facility.external_id, slug)→f-<facility_external_id>-<slug_value>. - Facility binding (create).
perform_createsetsinstance.facilityfrom thefacility_external_idURL kwarg before saving. - Slug decomposition (read).
SpecimenDefinitionReadSpec.perform_extra_serializationexposesslug_config = obj.parse_slug(obj.slug), splitting the stored slug back into{ facility, slug_value }. - Specimen instantiation.
convert_sd_to_specimen(specimen.py) builds aSpecimenfrom a definition withstatus="available",specimen_type = definition.type_collected, andspecimen_definition = <definition>, preserving the link and a copy of the type.
API integration notes
- Endpoints are facility-scoped. The ViewSet supports create, retrieve, update, list, and upsert with
lookup_field = "slug". Every operation requiresfacility_external_idin the URL. - Authorization. Writes require
can_write_facility_specimen_definition; list/retrieve requirecan_list_facility_specimen_definitionon the facility — otherwise403 PermissionDenied. The queryset is filtered to the URL facility. - Filtering / ordering.
status(iexact) andtitle(icontains) filters; ordering bycreated_date/modified_date. - Write payload (
SpecimenDefinitionWriteSpec): sendslug_value,title,status,description, the coded fields (type_collected,patient_preparation,collection) asCodingobjects, andtype_tested. Don't sendfacility,version, or the qualifiedslug— they're server-managed. - Read payload (
SpecimenDefinitionReadSpec): addsid(=external_id),version, the qualifiedslug, andslug_config. - The model maps to the FHIR
SpecimenDefinitionresource. Care's spec is intentionally minimal: one container per definition, and behaviour changes bumpversionrather than mutate published records.
Related
- Reference: Specimen
- Reference: Service Request
- Reference: Observation Definition
- Reference: Activity Definition
- Reference: Base model
- Reference: Valueset
- Source: model on GitHub · spec on GitHub · value sets on GitHub