AllergyIntolerance records a patient's allergy or intolerance to a substance, scoped to the encounter where it was captured. Care aligns it to FHIR AllergyIntolerance. You touch this resource when recording a known allergy during an encounter or reading a patient's allergy list.
The Django model is the storage layer. Several of its fields are opaque JSONFields whose real structure lives only in the Pydantic resource specs, which also define the enums, validation, the bound value set, and the read/write API schemas.
Records a patient's allergy or intolerance to a substance, scoped to an encounter
AllergyIntolerance extends EMRBaseModel, the shared Care EMR base that provides external_id, created_date/modified_date, soft-delete via deleted, created_by/updated_by, and history/meta JSON.
On write, code binds to this value set via ValueSetBoundCoding[...slug], which validates the submitted Coding against the value set (validate_valueset). The compose admits SNOMED CT concepts that are is-a descendants of: 105590001, 418038007, 267425008, 29736007, 340519003, 190753003, 413427002, 716186003. The value set is also registered as a system (register_as_system()).
Resource specs (API schema)
Every spec extends EMRResource (care/emr/resources/base.py), which provides serialize (DB object → pydantic, via model_construct) and de_serialize (pydantic → DB object), plus the perform_extra_serialization / perform_extra_deserialization hooks. BaseAllergyIntoleranceSpec sets __model__ = AllergyIntolerance and __exclude__ = ["patient", "encounter"]; those two fields skip auto-mapping and are wired by the hooks instead. The base also carries meta on every spec.
category, code, onset, and recorded_date are accepted only on create (AllergyIntoleranceWriteSpec) and absent from AllergyIntoleranceUpdateSpec — once set, the update path cannot change them.
AllergyIntoleranceReadSpec types the coded fields as plain str and code as Coding, and skips value-set re-validation, relying on model_construct for speed.
Validation
encounter (both write specs): validate_encounter_exists rejects with "Encounter not found" when no Encounter has that external_id.
code (create): validated against value set system-allergy-code — must be a permitted SNOMED CT allergy concept.
onset.note is required whenever an onset object is supplied.
datetime fields are stored as-is. The base enforces tz-aware handling for period-style values through PeriodSpec (start ≤ end, both tz-aware), but AllergyIntolerance uses scalar datetimes rather than a PeriodSpec.
Server-side side effects
Create (AllergyIntoleranceWriteSpec.perform_extra_deserialization): resolves encounter by external_id, sets obj.encounter, then sets obj.patient = obj.encounter.patient. The client never sends patient directly.
Update (AllergyIntoleranceUpdateSpec.perform_extra_deserialization): when encounter is present, re-resolves it and sets obj.encounter.
Read (AllergyIntoleranceReadSpec.perform_extra_serialization): sets mapping["id"] = obj.external_id, sets encounter to obj.encounter.external_id, and serializes audit users (created_by / updated_by) via serialize_audit_users.
Methods & save behaviour
serialize / de_serialize are inherited from EMRResource. de_serialize maps only DB fields that are neither in __exclude__ nor id/external_id, then calls perform_extra_deserialization for the encounter/patient wiring above.
patient is always derived from the encounter on create; no client payload can set it.
copied_from is platform-maintained for propagated/copied records and belongs to no spec.
patient and encounter both CASCADE-delete, so an allergy record never outlives its patient or encounter.
API integration notes
API field names follow the spec classes above. encounter is sent and returned as a UUID external_id, not a numeric FK.
Submit code as a Coding drawn from the bound value set system-allergy-code, not free text, so allergies can be matched against medications and other business logic.
The coded status fields (clinical_status, verification_status, category, criticality) accept only the enum values listed above; anything else is rejected on write.
Never send patient or copied_from — both are server-maintained.