class CareModelMixin(models.Model): care = models.CharField( verbose_name="Is the patient in care?", choices=YES_NO_UNKNOWN, max_length=25, ) care_not_in_reason = models.CharField(verbose_name="If not in care, why?", max_length=25, null=True, blank=True) care_facility_location = models.CharField( verbose_name="Does the patient receive care in this facility", max_length=25, choices=YES_NO_NA, default=NOT_APPLICABLE, help_text="Either integrated care or vertical care", ) icc_since_mocca = models.CharField( verbose_name=("Has the patient received integrated care " "since the leaving the MOCCA (orig) trial until now?"), max_length=25, choices=CARE_SINCE_MOCCA, ) icc_since_mocca_comment = OtherCharField( verbose_name="If some interruption in integrated care, please explain") icc = models.CharField( verbose_name="Does the patient currently receive integrated care", max_length=25, choices=YES_NO_NA, default=NOT_APPLICABLE, help_text="Either at this facility or elsewhere", ) icc_not_in_reason = models.CharField( verbose_name="If not receiving integrated care, why not?", max_length=25, choices=NOT_ICC_REASONS, default=NOT_APPLICABLE, ) care_comment = models.TextField( verbose_name="Additional comments relevant to this patient's care", null=True, blank=True, ) class Meta: abstract = True
class InteDeathReportModelMixin(models.Model): death_location_type = models.CharField( verbose_name="Where did the participant die?", max_length=50, choices=DEATH_LOCATIONS, ) death_location_name = models.CharField( verbose_name=( "If death occurred at hospital / clinic, please give name of the facility" ), max_length=150, null=True, blank=True, ) informant_contacts = EncryptedTextField(null=True, blank=True) informant_relationship = models.CharField( max_length=50, choices=INFORMANT_RELATIONSHIP, verbose_name="Informants relationship to the participant?", ) other_informant_relationship = OtherCharField() death_certificate = models.CharField( verbose_name="Is a death certificate is available?", max_length=15, choices=YES_NO, ) secondary_cause_of_death = models.ForeignKey( CauseOfDeath, on_delete=models.PROTECT, related_name="secondary_cause_of_death", verbose_name="Secondary cause of death", help_text=( "Secondary cause of death in the opinion of the " "local study doctor and local PI" ), ) secondary_cause_of_death_other = models.CharField( max_length=100, blank=True, null=True, verbose_name='If "Other" above, please specify', ) class Meta: abstract = True
class OffstudyModelMixin(UniqueSubjectIdentifierFieldMixin, models.Model): """Model mixin for the Off-study model. Override in admin like this: def formfield_for_choice_field(self, db_field, request, **kwargs): if db_field.name == "offstudy_reason": kwargs['choices'] = OFF_STUDY_REASONS return super().formfield_for_choice_field(db_field, request, **kwargs) """ offstudy_reason_choices = OFF_STUDY_REASONS offstudy_datetime = models.DateTimeField( verbose_name="Off-study date and time", validators=[datetime_not_before_study_start, datetime_not_future], default=get_utcnow, ) offstudy_reason = models.CharField( verbose_name= "Please code the primary reason participant taken off-study", choices=offstudy_reason_choices, max_length=125, ) offstudy_reason_other = OtherCharField() def __str__(self): local = timezone.localtime(self.offstudy_datetime) return f"{self.subject_identifier} {formatted_datetime(local)}" def save(self, *args, **kwargs): off_all_schedules_or_raise( subject_identifier=self.subject_identifier, offstudy_datetime=self.offstudy_datetime, ) super().save(*args, **kwargs) def natural_key(self): return (self.subject_identifier, ) @property def report_datetime(self): return self.offstudy_datetime class Meta: abstract = True
class MissedDosesModelMixin(models.Model): week2 = models.ForeignKey(Week2, on_delete=models.PROTECT) day_missed = models.IntegerField(verbose_name="Day missed:", choices=DAYS_MISSED) missed_reason = models.CharField(verbose_name="Reason:", max_length=25, blank=True, choices=REASON_DRUG_MISSED) missed_reason_other = OtherCharField() class Meta: abstract = True
class Week4(ClinicalAssessmentModelMixin, CrfModelMixin): fluconazole_dose = models.CharField( verbose_name="Fluconazole dose (day prior to visit)", max_length=25, choices=FLUCONAZOLE_DOSE, ) fluconazole_dose_other = OtherCharField(max_length=25) rifampicin_started = models.CharField( verbose_name="Rifampicin started since last visit?", max_length=25, choices=YES_NO_ALREADY_ND, ) rifampicin_start_date = models.DateField( verbose_name="Date Rifampicin started", validators=[date_not_future], null=True, blank=True, ) lp_done = models.CharField( verbose_name="LP done?", max_length=5, choices=YES_NO, help_text="If yes, ensure LP CRF completed.", ) other_significant_dx = models.CharField( verbose_name="Other significant diagnosis since last visit?", max_length=5, choices=YES_NO_NA, ) on_site = CurrentSiteManager() objects = CrfModelManager() history = HistoricalRecords() class Meta(CrfModelMixin.Meta): verbose_name = "Week 4" verbose_name_plural = "Week 4"
class MissedDosesModelMixin(models.Model): study_termination_conclusion = models.ForeignKey( StudyTerminationConclusion, on_delete=models.PROTECT) day_missed = models.IntegerField(verbose_name="Day missed:", choices=DAYS_MISSED) missed_reason = models.CharField(verbose_name="Reason:", max_length=25, blank=True, choices=REASON_DRUG_MISSED) missed_reason_other = OtherCharField() def __str__(self): return (f"{self.study_termination_conclusion}: " f"Missed {self.get_day_missed_display()}") class Meta: abstract = True
class Microbiology(CrfModelMixin): urine_culture_performed = models.CharField( max_length=5, choices=YES_NO, help_text="only for patients with >50 white cells in urine", ) urine_taken_date = models.DateField( validators=[date_not_before_study_start, date_not_future], null=True, blank=True) urine_culture_results = models.CharField( verbose_name="Urine culture results, if completed", max_length=10, choices=CULTURE_RESULTS, default=NOT_APPLICABLE, ) urine_culture_organism = models.CharField( verbose_name="If positive, organism", max_length=25, choices=URINE_CULTURE_RESULTS_ORGANISM, default=NOT_APPLICABLE, ) urine_culture_organism_other = OtherCharField(max_length=50, null=True, blank=True) blood_culture_performed = models.CharField(max_length=5, choices=YES_NO) blood_culture_results = models.CharField( verbose_name="Blood culture results, if completed", max_length=10, choices=CULTURE_RESULTS, default=NOT_APPLICABLE, ) blood_taken_date = models.DateField( validators=[date_not_before_study_start, date_not_future], null=True, blank=True) day_blood_taken = models.IntegerField( verbose_name="If positive, study day positive culture sample taken", validators=[MinValueValidator(1)], null=True, blank=True, ) blood_culture_organism = models.CharField( verbose_name="If growth positive, organism", max_length=50, choices=BLOOD_CULTURE_RESULTS_ORGANISM, default=NOT_APPLICABLE, ) blood_culture_organism_other = OtherCharField(max_length=50, null=True, blank=True) bacteria_identified = models.CharField( verbose_name="If bacteria, type", max_length=50, choices=BACTERIA_TYPE, default=NOT_APPLICABLE, ) bacteria_identified_other = OtherCharField(max_length=100, null=True, blank=True) sputum_afb_performed = models.CharField( verbose_name="AFB microscopy performed?", max_length=5, choices=YES_NO, help_text="Was sputum AFB done?", ) sputum_afb_date = models.DateField( validators=[date_not_before_study_start, date_not_future], null=True, blank=True) sputum_results_afb = models.CharField( verbose_name="AFB results", max_length=10, choices=POS_NEG_NA, default=NOT_APPLICABLE, ) sputum_performed = models.CharField( verbose_name="Culture performed?", max_length=15, choices=YES_NO_NA, default=NOT_APPLICABLE, ) sputum_taken_date = models.DateField( validators=[date_not_before_study_start, date_not_future], null=True, blank=True) sputum_results_culture = models.CharField( verbose_name="Culture results", max_length=10, choices=POS_NEG_NA, default=NOT_APPLICABLE, ) sputum_results_positive = models.CharField( verbose_name="If culture is positive, please specify:", max_length=50, null=True, blank=True, ) sputum_genexpert_performed = models.CharField( verbose_name="Sputum Gene-Xpert performed?", max_length=15, choices=YES_NO_NA, default=NOT_APPLICABLE, ) sputum_genexpert_date = models.DateField( verbose_name="Date sputum Gene-Xpert taken", validators=[date_not_before_study_start, date_not_future], null=True, blank=True, ) sputum_result_genexpert = models.CharField( verbose_name="Sputum Gene-Xpert results", max_length=45, choices=SPUTUM_GENEXPERT, default=NOT_APPLICABLE, ) tissue_biopsy_taken = models.CharField(max_length=5, choices=YES_NO) tissue_biopsy_results = models.CharField( verbose_name="If YES, results", max_length=10, choices=CULTURE_RESULTS, default=NOT_APPLICABLE, ) biopsy_date = models.DateField( validators=[date_not_before_study_start, date_not_future], null=True, blank=True) day_biopsy_taken = models.IntegerField( verbose_name="If positive, Study day positive culture sample taken", validators=[MinValueValidator(1)], null=True, blank=True, ) tissue_biopsy_organism = models.CharField( verbose_name="If growth positive, organism", max_length=50, choices=BIOPSY_RESULTS_ORGANISM, default=NOT_APPLICABLE, ) tissue_biopsy_organism_other = OtherCharField(max_length=50, null=True, blank=True) histopathology_report = models.TextField(null=True, blank=True) csf_genexpert_performed = models.CharField( verbose_name="CSF Gene-Xpert performed?", max_length=15, choices=YES_NO_NA, default=NOT_APPLICABLE, ) csf_genexpert_date = models.DateField( verbose_name="Date CSF Gene-Xpert taken", validators=[date_not_before_study_start, date_not_future], null=True, blank=True, ) csf_result_genexpert = models.CharField( verbose_name="CSF Gene-Xpert results", max_length=45, choices=SPUTUM_GENEXPERT, default=NOT_APPLICABLE, ) on_site = CurrentSiteManager() objects = CrfModelManager() history = HistoricalRecords() class Meta(CrfModelMixin.Meta): verbose_name = "Microbiology" verbose_name_plural = "Microbiology"
class PatientHistory(CrfModelMixin, BaseUuidModel): symptoms = models.ManyToManyField( Symptoms, verbose_name="Do you have any of the following symptoms?" ) other_symptoms = OtherCharField(null=True, blank=True) hiv_diagnosis_date = models.DateField( verbose_name="When was the diagnosis of HIV made?", null=True, blank=True ) arv_initiation_date = models.DateField( verbose_name="Date of start of antiretroviral therapy (ART)", null=True, blank=True, ) viral_load = models.IntegerField( verbose_name="Last viral load", validators=[MinValueValidator(0), MaxValueValidator(999999)], null=True, blank=True, help_text=COPIES_PER_MILLILITER, ) viral_load_date = models.DateField( verbose_name="Date of last viral load", null=True, blank=True ) cd4 = models.IntegerField( verbose_name="Last CD4", validators=[MinValueValidator(0), MaxValueValidator(3000)], null=True, blank=True, help_text=CELLS_PER_MILLIMETER_CUBED_DISPLAY, ) cd4_date = models.DateField(verbose_name="Date of last CD4", null=True, blank=True) current_arv_regimen = models.ForeignKey( ArvRegimens, on_delete=models.PROTECT, related_name="current_arv_regimen", verbose_name=( "Which antiretroviral therapy regimen is the patient currently on?" ), null=True, blank=False, ) other_current_arv_regimen = OtherCharField(null=True, blank=True) current_arv_regimen_start_date = models.DateField( verbose_name=( "When did the patient start this current antiretroviral therapy regimen?" ), null=True, blank=True, ) has_previous_arv_regimen = models.CharField( verbose_name="Has the patient been on any previous regimen?", max_length=15, choices=YES_NO, ) previous_arv_regimen = models.ForeignKey( ArvRegimens, on_delete=models.PROTECT, related_name="previous_arv_regimen", verbose_name=( "Which antiretroviral therapy regimen was the patient previously on?" ), null=True, blank=True, ) other_previous_arv_regimen = OtherCharField(null=True, blank=True) on_oi_prophylaxis = models.CharField( verbose_name=( "Is the patient on any prophylaxis against opportunistic infections?" ), max_length=15, choices=YES_NO, ) oi_prophylaxis = models.ManyToManyField( OiProphylaxis, verbose_name="If YES, which prophylaxis is the patient on?", blank=True, ) other_oi_prophylaxis = OtherCharField(null=True, blank=True) hypertension_diagnosis = models.CharField( verbose_name="Has the patient been diagnosed with hypertension?", max_length=15, choices=YES_NO, ) on_hypertension_treatment = models.CharField( verbose_name="Is the patient on treatment for hypertension?", max_length=15, choices=YES_NO, ) hypertension_treatment = models.ManyToManyField( HypertensionMedications, verbose_name=( "What medications is the patient currently taking for hypertension?" ), blank=True, ) other_hypertension_treatment = OtherCharField( verbose_name=mark_safe("If other medication(s), please specify ..."), null=True, blank=True, ) taking_statins = models.CharField( verbose_name="Is the patient currently taking any statins?", max_length=15, choices=YES_NO, ) current_smoker = models.CharField( verbose_name=mark_safe("Is the patient a <u>current</u> smoker?"), max_length=15, choices=YES_NO, ) former_smoker = models.CharField( verbose_name=mark_safe("Is the patient a <u>previous</u> smoker?"), max_length=15, choices=YES_NO_NA, default=NOT_APPLICABLE, ) diabetes_symptoms = models.ManyToManyField( DiabetesSymptoms, verbose_name=mark_safe( "In the <u>past year</u>, have you had any of the following symptoms?" ), ) other_diabetes_symptoms = OtherCharField( verbose_name=mark_safe( "If other symptom in the <u>past year</u>, please specify ..." ), null=True, blank=True, ) diabetes_in_family = models.CharField( verbose_name=( "Has anyone in your immediate family " "ever been diagnosed with diabetes?" ), max_length=15, choices=YES_NO, help_text="Immediate family is parents, siblings, and children", ) class Meta(CrfModelMixin.Meta): verbose_name = "Patient History" verbose_name_plural = "Patient History"
class FollowupExamination(CrfStatusModelMixin, CrfWithActionModelMixin, edc_models.BaseUuidModel): action_name = FOLLOWUP_EXAMINATION_ACTION tracking_identifier_prefix = "FU" action_identifier = models.CharField(max_length=50, unique=True, null=True) tracking_identifier = models.CharField(max_length=30, unique=True, null=True) # 4a symptoms = models.ManyToManyField( Symptoms, related_name="symptoms", verbose_name=( "Since the participant's last appointment have they experienced " "any of the following symptoms"), help_text="either at this hospital or at a different clinic", ) # 4b symptoms_sought_care = models.ManyToManyField( Symptoms, related_name="symptoms_sought_care", verbose_name= "Did they seek care from any health worker for these symptoms", ) # 4a symptoms_g3 = models.ManyToManyField( Symptoms, related_name="symptoms_g3", verbose_name="For these symptoms, were any grade 3 events", help_text=("Refer to DAIDS toxicity table. " "Please complete Serious Adverse Event form"), ) symptoms_g3_detail = models.TextField( verbose_name= "Please provide details on any of the Grade 3 symptoms above.", null=True, blank=True, ) # 4a symptoms_g4 = models.ManyToManyField( Symptoms, related_name="symptoms_g4", verbose_name="For these symptoms, were any grade 4 events", help_text=("Refer to DAIDS toxicity table. " "Please complete Serious Adverse Event form"), ) symptoms_g4_detail = models.TextField( verbose_name= "Please provide details on any of the Grade 4 symptoms above.", null=True, blank=True, ) # 4c symptoms_detail = models.TextField( verbose_name="Please provide details on any of the symptoms above.", null=True, blank=True, ) # 5a attended_clinic = models.CharField( verbose_name= ("Since the participant's last visit did they attend any other clinic or hospital " "for care for any reason"), max_length=25, choices=YES_NO, help_text= ("Includes other routine appointments, e.g. BP check or family planning" ), ) # 5b admitted_hospital = models.CharField( verbose_name="If YES, were they admitted to hospital?", max_length=25, choices=YES_NO_NA, default=NOT_APPLICABLE, ) # 5c attended_clinic_detail = models.TextField( verbose_name=("If YES, attend other clinic or hospital, " "please provide details of this event"), help_text=("If the participant was given a referral letter or " "discharge summary record details here"), null=True, blank=True, ) attended_clinic_sae = models.CharField( verbose_name=mark_safe( "Does the event constitute a <u>Serious Adverse Event</u>"), max_length=25, choices=YES_NO_NA, default=NOT_APPLICABLE, help_text="If YES, submit a <u>Serious Adverse Event</u> Form", ) # 5d prescribed_medication = models.CharField( verbose_name=("Was the participant prescribed any other medication at " "this clinic or hospital visit?"), max_length=25, choices=YES_NO_NA, default=NOT_APPLICABLE, ) # 5d prescribed_medication_detail = models.TextField( verbose_name=("If YES, prescribed any other medication, " "please provide details of this visit"), null=True, blank=True, ) # 6a any_other_problems = models.CharField( verbose_name=( "Since your last visit has the participant experienced any other " "medical or health problems NOT listed above"), max_length=25, choices=YES_NO, ) # 6a any_other_problems_detail = models.TextField( verbose_name="If YES, please provide details of the event", null=True, blank=True, ) any_other_problems_sae = models.CharField( verbose_name="Does this event constitute an Adverse Event?", max_length=25, choices=YES_NO_NA, default=NOT_APPLICABLE, ) any_other_problems_sae_grade = models.CharField( verbose_name="If YES, what grade?", choices=GRADE34_CHOICES, max_length=25, default=NOT_APPLICABLE, help_text="If YES, grade 3 or 4, submit Serious Adverse Event form", ) # 7a art_change = models.CharField( verbose_name=("Since the participant's last visit has there " "been any change in their HIV medication?"), max_length=25, choices=YES_NO, ) # 7b art_change_reason = models.TextField( verbose_name="If YES, please provide reason for change", null=True, blank=True) # 7c art_new_regimen = models.ForeignKey( ArvRegimens, on_delete=PROTECT, verbose_name="Please indicate new regimen", related_name="art_new_regimen", null=True, blank=True, ) art_new_regimen_other = OtherCharField() abdominal_tenderness = models.CharField( verbose_name="Abdominal tenderness", max_length=25, choices=YES_NO) enlarged_liver = models.CharField(verbose_name="Enlarged liver", max_length=25, choices=YES_NO) jaundice = models.CharField(verbose_name="Jaundice", max_length=25, choices=YES_NO) comment = models.TextField(verbose_name=( "Comment on the clinical course, any other symptoms present, " "assessment and management plan")) lactic_acidosis = models.CharField( verbose_name="Do you think the participant has lactic acidosis?", max_length=25, choices=YES_NO, help_text= ("Classical signs of lactic acidosis include: abdominal or stomach " "discomfort, decreased appetite, diarrhoea, fast or shallow breathing, " "a general feeling of discomfort, muscle pain or cramping; and " "unusual sleepiness, fatigue, or weakness."), ) hepatomegaly = models.CharField( verbose_name= "Do you think the participant has hepatomegaly with steatosis?", max_length=25, choices=YES_NO, help_text= ("This condition often does not have any clinical signs and symptoms, " "it may present with an enlarge liver on examination, and symptoms " "of fatigue and right upper abdominal pain. The risk of developing " "this condition is higher in patients who are obese and who have " "type 2 diabetes or metabolic syndrome"), ) referral = models.CharField( verbose_name="Is the participant being referred", max_length=25, choices=YES_NO) referral_reason = models.TextField( verbose_name="If YES, where are they being referred to", null=True, blank=True, help_text=( "Note: remind participant that admission or discharge information " "will be needed at the next follow up visit."), ) class Meta(CrfWithActionModelMixin.Meta, edc_models.BaseUuidModel.Meta): verbose_name = "Clinic follow up: Examination" verbose_name_plural = "Clinic follow up: Examination"
class StudyTerminationConclusion( NonUniqueSubjectIdentifierFieldMixin, BaseStudyTerminationConclusion, OffScheduleModelMixin, StudyMedicationModelMixin, MedAndDrugInterventionModelMixin, BloodTransfusionModelMixin, ActionModelMixin, TrackingModelMixin, BaseUuidModel, ): action_name = STUDY_TERMINATION_CONCLUSION_ACTION tracking_identifier_prefix = "ST" subject_identifier = models.CharField(max_length=50, unique=True) discharged_after_initial_admission = models.CharField( verbose_name="Was the patient discharged after initial admission?", max_length=6, choices=YES_NO, ) initial_discharge_date = models.DateField( verbose_name="Date of initial discharge", validators=[date_not_future], blank=True, null=True, ) readmission_after_initial_discharge = models.CharField( verbose_name="Was the patient re-admitted following initial discharge?", max_length=7, choices=YES_NO_NA, default=NOT_APPLICABLE, ) readmission_date = models.DateField( verbose_name="Date of readmission", validators=[date_not_future], blank=True, null=True, ) discharged_date = models.DateField( verbose_name="Date discharged", validators=[date_not_future], blank=True, null=True, ) termination_reason = models.CharField( verbose_name="Reason for study termination", max_length=75, choices=REASON_STUDY_TERMINATED, help_text=( "If included in error, be sure to fill in protocol deviation form." ), ) willing_to_complete_10w = models.CharField( verbose_name=("Is the patient willing to complete the W10 " "and W16 FU visit only?"), max_length=12, choices=YES_NO_NA, default=NOT_APPLICABLE, ) willing_to_complete_centre = models.CharField( verbose_name=("Is the patient willing to complete the W10" "and W16 FU visit only at their new care centre?"), max_length=17, choices=YES_NO_NA, default=NOT_APPLICABLE, ) willing_to_complete_date = models.DateField( verbose_name="Date the 10W FU due", validators=[date_not_future], editable=False, null=True, help_text="get value from Ambition visit schedule", ) protocol_exclusion_criterion = models.CharField( verbose_name="Late protocol exclusion met?", max_length=12, choices=YES_NO_NA, default=NOT_APPLICABLE, ) included_in_error_date = models.DateField( verbose_name="If included in error, date", validators=[date_not_future], blank=True, null=True, ) included_in_error = models.TextField( verbose_name="If included in error, narrative:", max_length=300, blank=True, null=True, ) rifampicin_started = models.CharField( verbose_name="Rifampicin started since week 4?", max_length=30, choices=YES_NO_ALREADY, ) first_line_regimen = models.CharField( verbose_name=("ART regimen started for naive patients (or regimen" " switched for those already on ARVs)"), max_length=75, choices=FIRST_ARV_REGIMEN, default=NOT_APPLICABLE, ) first_line_regimen_other = OtherCharField() second_line_regimen = models.CharField( verbose_name="Second line / second switch ARV regimen", max_length=50, choices=SECOND_ARV_REGIMEN, default=NOT_APPLICABLE, ) second_line_regimen_other = OtherCharField() arvs_switch_date = models.DateField( verbose_name="ARV start/switch date", blank=True, null=True, validators=[date_not_future], ) first_line_choice = models.CharField( verbose_name="If first line:", max_length=5, choices=FIRST_LINE_REGIMEN, default=NOT_APPLICABLE, ) arvs_delay_reason = models.CharField( verbose_name="Reason ARVs not started", max_length=75, blank=True, null=True) medicines = models.ManyToManyField( Day14Medication, verbose_name="Medicines on study termination day:") on_study_drug = models.CharField( verbose_name="Has the patient started 'study' drug", max_length=25, choices=YES_NO_NA, default=NOT_APPLICABLE, ) def save(self, *args, **kwargs): if not self.last_study_fu_date: self.last_study_fu_date = self.offschedule_datetime.date() super().save(*args, **kwargs) class Meta(OffScheduleModelMixin.Meta): verbose_name = "Study Termination/Conclusion" verbose_name_plural = "Study Terminations/Conclusions"
class PatientHistory(CrfModelMixin): symptom = models.ManyToManyField( Symptom, blank=True, related_name="symptoms", verbose_name="What are your current symptoms?", ) headache_duration = models.IntegerField( verbose_name="If headache, how many days did it last?", validators=[MinValueValidator(1)], null=True, blank=True, ) visual_loss_duration = models.IntegerField( verbose_name="If visual loss, how many days did it last?", validators=[MinValueValidator(1)], null=True, blank=True, ) tb_history = models.CharField( verbose_name="Previous medical history of Tuberculosis?", max_length=5, choices=YES_NO, ) tb_site = models.CharField( verbose_name="If YES, site of TB?", max_length=15, choices=TB_SITE, default=NOT_APPLICABLE, ) tb_treatment = models.CharField( verbose_name="Are you currently taking TB treatment?", max_length=5, choices=YES_NO, ) taking_rifampicin = models.CharField( verbose_name="If YES, are you currently also taking Rifampicin?", max_length=5, choices=YES_NO_NA, default=NOT_APPLICABLE, ) rifampicin_started_date = models.DateField( verbose_name="If YES, when did you first start taking Rifampicin?", validators=[date_not_future], null=True, blank=True, ) new_hiv_diagnosis = models.CharField( verbose_name="Is this a new HIV diagnosis?", max_length=5, choices=YES_NO ) taking_arv = models.CharField( verbose_name="If NO, has the patient ever been on ART?", max_length=5, choices=YES_NO_NA, default=NOT_APPLICABLE, ) # retired first_arv_regimen = models.CharField( verbose_name="If YES, which drugs were prescribed for their first ART regimen?", max_length=50, choices=FIRST_ARV_REGIMEN_RETIRED, default=QUESTION_RETIRED, editable=False, ) # retired first_arv_regimen_other = OtherCharField(editable=False) # retired first_line_choice = models.CharField( verbose_name="If first line:", max_length=25, choices=FIRST_LINE_REGIMEN_RETIRED, default=QUESTION_RETIRED, editable=False, ) initial_arv_date = models.DateField( verbose_name=mark_safe( "If YES, when did the patient <u>start</u> ART for the first time." ), validators=[date_not_future], null=True, blank=True, ) initial_arv_date_estimated = IsDateEstimatedFieldNa( verbose_name="If YES, is this ART date estimated?", default=NOT_APPLICABLE ) initial_arv_regimen = models.ManyToManyField( ArvRegimens, verbose_name=mark_safe( "If YES, which drugs were prescribed for their first ART regimen?" ), related_name="initial_arv", ) initial_arv_regimen_other = OtherCharField() has_switched_regimen = models.CharField( verbose_name="Has the patient ever switched ART regimen?", max_length=5, choices=YES_NO_NA, default=NOT_APPLICABLE, ) current_arv_date = models.DateField( verbose_name=mark_safe( "If YES, when was their <u>current or most recent</u> " "ART regimen started?" ), validators=[date_not_future], null=True, blank=True, ) current_arv_date_estimated = IsDateEstimatedFieldNa( verbose_name="If YES, is this ART date estimated?", default=NOT_APPLICABLE ) current_arv_regimen = models.ManyToManyField( ArvRegimens, verbose_name=mark_safe( "If YES, what is their current or most recent ART regimen?" ), related_name="current_arv", ) current_arv_regimen_other = OtherCharField() current_arv_is_defaulted = models.CharField( verbose_name=mark_safe( "Has the patient <u>now</u> defaulted from their ART regimen?" ), max_length=5, choices=YES_NO_NA, default=NOT_APPLICABLE, help_text="'DEFAULTED' means no ART for at least one month.", ) current_arv_defaulted_date = models.DateField( verbose_name=mark_safe( "If the patient has DEFAULTED, on what date did they default " "from their <u>most recent</u> ART regimen?" ), validators=[date_not_future], null=True, blank=True, ) current_arv_defaulted_date_estimated = IsDateEstimatedFieldNa( verbose_name="If DEFAULTED, is this date estimated?", default=NOT_APPLICABLE ) current_arv_is_adherent = models.CharField( verbose_name=mark_safe( "If the patient is currently on ART, are they ADHERENT to " "their <u>current</u> ART regimen?" ), max_length=5, choices=YES_NO_NA, default=NOT_APPLICABLE, ) current_arv_tablets_missed = models.IntegerField( verbose_name=("If not ADHERENT, how many doses missed in the last month?"), validators=[MinValueValidator(0), MaxValueValidator(31)], null=True, blank=True, ) current_arv_decision = models.CharField( verbose_name=mark_safe( "What decision was made at admission regarding their " "<u>current</u> ART regimen?" ), max_length=25, choices=ARV_DECISION, default=NOT_APPLICABLE, ) # retired second_arv_regimen = models.CharField( verbose_name="Second line ARV regimen", max_length=50, choices=SECOND_ARV_REGIMEN_RETIRED, default=QUESTION_RETIRED, editable=False, ) # retired second_arv_regimen_other = OtherCharField(editable=False) # retired patient_adherence = models.CharField( verbose_name="Is the patient reportedly adherent?", max_length=25, choices=YES_NO_NA_RETIRED, default=QUESTION_RETIRED, editable=False, ) # retired last_dose = models.IntegerField( verbose_name=( "If no tablets taken this month, how many months " "since the last dose taken?" ), validators=[MinValueValidator(0)], null=True, blank=True, editable=False, ) last_viral_load = models.DecimalField( verbose_name="Last Viral Load, if known?", decimal_places=3, max_digits=10, null=True, blank=True, help_text="copies/mL", ) viral_load_date = models.DateField( verbose_name="Viral Load date", validators=[date_not_future], null=True, blank=True, ) vl_date_estimated = IsDateEstimatedFieldNa( verbose_name=("Is the subject's Viral Load date estimated?"), default=NOT_APPLICABLE, ) last_cd4 = models.IntegerField( verbose_name="Last CD4, if known?", validators=[MinValueValidator(1), MaxValueValidator(2500)], null=True, blank=True, help_text=mark_safe("acceptable units are mm<sup>3</sup>"), ) cd4_date = models.DateField( verbose_name="CD4 date", validators=[date_not_future], null=True, blank=True ) cd4_date_estimated = IsDateEstimatedFieldNa( verbose_name=("Is the subject's CD4 date estimated?"), default=NOT_APPLICABLE ) temp = models.DecimalField( verbose_name="Temperature:", validators=[MinValueValidator(30), MaxValueValidator(45)], decimal_places=1, max_digits=3, help_text="in degrees Celcius", ) heart_rate = models.IntegerField( verbose_name="Heart rate:", validators=[MinValueValidator(30), MaxValueValidator(200)], help_text="bpm", ) sys_blood_pressure = models.IntegerField( verbose_name="Blood pressure: systolic", validators=[MinValueValidator(50), MaxValueValidator(220)], help_text="in mm. format SYS, e.g. 120", ) dia_blood_pressure = models.IntegerField( verbose_name="Blood pressure: diastolic", validators=[MinValueValidator(20), MaxValueValidator(150)], help_text="in Hg. format DIA, e.g. 80", ) respiratory_rate = models.IntegerField( verbose_name="Respiratory rate:", validators=[MinValueValidator(6), MaxValueValidator(50)], help_text="breaths/min", ) weight = models.DecimalField( verbose_name="Weight:", validators=[MinValueValidator(20), MaxValueValidator(150)], decimal_places=1, max_digits=4, help_text="kg", ) weight_determination = models.CharField( verbose_name="Is weight estimated or measured?", max_length=15, choices=WEIGHT_DETERMINATION, ) glasgow_coma_score = models.IntegerField( verbose_name="Glasgow Coma Score:", validators=[MinValueValidator(3), MaxValueValidator(15)], help_text="/15", ) neurological = models.ManyToManyField(Neurological, blank=True) neurological_other = OtherCharField( verbose_name='If "Other CN palsy", specify', max_length=250, blank=True, null=True, ) focal_neurologic_deficit = models.TextField( verbose_name='If "Focal neurologic deficit" chosen, please specify details:', null=True, blank=True, ) visual_acuity_day = models.DateField( verbose_name="Study day visual acuity recorded?", validators=[date_not_future], null=True, blank=True, ) left_acuity = models.DecimalField( verbose_name="Visual acuity left eye:", decimal_places=3, max_digits=4, null=True, blank=True, ) right_acuity = models.DecimalField( verbose_name="Visual acuity right eye", decimal_places=3, max_digits=4, null=True, blank=True, ) ecog_score = models.CharField( verbose_name="ECOG Disability Score", max_length=15, choices=ECOG_SCORE ) ecog_score_value = models.CharField( verbose_name="ECOG Score", max_length=15, choices=ECOG_SCORE ) lung_exam = models.CharField( verbose_name="Abnormal lung exam:", max_length=5, choices=YES_NO ) cryptococcal_lesions = models.CharField( verbose_name="Cryptococcal related skin lesions:", max_length=5, choices=YES_NO ) specify_medications = models.ManyToManyField(Medication, blank=True) specify_medications_other = models.TextField(max_length=150, blank=True, null=True) previous_oi = models.CharField( verbose_name="Previous opportunistic infection other than TB?", max_length=5, choices=YES_NO, ) on_site = CurrentSiteManager() objects = CrfModelManager() history = HistoricalRecords() class Meta(CrfModelMixin.Meta): verbose_name = "Patient's History" verbose_name_plural = "Patient's History"
class MedicalExpenses(CrfModelMixin): info_source = models.CharField( verbose_name="What is the main source of this information?", max_length=25, choices=PATIENT_REL, ) currency = models.CharField(verbose_name="Which currency do you use?", max_length=20, choices=CURRENCY) food_spend = models.DecimalField( verbose_name="How much do you/your family spend on food in a week?", decimal_places=2, max_digits=15, null=True, validators=[MinValueValidator(0)], ) utilities_spend = models.DecimalField( verbose_name= "How much do you/your family spent on rent and utilities a month?", decimal_places=2, max_digits=15, null=True, validators=[MinValueValidator(0)], ) item_spend = models.DecimalField( verbose_name= ("How much have you spent on large items (e.g. furniture, electrical " "items, cars) in the last year?"), decimal_places=2, max_digits=15, null=True, validators=[MinValueValidator(0)], ) subject_spent_last_4wks = models.DecimalField( verbose_name=("Over the last 4/10 weeks, how much have you " "spent on activities relating to your health?"), decimal_places=2, max_digits=15, null=True, validators=[MinValueValidator(0)], help_text=( "On D1 record data for the four weeks prior to recruitment. " "On W10 record data for the ten weeks since recruitment."), ) someone_spent_last_4wks = models.DecimalField( verbose_name=("Over the last 4/10 weeks, how much has someone else " "spent on activities relating to your health?"), decimal_places=2, max_digits=15, null=True, validators=[MinValueValidator(0)], help_text=( "On D1 record data for the four weeks prior to recruitment. " "On W10 record data for the ten weeks since recruitment."), ) total_spent_last_4wks = models.DecimalField( verbose_name= ("How much in total has been spent on your healthcare in the last 4/10 weeks?" ), decimal_places=2, max_digits=16, null=True, validators=[MinValueValidator(0)], help_text=( "On D1 record data for the four weeks prior to recruitment. " "On W10 record data for the ten weeks since recruitment."), ) care_before_hospital = models.CharField( verbose_name=( "Have you received any treatment or care " "for your present condition, before coming to the hospital?"), max_length=5, choices=YES_NO, help_text="If YES, please complete medical expenses part 2", ) duration_present_condition = models.IntegerField( verbose_name="How long have you been sick with your current condition?", validators=[MinValueValidator(0)], null=True, help_text="in days", ) activities_missed = models.CharField( verbose_name=("What would you have been doing if you were not sick " "with your present condition"), max_length=25, null=True, choices=ACTIVITIES_MISSED, ) activities_missed_other = OtherCharField(max_length=25, blank=True, null=True) time_off_work = models.DecimalField( verbose_name="How much time did you take off work?", max_digits=4, decimal_places=1, validators=[MinValueValidator(0)], blank=True, null=True, help_text="in days", ) carer_time_off = models.IntegerField( verbose_name=("How much time did a caring family member " "take to accompany you to the hospital?"), validators=[MinValueValidator(0)], blank=True, null=True, help_text="in days", ) loss_of_earnings = models.CharField( verbose_name="Did you lose earnings as a result?", max_length=5, choices=YES_NO_NA, ) earnings_lost_amount = models.DecimalField( verbose_name="How much did you lose?", decimal_places=2, max_digits=15, validators=[MinValueValidator(0)], null=True, blank=True, ) form_of_transport = models.CharField( verbose_name="Which form of transport did you take to get here today?", max_length=25, default=NOT_APPLICABLE, choices=TRANSPORT, ) transport_fare = models.DecimalField( verbose_name="How much did you spend on the transport (in total)?", decimal_places=2, max_digits=15, validators=[MinValueValidator(0)], blank=True, null=True, ) travel_time = models.CharField( verbose_name="How long did it take you to reach there?", validators=[hm_validator], max_length=8, help_text="Specify as hours:minutes (format HH:MM)", null=True, blank=True, ) loans = models.CharField( verbose_name="Did you take out any loans to pay for your healthcare?", max_length=5, choices=YES_NO, ) sold_anything = models.CharField( verbose_name="Did you sell anything to pay for your healthcare?", max_length=5, choices=YES_NO, ) private_healthcare = models.CharField( verbose_name="Do you have private healthcare insurance?", max_length=5, choices=YES_NO, ) healthcare_insurance = models.CharField( verbose_name="Did you use it to help pay for your healthcare?", max_length=5, choices=YES_NO_NA, ) welfare = models.CharField( verbose_name="Do you receive any welfare or social service support?", max_length=5, choices=YES_NO, ) on_site = CurrentSiteManager() objects = CrfModelManager() history = HistoricalRecords() class Meta(CrfModelMixin.Meta): verbose_name = "Health Economics: Medical Expenses" verbose_name_plural = "Health Economics: Medical Expenses"
class MedicalExpensesTwoDetail(BaseUuidModel): medical_expenses_two = models.ForeignKey(MedicalExpensesTwo, on_delete=PROTECT) location_care = models.CharField( verbose_name="Where did you receive treatment or care?", max_length=35, choices=LOCATION_CARE, ) location_care_other = OtherCharField() transport_form = models.CharField( verbose_name="Which form of transport did you take to reach there?", max_length=20, choices=TRANSPORT, default=NOT_APPLICABLE, ) transport_cost = models.DecimalField( verbose_name="How much did you spend on the transport (return)?", decimal_places=2, max_digits=15, validators=[MinValueValidator(0)], null=True, blank=True, ) transport_duration = models.CharField( verbose_name="How long did it take you to reach there?", validators=[hm_validator], max_length=8, help_text="Specify as hours:minutes (format HH:MM)", null=True, blank=True, ) care_provider = models.CharField( verbose_name="Who provided treatment or care during that visit?", max_length=35, choices=CARE_PROVIDER, ) care_provider_other = OtherCharField(max_length=25, blank=True, null=True) paid_treatment = models.CharField( verbose_name=( "Did you pay for the consultation you received during that visit" ), max_length=15, choices=YES_NO, ) paid_treatment_amount = models.DecimalField( verbose_name=("How much did you pay for this visit?"), decimal_places=2, max_digits=15, validators=[MinValueValidator(0)], null=True, blank=True, ) medication_bought = models.CharField( verbose_name="Did you buy other medication for relief?", max_length=15, choices=YES_NO, ) medication_payment = models.DecimalField( verbose_name="How much did you pay?", decimal_places=2, max_digits=15, validators=[MinValueValidator(0)], null=True, blank=True, ) other_place_visited = models.CharField( verbose_name="Before this, did you go to another place " "for the treatment of the present situation?", max_length=15, choices=YES_NO, help_text='If YES, click "Add another Medical Expenses Part 2: Detail" below.', ) objects = ModelManager() history = HistoricalRecords() def __str__(self): return self.medical_expenses_two.visit.subject_identifier def natural_key(self): return (self.location_care,) + self.medical_expenses_two.natural_key() natural_key.dependencies = ["ambition_subject.medicalexpensestwo"] class Meta: verbose_name = "Medical Expenses Part 2: Detail" verbose_name_plural = "Medical Expenses Part 2: Detail"
class FollowUp(ClinicalAssessmentModelMixin, CrfModelMixin): fluconazole_dose = models.CharField( verbose_name="Fluconazole dose (day prior to visit)", max_length=25, choices=FLUCONAZOLE_DOSE, ) fluconazole_dose_other = OtherCharField( verbose_name="If other, specify dose:", max_length=25) rifampicin_started = models.CharField( verbose_name="Rifampicin started since last visit?", max_length=25, choices=YES_NO_ALREADY_ND, ) rifampicin_start_date = models.DateField( verbose_name="Date Rifampicin started", validators=[date_not_future], null=True, blank=True, ) days_hospitalized = models.DecimalField( verbose_name=("Over the ten weeks spent in the study how " "many days did the patient spend in hospital?"), decimal_places=3, max_digits=5, null=True, ) antibiotic = models.ManyToManyField( Antibiotic, blank=True, verbose_name="Were any of the following antibiotics given?", ) antibiotic_other = models.CharField( verbose_name="If other antibiotics, please specify:", max_length=50, null=True, blank=True, ) blood_transfusions = models.CharField( verbose_name= "Has the patient had any blood transfusions since week two? ", max_length=5, choices=YES_NO, null=True, ) blood_transfusions_units = models.DecimalField( verbose_name="If YES, no. of units? ", decimal_places=3, max_digits=5, null=True, blank=True, ) patient_help = models.CharField( verbose_name=("Does the patient require help from" " anybody for everyday activities? "), max_length=10, choices=YES_NO_ND, help_text=("For example eating, drinking, washing," " brushing teeth, going to the toilet"), ) patient_problems = models.CharField( verbose_name= "Has the illness left the patient with any other problems?", max_length=10, choices=YES_NO_ND, ) rankin_score = models.CharField( verbose_name="Modified Rankin score", choices=RANKIN_SCORE, max_length=10, null=True, ) other_significant_dx = models.CharField( verbose_name="Other significant diagnosis since last visit?", max_length=5, choices=YES_NO_NA, ) on_site = CurrentSiteManager() objects = CrfModelManager() history = HistoricalRecords() class Meta(CrfModelMixin.Meta): verbose_name = "Follow-up" verbose_name_plural = "Follow-up"
class VisitModelFieldsMixin(models.Model): report_datetime = models.DateTimeField( verbose_name="Report date and time", validators=[datetime_not_before_study_start, datetime_not_future], default=get_utcnow, help_text="Date and time of this report", ) reason = models.CharField( verbose_name="What is the reason for this report?", max_length=25, ) reason_unscheduled = models.CharField( verbose_name="If 'unscheduled', provide the reason for " "the unscheduled visit", max_length=25, choices=VISIT_REASON_UNSCHEDULED, default=NOT_APPLICABLE, ) reason_unscheduled_other = OtherCharField( verbose_name='If the reason for the unscheduled visit is "other", specify', max_length=25, blank=True, null=True, ) reason_missed = models.CharField( verbose_name="If 'missed', provide the reason for the missed visit", max_length=35, blank=True, null=True, ) reason_missed_other = OtherCharField( verbose_name='If the reason for the missed visit is "other", specify', max_length=25, blank=True, null=True, ) study_status = models.CharField( verbose_name="What is the participant's current study status", max_length=50, null=True, ) require_crfs = models.CharField( max_length=10, verbose_name="Are scheduled data being submitted with this visit?", choices=YES_NO, default=YES, ) info_source = models.CharField( verbose_name="What is the main source of this information?", max_length=25 ) info_source_other = OtherCharField( verbose_name='If "Other" source of information, specify' ) survival_status = models.CharField( max_length=10, verbose_name="Participant's survival status", choices=ALIVE_DEAD_UNKNOWN, null=True, default=ALIVE, ) last_alive_date = models.DateField( verbose_name="Date participant last known alive", validators=[date_not_before_study_start, date_not_future], null=True, blank=True, ) comments = models.TextField( verbose_name=( "Comment if any additional pertinent information " "about the participant" ), max_length=250, blank=True, null=True, ) class Meta: abstract = True