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
Tag: Reverted
Automated edit (via update-page on MediaWiki MCP Server)
 
(One intermediate revision by the same user not shown)
Line 2: Line 2:
|type=reference
|type=reference
|domain=clinical
|domain=clinical
|title=Patient
|title=Patient (reference)
|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 12: Line 14:


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


Line 45: Line 38:


{| 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 57: Line 47:
|}
|}


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


{| class="wikitable"
{| class="wikitable"
! Field !! Type !! Notes
|-
{{Field|model=Patient|section=Contact & address|name=phone_number|type=CharField(14)|notes=Validated with <code>mobile_or_landline_number_validator</code>}}
! Field
{{Field|model=Patient|section=Contact & address|name=emergency_phone_number|type=CharField(14)|notes=Same validator}}
! Type
{{Field|model=Patient|section=Contact & address|name=address|type=TextField|notes=Current address}}
! 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=permanent_address|type=TextField|notes=}}
{{Field|model=Patient|section=Contact &amp; address|name=emergency_phone_number|type=CharField(14)|notes=Same validator}}
{{Field|model=Patient|section=Contact & address|name=pincode|type=IntegerField|notes=Nullable}}
{{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 &amp; access caches ===
=== Organization & 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|model=Patient|section=Organization & access caches|name=geo_organization|type=FK → Organization|notes=Geographic/administrative org assignment}}
! Field
{{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}}
! Type
{{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}}
! Rebuilt by
|-
| <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 &amp; tags ===
=== Identifiers & tags ===


{| class="wikitable"
{| class="wikitable"
! Field !! Type !! Notes
|-
{{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)}}
! Field
{{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>}}
! Type
{{Field|model=Patient|section=Identifiers & tags|name=instance_tags|type=ArrayField[int]|notes=Instance-level tag IDs}}
! Notes
{{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=facility_tags|type=JSONField|notes=Dict keyed by facility tag IDs}}
{{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 & tags|name=extensions|type=JSONField|notes=Open extension bag for deployment-specific metadata}}
{{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 114: Line 86:
=== <code>PatientOrganization</code> ===
=== <code>PatientOrganization</code> ===


<syntaxhighlight lang="text">patient → FK Patient
<syntaxhighlight lang="text">
patient → FK Patient
organization → FK Organization</syntaxhighlight>
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 122: Line 97:
Grants a Care user access to a patient record.
Grants a Care user access to a patient record.


<syntaxhighlight lang="text">user → FK User
<syntaxhighlight lang="text">
user → FK User
patient → FK Patient
patient → FK Patient
role → FK RoleModel (PROTECT)</syntaxhighlight>
role → FK RoleModel (PROTECT)
</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 131: Line 109:
<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">patient → FK Patient
<syntaxhighlight lang="text">
patient → FK Patient
config → FK PatientIdentifierConfig
config → FK PatientIdentifierConfig
facility → FK Facility (nullable)
facility → FK Facility (nullable)
value → CharField(1024), indexed</syntaxhighlight>
value → CharField(1024), indexed
</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 &amp; save behaviour ==
== Methods & save behaviour ==


=== Age ===
=== Age ===
Line 153: Line 134:
# <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=[&quot;organization_cache&quot;, &quot;users_cache&quot;])</code> persists the caches
# A second <code>save(update_fields=["organization_cache", "users_cache"])</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.
Line 163: Line 144:
* <code>extensions</code> is the supported place for custom key-value data without schema migrations.
* <code>extensions</code> is the supported place for custom key-value data without schema migrations.
* <code>users_cache</code> and <code>organization_cache</code> are maintained by the platform — do not set them directly from clients.
* <code>users_cache</code> and <code>organization_cache</code> are maintained by the platform — do not set them directly from clients.

{{Navbox clinical}}


{{Related}}
{{Related}}
Wiki: ohcnwiki.tellmey.fyi

Latest revision as of 09:31, 6 July 2026

referenceclinicalFHIR: PatientCARE 3.0+source

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

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

edit edit source
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

edit edit source
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

edit edit source

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

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

Identifiers & tags

edit edit source
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).

edit edit source

PatientOrganization

edit edit source
patient  → FK Patient
organization → FK Organization

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

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

edit edit source

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

edit edit source
  • 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

edit edit source

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

edit edit source
  • 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:

Wiki: ohcnwiki.tellmey.fyi