Labs

Introduction #

The Canvas SDK provides comprehensive models for working with laboratory data throughout the entire lab workflow—from ordering tests to reviewing results. The primary models include:

  • LabOrder: Represents a lab order placed for a patient, including order details, transmission type, and associated tests
  • LabTest: Individual tests within a lab order, tracking status from creation through processing
  • LabReport: Contains the results returned from the lab, including all values and associated metadata
  • LabValue: Individual test results within a lab report, including values, units, and reference ranges
  • LabReview: Tracks the clinical review process for lab results, including provider comments and patient communication

Basic Usage #

To retrieve a LabReport model by id, use the objects.get method on the model. For example:

from canvas_sdk.v1.data.lab import LabReport

lab_report = LabReport.objects.get(id="bcd287b7-8b04-4540-a1ea-6529eb576565")

Filtering #

To retrieve the LabValue instances that are associated with the LabReport, you can either call the values on the LabReport instance:

from canvas_sdk.v1.data.lab import LabReport

lab_report = LabReport.objects.get(id="bcd287b7-8b04-4540-a1ea-6529eb576565")
lab_values = lab_report.values.all()

Or query the LabValue model and pass the report argument:

from canvas_sdk.v1.data.lab import LabReport, LabValue

lab_report = LabReport.objects.get(id="bcd287b7-8b04-4540-a1ea-6529eb576565")
lab_values = LabValue.objects.filter(lab_report=lab_report)

Additionally, codings for lab values can be attained by querying the LabValueCoding model. To retrieve the codings associated with a LabValue, you can call codings on the LabValue instance:

from logger import log
from canvas_sdk.v1.data.lab import LabReport, LabValue

lab_report = LabReport.objects.get(id="bcd287b7-8b04-4540-a1ea-6529eb576565")
lab_values = LabValue.objects.filter(lab_report=lab_report)
for value in lab_values:
    log.info(value.codings.all())

Or query the LabValueCoding model directly:

from logger import log
from canvas_sdk.v1.data.lab import LabReport, LabValue, LabValueCoding

lab_report = LabReport.objects.get(id="bcd287b7-8b04-4540-a1ea-6529eb576565")
lab_values = LabValue.objects.filter(lab_report=lab_report)
for value in lab_values:
    lab_value_codings = LabValueCoding.objects.filter(value=value)
    log.info(lab_value_codings)

To query all lab reports for a particular patient, the patient argument can be used:

from logger import log
from canvas_sdk.v1.data.lab import LabReport
from canvas_sdk.v1.data.patient import Patient

patient = Patient.objects.get(id="6cbc40b408294a5f9b41f57ba1b2b487")
lab_report = LabReport.objects.filter(patient=patient)

Example #

The following plugin code will run every time a new Lab Report is created and log the patient it is for, along with the values and codings from the report’s results:

from canvas_sdk.events import EventType
from canvas_sdk.protocols import BaseProtocol
from logger import log

from canvas_sdk.v1.data.lab import LabReport


class Protocol(BaseProtocol):
    RESPONDS_TO = EventType.Name(EventType.LAB_REPORT_CREATED)

    def compute(self):
        lab_report = LabReport.objects.select_related("patient").get(id=self.target)
        if lab_report.patient:
            log.info(f"{lab_report.patient.first_name} {lab_report.patient.last_name}")
        for value in lab_report.values.all():
            log.info(f"{value.value} {value.units}")
            for coding in value.codings.all():
                log.info(coding.system)
                log.info(coding.name)
                log.info(coding.code)
        return []

For complete field documentation on all lab models, see the Attributes section below.

Working with Lab Orders and Tests #

You can also work with lab orders and their associated tests. Here’s an example of querying a lab order and checking the status of its tests:

from canvas_sdk.v1.data.lab import LabOrder, LabTest

# Get a lab order by ID
lab_order = LabOrder.objects.get(id="abc123...")

# Access all tests in the order
for test in lab_order.tests.all():
    print(f"Test: {test.ontology_test_name}")
    print(f"Status: {test.status}")
    print(f"Code: {test.ontology_test_code}")

    # Check if results have been received
    if test.report:
        print(f"Report available with {test.report.values.count()} values")

Navigating Between Lab Orders and Reports #

Lab orders and lab reports are connected through the LabTest model. Here’s how to navigate between them:

Getting the LabOrder from a LabReport #

from canvas_sdk.v1.data.lab import LabReport

# Get a lab report
lab_report = LabReport.objects.get(id="report-id")

# Direct access to all orders via the reverse many-to-many relationship
for lab_order in lab_report.laborder_set.all():
    print(f"Order ID: {lab_order.id}")
    print(f"Ordered by: {lab_order.ordering_provider.full_name if lab_order.ordering_provider else 'N/A'}")
    print(f"Date ordered: {lab_order.date_ordered}")

# Alternatively, access the order through the tests
for test in lab_report.tests.all():
    lab_order = test.order
    print(f"Order ID: {lab_order.id}")
    break  # Usually all tests in a report share the same order

Getting LabReports from a LabOrder #

from canvas_sdk.v1.data.lab import LabOrder

# Get a lab order
lab_order = LabOrder.objects.get(id="order-id")

# Direct access to all reports via the many-to-many relationship
for report in lab_order.reports.all():
    print(f"Report ID: {report.id}")
    print(f"Date performed: {report.date_performed}")
    print(f"Number of values: {report.values.count()}")

# Alternatively, access reports through the tests if you need test-level details
for test in lab_order.tests.all():
    if test.report:
        print(f"Test: {test.ontology_test_name}")
        print(f"Report ID: {test.report.id}")

Working with Lab Reviews #

Lab reviews track the clinical review process for lab results, including provider comments and patient communication. Here’s how to work with the LabReport and LabReview relationship:

Accessing the Review from a LabReport #

from canvas_sdk.v1.data.lab import LabReport

# Get a lab report
lab_report = LabReport.objects.get(id="report-id")

# Check if the report has been reviewed
if lab_report.review:
    lab_review = lab_report.review
    print(f"Review status: {lab_review.status}")
    print(f"Internal comment: {lab_review.internal_comment}")
    print(f"Message to patient: {lab_review.message_to_patient}")

    # Access the provider who reviewed it
    if lab_review.originator:
        print(f"Reviewed by: {lab_review.originator.full_name}")
else:
    print("Report has not been reviewed yet")

Accessing Reports from a LabReview #

from canvas_sdk.v1.data.lab import LabReview

# Get a lab review
lab_review = LabReview.objects.get(id="review-id")

# Access all reports in this review batch
for report in lab_review.reports.all():
    print(f"Report ID: {report.id}")
    print(f"Date performed: {report.date_performed}")
    print(f"Number of values: {report.values.count()}")

    # Check if this report requires signature
    if report.requires_signature:
        print("  ⚠️  Requires provider signature")

Finding Unreviewed Lab Reports #

from canvas_sdk.v1.data.lab import LabReport
from canvas_sdk.v1.data.patient import Patient

# Get all unreviewed lab reports for a patient
patient = Patient.objects.get(id="patient-id")
unreviewed_reports = LabReport.objects.filter(
    patient=patient,
    review__isnull=True,
    deleted=False
)

print(f"Found {unreviewed_reports.count()} unreviewed reports")
for report in unreviewed_reports:
    print(f"Report from {report.date_performed} - {report.values.count()} values")

Filtering Lab Results by Abnormal Values #

A common use case is to identify abnormal lab values that may require clinical attention:

from canvas_sdk.v1.data.lab import LabReport, LabValue
from canvas_sdk.v1.data.patient import Patient

# Get all lab reports for a patient
patient = Patient.objects.get(id="patient-id")
lab_reports = LabReport.objects.filter(patient=patient)

# Find all abnormal values
for report in lab_reports:
    abnormal_values = report.values.filter(abnormal_flag__isnull=False).exclude(abnormal_flag="")

    if abnormal_values.exists():
        print(f"Report from {report.date_performed}:")
        for value in abnormal_values:
            for coding in value.codings.all():
                print(f"  {coding.name}: {value.value} {value.units} (Flag: {value.abnormal_flag})")

Attributes #

LabReport #

Field NameType
idUUID
dbidInteger
createdDateTime
modifiedDateTime
review_modeString
junkedBoolean
requires_signatureBoolean
assigned_dateDateTime
patientPatient
transmission_typeTransmissionType
for_test_onlyBoolean
external_idString
versionInteger
requisition_numberString
reviewLabReview
original_dateDateTime
date_performedDateTime
custom_document_nameString
originatorCanvasUser
committerCanvasUser
entered_in_errorCanvasUser
deletedBoolean
valuesLabValue[]

LabReview #

Field NameType
idUUID
dbidInteger
createdDateTime
modifiedDateTime
originatorCanvasUser
deletedBoolean
committerCanvasUser
entered_in_errorCanvasUser
internal_commentString
message_to_patientString
statusString
patientPatient
patient_communication_methodString
reportsLabReport[]
testsLabTest[]

LabValue #

Field NameType
idUUID
dbidInteger
createdDateTime
modifiedDateTime
reportLabReport
valueString
unitsString
abnormal_flagString
reference_rangeString
low_thresholdString
high_thresholdString
commentString
observation_statusString
codingsLabValueCoding[]

LabValueCoding #

Field NameType
dbidInteger
createdDateTime
modifiedDateTime
valueLabValue
codeString
nameString
systemString

LabOrder #

Field NameType
idUUID
dbidInteger
createdDateTime
modifiedDateTime
originatorCanvasUser
deletedBoolean
committerCanvasUser
entered_in_errorCanvasUser
patientPatient
noteNote
ontology_lab_partnerString
ordering_providerStaff
commentString
requisition_numberString
is_patient_billBoolean
date_orderedDateTime
fasting_statusBoolean
specimen_collection_typeSpecimenCollectionType
transmission_typeTransmissionType
courtesy_copy_typeCourtesyCopyType
courtesy_copy_numberString
courtesy_copy_textString
parent_orderLabOrder
healthgorilla_idString
manual_processing_statusManualProcessingStatus
manual_processing_commentString
labcorp_abn_urlURL
reasonsLabOrderReason[]
testsLabTest[]
reportsLabReport[]

LabOrderReason #

Field NameType
dbidInteger
createdDateTime
modifiedDateTime
originatorCanvasUser
deletedBoolean
committerCanvasUser
entered_in_errorCanvasUser
orderLabOrder
modeLabReasonMode
reason_conditionsLabOrderReasonCondition[]

LabOrderReasonCondition #

Field NameType
dbidInteger
createdDateTime
modifiedDateTime
originatorCanvasUser
deletedBoolean
committerCanvasUser
entered_in_errorCanvasUser
reasonLabOrderReason
conditionCondition

LabTest #

Represents an individual test within a lab order. Each LabTest tracks the lifecycle of a specific test from order creation through processing and result receipt.

Field NameType
idUUID
dbidInteger
createdDateTime
modifiedDateTime
ontology_test_nameString
ontology_test_codeString
statusLabTestOrderStatus
reportLabReport
specimen_typeString
specimen_source_codeString
specimen_source_descriptionString
specimen_source_coding_systemString
orderLabOrder
aoe_codeString
procedure_classString

Enumeration types #

TransmissionType #

ValueLabel
Ffax
Hhl7
Mmanual

SpecimenCollectionType #

ValueLabel
Lon location
Ppatient service center
Oother

CourtesyCopyType #

ValueLabel
Aaccount
Ffax
Ppatient

ManualProcessingStatus #

ValueLabel
NEEDS_REVIEWNeeds Review
IN_PROGRESSIn Progress
PROCESSEDProcessed
FLAGGEDFlagged

LabReasonMode #

ValueLabel
MOmonitor
INinvestigate
SFscreen for
UNKunknown

LabTestOrderStatus #

ValueLabel
NEnew
SRstaged for requisition
SEsending
SFsending failed
PRprocessing
PFprocessing failed
REreceived
RVreviewed
INinactive