Toggle menu
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.

References/Patient: Difference between revisions

From OHC Network Wiki
Content deleted Content added
OHC identity seed
 
OHC identity seed
Tag: Reverted
Line 2: Line 2:
|type=reference
|type=reference
|domain=clinical
|domain=clinical
|title=Patient (reference)
|title=Patient
|summary=Technical reference for the Patient module in Care EMR — models, fields, relationships, and save behaviour.
|order=1
|order=1
|introduced=3.0
|introduced=3.0
|fhir=Patient
|fhir=Patient
|model=Patient
|model=Patient
|source=care/emr/models/patient.py
|concept=Concepts/Patient
|concept=Concepts/Patient
|flow=Flows/Create a patient
|flow=Flows/Create a patient
Line 14: Line 12:


Technical reference for the <code>Patient</code> module in Care EMR. For a product-oriented overview, see the [[Concepts/Patient|Patient concept]].
Technical reference for the <code>Patient</code> module in Care EMR. For a product-oriented overview, see the [[Concepts/Patient|Patient concept]].

'''Source:''' [<nowiki/>https://github.com/ohcnetwork/care/blob/develop/care/emr/models/patient.py <code>care/emr/models/patient.py</code>]


== Models ==
== Models ==


{| class="wikitable"
{| class="wikitable"
! Model !! Purpose
|-
|-
! Model
| <code>Patient</code> || Core patient record
! Purpose
|-
|-
| <code>Patient</code>
| <code>PatientOrganization</code> || Links a patient to an <code>Organization</code>
| Core patient record
|-
|-
| <code>PatientOrganization</code>
| <code>PatientUser</code> || Grants a <code>User</code> access to a patient with a <code>RoleModel</code>
| Links a patient to an <code>Organization</code>
|-
|-
| <code>PatientUser</code>
| <code>PatientIdentifierConfig</code> || Defines identifier types (instance-wide or per-facility)
| Grants a <code>User</code> access to a patient with a <code>RoleModel</code>
|-
|-
| <code>PatientIdentifierConfig</code>
| <code>PatientIdentifier</code> || Stores an identifier value for a patient
| Defines identifier types (instance-wide or per-facility)
|-
| <code>PatientIdentifier</code>
| Stores an identifier value for a patient
|}
|}


Line 38: Line 45:


{| class="wikitable"
{| class="wikitable"
|-
! Field !! Type !! Notes
! Field
! Type
! Notes
{{Field|model=Patient|section=Demographics|name=name|type=CharField(200)|notes=Display name}}
{{Field|model=Patient|section=Demographics|name=name|type=CharField(200)|notes=Display name}}
{{Field|model=Patient|section=Demographics|name=gender|type=CharField(35)|notes=Administrative gender}}
{{Field|model=Patient|section=Demographics|name=gender|type=CharField(35)|notes=Administrative gender}}
Line 47: Line 57:
|}
|}


=== Contact & address ===
=== Contact &amp; address ===


{| class="wikitable"
{| class="wikitable"
|-
! Field !! Type !! Notes
! Field
{{Field|model=Patient|section=Contact & address|name=phone_number|type=CharField(14)|notes=Validated with <code>mobile_or_landline_number_validator</code>}}
! Type
{{Field|model=Patient|section=Contact & address|name=emergency_phone_number|type=CharField(14)|notes=Same validator}}
! Notes
{{Field|model=Patient|section=Contact & address|name=address|type=TextField|notes=Current address}}
{{Field|model=Patient|section=Contact & address|name=permanent_address|type=TextField|notes=}}
{{Field|model=Patient|section=Contact &amp; address|name=phone_number|type=CharField(14)|notes=Validated with <code>mobile_or_landline_number_validator</code>}}
{{Field|model=Patient|section=Contact & address|name=pincode|type=IntegerField|notes=Nullable}}
{{Field|model=Patient|section=Contact &amp; address|name=emergency_phone_number|type=CharField(14)|notes=Same validator}}
{{Field|model=Patient|section=Contact &amp; address|name=address|type=TextField|notes=Current address}}
{{Field|model=Patient|section=Contact &amp; address|name=permanent_address|type=TextField|notes=}}
{{Field|model=Patient|section=Contact &amp; address|name=pincode|type=IntegerField|notes=Nullable}}
|}
|}


=== Organization & access caches ===
=== Organization &amp; access caches ===


These are '''denormalized caches''' rebuilt on every <code>Patient.save()</code> for fast filtering without deep joins.
These are '''denormalized caches''' rebuilt on every <code>Patient.save()</code> for fast filtering without deep joins.


{| class="wikitable"
{| class="wikitable"
|-
! Field !! Type !! Notes
! Field
{{Field|model=Patient|section=Organization & access caches|name=geo_organization|type=FK → Organization|notes=Geographic/administrative org assignment}}
! Type
{{Field|model=Patient|section=Organization & access caches|name=organization_cache|type=ArrayField[int]|notes=Rebuilt by <code>rebuild_organization_cache()</code> — includes <code>geo_organization</code> parent chain and all linked <code>PatientOrganization</code> orgs}}
! Rebuilt by
{{Field|model=Patient|section=Organization & access caches|name=users_cache|type=ArrayField[int]|notes=Rebuilt by <code>rebuild_users_cache()</code> — user IDs from <code>PatientUser</code> rows}}
|-
| <code>geo_organization</code>
| <code>FK Organization</code>
| Geographic/administrative org assignment
|-
| <code>organization_cache</code>
| <code>ArrayField[int]</code>
| <code>rebuild_organization_cache()</code> — includes <code>geo_organization</code> parent chain and all linked <code>PatientOrganization</code> orgs
|-
| <code>users_cache</code>
| <code>ArrayField[int]</code>
| <code>rebuild_users_cache()</code> — user IDs from <code>PatientUser</code> rows
|}
|}


=== Identifiers & tags ===
=== Identifiers &amp; tags ===


{| class="wikitable"
{| class="wikitable"
|-
! Field !! Type !! Notes
! Field
{{Field|model=Patient|section=Identifiers & tags|name=instance_identifiers|type=JSONField|notes=List of <code>{config, value}</code> built from <code>PatientIdentifier</code> rows (instance-scoped configs)}}
! Type
{{Field|model=Patient|section=Identifiers & tags|name=facility_identifiers|type=JSONField|notes=Dict keyed by <code>facility_id</code>list of <code>{config, value}</code>}}
! Notes
{{Field|model=Patient|section=Identifiers & tags|name=instance_tags|type=ArrayField[int]|notes=Instance-level tag IDs}}
{{Field|model=Patient|section=Identifiers & tags|name=facility_tags|type=JSONField|notes=Dict keyed by facility tag IDs}}
{{Field|model=Patient|section=Identifiers &amp; tags|name=instance_identifiers|type=JSONField|notes=List of <code>{config, value}</code> built from <code>PatientIdentifier</code> rows (instance-scoped configs)}}
{{Field|model=Patient|section=Identifiers & tags|name=extensions|type=JSONField|notes=Open extension bag for deployment-specific metadata}}
{{Field|model=Patient|section=Identifiers &amp; tags|name=facility_identifiers|type=JSONField|notes=Dict keyed by <code>facility_id</code> list of <code>{config, value}</code>}}
{{Field|model=Patient|section=Identifiers &amp; tags|name=instance_tags|type=ArrayField[int]|notes=Instance-level tag IDs}}
{{Field|model=Patient|section=Identifiers &amp; tags|name=facility_tags|type=JSONField|notes=Dict keyed by facilitytag IDs}}
{{Field|model=Patient|section=Identifiers &amp; tags|name=extensions|type=JSONField|notes=Open extension bag for deployment-specific metadata}}
|}
|}


Line 86: Line 114:
=== <code>PatientOrganization</code> ===
=== <code>PatientOrganization</code> ===


<syntaxhighlight lang="text">
<syntaxhighlight lang="text">patient → FK Patient
organization → FK Organization</syntaxhighlight>
patient → FK Patient
organization → FK Organization
</syntaxhighlight>

Saving a <code>PatientOrganization</code> triggers <code>patient.save()</code>, which rebuilds <code>organization_cache</code>.
Saving a <code>PatientOrganization</code> triggers <code>patient.save()</code>, which rebuilds <code>organization_cache</code>.


Line 97: Line 122:
Grants a Care user access to a patient record.
Grants a Care user access to a patient record.


<syntaxhighlight lang="text">
<syntaxhighlight lang="text">user → FK User
user → FK User
patient → FK Patient
patient → FK Patient
role → FK RoleModel (PROTECT)
role → FK RoleModel (PROTECT)</syntaxhighlight>
</syntaxhighlight>

Saving a <code>PatientUser</code> triggers <code>patient.save()</code>, which rebuilds <code>users_cache</code>.
Saving a <code>PatientUser</code> triggers <code>patient.save()</code>, which rebuilds <code>users_cache</code>.


Line 109: Line 131:
<code>PatientIdentifierConfig</code> defines what identifiers exist (status, optional facility scope, JSON config). <code>PatientIdentifier</code> stores the actual value:
<code>PatientIdentifierConfig</code> defines what identifiers exist (status, optional facility scope, JSON config). <code>PatientIdentifier</code> stores the actual value:


<syntaxhighlight lang="text">
<syntaxhighlight lang="text">patient → FK Patient
patient → FK Patient
config → FK PatientIdentifierConfig
config → FK PatientIdentifierConfig
facility → FK Facility (nullable)
facility → FK Facility (nullable)
value → CharField(1024), indexed
value → CharField(1024), indexed</syntaxhighlight>
</syntaxhighlight>

<code>PatientIdentifierConfigCache</code> provides in-process caching for configs (<code>get_instance_config()</code>, <code>get_facility_config(facility_id)</code>).
<code>PatientIdentifierConfigCache</code> provides in-process caching for configs (<code>get_instance_config()</code>, <code>get_facility_config(facility_id)</code>).


== Methods & save behaviour ==
== Methods &amp; save behaviour ==


=== Age ===
=== Age ===
Line 134: Line 153:
# <code>rebuild_organization_cache()</code> runs
# <code>rebuild_organization_cache()</code> runs
# <code>rebuild_users_cache()</code> runs
# <code>rebuild_users_cache()</code> runs
# A second <code>save(update_fields=["organization_cache", "users_cache"])</code> persists the caches
# A second <code>save(update_fields=[&quot;organization_cache&quot;, &quot;users_cache&quot;])</code> persists the caches


Integrators should expect '''two write passes''' when creating or updating patients through the ORM.
Integrators should expect '''two write passes''' when creating or updating patients through the ORM.

Revision as of 04:14, 5 July 2026

referenceclinicalFHIR: PatientCARE 3.0+

Technical reference for the Patient module in Care EMR. For a product-oriented overview, see the Patient concept.

Source: [https://github.com/ohcnetwork/care/blob/develop/care/emr/models/patient.py care/emr/models/patient.py]

Models

Model Purpose
Patient Core patient record
PatientOrganization Links a patient to an Organization
PatientUser Grants a User access to a patient with a RoleModel
PatientIdentifierConfig Defines identifier types (instance-wide or per-facility)
PatientIdentifier Stores an identifier value for a patient

All models extend EMRBaseModel (shared Care EMR base with external_id, audit fields, and soft-delete semantics).

Patient fields

Demographics

Field Type Notes
name CharField(200) Display name
gender CharField(35) Administrative gender
date_of_birth DateField Nullable; preferred when known
year_of_birth IntegerField Min 1900; used when full DOB is unknown. Auto-set from date_of_birth on save
deceased_datetime DateTimeField Set when patient is marked deceased; affects age calculation
blood_group CharField(16)

Contact & address

Field Type Notes
phone_number CharField(14) Validated with mobile_or_landline_number_validator
emergency_phone_number CharField(14) Same validator
address TextField Current address
permanent_address TextField
pincode IntegerField Nullable

Organization & access caches

These are denormalized caches rebuilt on every Patient.save() for fast filtering without deep joins.

Field Type Rebuilt by
geo_organization FK → Organization Geographic/administrative org assignment
organization_cache ArrayField[int] rebuild_organization_cache() — includes geo_organization parent chain and all linked PatientOrganization orgs
users_cache ArrayField[int] rebuild_users_cache() — user IDs from PatientUser rows

Identifiers & tags

Field Type Notes
instance_identifiers JSONField List of {config, value} built from PatientIdentifier rows (instance-scoped configs)
facility_identifiers JSONField Dict keyed by facility_id → list of {config, value}
instance_tags ArrayField[int] Instance-level tag IDs
facility_tags JSONField Dict keyed by facility → tag IDs
extensions JSONField Open extension bag for deployment-specific metadata

Identifier values live in PatientIdentifier and are materialized into the JSON caches via build_instance_identifiers() and build_facility_identifiers(facility_id).

PatientOrganization

patient  → FK Patient
organization → FK Organization

Saving a PatientOrganization triggers patient.save(), which rebuilds organization_cache.

PatientUser

Grants a Care user access to a patient record.

user   → FK User
patient → FK Patient
role   → FK RoleModel (PROTECT)

Saving a PatientUser triggers patient.save(), which rebuilds users_cache.

PatientIdentifier / PatientIdentifierConfig

PatientIdentifierConfig defines what identifiers exist (status, optional facility scope, JSON config). PatientIdentifier stores the actual value:

patient → FK Patient
config  → FK PatientIdentifierConfig
facility → FK Facility (nullable)
value   → CharField(1024), indexed

PatientIdentifierConfigCache provides in-process caching for configs (get_instance_config(), get_facility_config(facility_id)).

Methods & save behaviour

Age

  • get_age() → str — human-readable age (years, months, days) relative to deceased_datetime or now
  • age → int — whole years only

Both use date_of_birth when present, otherwise year_of_birth (January 1).

save() side effects

On every save:

  1. If date_of_birth is set and year_of_birth is empty → year_of_birth is derived
  2. rebuild_organization_cache() runs
  3. rebuild_users_cache() runs
  4. A second save(update_fields=["organization_cache", "users_cache"]) persists the caches

Integrators should expect two write passes when creating or updating patients through the ORM.

API integration notes

  • Patient records are exposed through Care's REST API and FHIR Patient resources; field names in API payloads may differ from Django model names.
  • Use instance_identifiers / facility_identifiers JSON for read-optimized identifier lookup; write through PatientIdentifier for consistency.
  • extensions is the supported place for custom key-value data without schema migrations.
  • users_cache and organization_cache are maintained by the platform — do not set them directly from clients.

Pages that link here: