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:

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 NameTypeDescription
idString 
dbidInteger 
first_nameString 
last_nameString 
birth_dateDate 
sex_at_birthSexAtBirth 
createdDateTime 
modifiedDateTime 
prefixString 
suffixString 
middle_nameString 
maiden_nameString 
nicknameString 
sexual_orientation_termString 
sexual_orientation_codeString 
gender_identity_termString 
gender_identity_codeString 
preferred_pronounsString 
biological_race_codesArray[String] 
cultural_ethnicity_codesArray[String] 
last_known_timezoneString 
mrnString 
activeBoolean 
deceasedBoolean 
deceased_datetimeDateTime 
deceased_causeString 
deceased_commentString 
other_gender_descriptionString 
social_security_numberString 
administrative_noteString 
clinical_noteString 
mothers_maiden_nameString 
multiple_birth_indicatorBoolean 
birth_orderInteger 
default_location_idInteger 
default_provider_idInteger 
addressesPatientAddress[] 
allergy_intolerancesAllergyIntolerance[] 
assessed_coding_gapsAssessCodingGapEvent[] 
assessed_detected_issuesValidateCodingGapEvent[] 
billing_line_itemsBillingLineItem 
business_lineBusinessLine 
care_team_membershipsCareTeamMembership[] 
change_medicationsChangeMedication[] 
clipboardsClipboard[] 
conditionsCondition[] 
coveragesCoverage[] 
created_detected_issuesCreateCodingGapEvent[] 
custom_commandsCustomCommand[] 
deferred_detected_issuesDeferCodingGapEvent[] 
dependent_coveragesCoverage[] 
detected_issuesDetectedIssue[] 
devicesDevice[] 
external_identifiersPatientExternalIdentifier[] 
identification_cardsPatientIdentificationCard[] 
imaging_ordersImagingOrder[] 
imaging_resultsImagingReport[] 
imaging_reviewsImagingReview[] 
interviewsInterview[] 
lab_ordersLabOrder[] 
lab_reportsLabReport[] 
lab_reviewsLabReview[] 
medicationsMedication[] 
metadataPatientMetadata[] 
observationsObservation[] 
payment_cardsPaymentCard[] 
photosPatientPhoto[] 
preferred_pharmacyJSON 
preferred_pharmaciesJSON 
protocol_overridesProtocolOverride[] 
settingsPatientSetting 
subscribed_coveragesCoverage[] 
tasksTask[] 
telecomPatientContactPoint[] 
contactsPatientContactPerson[] 
related_contactsPatientContactPerson[]Contacts on other patients that reference this one
userCanvasUser[] 
patient_groupsPatientGroup[] 
chart_section_reviewsChartSectionReview[] 
visual_exam_findingsVisualExamFinding[] 
vital_sign_readingsVitalSignReading[] 
assessmentsAssessment[] 
patient_visitsExternalVisit[] 
patient_eventsExternalEvent[] 
medication_statementsMedicationStatement[] 
diagnostic_reportsDiagnosticReport[] 
medication_history_medicationsMedicationHistoryMedication[] 
medication_history_responsesMedicationHistoryResponse[] 
paymentsBulkPatientPosting[] 
protocol_currentsProtocolCurrent[] 
stopped_medicationsStopMedicationEvent[] 
banner_alertsBannerAlert[] 
immunizationsImmunization[] 
immunization_statementsImmunizationStatement[] 
integration_tasksIntegrationTask[] 
installment_plansInstallmentPlan[] 
uncategorized_clinical_document_reviewsUncategorizedClinicalDocumentReview[] 
patient_consentPatientConsent[] 
goalsGoal[] 
updategoalsUpdateGoal[] 
instructionsInstruction[] 
appointmentsAppointment[] 
notesNote[] 
prescriptionsPrescription[] 
refill_requestsRefillRequest[] 
referral_reviewsReferralReview[] 
referral_reportsReferralReport[] 
invoicesInvoice[] 
education_materialEducationalMaterial[] 
proceduresProcedure[] 
family_historiesFamilyHistory[] 
histories_of_present_illnessHistoryOfPresentIllness[] 
plansPlan[] 
follow_upsFollowUp[] 
reasons_for_visitReasonForVisit[] 
removed_allergiesRemoveAllergyEvent[] 
removed_past_medical_historyRemovePastMedicalHistoryEvent[] 
resolved_conditionsResolveConditionEvent[] 
cancel_prescriptionsCancelPrescription[] 
cancel_prescription_responsesCancelPrescriptionResponse[] 
prescription_change_requestsPrescriptionChangeRequest[] 
prescription_change_responsesPrescriptionChangeResponse[] 
full_nameString (computed)The full name of the patient, combining first, middle, and last names
preferred_pharmacyDict (computed)The patient’s preferred pharmacy for medication fulfillment
preferred_full_nameString (computed)The patient’s preferred full name, if different from the legal name
preferred_first_nameString (computed)The patient’s preferred first name, if different from the legal first name
primary_phone_numberPatientContactPoint (computed)The patient’s primary contact number
photoPatientPhoto (computed)The patient’s first uploaded avatar, if any
photo_urlString (computed)A presigned URL for the patient’s avatar photo, or the default avatar URL when no photo is set

PatientAddress #

Field NameType
idUUID
dbidInteger
createdDateTime
modifiedDateTime
line1String
line2String
cityString
districtString
state_codeString
postal_codeString
useAddressUse
typeAddressType
longitudeFloat
latitudeFloat
startDate
endDate
countryString
stateAddressState
patientPatient
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 NameType
idUUID
dbidInteger
createdDateTime
modifiedDateTime
systemContactPointSystem
valueString
useString
use_notesString
rankInteger
stateContactPointState
patientPatient
has_consentBoolean
last_verifiedDateTime
verification_tokenString
opted_outBoolean

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 NameType
idUUID
dbidInteger
createdDateTime
modifiedDateTime
patientPatient
useString
identifier_typeString
systemString
valueString
issued_dateDate
expiration_dateDate
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 NameType
dbidInteger
createdDateTime
modifiedDateTime
patientPatient
nameString
valueJSON

Setting names #

A patient carries at most one setting per name. Canvas maintains these:

NameHolds
pharmacyThe patient’s preferred pharmacies. Read this through preferred_pharmacies, which normalizes the older single-pharmacy shape into a list
preferredSchedulingTimezoneThe 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 NameType
idUUID
dbidInteger
createdDateTime
modifiedDateTime
patientPatient
keyString
valueString
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 NameType
dbidInteger
createdDateTime
modifiedDateTime
patientPatient
urlFile (S3 key)
titleString
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 NameTypeDescription
dbidInteger 
createdDateTime 
modifiedDateTime 
patientPatient 
imageFile (S3 key) 
titleString 
activeBoolean 
image_urlString (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 NameType
patientaddressPatientAddress
facilityFacility
room_numberString

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 NameType
idUUID
dbidInteger
createdDateTime
modifiedDateTime
patientPatient
nameString
phone_numberString
emailString
commentsString
related_patientPatient
categoriesPatientContactCategory[]
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 NameType
dbidInteger
createdDateTime
modifiedDateTime
contact_personPatientContactPerson
categoryContactCategory

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 NameType
dbidInteger
createdDateTime
modifiedDateTime
nameString
codeString
systemString
protectedBoolean
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 #

ValueLabel
Ffemale
Mmale
Oother
UNKunknown
”” (empty string)””