Package: edc-appointment
edc-appointmentThis module works closely withedc_visit_trackingandedc_visit_schedule.Subject data is collected on predefined timepoints. We describe these data collection timepoints in avisit_scheduleas provided byedc-visit-schedule. Inedc-appointmenttimepoints are represented by appointments.edc-appointmentprovides classes for creating and managing appointments.See alsoedc-visit-schedule.AppointmentModelMixinA model mixin for the Appointment model. Each project may have one appointment model. For example:classAppointment(AppointmentModelMixin,RequiresConsentModelMixin,BaseUuidModel):classMeta(AppointmentModelMixin.Meta):consent_model='edc_example.subjectconsent'app_label='edc_example'Appointment is a required foreignkey for the visit reportTheAppointmentmodel is a required foreignkey for the visit report. Be sure to seton_delete=PROTECT.classSubjectVisit(VisitModelMixin,OffstudyMixin,CreatesMetadataModelMixin,RequiresConsentModelMixin,BaseUuidModel):appointment=models.OneToOneField(Appointment,on_delete=PROTECT)objects=VisitModelManager()classMeta(VisitModelMixin.Meta):consent_model='edc_example.subjectconsent'app_label='edc_example'CreatesAppointmentsModelMixinA model mixin for the model that triggers the creation of appointments when the model is saved. This is typically an enrollment model.Adds the model fieldfacility. The value of fieldfacilitytells theCreateAppointmentsMixinto create appointments for the subject on dates that are available at thefacility.classEnrollment(EnrollmentModelMixin,CreateAppointmentsMixin,RequiresConsentModelMixin,BaseUuidModel):classMeta(EnrollmentModelMixin.Meta):visit_schedule_name='subject_visit_schedule.schedule1'consent_model='edc_example.subjectconsent'app_label='edc_example'WhenEnrollmentdeclared above is saved, one appointment will be created for the subject for eachvisitin scheduleschedule1of visit_schedulesubject_visit_schedule.Note: the value forfacilitymust be provided by the user, either through the form interface or programmatically.Customizing appointment scheduling byFacilityseeedc_facilityAvailable Appointment Model Manager MethodsTheAppointmentmodel is declared withAppointmentManager. It has several useful methods.first_appointment() last_appointment()Returns the first (or last) appointment. If just thesubject_identifieris provided, the first appointment of the protocol for the subject is returned. To be more specific, provide{subject_identifier=subject_identifier, visit_schedule_name=visit_schedule_name}.
To be even more specific,{subject_identifier=subject_identifier, visit_schedule_name=visit_schedule_name, schedule_name=schedule_name}.The most common usage is to just provide these values with an appointment instance:first_appointment=Appointment.objects.first_appointment(appointment=appointment)next_appointment() previous_appointment()The next and previous appointment are relative to the schedule and a visit_code within that schedule. If next is called on the last appointment in the sequenceNoneis returned. If previous is called on the first appointment in the sequenceNoneis returned.For example, in a sequence of appointment 1000, 2000, 3000, 4000:>>>appointment.visit_code1000>>>next_appointment=Appointment.objects.next_appointment(appointment=appointment)>>>next_appointment.visit_code2000But you can also pass an appointment instance and pass the visit code:>>>appointment.visit_code1000>>>next_appointment=Appointment.objects.next_appointment(appointment=appointment,visit_code=3000)>>>next_appointment.visit_code4000If you ask for the next appointment from the last,Noneis returned:>>>appointment.visit_code4000>>>next_appointment=Appointment.objects.next_appointment(appointment=appointment,visit_code=3000)>>>next_appointment.visit_codeAttributeError:'NoneType'objecthasnoattribute'visit_code'Theprevious_appointmentacts as expected:>>>appointment.visit_code1000>>>previous_appointment=Appointment.objects.previous_appointment(appointment=appointment)>>>previous_appointment.visit_codeAttributeError:'NoneType'objecthasnoattribute'visit_code'delete_for_subject_after_date()This method will delete all appointments for a subject after a given datetime. See alsoedc-offstudy.Appointmentis usually a foreignkey of a visit model. It’s important when using this method to ensure that when declaringAppointmentas a foreignkey you explicitly seton_delete=PROTECT. If you don’t, the deletion will cascade to other related instances – and that’s bad.appointment=models.OneToOneField(Appointment,on_delete=PROTECT)Allowing appointments to be skipped using SKIPPED_APPTSetsettings.EDC_APPOINTMENT_ALLOW_SKIPPED_APPT_USINGto a list of tuples .. [(lower_label, field_name), …]. The default is[]:EDC_APPOINTMENT_ALLOW_SKIPPED_APPT_USING = [("edc_appointment_app.nextappointment", "appt_date")]When set, options to skip the appointment will be available on the Appointment form.Note:This option does not make sense for longitudinal trials following a protocol defined schedule. However
if part of the follow up is driven by routine care, for example, where patients do not follow a strict
schedule, then it may be useful.Using a CRF to record the next appointment dateFor routine care, the next appointment date is not set by the protocol. The EDC will create appointments
according to the visit schedule as usual, but the dates will be approximate. You can administer a CRF at the
end of each visit to capture the next appointment date. A signal will update the appointment
that best matches the date given. Use this together with SKIPPED_APPT (see above).Setsettings.EDC_APPOINTMENT_MAX_MONTHS_TO_NEXT_APPTto a limit the number of months ahead for next appointment date:EDC_APPOINTMENT_MAX_MONTHS_TO_NEXT_APPT = 6 # default# model.pyclassNextAppointmentCrf(NextAppointmentCrfModelMixin,CrfModelMixin,BaseUuidModel):classMeta(CrfModelMixin.Meta,BaseUuidModel.Meta):verbose_name="Next Appointment"verbose_name_plural="Next Appointments"# forms.pyclassNextAppointmentCrfForm(NextAppointmentCrfModelFormMixin,CrfModelFormMixin,forms.ModelForm):form_validator_cls=NextAppointmentCrfFormValidatorclassMeta:model=NextAppointmentCrffields="__all__"# admin.py@admin.register(NextAppointmentCrf,site=intecomm_subject_admin)classNextAppointmentCrfAdmin(NextAppointmenCrftModelAdminMixin,CrfModelAdmin):form=NextAppointmentCrfForm