Skip to main content
Version: 3.1

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:

Models

ModelPurpose
SpecimenDefinitionReusable 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

FieldTypeRequiredNotes
facilityFK → facility.Facility (PROTECT)model: optionalnull=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"])
versionIntegerFielddefault 1Definition version. Read-only over the API — exposed by SpecimenDefinitionReadSpec, never accepted on write
slugCharField(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
titleCharField(1024)yesHuman-readable name
derived_from_uriTextFieldoptionalnull=True, blank=True. URI of the canonical/external definition this was derived from
statusCharField(255)yesLifecycle status, constrained by SpecimenDefinitionStatusOptions — see enum
descriptionTextFieldyesNatural-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.

FieldModel typeSpec typeNotes
type_collectedJSONField (null=True)Coding bound to Specimen Type Code value setRequired on write. The kind of material collected. See value sets
patient_preparationJSONField (default=list)list[Coding] bound to Prepare Patient Prior Specimen Code value setDefaults to []. Steps the patient follows before collection
collectionJSONField (null=True)Coding bound to Specimen Collection Code value set, optionalThe specimen collection procedure
type_testedJSONField (default=dict)TypeTestedSpec (nested), optionalContainer, handling, and testing detail. See TypeTestedSpec

Each bound coded field accepts a Coding object ({ system, version?, code, display? }); ValueSetBoundCoding validates the code against the bound value set at de-serialization time.

TypeWhereShape
Codingresources/common/coding.py{ system: str?, version: str?, code: str (required), display: str? }, extra="forbid"
QuantitySpecspec.py{ value: Decimal (max_digits=20, decimal_places=0), unit: Coding }decimal_places=0, so integer-valued
MinimumVolumeSpecspec.py{ quantity: QuantitySpec?, string: str? }; a validator forbids supplying both
ContainerSpecspec.py{ description: str?, capacity: QuantitySpec?, minimum_volume: MinimumVolumeSpec?, cap: Coding? (bound to Container Cap), preparation: str? }
DurationSpecspec.py{ value: Decimal (max_digits=20, decimal_places=0), unit: Coding }unit not yet restricted to datetime units
RangeSpecspec.py{ low: QuantitySpec?, high: QuantitySpec? }
HandlingSpecspec.py{ temperature_qualifier: HandlingConditionOptions?, temperature_range: RangeSpec?, max_duration: DurationSpec?, instruction: str? }
TypeTestedSpecspec.pysee 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.

FieldTypeRequiredNotes
is_derivedboolyesfalse for a primary specimen, true for a secondary/derived one
preferencePreferenceOptionsyespreferred / alternate — see enum
containerContainerSpecoptionalThe specimen's container — description, capacity, minimum volume, cap, preparation
requirementstroptionalDelivery requirements / special handling (markdown)
retention_timeDurationSpecoptionalUsual time this kind of specimen is retained
single_usebooloptionalSpecimen for single use only
handlingHandlingSpecoptionalTemperature qualifier/range, max duration, instruction

Enums

SpecimenDefinitionStatusOptions values

ValueMeaning
draftBeing authored, not yet in use
activeIn use
retiredWithdrawn from use

PreferenceOptions values

ValueMeaning
preferredPreferred specimen for the test
alternateAcceptable alternative specimen

HandlingConditionOptions values

ValueMeaning
roomRoom temperature
refrigeratedRefrigerated
frozenFrozen

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 classRoleFields / behaviour
BaseSpecimenDefinitionSpecshared baseid, 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
SpecimenDefinitionWriteSpecwrite · create & updateBase fields plus slug_value: SlugType. perform_extra_deserialization copies slug_valueobj.slug (the ViewSet then fully-qualifies it). facility, version, and the stored slug are never client-supplied
SpecimenDefinitionReadSpecread · list & detailBase 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, and container.cap: ValueSetBoundCoding validates each Coding.code against its bound value set during de-serialization and rejects unknown codes.
  • MinimumVolumeSpec: quantity and string are mutually exclusive — supplying both raises "Only one of quantity or string should be provided".
  • QuantitySpec / DurationSpec value: Decimal, max_digits=20, decimal_places=0 (integer-valued).
  • Slug uniqueness (ViewSet validate_data): the fully-qualified f-<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

FieldValue setSlugSource system(s)
type_collectedSpecimen Type Codesystem-specimen_type-codeHL7 v2-0487 (unbounded include)
patient_preparation[*]Prepare Patient Prior Specimen Codesystem-prepare_patient_prior_specimen_codeSNOMED CT, is-a 703763000
collectionSpecimen Collection Codesystem-specimen_collection_codeSNOMED CT (curated list: aspiration, biopsy, puncture, excision, scraping, clean-catch/timed/catheterized urine, coughed sputum, finger-prick)
container.capContainer Capsystem-container_cap-codeHL7 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_deserialization sets obj.slug = slug_value; then the ViewSet's perform_create/perform_update rewrites it via SpecimenDefinition.calculate_slug_from_facility(facility.external_id, slug)f-<facility_external_id>-<slug_value>.
  • Facility binding (create). perform_create sets instance.facility from the facility_external_id URL kwarg before saving.
  • Slug decomposition (read). SpecimenDefinitionReadSpec.perform_extra_serialization exposes slug_config = obj.parse_slug(obj.slug), splitting the stored slug back into { facility, slug_value }.
  • Specimen instantiation. convert_sd_to_specimen (specimen.py) builds a Specimen from a definition with status="available", specimen_type = definition.type_collected, and specimen_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 requires facility_external_id in the URL.
  • Authorization. Writes require can_write_facility_specimen_definition; list/retrieve require can_list_facility_specimen_definition on the facility — otherwise 403 PermissionDenied. The queryset is filtered to the URL facility.
  • Filtering / ordering. status (iexact) and title (icontains) filters; ordering by created_date / modified_date.
  • Write payload (SpecimenDefinitionWriteSpec): send slug_value, title, status, description, the coded fields (type_collected, patient_preparation, collection) as Coding objects, and type_tested. Don't send facility, version, or the qualified slug — they're server-managed.
  • Read payload (SpecimenDefinitionReadSpec): adds id (= external_id), version, the qualified slug, and slug_config.
  • The model maps to the FHIR SpecimenDefinition resource. Care's spec is intentionally minimal: one container per definition, and behaviour changes bump version rather than mutate published records.