An ActivityDefinition is a FHIR-aligned, facility-scoped template for a clinical activity. It stores the defaults needed to spin up a downstream resource — currently a References/Service Request — and you "apply" it against an encounter, which merges those defaults with the encounter context to produce the live resource.
The Django model is just storage. Several fields are opaque JSONFields or integer ArrayFields whose real structure lives in the Pydantic resource specs — the API layer that defines the enums, JSON shapes, validation rules, and the split between read and write schemas. Neither layer is complete on its own; read them together.
Models
Model
Purpose
ActivityDefinition
Versioned, facility-scoped template describing a clinical activity and the defaults used to create the resources it produces
ActivityDefinition extends SlugBaseModel, which adds a facility-scoped slug on top of EMRBaseModel. From EMRBaseModel it inherits external_id, created_date/modified_date, soft-delete via deleted, created_by/updated_by, and the history/meta JSON fields. See Base model.
ActivityDefinition fields
Each field lists its storage type (Django model) and, where the spec constrains it, the API shape or values the Pydantic specs enforce.
Identity & versioning
Field
Storage type
API shape / notes
facility
FK → facility.Facility (PROTECT)
Owning facility. Spec-__exclude__d — set server-side and never accepted in the payload.
slug
CharField(255)
Facility-scoped identifier. On write you supply it as slug_value (SlugType); perform_extra_deserialization assigns it to obj.slug. On read it comes back as slug plus a parsed slug_config dict.
version
IntegerField
None), serialized on list and retrieve. Drives the append-only version chain.
latest
BooleanField
Default True. Marks the current version within a slug's chain. Server-maintained, not exposed in the specs.
Required enum — ActivityDefinitionKindOptions (only service_request). Determines the resource produced on apply.
description
TextField
Optional in specs; default "".
usage
TextField
Optional in specs; default "".
Coded clinical attributes (JSON)
These are JSONFields. The spec binds each to a value set via ValueSetBoundCoding[<slug>], which validates the submitted code against that value set. Every coding is shaped { system?: str, version?: str, code: str (required), display?: str } with extra="forbid", so unknown keys are rejected.
Field
Storage type
API shape / notes
code
JSONField (nullable)
Required Coding bound to value set activity-definition-procedure-code (SNOMED CT, concept is-a 71388002 "Procedure"). Nullable in the DB but rejected on write if absent.
body_site
JSONField (nullable)
None = None bound to value set system-body-site-observation (SNOMED CT body sites).
diagnostic_report_codes
JSONField (nullable)
list[Coding], default []. Each Coding bound to value set system-observation (LOINC).
Requirement & linkage arrays
These store integer primary keys, not Django FK relations — ArrayField(IntegerField, default=list). The specs never expose those raw PKs: writes reference targets by external slug or UUID, and retrieves expand them back into serialized objects.
list[dict] — rendered via SingleFacilityTagManager().render_tags(obj)
ExtendedSlugType: 7–88 chars, URL-safe, must start with f- or i-. SlugType (used for slug_value): 5–50 chars, URL-safe. The stored integer arrays carry no referential integrity — nothing stops you storing an ID whose target is later deleted, and retrieve serialization silently skips any ID that no longer resolves.
Service relationships
Field
Storage type
API shape / notes
healthcare_service
FK → emr.HealthcareService (PROTECT)
None, resolved by external_id in perform_extra_deserialization. Retrieve: serialized via HealthcareServiceReadSpec. See References/Healthcare Service.
category
FK → emr.ResourceCategory (CASCADE)
None, resolved by slug. Read: serialized via ResourceCategoryReadSpec. Deleting the References/Resource Category cascades to the definition.
All specs extend EMRResource (see Base model), which provides serialize (DB → Pydantic) and de_serialize (Pydantic → DB) plus the perform_extra_serialization / perform_extra_deserialization hooks. Here __model__ = ActivityDefinition and __exclude__ = ["facility"].
Resolves healthcare_service by external_id, or clears it to None when absent.
Resolves category by slug, only when provided.
Assigns obj.slug = self.slug_value.
ActivityDefinitionReadSpec.perform_extra_serialization (read path): sets id = external_id, renders tags, serializes category (when present) via ResourceCategoryReadSpec, and parses slug_config = obj.parse_slug(obj.slug).
ActivityDefinitionRetrieveSpec.perform_extra_serialization: calls the parent, then resolves each ID array (specimen_requirements, observation_result_requirements, locations, charge_item_definitions) against its model — dropping IDs that no longer exist — and serializes healthcare_service.
The base de_serialize writes only model-mapped fields with exclude_defaults=True, so any unset optional field falls back to its model default.
Charge items on apply: apply_ad_charge_definitions(activity_definition, encounter, service_request) loads every linked References/Charge Item Definition and, for each, instantiates a Charge Item (via apply_charge_item_definition), tags it to the service request (service_resource = service_request, service_resource_id = external_id), copies the creator, and sets performer_actor to the request's requester when one is set.
version and latest form an append-only chain per slug: query latest=True for the current definition; superseded versions stay readable so existing references don't break.
API integration notes
Payload field names follow the Pydantic specs, not the Django model. Send slug as slug_value. Reference specimen_requirements, observation_result_requirements, charge_item_definitions, and category by external slug (ExtendedSlugType, f-/i- prefixed); reference locations and healthcare_service by UUID.
code is required and must validate against the activity-definition-procedure-code value set. body_site and each entry of diagnostic_report_codes validate against their bound value sets.
Apply instantiates the target kind (only service_request today) by merging stored defaults with the encounter, and instantiates any linked charge_item_definitions in the same pass.
The requirement and linkage fields are plain integer ID arrays. Retrieve serialization resolves them to nested objects and skips any ID that no longer resolves, so a response can omit a requirement you stored.