Skip to content

onconova.oncology.models.patient_case

DATA_CATEGORIES_COUNT module-attribute

ContributorsProperty

Bases: AnnotationGetterMixin, QueryableProperty

A property that retrieves a list of unique contributor usernames associated with a patient case.

This property uses a SQL common table expression (CTE) to aggregate distinct usernames from related events, returning them as an array. If no contributors are found, it returns an empty list.

get_annotation(cls)

Source code in onconova/oncology/models/patient_case.py
def get_annotation(self, cls):
    return Coalesce(
        RawSQL(
            f"""
        (
            SELECT ARRAY_AGG(DISTINCT cte.username)
            FROM (
                {events_common_table_expression()}
            ) AS cte
        )
    """,
            [],
            output_field=ArrayField(models.CharField()),
        ),
        Value([]),
    )

PatientCase

Bases: BaseModel

Represents a patient case in the oncology domain, capturing demographic, clinical, and consent information.

Attributes:

Name Type Description
pseudoidentifier CharField

Unique, anonymized identifier for the patient (auto-generated if not provided).

clinical_center CharField

Medical center where the patient data originates.

clinical_identifier CharField

Unique clinical identifier for the patient within the center.

consent_status CharField[ConsentStatus]

Status of patient consent for research use (valid, revoked, unknown).

gender CodedConceptField[AdministrativeGender]

Legal/administrative gender of the patient.

race CodedConceptField[Race]

Race of the patient (optional).

sex_at_birth CodedConceptField[Sex]

Sex assigned at birth (optional).

gender_identity CodedConceptField[GenderIdentity]

Patient's reported gender identity (optional).

date_of_birth DateField

Anonymized date of birth (day always set to 1).

age AnnotationProperty

Calculated age of the patient.

has_neoplastic_entities RelatedExistenceCheckProperty

Indicates if neoplastic entities exist for the patient.

age_at_diagnosis AnnotationProperty

Calculated age at first diagnosis (if applicable).

date_of_death DateField

Anonymized date of death (optional, day always set to 1).

cause_of_death CodedConceptField[CauseOfDeath]

Cause of death classification (optional).

data_completion_rate AnnotationProperty

Percentage of completed data categories.

total_entities AnnotationProperty

Count of neoplastic entities associated with the patient.

overall_survival AnnotationProperty

Overall survival since diagnosis in months (calculated).

end_of_records DateField

Date of last known record if lost to follow-up or vital status unknown (optional).

updated_at UpdatedAtProperty

Timestamp of last update.

contributors ContributorsProperty

List of contributors to the patient case.

vital_status CharField[VitalStatus]

Patient's vital status (alive, deceased, unknown).

Constraints
  • Enforces uniqueness of clinical identifier per center.
  • Ensures dates are anonymized (first day of month).
  • Validates logical combinations of vital status, date of death, end of records, and cause of death.

age class-attribute instance-attribute

age_at_diagnosis class-attribute instance-attribute

cause_of_death class-attribute instance-attribute

clinical_center class-attribute instance-attribute

clinical_identifier class-attribute instance-attribute

consent_status class-attribute instance-attribute

contributors class-attribute instance-attribute

data_completion_rate class-attribute instance-attribute

date_of_birth class-attribute instance-attribute

date_of_death class-attribute instance-attribute

description property

end_of_records class-attribute instance-attribute

gender class-attribute instance-attribute

gender_identity class-attribute instance-attribute

has_neoplastic_entities class-attribute instance-attribute

objects class-attribute instance-attribute

overall_survival class-attribute instance-attribute

pseudoidentifier class-attribute instance-attribute

race class-attribute instance-attribute

sex_at_birth class-attribute instance-attribute

total_entities class-attribute instance-attribute

updated_at class-attribute instance-attribute

vital_status class-attribute instance-attribute

Meta

constraints class-attribute instance-attribute

save(*args, **kwargs)

If an ID has not been manually specified, add an automated one.

When saving a patient record, if no ID is specified, this method will generate a random one and check it against existing records in the database. If a conflict is found, it will generate a new ID and check it again. This ensures that the ID is unique.

Also, ensures that the date of birth and date of death are properly de-identified before storing them in the database.

Source code in onconova/oncology/models/patient_case.py
def save(self, *args, **kwargs):
    # If an ID has not been manually specified, add an automated one
    """
    If an ID has not been manually specified, add an automated one.

    When saving a patient record, if no ID is specified, this method will generate
    a random one and check it against existing records in the database. If a conflict
    is found, it will generate a new ID and check it again. This ensures that the ID
    is unique.

    Also, ensures that the date of birth and date of death are properly de-identified before
    storing them in the database.
    """
    if not self.pseudoidentifier:
        # Generate random digits
        new_pseudoidentifier = self._generate_random_id()
        # Check for ID clashes in the database
        while PatientCase.objects.filter(
            pseudoidentifier=new_pseudoidentifier
        ).exists():
            new_pseudoidentifier = self._generate_random_id()
        # Set the ID for the patient
        self.pseudoidentifier = new_pseudoidentifier
    # Ensure the date_of_birth is anonymized
    if self.date_of_birth.day != 1:
        self.date_of_birth = self.date_of_birth.replace(day=1)
    if self.date_of_death and self.date_of_death.day != 1:
        self.date_of_death = self.date_of_death.replace(day=1)
    if self.end_of_records and self.end_of_records.day != 1:
        self.end_of_records = self.end_of_records.replace(day=1)
    return super().save(*args, **kwargs)

PatientCaseConsentStatusChoices

Bases: TextChoices

An enumeration representing the consent status of a patient case.

Attributes:

Name Type Description
VALID

Indicates that consent is valid.

REVOKED

Indicates that consent has been revoked.

UNKNOWN

Indicates that the consent status is unknown.

REVOKED class-attribute instance-attribute

UNKNOWN class-attribute instance-attribute

VALID class-attribute instance-attribute

PatientCaseDataCategoryChoices

Bases: TextChoices

Enumeration of data categories associated with a patient case in oncology.

Attributes:

Name Type Description
COMORBIDITIES_ASSESSMENTS

Category for comorbidities assessments.

FAMILY_HISTORIES

Category for family medical histories.

GENOMIC_SIGNATURES

Category for genomic signatures.

GENOMIC_VARIANTS

Category for genomic variants.

LIFESTYLES

Category for patient lifestyles.

COMORBIDITIES

Category for comorbidities.

NEOPLASTIC_ENTITIES

Category for neoplastic entities.

PERFORMANCE_STATUS

Category for performance status.

RADIOTHERAPIES

Category for radiotherapy treatments.

RISK_ASSESSMENTS

Category for risk assessments.

STAGINS

Category for cancer stagings.

SURGERIES

Category for surgical procedures.

SYSTEMIC_THERAPIES

Category for systemic therapies.

TUMOR_MARKERS

Category for tumor marker data.

VITALS

Category for vital signs.

TUMOR_BOARD_REVIEWS

Category for tumor board reviews.

ADVERSE_EVENTS

Category for adverse events.

THERAPY_RESPONSES

Category for therapy responses.

ADVERSE_EVENTS class-attribute instance-attribute

COMORBIDITIES class-attribute instance-attribute

COMORBIDITIES_ASSESSMENTS class-attribute instance-attribute

FAMILY_HISTORIES class-attribute instance-attribute

GENOMIC_SIGNATURES class-attribute instance-attribute

GENOMIC_VARIANTS class-attribute instance-attribute

LIFESTYLES class-attribute instance-attribute

NEOPLASTIC_ENTITIES class-attribute instance-attribute

PERFORMANCE_STATUS class-attribute instance-attribute

RADIOTHERAPIES class-attribute instance-attribute

RISK_ASSESSMENTS class-attribute instance-attribute

STAGINS class-attribute instance-attribute

SURGERIES class-attribute instance-attribute

SYSTEMIC_THERAPIES class-attribute instance-attribute

THERAPY_RESPONSES class-attribute instance-attribute

TUMOR_BOARD_REVIEWS class-attribute instance-attribute

TUMOR_MARKERS class-attribute instance-attribute

VITALS class-attribute instance-attribute

PatientCaseDataCompletion

Bases: BaseModel

Represents the completion status of a specific data category for a patient case.

Attributes:

Name Type Description
case ForeignKey[PatientCase]

Reference to the PatientCase whose data category has been marked as completed.

category CharField[PatientCaseDataCategories]

The finalized data category for the patient case, indicating that its data entries are complete and/or up-to-date.

description str

A human-readable summary of the completed category, including the case identifier, user, and timestamp.

Constraints

Ensures that each data category can only be marked as completed once per patient case.

DATA_CATEGORIES_COUNT class-attribute instance-attribute

PatientCaseDataCategories class-attribute instance-attribute

case class-attribute instance-attribute

category class-attribute instance-attribute

description property

Meta

constraints class-attribute instance-attribute

PatientCaseVitalStatusChoices

Bases: TextChoices

An enumeration representing the vital status of a patient.

Attributes:

Name Type Description
ALIVE

Indicates the patient is alive.

DECEASED

Indicates the patient is deceased.

UNKNOWN

Indicates the vital status of the patient is unknown.

ALIVE class-attribute instance-attribute

DECEASED class-attribute instance-attribute

UNKNOWN class-attribute instance-attribute

UpdatedAtProperty

Bases: AnnotationGetterMixin, QueryableProperty

A QueryableProperty that retrieves the most recent 'update' event timestamp for a model instance.

This property uses a raw SQL query to select the latest 'update' event's creation date from a common table expression (CTE) generated by events_common_table_expression(). The result is returned as a DateField.

get_annotation(cls)

Source code in onconova/oncology/models/patient_case.py
def get_annotation(self, cls):
    return RawSQL(
        f"""
        (
            SELECT cte.pgh_created_at
            FROM (
                {events_common_table_expression()}
            ) AS cte WHERE cte.pgh_label = 'update'
            ORDER BY cte.pgh_created_at DESC LIMIT 1
        )
    """,
        [],
        output_field=models.DateField(),
    )

events_common_table_expression()

Generates a SQL Common Table Expression (CTE) that combines event data from multiple event tables related to patient cases.

This function dynamically constructs a SQL query that performs a UNION ALL across all event tables associated with models in the 'oncology' app that have a 'pgh_event_model' with a 'case_id' field. Each SELECT statement extracts the username, creation timestamp, and event label from the event's context for events linked to a specific patient case. Additionally, it includes events directly associated with the PatientCase model itself.

Returns:

Type Description
str

A SQL string representing the UNION ALL of SELECT statements from relevant event tables.

Source code in onconova/oncology/models/patient_case.py
def events_common_table_expression():
    """
    Generates a SQL Common Table Expression (CTE) that combines event data from multiple event tables related to patient cases.

    This function dynamically constructs a SQL query that performs a UNION ALL across all event tables associated with models in the 'oncology' app that have a 'pgh_event_model' with a 'case_id' field. Each SELECT statement extracts the username, creation timestamp, and event label from the event's context for events linked to a specific patient case. Additionally, it includes events directly associated with the PatientCase model itself.

    Returns:
        (str): A SQL string representing the UNION ALL of SELECT statements from relevant event tables.
    """
    event_tables = [
        model.pgh_event_model._meta.db_table  # type: ignore
        for model in apps.get_app_config("oncology").get_models()
        if hasattr(model, "pgh_event_model")
        and hasattr(model.pgh_event_model, "case_id")  # type: ignore
    ]
    union_selects = [
        f"SELECT ({table}.pgh_context->>'username')::varchar as username, {table}.pgh_created_at, {table}.pgh_label FROM {table} WHERE {table}.case_id = {PatientCase._meta.db_table}.id  AND {table}.pgh_context ? 'username'"
        for table in event_tables
    ]
    case_event_table = PatientCase.pgh_event_model._meta.db_table  # type: ignore
    union_selects.append(
        f"SELECT ({case_event_table}.pgh_context->>'username')::varchar as username, {case_event_table}.pgh_created_at, {case_event_table}.pgh_label FROM {case_event_table} WHERE {case_event_table}.id = {PatientCase._meta.db_table}.id  AND {case_event_table}.pgh_context ? 'username'"
    )
    return " UNION ALL ".join(union_selects)
runner