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_value → obj.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.