Patient
Introduction #
The Patient model represents an individual receiving care or other health-related services.
Basic usage #
To get a patient by identifier, use the get method on the Patient model manager:
from canvas_sdk.v1.data.patient import Patient
patient = Patient.objects.get(id="b80b1cdc2e6a4aca90ccebc02e683f35")
Filtering #
Patients can be filtered by any attribute that exists on the model.
Filtering for patients is done with the filter method on the Patient model manager.
By attribute #
Specify attributes with filter to filter by those attributes:
from canvas_sdk.v1.data.patient import Patient
patients = Patient.objects.filter(first_name="Bob", last_name="Loblaw", birth_date="1960-09-22")
Retrieving only committed, recorded data #
To restrict a patient’s clinical data to committed records, use the queryset’s committed() method. It keeps records with a non-null committer and a null entered_in_error, and the model’s default manager already excludes deleted records. For example, for a patient’s observations:
from canvas_sdk.v1.data.observation import Observation
observations = Observation.objects.for_patient(patient.id).committed()
Most clinical data models provide committed(). On a model that records a committer without providing it, such as Command, filter on committer_id__isnull=False, entered_in_error_id__isnull=True directly.
Accessing the patient photo #
The photo_url property returns a presigned S3 URL for securely accessing the patient’s uploaded avatar photo. If the patient has no uploaded avatar, the property returns a default avatar URL instead — so the value is always safe to render without a null check.
from canvas_sdk.v1.data.patient import Patient
patient = Patient.objects.get(id="d7af3e356368446c85b40a5d6ff7288e")
# Returns a presigned S3 URL (valid for 1 hour), or the default avatar URL when no photo is on file
url = patient.photo_url
If you need the underlying PatientPhoto record (for example, to read its title, or the stored file key with url.name), use the photo property:
from canvas_sdk.v1.data.patient import Patient
patient = Patient.objects.get(id="d7af3e356368446c85b40a5d6ff7288e")
photo = patient.photo # PatientPhoto or None
if photo:
print(photo.title)
Reading uploaded images and PDFs #
To read uploaded files (such as insurance card images or scanned PDFs) programmatically, use the file-upload data models, which expose the underlying S3 link rather than requiring direct bucket/AWS credentials:
DocumentReference— uploaded documentsSnapshot/SnapshotImage— snapshot imagesPatientIdentificationCard— insurance card and ID card images (image_urlproperty)MessageAttachment.file_url— files attached to messages
Accessing educational materials #
If you have a Patient object, the educational materials recorded on their notes can be accessed with the education_material reverse relation:
from canvas_sdk.v1.data.patient import Patient
patient = Patient.objects.get(id="d7af3e356368446c85b40a5d6ff7288e")
educational_materials = patient.education_material.all()
Detecting patient portal registration #
To detect whether a patient has registered for the patient portal, use the is_portal_registered boolean on the patient’s CanvasUser record (via the user relation). Patient portal verification is a separate process from contact-point verification, so check this boolean rather than PatientContactPoint.last_verified for portal registration:
from canvas_sdk.v1.data.patient import Patient
patient = Patient.objects.get(id="d7af3e356368446c85b40a5d6ff7288e")
registered = patient.user.is_portal_registered
Attributes #
Patient #
| Field Name | Type | Description |
|---|---|---|
| id | String | |
| dbid | Integer | |
| first_name | String | |
| last_name | String | |
| birth_date | Date | |
| sex_at_birth | SexAtBirth | |
| created | DateTime | |
| modified | DateTime | |
| prefix | String | |
| suffix | String | |
| middle_name | String | |
| maiden_name | String | |
| nickname | String | |
| sexual_orientation_term | String | |
| sexual_orientation_code | String | |
| gender_identity_term | String | |
| gender_identity_code | String | |
| preferred_pronouns | String | |
| biological_race_codes | Array[String] | |
| cultural_ethnicity_codes | Array[String] | |
| last_known_timezone | String | |
| mrn | String | |
| active | Boolean | |
| deceased | Boolean | |
| deceased_datetime | DateTime | |
| deceased_cause | String | |
| deceased_comment | String | |
| other_gender_description | String | |
| social_security_number | String | |
| administrative_note | String | |
| clinical_note | String | |
| mothers_maiden_name | String | |
| multiple_birth_indicator | Boolean | |
| birth_order | Integer | |
| default_location_id | Integer | |
| default_provider_id | Integer | |
| addresses | PatientAddress[] | |
| allergy_intolerances | AllergyIntolerance[] | |
| assessed_coding_gaps | AssessCodingGapEvent[] | |
| assessed_detected_issues | ValidateCodingGapEvent[] | |
| billing_line_items | BillingLineItem | |
| business_line | BusinessLine | |
| care_team_memberships | CareTeamMembership[] | |
| change_medications | ChangeMedication[] | |
| clipboards | Clipboard[] | |
| conditions | Condition[] | |
| coverages | Coverage[] | |
| created_detected_issues | CreateCodingGapEvent[] | |
| custom_commands | CustomCommand[] | |
| deferred_detected_issues | DeferCodingGapEvent[] | |
| dependent_coverages | Coverage[] | |
| detected_issues | DetectedIssue[] | |
| devices | Device[] | |
| external_identifiers | PatientExternalIdentifier[] | |
| identification_cards | PatientIdentificationCard[] | |
| imaging_orders | ImagingOrder[] | |
| imaging_results | ImagingReport[] | |
| imaging_reviews | ImagingReview[] | |
| interviews | Interview[] | |
| lab_orders | LabOrder[] | |
| lab_reports | LabReport[] | |
| lab_reviews | LabReview[] | |
| medications | Medication[] | |
| metadata | PatientMetadata[] | |
| observations | Observation[] | |
| payment_cards | PaymentCard[] | |
| photos | PatientPhoto[] | |
| preferred_pharmacy | JSON | |
| preferred_pharmacies | JSON | |
| protocol_overrides | ProtocolOverride[] | |
| settings | PatientSetting | |
| subscribed_coverages | Coverage[] | |
| tasks | Task[] | |
| telecom | PatientContactPoint[] | |
| contacts | PatientContactPerson[] | |
| related_contacts | PatientContactPerson[] | Contacts on other patients that reference this one |
| user | CanvasUser[] | |
| patient_groups | PatientGroup[] | |
| chart_section_reviews | ChartSectionReview[] | |
| visual_exam_findings | VisualExamFinding[] | |
| vital_sign_readings | VitalSignReading[] | |
| assessments | Assessment[] | |
| patient_visits | ExternalVisit[] | |
| patient_events | ExternalEvent[] | |
| medication_statements | MedicationStatement[] | |
| diagnostic_reports | DiagnosticReport[] | |
| medication_history_medications | MedicationHistoryMedication[] | |
| medication_history_responses | MedicationHistoryResponse[] | |
| payments | BulkPatientPosting[] | |
| protocol_currents | ProtocolCurrent[] | |
| stopped_medications | StopMedicationEvent[] | |
| banner_alerts | BannerAlert[] | |
| immunizations | Immunization[] | |
| immunization_statements | ImmunizationStatement[] | |
| integration_tasks | IntegrationTask[] | |
| installment_plans | InstallmentPlan[] | |
| uncategorized_clinical_document_reviews | UncategorizedClinicalDocumentReview[] | |
| patient_consent | PatientConsent[] | |
| goals | Goal[] | |
| updategoals | UpdateGoal[] | |
| instructions | Instruction[] | |
| appointments | Appointment[] | |
| notes | Note[] | |
| prescriptions | Prescription[] | |
| refill_requests | RefillRequest[] | |
| referral_reviews | ReferralReview[] | |
| referral_reports | ReferralReport[] | |
| invoices | Invoice[] | |
| education_material | EducationalMaterial[] | |
| procedures | Procedure[] | |
| family_histories | FamilyHistory[] | |
| histories_of_present_illness | HistoryOfPresentIllness[] | |
| plans | Plan[] | |
| follow_ups | FollowUp[] | |
| reasons_for_visit | ReasonForVisit[] | |
| removed_allergies | RemoveAllergyEvent[] | |
| removed_past_medical_history | RemovePastMedicalHistoryEvent[] | |
| resolved_conditions | ResolveConditionEvent[] | |
| cancel_prescriptions | CancelPrescription[] | |
| cancel_prescription_responses | CancelPrescriptionResponse[] | |
| prescription_change_requests | PrescriptionChangeRequest[] | |
| prescription_change_responses | PrescriptionChangeResponse[] | |
| full_name | String (computed) | The full name of the patient, combining first, middle, and last names |
| preferred_pharmacy | Dict (computed) | The patient’s preferred pharmacy for medication fulfillment |
| preferred_full_name | String (computed) | The patient’s preferred full name, if different from the legal name |
| preferred_first_name | String (computed) | The patient’s preferred first name, if different from the legal first name |
| primary_phone_number | PatientContactPoint (computed) | The patient’s primary contact number |
| photo | PatientPhoto (computed) | The patient’s first uploaded avatar, if any |
| photo_url | String (computed) | A presigned URL for the patient’s avatar photo, or the default avatar URL when no photo is set |
PatientAddress #
| Field Name | Type |
|---|---|
| id | UUID |
| dbid | Integer |
| created | DateTime |
| modified | DateTime |
| line1 | String |
| line2 | String |
| city | String |
| district | String |
| state_code | String |
| postal_code | String |
| use | AddressUse |
| type | AddressType |
| longitude | Float |
| latitude | Float |
| start | Date |
| end | Date |
| country | String |
| state | AddressState |
| patient | Patient |
from canvas_sdk.v1.data.patient import Patient
from logger import log
patient_id = "d7af3e356368446c85b40a5d6ff7288e"
patient = Patient.objects.get(id=patient_id)
patient_addresses = patient.addresses.all()
for addr in patient_addresses:
log.info(f"Patient address: {addr.city}, {addr.state_code}, {addr.postal_code}") # Seattle, WA, 98118
PatientContactPoint #
| Field Name | Type |
|---|---|
| id | UUID |
| dbid | Integer |
| created | DateTime |
| modified | DateTime |
| system | ContactPointSystem |
| value | String |
| use | String |
| use_notes | String |
| rank | Integer |
| state | ContactPointState |
| patient | Patient |
| has_consent | Boolean |
| last_verified | DateTime |
| verification_token | String |
| opted_out | Boolean |
To fetch a patient’s contact points, query the patient’s telecom relation. Use .all() for every contact point, or .filter() for a subset such as phone numbers:
from canvas_sdk.v1.data.patient import Patient
from logger import log
patient_id = "d7af3e356368446c85b40a5d6ff7288e"
patient = Patient.objects.get(id=patient_id)
# All contact points
patient_contacts = patient.telecom.all()
# Just the phone numbers
phone_contacts = patient.telecom.filter(system="phone")
for contact in patient_contacts:
log.info(f"Patient contact: {contact.system} - {contact.value}") # phone - 5555555555
PatientExternalIdentifier #
| Field Name | Type |
|---|---|
| id | UUID |
| dbid | Integer |
| created | DateTime |
| modified | DateTime |
| patient | Patient |
| use | String |
| identifier_type | String |
| system | String |
| value | String |
| issued_date | Date |
| expiration_date | Date |
from canvas_sdk.v1.data.patient import Patient
from logger import log
patient_id = "d7af3e356368446c85b40a5d6ff7288e"
patient = Patient.objects.get(id=patient_id)
patient_external_identifiers = patient.external_identifiers.all()
for identifier in patient_external_identifiers:
log.info(f"Patient external identifier: {identifier.system}, {identifier.value}") # https://www.example.com - abc123
PatientSetting #
| Field Name | Type |
|---|---|
| dbid | Integer |
| created | DateTime |
| modified | DateTime |
| patient | Patient |
| name | String |
| value | JSON |
Setting names #
A patient carries at most one setting per name. Canvas maintains these:
| Name | Holds |
|---|---|
pharmacy | The patient’s preferred pharmacies. Read this through preferred_pharmacies, which normalizes the older single-pharmacy shape into a list |
preferredSchedulingTimezone | The timezone to schedule the patient in, for example America/New_York |
Because value is JSON, its shape differs from one setting to the next.
Use get_setting to read one by name. It returns None when the patient has no setting by that name, so a missing setting and a stored empty value are distinguishable.
from canvas_sdk.v1.data.patient import Patient
from logger import log
patient_id = "d7af3e356368446c85b40a5d6ff7288e"
patient = Patient.objects.get(id=patient_id)
log.info(patient.get_setting("preferredSchedulingTimezone")) # America/New_York
log.info(patient.get_setting("unset-setting-name")) # None
PatientMetadata #
| Field Name | Type |
|---|---|
| id | UUID |
| dbid | Integer |
| created | DateTime |
| modified | DateTime |
| patient | Patient |
| key | String |
| value | String |
from canvas_sdk.v1.data.patient import Patient
from logger import log
patient_id = "d7af3e356368446c85b40a5d6ff7288e"
patient = Patient.objects.get(id=patient_id)
patient_metadata = patient.metadata.all()
for metadata in patient_metadata:
log.info(f"Patient metadata: {metadata.key}, {metadata.value}") # favorite_color - red
PatientPhoto #
Represents a patient’s uploaded avatar photo.
| Field Name | Type |
|---|---|
| dbid | Integer |
| created | DateTime |
| modified | DateTime |
| patient | Patient |
| url | File (S3 key) |
| title | String |
from canvas_sdk.v1.data.patient import Patient
from logger import log
patient = Patient.objects.get(id="d7af3e356368446c85b40a5d6ff7288e")
for photo in patient.photos.all():
log.info(f"Photo: {photo.title}, stored at: {photo.url.name}")
PatientIdentificationCard #
Represents a patient identification card image (e.g., driver’s license, insurance card).
| Field Name | Type | Description |
|---|---|---|
| dbid | Integer | |
| created | DateTime | |
| modified | DateTime | |
| patient | Patient | |
| image | File (S3 key) | |
| title | String | |
| active | Boolean | |
| image_url | String (computed) | Presigned S3 URL |
from canvas_sdk.v1.data.patient import Patient
from logger import log
patient = Patient.objects.get(id="d7af3e356368446c85b40a5d6ff7288e")
for card in patient.identification_cards.filter(active=True):
log.info(f"ID card: {card.title}, URL: {card.image_url}")
PatientFacilityAddress #
| Field Name | Type |
|---|---|
| patientaddress | PatientAddress |
| facility | Facility |
| room_number | String |
PatientContactPerson #
One of the patient’s contacts — an emergency contact, next-of-kin, or other related person. A contact either holds the person’s details directly, or references another Canvas patient through related_patient; when it does, that patient’s own details supersede the values stored here.
id is the value the Patient effect takes as contact_identifier when modifying or removing a contact.
| Field Name | Type |
|---|---|
| id | UUID |
| dbid | Integer |
| created | DateTime |
| modified | DateTime |
| patient | Patient |
| name | String |
| phone_number | String |
| String | |
| comments | String |
| related_patient | Patient |
| categories | PatientContactCategory[] |
from canvas_sdk.v1.data import PatientContactPerson
from logger import log
contacts = PatientContactPerson.objects.filter(
patient__id="d7af3e356368446c85b40a5d6ff7288e"
).select_related("related_patient").prefetch_related("categories__category")
for contact in contacts:
who = contact.related_patient.first_name if contact.related_patient else contact.name
codings = ", ".join(link.category.code for link in contact.categories.all())
log.info(f"Contact: {who} ({codings})") # Contact: Jane (EMC)
PatientContactCategory #
Links one of the patient’s contacts to one of the category codings the instance defines.
| Field Name | Type |
|---|---|
| dbid | Integer |
| created | DateTime |
| modified | DateTime |
| contact_person | PatientContactPerson |
| category | ContactCategory |
ContactCategory #
A contact-category coding available in this Canvas instance — the set a contact’s relationship can be drawn from.
Use this to look up a coding before writing it with the Patient effect. Writing a coding that does not appear here is rejected rather than created, so querying this model first is how you find out what the instance actually has.
| Field Name | Type |
|---|---|
| dbid | Integer |
| created | DateTime |
| modified | DateTime |
| name | String |
| code | String |
| system | String |
| protected | Boolean |
from canvas_sdk.v1.data import ContactCategory
from logger import log
for coding in ContactCategory.objects.order_by("code"):
log.info(f"{coding.code} / {coding.system} — {coding.name}") # EMC / INTERNAL — Emergency contact
Enumeration types #
SexAtBirth #
| Value | Label |
|---|---|
| F | female |
| M | male |
| O | other |
| UNK | unknown |
| ”” (empty string) | ”” |