endoreg-db 0.8.4.4__py3-none-any.whl → 0.8.8.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of endoreg-db might be problematic. Click here for more details.
- endoreg_db/authz/auth.py +74 -0
- endoreg_db/authz/backends.py +168 -0
- endoreg_db/authz/management/commands/list_routes.py +18 -0
- endoreg_db/authz/middleware.py +83 -0
- endoreg_db/authz/permissions.py +127 -0
- endoreg_db/authz/policy.py +218 -0
- endoreg_db/authz/views_auth.py +66 -0
- endoreg_db/config/env.py +13 -8
- endoreg_db/data/__init__.py +8 -31
- endoreg_db/data/_examples/disease.yaml +55 -0
- endoreg_db/data/_examples/disease_classification.yaml +13 -0
- endoreg_db/data/_examples/disease_classification_choice.yaml +62 -0
- endoreg_db/data/_examples/event.yaml +64 -0
- endoreg_db/data/_examples/examination.yaml +72 -0
- endoreg_db/data/_examples/finding/anatomy_colon.yaml +128 -0
- endoreg_db/data/_examples/finding/colonoscopy.yaml +40 -0
- endoreg_db/data/_examples/finding/colonoscopy_bowel_prep.yaml +56 -0
- endoreg_db/data/_examples/finding/complication.yaml +16 -0
- endoreg_db/data/_examples/finding/data.yaml +105 -0
- endoreg_db/data/_examples/finding/examination_setting.yaml +16 -0
- endoreg_db/data/_examples/finding/medication_related.yaml +18 -0
- endoreg_db/data/_examples/finding/outcome.yaml +12 -0
- endoreg_db/data/_examples/finding_classification/colonoscopy_bowel_preparation.yaml +68 -0
- endoreg_db/data/_examples/finding_classification/colonoscopy_jnet.yaml +22 -0
- endoreg_db/data/_examples/finding_classification/colonoscopy_kudo.yaml +25 -0
- endoreg_db/data/_examples/finding_classification/colonoscopy_lesion_circularity.yaml +20 -0
- endoreg_db/data/_examples/finding_classification/colonoscopy_lesion_planarity.yaml +24 -0
- endoreg_db/data/_examples/finding_classification/colonoscopy_lesion_size.yaml +68 -0
- endoreg_db/data/_examples/finding_classification/colonoscopy_lesion_surface.yaml +20 -0
- endoreg_db/data/_examples/finding_classification/colonoscopy_location.yaml +80 -0
- endoreg_db/data/_examples/finding_classification/colonoscopy_lst.yaml +21 -0
- endoreg_db/data/_examples/finding_classification/colonoscopy_nice.yaml +20 -0
- endoreg_db/data/_examples/finding_classification/colonoscopy_paris.yaml +26 -0
- endoreg_db/data/_examples/finding_classification/colonoscopy_sano.yaml +22 -0
- endoreg_db/data/_examples/finding_classification/colonoscopy_summary.yaml +53 -0
- endoreg_db/data/_examples/finding_classification/complication_generic.yaml +25 -0
- endoreg_db/data/_examples/finding_classification/examination_setting_generic.yaml +40 -0
- endoreg_db/data/_examples/finding_classification/histology_colo.yaml +51 -0
- endoreg_db/data/_examples/finding_classification/intervention_required.yaml +26 -0
- endoreg_db/data/_examples/finding_classification/medication_related.yaml +23 -0
- endoreg_db/data/_examples/finding_classification/visualized.yaml +33 -0
- endoreg_db/data/_examples/finding_classification_choice/bowel_preparation.yaml +78 -0
- endoreg_db/data/_examples/finding_classification_choice/colon_lesion_circularity_default.yaml +32 -0
- endoreg_db/data/_examples/finding_classification_choice/colon_lesion_jnet.yaml +15 -0
- endoreg_db/data/_examples/finding_classification_choice/colon_lesion_kudo.yaml +23 -0
- endoreg_db/data/_examples/finding_classification_choice/colon_lesion_lst.yaml +15 -0
- endoreg_db/data/_examples/finding_classification_choice/colon_lesion_nice.yaml +17 -0
- endoreg_db/data/_examples/finding_classification_choice/colon_lesion_paris.yaml +57 -0
- endoreg_db/data/_examples/finding_classification_choice/colon_lesion_planarity_default.yaml +49 -0
- endoreg_db/data/_examples/finding_classification_choice/colon_lesion_sano.yaml +14 -0
- endoreg_db/data/_examples/finding_classification_choice/colon_lesion_surface_intact_default.yaml +36 -0
- endoreg_db/data/_examples/finding_classification_choice/colonoscopy_location.yaml +229 -0
- endoreg_db/data/_examples/finding_classification_choice/colonoscopy_not_complete_reason.yaml +19 -0
- endoreg_db/data/_examples/finding_classification_choice/colonoscopy_size.yaml +82 -0
- endoreg_db/data/_examples/finding_classification_choice/colonoscopy_summary_worst_finding.yaml +15 -0
- endoreg_db/data/_examples/finding_classification_choice/complication_generic_types.yaml +15 -0
- endoreg_db/data/_examples/finding_classification_choice/examination_setting_generic_types.yaml +15 -0
- endoreg_db/data/_examples/finding_classification_choice/histology.yaml +24 -0
- endoreg_db/data/_examples/finding_classification_choice/histology_polyp.yaml +20 -0
- endoreg_db/data/_examples/finding_classification_choice/outcome.yaml +19 -0
- endoreg_db/data/_examples/finding_classification_choice/yes_no_na.yaml +11 -0
- endoreg_db/data/_examples/finding_classification_type/colonoscopy_basic.yaml +48 -0
- endoreg_db/data/_examples/finding_intervention/endoscopy.yaml +43 -0
- endoreg_db/data/_examples/finding_intervention/endoscopy_colonoscopy.yaml +168 -0
- endoreg_db/data/_examples/finding_intervention/endoscopy_egd.yaml +128 -0
- endoreg_db/data/_examples/finding_intervention/endoscopy_ercp.yaml +32 -0
- endoreg_db/data/_examples/finding_intervention/endoscopy_eus_lower.yaml +9 -0
- endoreg_db/data/_examples/finding_intervention/endoscopy_eus_upper.yaml +36 -0
- endoreg_db/data/_examples/finding_intervention_type/endoscopy.yaml +15 -0
- endoreg_db/data/_examples/finding_type/data.yaml +43 -0
- endoreg_db/data/_examples/requirement/age.yaml +26 -0
- endoreg_db/data/_examples/requirement/colonoscopy_baseline_austria.yaml +45 -0
- endoreg_db/data/_examples/requirement/disease_cardiovascular.yaml +79 -0
- endoreg_db/data/_examples/requirement/disease_classification_choice_cardiovascular.yaml +41 -0
- endoreg_db/data/_examples/requirement/disease_hepatology.yaml +12 -0
- endoreg_db/data/_examples/requirement/disease_misc.yaml +12 -0
- endoreg_db/data/_examples/requirement/disease_renal.yaml +96 -0
- endoreg_db/data/_examples/requirement/endoscopy_bleeding_risk.yaml +59 -0
- endoreg_db/data/_examples/requirement/event_cardiology.yaml +251 -0
- endoreg_db/data/_examples/requirement/event_requirements.yaml +145 -0
- endoreg_db/data/_examples/requirement/finding_colon_polyp.yaml +50 -0
- endoreg_db/data/_examples/requirement/gender.yaml +25 -0
- endoreg_db/data/_examples/requirement/lab_value.yaml +441 -0
- endoreg_db/data/_examples/requirement/medication.yaml +93 -0
- endoreg_db/data/_examples/requirement_operator/age.yaml +13 -0
- endoreg_db/data/_examples/requirement_operator/lab_operators.yaml +129 -0
- endoreg_db/data/_examples/requirement_operator/model_operators.yaml +96 -0
- endoreg_db/data/_examples/requirement_set/01_endoscopy_generic.yaml +48 -0
- endoreg_db/data/_examples/requirement_set/colonoscopy_austria_screening.yaml +57 -0
- endoreg_db/data/_examples/yaml_examples.xlsx +0 -0
- endoreg_db/data/ai_model_meta/default_multilabel_classification.yaml +4 -3
- endoreg_db/data/event_classification/data.yaml +4 -0
- endoreg_db/data/event_classification_choice/data.yaml +9 -0
- endoreg_db/data/finding_classification/colonoscopy_bowel_preparation.yaml +43 -70
- endoreg_db/data/finding_classification/colonoscopy_lesion_size.yaml +22 -52
- endoreg_db/data/finding_classification/colonoscopy_location.yaml +31 -62
- endoreg_db/data/finding_classification/histology_colo.yaml +28 -36
- endoreg_db/data/requirement/colon_polyp_intervention.yaml +49 -0
- endoreg_db/data/requirement/coloreg_colon_polyp.yaml +49 -0
- endoreg_db/data/requirement_set/01_endoscopy_generic.yaml +31 -12
- endoreg_db/data/requirement_set/01_laboratory.yaml +13 -0
- endoreg_db/data/requirement_set/02_endoscopy_bleeding_risk.yaml +46 -0
- endoreg_db/data/requirement_set/90_coloreg.yaml +178 -0
- endoreg_db/data/requirement_set/_old_ +109 -0
- endoreg_db/data/requirement_set_type/data.yaml +21 -0
- endoreg_db/data/setup_config.yaml +4 -4
- endoreg_db/data/tag/requirement_set_tags.yaml +21 -0
- endoreg_db/exceptions.py +5 -2
- endoreg_db/helpers/data_loader.py +1 -1
- endoreg_db/management/commands/create_model_meta_from_huggingface.py +21 -10
- endoreg_db/management/commands/create_multilabel_model_meta.py +299 -129
- endoreg_db/management/commands/import_video.py +9 -10
- endoreg_db/management/commands/import_video_with_classification.py +1 -1
- endoreg_db/management/commands/init_default_ai_model.py +1 -1
- endoreg_db/management/commands/list_routes.py +18 -0
- endoreg_db/management/commands/load_ai_model_data.py +2 -1
- endoreg_db/management/commands/load_center_data.py +12 -12
- endoreg_db/management/commands/load_requirement_data.py +60 -31
- endoreg_db/management/commands/load_requirement_set_tags.py +95 -0
- endoreg_db/management/commands/setup_endoreg_db.py +14 -10
- endoreg_db/management/commands/storage_management.py +271 -203
- endoreg_db/migrations/0001_initial.py +1799 -1300
- endoreg_db/migrations/0002_requirementset_depends_on.py +18 -0
- endoreg_db/migrations/_old/0001_initial.py +1857 -0
- endoreg_db/migrations/_old/0004_employee_city_employee_post_code_employee_street_and_more.py +68 -0
- endoreg_db/migrations/_old/0004_remove_casetemplate_rules_and_more.py +77 -0
- endoreg_db/migrations/_old/0005_merge_20251111_1003.py +14 -0
- endoreg_db/migrations/_old/0006_sensitivemeta_anonymized_text_and_more.py +68 -0
- endoreg_db/migrations/_old/0007_remove_rule_attribute_dtype_remove_rule_rule_type_and_more.py +89 -0
- endoreg_db/migrations/_old/0008_remove_event_event_classification_and_more.py +27 -0
- endoreg_db/migrations/_old/0009_alter_modelmeta_options_and_more.py +21 -0
- endoreg_db/models/__init__.py +78 -123
- endoreg_db/models/administration/__init__.py +21 -42
- endoreg_db/models/administration/ai/active_model.py +2 -2
- endoreg_db/models/administration/ai/ai_model.py +7 -6
- endoreg_db/models/administration/case/__init__.py +1 -15
- endoreg_db/models/administration/case/case.py +3 -3
- endoreg_db/models/administration/case/case_template/__init__.py +2 -14
- endoreg_db/models/administration/case/case_template/case_template.py +2 -124
- endoreg_db/models/administration/case/case_template/case_template_rule.py +2 -268
- endoreg_db/models/administration/case/case_template/case_template_rule_value.py +2 -85
- endoreg_db/models/administration/case/case_template/case_template_type.py +2 -25
- endoreg_db/models/administration/center/center.py +33 -19
- endoreg_db/models/administration/center/center_product.py +12 -9
- endoreg_db/models/administration/center/center_resource.py +25 -19
- endoreg_db/models/administration/center/center_shift.py +21 -17
- endoreg_db/models/administration/center/center_waste.py +16 -8
- endoreg_db/models/administration/person/__init__.py +2 -0
- endoreg_db/models/administration/person/employee/employee.py +10 -5
- endoreg_db/models/administration/person/employee/employee_qualification.py +9 -4
- endoreg_db/models/administration/person/employee/employee_type.py +12 -6
- endoreg_db/models/administration/person/examiner/examiner.py +13 -11
- endoreg_db/models/administration/person/patient/__init__.py +2 -0
- endoreg_db/models/administration/person/patient/patient.py +103 -100
- endoreg_db/models/administration/person/patient/patient_external_id.py +37 -0
- endoreg_db/models/administration/person/person.py +4 -0
- endoreg_db/models/administration/person/profession/__init__.py +8 -4
- endoreg_db/models/administration/person/user/portal_user_information.py +11 -7
- endoreg_db/models/administration/product/product.py +20 -15
- endoreg_db/models/administration/product/product_material.py +17 -18
- endoreg_db/models/administration/product/product_weight.py +12 -8
- endoreg_db/models/administration/product/reference_product.py +23 -55
- endoreg_db/models/administration/qualification/qualification.py +7 -3
- endoreg_db/models/administration/qualification/qualification_type.py +7 -3
- endoreg_db/models/administration/shift/scheduled_days.py +8 -5
- endoreg_db/models/administration/shift/shift.py +16 -12
- endoreg_db/models/administration/shift/shift_type.py +23 -31
- endoreg_db/models/label/__init__.py +7 -8
- endoreg_db/models/label/annotation/image_classification.py +10 -9
- endoreg_db/models/label/annotation/video_segmentation_annotation.py +8 -5
- endoreg_db/models/label/label.py +15 -15
- endoreg_db/models/label/label_set.py +19 -6
- endoreg_db/models/label/label_type.py +1 -1
- endoreg_db/models/label/label_video_segment/_create_from_video.py +5 -8
- endoreg_db/models/label/label_video_segment/label_video_segment.py +76 -102
- endoreg_db/models/label/video_segmentation_label.py +4 -0
- endoreg_db/models/label/video_segmentation_labelset.py +4 -3
- endoreg_db/models/media/frame/frame.py +22 -22
- endoreg_db/models/media/pdf/raw_pdf.py +249 -177
- endoreg_db/models/media/pdf/report_file.py +25 -29
- endoreg_db/models/media/pdf/report_reader/report_reader_config.py +30 -46
- endoreg_db/models/media/pdf/report_reader/report_reader_flag.py +23 -7
- endoreg_db/models/media/video/__init__.py +1 -0
- endoreg_db/models/media/video/create_from_file.py +48 -56
- endoreg_db/models/media/video/pipe_1.py +30 -33
- endoreg_db/models/media/video/pipe_2.py +8 -9
- endoreg_db/models/media/video/video_file.py +359 -204
- endoreg_db/models/media/video/video_file_ai.py +288 -74
- endoreg_db/models/media/video/video_file_anonymize.py +38 -38
- endoreg_db/models/media/video/video_file_frames/__init__.py +3 -1
- endoreg_db/models/media/video/video_file_frames/_bulk_create_frames.py +6 -8
- endoreg_db/models/media/video/video_file_frames/_create_frame_object.py +7 -9
- endoreg_db/models/media/video/video_file_frames/_delete_frames.py +9 -8
- endoreg_db/models/media/video/video_file_frames/_extract_frames.py +38 -45
- endoreg_db/models/media/video/video_file_frames/_get_frame.py +6 -8
- endoreg_db/models/media/video/video_file_frames/_get_frame_number.py +4 -18
- endoreg_db/models/media/video/video_file_frames/_get_frame_path.py +4 -3
- endoreg_db/models/media/video/video_file_frames/_get_frame_paths.py +7 -6
- endoreg_db/models/media/video/video_file_frames/_get_frame_range.py +6 -8
- endoreg_db/models/media/video/video_file_frames/_get_frames.py +6 -8
- endoreg_db/models/media/video/video_file_frames/_initialize_frames.py +15 -25
- endoreg_db/models/media/video/video_file_frames/_manage_frame_range.py +26 -23
- endoreg_db/models/media/video/video_file_frames/_mark_frames_extracted_status.py +23 -14
- endoreg_db/models/media/video/video_file_io.py +109 -62
- endoreg_db/models/media/video/video_file_meta/get_crop_template.py +3 -3
- endoreg_db/models/media/video/video_file_meta/get_endo_roi.py +5 -3
- endoreg_db/models/media/video/video_file_meta/get_fps.py +37 -34
- endoreg_db/models/media/video/video_file_meta/initialize_video_specs.py +19 -25
- endoreg_db/models/media/video/video_file_meta/text_meta.py +41 -38
- endoreg_db/models/media/video/video_file_meta/video_meta.py +14 -7
- endoreg_db/models/media/video/video_file_segments.py +24 -17
- endoreg_db/models/media/video/video_metadata.py +19 -35
- endoreg_db/models/media/video/video_processing.py +96 -95
- endoreg_db/models/medical/contraindication/__init__.py +13 -3
- endoreg_db/models/medical/disease.py +22 -16
- endoreg_db/models/medical/event.py +31 -18
- endoreg_db/models/medical/examination/__init__.py +13 -6
- endoreg_db/models/medical/examination/examination.py +17 -18
- endoreg_db/models/medical/examination/examination_indication.py +26 -25
- endoreg_db/models/medical/examination/examination_time.py +16 -6
- endoreg_db/models/medical/examination/examination_time_type.py +9 -6
- endoreg_db/models/medical/examination/examination_type.py +3 -4
- endoreg_db/models/medical/finding/finding.py +38 -39
- endoreg_db/models/medical/finding/finding_classification.py +37 -48
- endoreg_db/models/medical/finding/finding_intervention.py +27 -22
- endoreg_db/models/medical/finding/finding_type.py +13 -12
- endoreg_db/models/medical/hardware/endoscope.py +20 -26
- endoreg_db/models/medical/hardware/endoscopy_processor.py +2 -2
- endoreg_db/models/medical/laboratory/lab_value.py +62 -91
- endoreg_db/models/medical/medication/medication.py +22 -10
- endoreg_db/models/medical/medication/medication_indication.py +29 -3
- endoreg_db/models/medical/medication/medication_indication_type.py +25 -14
- endoreg_db/models/medical/medication/medication_intake_time.py +31 -19
- endoreg_db/models/medical/medication/medication_schedule.py +27 -16
- endoreg_db/models/medical/organ/__init__.py +15 -12
- endoreg_db/models/medical/patient/medication_examples.py +1 -5
- endoreg_db/models/medical/patient/patient_disease.py +20 -23
- endoreg_db/models/medical/patient/patient_event.py +19 -22
- endoreg_db/models/medical/patient/patient_examination.py +48 -54
- endoreg_db/models/medical/patient/patient_examination_indication.py +16 -14
- endoreg_db/models/medical/patient/patient_finding.py +122 -139
- endoreg_db/models/medical/patient/patient_finding_classification.py +44 -49
- endoreg_db/models/medical/patient/patient_finding_intervention.py +8 -19
- endoreg_db/models/medical/patient/patient_lab_sample.py +28 -23
- endoreg_db/models/medical/patient/patient_lab_value.py +82 -89
- endoreg_db/models/medical/patient/patient_medication.py +27 -38
- endoreg_db/models/medical/patient/patient_medication_schedule.py +28 -36
- endoreg_db/models/medical/risk/risk.py +7 -6
- endoreg_db/models/medical/risk/risk_type.py +8 -5
- endoreg_db/models/metadata/model_meta.py +60 -29
- endoreg_db/models/metadata/model_meta_logic.py +139 -18
- endoreg_db/models/metadata/pdf_meta.py +19 -24
- endoreg_db/models/metadata/sensitive_meta.py +102 -85
- endoreg_db/models/metadata/sensitive_meta_logic.py +383 -43
- endoreg_db/models/metadata/video_meta.py +51 -31
- endoreg_db/models/metadata/video_prediction_logic.py +16 -23
- endoreg_db/models/metadata/video_prediction_meta.py +29 -33
- endoreg_db/models/other/distribution/date_value_distribution.py +89 -29
- endoreg_db/models/other/distribution/multiple_categorical_value_distribution.py +21 -5
- endoreg_db/models/other/distribution/numeric_value_distribution.py +114 -53
- endoreg_db/models/other/distribution/single_categorical_value_distribution.py +4 -3
- endoreg_db/models/other/emission/emission_factor.py +18 -8
- endoreg_db/models/other/gender.py +10 -5
- endoreg_db/models/other/information_source.py +25 -25
- endoreg_db/models/other/material.py +9 -5
- endoreg_db/models/other/resource.py +6 -4
- endoreg_db/models/other/tag.py +10 -5
- endoreg_db/models/other/transport_route.py +13 -8
- endoreg_db/models/other/unit.py +10 -6
- endoreg_db/models/other/waste.py +6 -5
- endoreg_db/models/requirement/requirement.py +580 -272
- endoreg_db/models/requirement/requirement_error.py +85 -0
- endoreg_db/models/requirement/requirement_evaluation/evaluate_with_dependencies.py +268 -0
- endoreg_db/models/requirement/requirement_evaluation/operator_evaluation_models.py +3 -6
- endoreg_db/models/requirement/requirement_evaluation/requirement_type_parser.py +90 -64
- endoreg_db/models/requirement/requirement_operator.py +36 -33
- endoreg_db/models/requirement/requirement_set.py +74 -57
- endoreg_db/models/state/__init__.py +4 -4
- endoreg_db/models/state/abstract.py +2 -2
- endoreg_db/models/state/anonymization.py +12 -0
- endoreg_db/models/state/audit_ledger.py +46 -47
- endoreg_db/models/state/label_video_segment.py +9 -0
- endoreg_db/models/state/raw_pdf.py +40 -46
- endoreg_db/models/state/sensitive_meta.py +6 -2
- endoreg_db/models/state/video.py +58 -53
- endoreg_db/models/upload_job.py +32 -55
- endoreg_db/models/utils.py +1 -2
- endoreg_db/root_urls.py +21 -2
- endoreg_db/serializers/__init__.py +26 -57
- endoreg_db/serializers/anonymization.py +18 -10
- endoreg_db/serializers/meta/report_meta.py +1 -1
- endoreg_db/serializers/meta/sensitive_meta_detail.py +63 -118
- endoreg_db/serializers/misc/__init__.py +1 -1
- endoreg_db/serializers/misc/file_overview.py +33 -91
- endoreg_db/serializers/misc/{vop_patient_data.py → sensitive_patient_data.py} +1 -1
- endoreg_db/serializers/requirements/requirement_sets.py +92 -22
- endoreg_db/serializers/video/segmentation.py +2 -1
- endoreg_db/serializers/video/video_processing_history.py +20 -5
- endoreg_db/serializers/video_examination.py +198 -0
- endoreg_db/services/anonymization.py +75 -73
- endoreg_db/services/lookup_service.py +256 -73
- endoreg_db/services/lookup_store.py +174 -30
- endoreg_db/services/pdf_import.py +711 -310
- endoreg_db/services/storage_aware_video_processor.py +140 -114
- endoreg_db/services/video_import.py +266 -117
- endoreg_db/urls/__init__.py +27 -27
- endoreg_db/urls/label_video_segments.py +2 -0
- endoreg_db/urls/media.py +108 -66
- endoreg_db/urls/root_urls.py +29 -0
- endoreg_db/utils/__init__.py +15 -5
- endoreg_db/utils/ai/multilabel_classification_net.py +116 -20
- endoreg_db/utils/case_generator/__init__.py +3 -0
- endoreg_db/utils/dataloader.py +88 -16
- endoreg_db/utils/defaults/set_default_center.py +32 -0
- endoreg_db/utils/names.py +22 -16
- endoreg_db/utils/permissions.py +2 -1
- endoreg_db/utils/pipelines/process_video_dir.py +1 -1
- endoreg_db/utils/requirement_operator_logic/model_evaluators.py +414 -127
- endoreg_db/utils/setup_config.py +8 -5
- endoreg_db/utils/storage.py +115 -0
- endoreg_db/utils/validate_endo_roi.py +8 -2
- endoreg_db/utils/video/ffmpeg_wrapper.py +184 -188
- endoreg_db/views/__init__.py +5 -12
- endoreg_db/views/anonymization/media_management.py +198 -163
- endoreg_db/views/anonymization/overview.py +4 -1
- endoreg_db/views/anonymization/validate.py +174 -40
- endoreg_db/views/media/__init__.py +2 -0
- endoreg_db/views/media/pdf_media.py +131 -150
- endoreg_db/views/media/sensitive_metadata.py +46 -6
- endoreg_db/views/media/video_media.py +89 -82
- endoreg_db/views/media/video_segments.py +187 -260
- endoreg_db/views/meta/sensitive_meta_detail.py +0 -63
- endoreg_db/views/patient/patient.py +5 -4
- endoreg_db/views/pdf/__init__.py +5 -8
- endoreg_db/views/pdf/pdf_stream.py +186 -0
- endoreg_db/views/pdf/pdf_stream_views.py +0 -127
- endoreg_db/views/pdf/reimport.py +86 -91
- endoreg_db/views/requirement/evaluate.py +188 -187
- endoreg_db/views/requirement/lookup.py +186 -288
- endoreg_db/views/requirement/requirement_utils.py +89 -0
- endoreg_db/views/video/__init__.py +0 -4
- endoreg_db/views/video/correction.py +2 -2
- endoreg_db/views/video/video_examination_viewset.py +202 -289
- {endoreg_db-0.8.4.4.dist-info → endoreg_db-0.8.8.0.dist-info}/METADATA +7 -3
- {endoreg_db-0.8.4.4.dist-info → endoreg_db-0.8.8.0.dist-info}/RECORD +350 -255
- endoreg_db/models/administration/permissions/__init__.py +0 -44
- endoreg_db/models/media/video/refactor_plan.md +0 -0
- endoreg_db/models/media/video/video_file_frames.py +0 -0
- endoreg_db/models/metadata/frame_ocr_result.py +0 -0
- endoreg_db/models/rule/__init__.py +0 -13
- endoreg_db/models/rule/rule.py +0 -27
- endoreg_db/models/rule/rule_applicator.py +0 -224
- endoreg_db/models/rule/rule_attribute_dtype.py +0 -17
- endoreg_db/models/rule/rule_type.py +0 -20
- endoreg_db/models/rule/ruleset.py +0 -17
- endoreg_db/serializers/video/video_metadata.py +0 -105
- endoreg_db/urls/report.py +0 -48
- endoreg_db/urls/video.py +0 -61
- endoreg_db/utils/case_generator/case_generator.py +0 -159
- endoreg_db/utils/case_generator/utils.py +0 -30
- endoreg_db/views/pdf/pdf_media.py +0 -239
- endoreg_db/views/report/__init__.py +0 -9
- endoreg_db/views/report/report_list.py +0 -112
- endoreg_db/views/report/report_with_secure_url.py +0 -28
- endoreg_db/views/report/start_examination.py +0 -7
- endoreg_db/views/video/video_media.py +0 -158
- endoreg_db/views.py +0 -0
- /endoreg_db/data/{requirement_set → _examples/requirement_set}/endoscopy_bleeding_risk.yaml +0 -0
- /endoreg_db/migrations/{0002_add_video_correction_models.py → _old/0002_add_video_correction_models.py} +0 -0
- /endoreg_db/migrations/{0003_add_center_display_name.py → _old/0003_add_center_display_name.py} +0 -0
- {endoreg_db-0.8.4.4.dist-info → endoreg_db-0.8.8.0.dist-info}/WHEEL +0 -0
- {endoreg_db-0.8.4.4.dist-info → endoreg_db-0.8.8.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -4,148 +4,149 @@ Video Processing History Model
|
|
|
4
4
|
Tracks all video correction operations (masking, frame removal, reprocessing).
|
|
5
5
|
Created as part of Phase 1.1: Video Correction API Endpoints.
|
|
6
6
|
"""
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
from django.conf import settings
|
|
7
12
|
from django.db import models
|
|
8
13
|
from django.utils import timezone
|
|
14
|
+
|
|
9
15
|
from .video_file import VideoFile
|
|
10
16
|
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
11
20
|
class VideoProcessingHistory(models.Model):
|
|
12
21
|
"""
|
|
13
22
|
History of all video processing operations.
|
|
14
|
-
|
|
23
|
+
|
|
15
24
|
Stores configuration and results of masking, frame removal, and reprocessing
|
|
16
25
|
operations for audit trail and download access.
|
|
17
26
|
"""
|
|
18
|
-
|
|
27
|
+
|
|
19
28
|
# Operation Types
|
|
20
|
-
OPERATION_MASKING =
|
|
21
|
-
OPERATION_FRAME_REMOVAL =
|
|
22
|
-
OPERATION_ANALYSIS =
|
|
23
|
-
OPERATION_REPROCESSING =
|
|
24
|
-
|
|
29
|
+
OPERATION_MASKING = "mask_overlay"
|
|
30
|
+
OPERATION_FRAME_REMOVAL = "frame_removal"
|
|
31
|
+
OPERATION_ANALYSIS = "analysis"
|
|
32
|
+
OPERATION_REPROCESSING = "reprocessing"
|
|
33
|
+
|
|
25
34
|
OPERATION_CHOICES = [
|
|
26
|
-
(OPERATION_MASKING,
|
|
27
|
-
(OPERATION_FRAME_REMOVAL,
|
|
28
|
-
(OPERATION_ANALYSIS,
|
|
29
|
-
(OPERATION_REPROCESSING,
|
|
35
|
+
(OPERATION_MASKING, "Mask Overlay"),
|
|
36
|
+
(OPERATION_FRAME_REMOVAL, "Frame Removal"),
|
|
37
|
+
(OPERATION_ANALYSIS, "Sensitivity Analysis"),
|
|
38
|
+
(OPERATION_REPROCESSING, "Full Reprocessing"),
|
|
30
39
|
]
|
|
31
|
-
|
|
40
|
+
|
|
32
41
|
# Status Types
|
|
33
|
-
STATUS_PENDING =
|
|
34
|
-
STATUS_RUNNING =
|
|
35
|
-
STATUS_SUCCESS =
|
|
36
|
-
STATUS_FAILURE =
|
|
37
|
-
STATUS_CANCELLED =
|
|
38
|
-
|
|
42
|
+
STATUS_PENDING = "pending"
|
|
43
|
+
STATUS_RUNNING = "running"
|
|
44
|
+
STATUS_SUCCESS = "success"
|
|
45
|
+
STATUS_FAILURE = "failure"
|
|
46
|
+
STATUS_CANCELLED = "cancelled"
|
|
47
|
+
|
|
39
48
|
STATUS_CHOICES = [
|
|
40
|
-
(STATUS_PENDING,
|
|
41
|
-
(STATUS_RUNNING,
|
|
42
|
-
(STATUS_SUCCESS,
|
|
43
|
-
(STATUS_FAILURE,
|
|
44
|
-
(STATUS_CANCELLED,
|
|
49
|
+
(STATUS_PENDING, "Pending"),
|
|
50
|
+
(STATUS_RUNNING, "Running"),
|
|
51
|
+
(STATUS_SUCCESS, "Success"),
|
|
52
|
+
(STATUS_FAILURE, "Failure"),
|
|
53
|
+
(STATUS_CANCELLED, "Cancelled"),
|
|
45
54
|
]
|
|
46
|
-
|
|
47
|
-
video = models.ForeignKey(
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
operation = models.CharField(
|
|
55
|
-
max_length=50,
|
|
56
|
-
choices=OPERATION_CHOICES,
|
|
57
|
-
help_text="Type of processing operation"
|
|
58
|
-
)
|
|
59
|
-
|
|
60
|
-
status = models.CharField(
|
|
61
|
-
max_length=20,
|
|
62
|
-
choices=STATUS_CHOICES,
|
|
63
|
-
default=STATUS_PENDING,
|
|
64
|
-
help_text="Current status of the operation"
|
|
65
|
-
)
|
|
66
|
-
|
|
55
|
+
|
|
56
|
+
video = models.ForeignKey(VideoFile, on_delete=models.CASCADE, related_name="processing_history", help_text="Video file this operation was performed on")
|
|
57
|
+
|
|
58
|
+
operation = models.CharField(max_length=50, choices=OPERATION_CHOICES, help_text="Type of processing operation")
|
|
59
|
+
|
|
60
|
+
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default=STATUS_PENDING, help_text="Current status of the operation")
|
|
61
|
+
|
|
67
62
|
# Configuration & Results
|
|
68
|
-
config = models.JSONField(
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
max_length=500,
|
|
75
|
-
blank=True,
|
|
76
|
-
help_text="Path to output file (relative to MEDIA_ROOT)"
|
|
77
|
-
)
|
|
78
|
-
|
|
79
|
-
details = models.TextField(
|
|
80
|
-
blank=True,
|
|
81
|
-
help_text="Additional details or error messages"
|
|
82
|
-
)
|
|
83
|
-
|
|
63
|
+
config = models.JSONField(default=dict, help_text="Operation configuration (mask settings, frame list, etc.)")
|
|
64
|
+
|
|
65
|
+
output_file = models.CharField(max_length=500, blank=True, help_text="Path to output file (relative to MEDIA_ROOT)")
|
|
66
|
+
|
|
67
|
+
details = models.TextField(blank=True, help_text="Additional details or error messages")
|
|
68
|
+
|
|
84
69
|
# Celery Integration
|
|
85
|
-
task_id = models.CharField(
|
|
86
|
-
|
|
87
|
-
blank=True,
|
|
88
|
-
help_text="Celery task ID for progress tracking"
|
|
89
|
-
)
|
|
90
|
-
|
|
70
|
+
task_id = models.CharField(max_length=100, blank=True, help_text="Celery task ID for progress tracking")
|
|
71
|
+
|
|
91
72
|
# Timestamps
|
|
92
|
-
created_at = models.DateTimeField(
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
completed_at = models.DateTimeField(
|
|
98
|
-
null=True,
|
|
99
|
-
blank=True,
|
|
100
|
-
help_text="When the operation completed (success or failure)"
|
|
101
|
-
)
|
|
102
|
-
|
|
73
|
+
created_at = models.DateTimeField(auto_now_add=True, help_text="When the operation was started")
|
|
74
|
+
|
|
75
|
+
completed_at = models.DateTimeField(null=True, blank=True, help_text="When the operation completed (success or failure)")
|
|
76
|
+
|
|
103
77
|
class Meta:
|
|
104
|
-
db_table =
|
|
105
|
-
verbose_name =
|
|
106
|
-
verbose_name_plural =
|
|
107
|
-
ordering = [
|
|
78
|
+
db_table = "video_processing_history"
|
|
79
|
+
verbose_name = "Video Processing History"
|
|
80
|
+
verbose_name_plural = "Video Processing Histories"
|
|
81
|
+
ordering = ["-created_at"]
|
|
108
82
|
indexes = [
|
|
109
|
-
models.Index(fields=[
|
|
110
|
-
models.Index(fields=[
|
|
111
|
-
models.Index(fields=[
|
|
83
|
+
models.Index(fields=["video", "-created_at"]),
|
|
84
|
+
models.Index(fields=["task_id"]),
|
|
85
|
+
models.Index(fields=["status"]),
|
|
112
86
|
]
|
|
113
|
-
|
|
87
|
+
|
|
114
88
|
def __str__(self):
|
|
115
|
-
|
|
116
|
-
|
|
89
|
+
operation_display = getattr(self, "get_operation_display", None)
|
|
90
|
+
status_display = getattr(self, "get_status_display", None)
|
|
91
|
+
|
|
92
|
+
operation = operation_display() if callable(operation_display) else self.operation
|
|
93
|
+
status = status_display() if callable(status_display) else self.status
|
|
94
|
+
return f"{operation} on {self.video.uuid} - {status}"
|
|
95
|
+
|
|
117
96
|
def mark_running(self, save=True):
|
|
118
97
|
"""Mark operation as running."""
|
|
119
98
|
self.status = self.STATUS_RUNNING
|
|
120
99
|
if save:
|
|
121
|
-
self.save(update_fields=[
|
|
122
|
-
|
|
100
|
+
self.save(update_fields=["status"])
|
|
101
|
+
|
|
102
|
+
@staticmethod
|
|
103
|
+
def _normalize_output_path(path: str | Path | None) -> str:
|
|
104
|
+
"""Return a path relative to MEDIA_ROOT when possible."""
|
|
105
|
+
if not path:
|
|
106
|
+
return ""
|
|
107
|
+
|
|
108
|
+
raw_path = Path(path)
|
|
109
|
+
if not raw_path.is_absolute():
|
|
110
|
+
return raw_path.as_posix()
|
|
111
|
+
media_root = Path(settings.MEDIA_ROOT)
|
|
112
|
+
|
|
113
|
+
try:
|
|
114
|
+
relative = raw_path.resolve().relative_to(media_root.resolve())
|
|
115
|
+
return relative.as_posix()
|
|
116
|
+
except (ValueError, RuntimeError):
|
|
117
|
+
logger.warning(
|
|
118
|
+
"Storing absolute output path '%s' because it is outside MEDIA_ROOT (%s).",
|
|
119
|
+
raw_path,
|
|
120
|
+
media_root,
|
|
121
|
+
)
|
|
122
|
+
return raw_path.as_posix()
|
|
123
|
+
|
|
123
124
|
def mark_success(self, output_file=None, details=None, save=True):
|
|
124
125
|
"""Mark operation as successful."""
|
|
125
126
|
self.status = self.STATUS_SUCCESS
|
|
126
127
|
self.completed_at = timezone.now()
|
|
127
128
|
if output_file:
|
|
128
|
-
self.output_file = output_file
|
|
129
|
+
self.output_file = self._normalize_output_path(output_file)
|
|
129
130
|
if details:
|
|
130
131
|
self.details = details
|
|
131
132
|
if save:
|
|
132
|
-
self.save(update_fields=[
|
|
133
|
-
|
|
133
|
+
self.save(update_fields=["status", "completed_at", "output_file", "details"])
|
|
134
|
+
|
|
134
135
|
def mark_failure(self, error_message, save=True):
|
|
135
136
|
"""Mark operation as failed."""
|
|
136
137
|
self.status = self.STATUS_FAILURE
|
|
137
138
|
self.completed_at = timezone.now()
|
|
138
139
|
self.details = error_message
|
|
139
140
|
if save:
|
|
140
|
-
self.save(update_fields=[
|
|
141
|
-
|
|
141
|
+
self.save(update_fields=["status", "completed_at", "details"])
|
|
142
|
+
|
|
142
143
|
@property
|
|
143
144
|
def duration(self):
|
|
144
145
|
"""Calculate operation duration if completed."""
|
|
145
146
|
if self.completed_at and self.created_at:
|
|
146
147
|
return (self.completed_at - self.created_at).total_seconds()
|
|
147
148
|
return None
|
|
148
|
-
|
|
149
|
+
|
|
149
150
|
@property
|
|
150
151
|
def is_complete(self) -> bool:
|
|
151
152
|
"""Check if operation is in a terminal state."""
|
|
@@ -1,17 +1,27 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING
|
|
2
|
+
|
|
1
3
|
from django.db import models
|
|
2
4
|
|
|
5
|
+
|
|
3
6
|
class ContraindicationManager(models.Manager):
|
|
4
7
|
def get_by_natural_key(self, name):
|
|
5
8
|
return self.get(name=name)
|
|
6
|
-
|
|
9
|
+
|
|
10
|
+
|
|
7
11
|
class Contraindication(models.Model):
|
|
8
12
|
name = models.CharField(max_length=100, unique=True)
|
|
9
13
|
description = models.TextField(blank=True, null=True)
|
|
10
14
|
|
|
11
15
|
objects = ContraindicationManager()
|
|
12
|
-
|
|
16
|
+
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
from endoreg_db.models import FindingIntervention
|
|
19
|
+
|
|
20
|
+
@property
|
|
21
|
+
def contraindicating_finding_interventions(self) -> "models.manager.RelatedManager[FindingIntervention]": ...
|
|
22
|
+
|
|
13
23
|
def natural_key(self):
|
|
14
24
|
return (self.name,)
|
|
15
|
-
|
|
25
|
+
|
|
16
26
|
def __str__(self):
|
|
17
27
|
return str(self.name)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING, List
|
|
2
|
+
|
|
1
3
|
from django.db import models
|
|
2
|
-
from typing import List, TYPE_CHECKING
|
|
3
4
|
|
|
4
5
|
if TYPE_CHECKING:
|
|
5
6
|
from .patient import PatientDisease
|
|
@@ -27,6 +28,7 @@ class Disease(models.Model):
|
|
|
27
28
|
|
|
28
29
|
Can define associated subcategories and numerical descriptors applicable to the disease itself.
|
|
29
30
|
"""
|
|
31
|
+
|
|
30
32
|
name = models.CharField(max_length=255, unique=True)
|
|
31
33
|
subcategories = models.JSONField(default=dict)
|
|
32
34
|
numerical_descriptors = models.JSONField(default=dict)
|
|
@@ -34,8 +36,12 @@ class Disease(models.Model):
|
|
|
34
36
|
objects = DiseaseManager()
|
|
35
37
|
|
|
36
38
|
if TYPE_CHECKING:
|
|
37
|
-
|
|
38
|
-
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def disease_classifications(self) -> models.QuerySet["DiseaseClassification"]: ...
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def patient_diseases(self) -> models.QuerySet["PatientDisease"]: ...
|
|
39
45
|
|
|
40
46
|
def natural_key(self):
|
|
41
47
|
"""Returns the natural key (name) as a tuple."""
|
|
@@ -52,9 +58,7 @@ class Disease(models.Model):
|
|
|
52
58
|
Returns:
|
|
53
59
|
List[DiseaseClassification]: A list of related disease classification objects.
|
|
54
60
|
"""
|
|
55
|
-
classifications: List[DiseaseClassification] = [
|
|
56
|
-
_ for _ in self.disease_classifications.all()
|
|
57
|
-
]
|
|
61
|
+
classifications: List[DiseaseClassification] = [_ for _ in self.disease_classifications.all()]
|
|
58
62
|
return classifications
|
|
59
63
|
|
|
60
64
|
|
|
@@ -78,17 +82,18 @@ class DiseaseClassification(models.Model):
|
|
|
78
82
|
"""
|
|
79
83
|
Represents a classification system applicable to a specific disease (e.g., Forrest classification for ulcers).
|
|
80
84
|
"""
|
|
85
|
+
|
|
81
86
|
name = models.CharField(max_length=255, unique=True)
|
|
82
87
|
|
|
83
|
-
disease = models.ForeignKey(
|
|
84
|
-
Disease, on_delete=models.CASCADE, related_name="disease_classifications"
|
|
85
|
-
)
|
|
88
|
+
disease = models.ForeignKey(Disease, on_delete=models.CASCADE, related_name="disease_classifications")
|
|
86
89
|
|
|
87
90
|
objects = DiseaseClassificationManager()
|
|
88
91
|
|
|
89
92
|
if TYPE_CHECKING:
|
|
90
|
-
disease: "Disease"
|
|
91
|
-
|
|
93
|
+
disease: models.ForeignKey["Disease"]
|
|
94
|
+
|
|
95
|
+
@property
|
|
96
|
+
def disease_classification_choices(self) -> models.manager.RelatedManager["DiseaseClassificationChoice"]: ...
|
|
92
97
|
|
|
93
98
|
def natural_key(self):
|
|
94
99
|
"""Returns the natural key (name) as a tuple."""
|
|
@@ -105,9 +110,7 @@ class DiseaseClassification(models.Model):
|
|
|
105
110
|
Returns:
|
|
106
111
|
List[DiseaseClassificationChoice]: A list of related disease classification choices.
|
|
107
112
|
"""
|
|
108
|
-
choices: List[DiseaseClassificationChoice] = [
|
|
109
|
-
_ for _ in self.disease_classification_choices.all()
|
|
110
|
-
]
|
|
113
|
+
choices: List[DiseaseClassificationChoice] = [_ for _ in self.disease_classification_choices.all()]
|
|
111
114
|
return choices
|
|
112
115
|
|
|
113
116
|
|
|
@@ -133,6 +136,7 @@ class DiseaseClassificationChoice(models.Model):
|
|
|
133
136
|
"""
|
|
134
137
|
Represents a specific choice within a disease classification system (e.g., Forrest IIa).
|
|
135
138
|
"""
|
|
139
|
+
|
|
136
140
|
name = models.CharField(max_length=255, unique=True)
|
|
137
141
|
|
|
138
142
|
disease_classification = models.ForeignKey(
|
|
@@ -144,8 +148,10 @@ class DiseaseClassificationChoice(models.Model):
|
|
|
144
148
|
objects = DiseaseClassificationChoiceManager()
|
|
145
149
|
|
|
146
150
|
if TYPE_CHECKING:
|
|
147
|
-
disease_classification: "DiseaseClassification"
|
|
148
|
-
|
|
151
|
+
disease_classification: models.ForeignKey["DiseaseClassification"]
|
|
152
|
+
|
|
153
|
+
@property
|
|
154
|
+
def patient_diseases(self) -> models.manager.RelatedManager["PatientDisease"]: ...
|
|
149
155
|
|
|
150
156
|
def natural_key(self):
|
|
151
157
|
"""Returns the natural key (name) as a tuple."""
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING, List
|
|
2
|
+
|
|
1
3
|
from django.db import models
|
|
2
|
-
from typing import List, TYPE_CHECKING
|
|
3
4
|
|
|
4
5
|
if TYPE_CHECKING:
|
|
5
6
|
from endoreg_db.models import PatientEvent
|
|
@@ -13,14 +14,14 @@ class EventManager(models.Manager):
|
|
|
13
14
|
def get_by_natural_key(self, name: str) -> "Event":
|
|
14
15
|
"""
|
|
15
16
|
Retrieves an Event instance using its natural key.
|
|
16
|
-
|
|
17
|
+
|
|
17
18
|
This method returns the event whose name matches the provided natural key.
|
|
18
|
-
It is primarily used to support Django's natural key serialization during
|
|
19
|
+
It is primarily used to support Django's natural key serialization during
|
|
19
20
|
data import/export and deserialization processes.
|
|
20
|
-
|
|
21
|
+
|
|
21
22
|
Args:
|
|
22
23
|
name: The unique event name serving as the natural key.
|
|
23
|
-
|
|
24
|
+
|
|
24
25
|
Returns:
|
|
25
26
|
The Event object corresponding to the given name.
|
|
26
27
|
"""
|
|
@@ -38,22 +39,19 @@ class Event(models.Model):
|
|
|
38
39
|
|
|
39
40
|
name = models.CharField(max_length=100, unique=True)
|
|
40
41
|
description = models.TextField(blank=True, null=True)
|
|
41
|
-
|
|
42
|
-
"EventClassification",
|
|
43
|
-
on_delete=models.CASCADE,
|
|
44
|
-
related_name="events",
|
|
45
|
-
null=True,
|
|
46
|
-
blank=True,
|
|
47
|
-
)
|
|
42
|
+
|
|
48
43
|
objects = EventManager()
|
|
49
44
|
|
|
50
45
|
if TYPE_CHECKING:
|
|
51
|
-
patient_events: models.
|
|
46
|
+
patient_events: models.ForeignKey["PatientEvent"]
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
def event_classifications(self) -> models.QuerySet["EventClassification"]: ...
|
|
52
50
|
|
|
53
51
|
def natural_key(self):
|
|
54
52
|
"""
|
|
55
53
|
Returns a tuple representing the natural key for this instance.
|
|
56
|
-
|
|
54
|
+
|
|
57
55
|
The natural key consists of the instance's unique name.
|
|
58
56
|
"""
|
|
59
57
|
return (self.name,)
|
|
@@ -61,7 +59,7 @@ class Event(models.Model):
|
|
|
61
59
|
def __str__(self):
|
|
62
60
|
"""
|
|
63
61
|
Return a string representation of the instance's name.
|
|
64
|
-
|
|
62
|
+
|
|
65
63
|
This method converts the 'name' attribute to a string, providing a human-readable
|
|
66
64
|
representation of the model instance.
|
|
67
65
|
"""
|
|
@@ -85,6 +83,18 @@ class EventClassification(models.Model):
|
|
|
85
83
|
|
|
86
84
|
objects = EventClassificationManager()
|
|
87
85
|
|
|
86
|
+
event = models.ForeignKey(
|
|
87
|
+
Event,
|
|
88
|
+
on_delete=models.CASCADE,
|
|
89
|
+
related_name="event_classifications",
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
if TYPE_CHECKING:
|
|
93
|
+
event: models.ForeignKey["Event"]
|
|
94
|
+
|
|
95
|
+
@property
|
|
96
|
+
def event_classification_choices(self) -> models.QuerySet["EventClassificationChoice"]: ...
|
|
97
|
+
|
|
88
98
|
def natural_key(self):
|
|
89
99
|
"""Returns the natural key (name) as a tuple."""
|
|
90
100
|
return (self.name,)
|
|
@@ -95,9 +105,7 @@ class EventClassification(models.Model):
|
|
|
95
105
|
|
|
96
106
|
def get_choices(self) -> List["EventClassificationChoice"]:
|
|
97
107
|
"""Retrieves all choices associated with this classification."""
|
|
98
|
-
choices: List[EventClassificationChoice] = [
|
|
99
|
-
_ for _ in self.event_classification_choices.all()
|
|
100
|
-
]
|
|
108
|
+
choices: List[EventClassificationChoice] = [_ for _ in self.event_classification_choices.all()]
|
|
101
109
|
return choices
|
|
102
110
|
|
|
103
111
|
|
|
@@ -128,6 +136,11 @@ class EventClassificationChoice(models.Model):
|
|
|
128
136
|
|
|
129
137
|
objects = EventClassificationChoiceManager()
|
|
130
138
|
|
|
139
|
+
@property
|
|
140
|
+
def event(self):
|
|
141
|
+
"""Returns the associated Event instance."""
|
|
142
|
+
return self.event_classification.event
|
|
143
|
+
|
|
131
144
|
def natural_key(self):
|
|
132
145
|
"""Returns the natural key (name) as a tuple."""
|
|
133
146
|
return (self.name,)
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
from .examination import Examination, ExaminationRequirementSet
|
|
2
|
-
from .
|
|
2
|
+
from .examination_indication import ExaminationIndication, ExaminationIndicationClassification, ExaminationIndicationClassificationChoice
|
|
3
3
|
from .examination_time import ExaminationTime
|
|
4
4
|
from .examination_time_type import ExaminationTimeType
|
|
5
|
-
from .
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
from .examination_type import ExaminationType
|
|
6
|
+
|
|
7
|
+
__all__ = [
|
|
8
|
+
"Examination",
|
|
9
|
+
"ExaminationRequirementSet",
|
|
10
|
+
"ExaminationType",
|
|
11
|
+
"ExaminationTime",
|
|
12
|
+
"ExaminationTimeType",
|
|
13
|
+
"ExaminationIndication",
|
|
14
|
+
"ExaminationIndicationClassification",
|
|
15
|
+
"ExaminationIndicationClassificationChoice",
|
|
16
|
+
]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING, List
|
|
2
|
+
|
|
1
3
|
from django.db import models
|
|
2
|
-
from typing import List
|
|
3
|
-
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
5
|
if TYPE_CHECKING:
|
|
6
6
|
from endoreg_db.models import Finding
|
|
@@ -33,19 +33,18 @@ class Examination(models.Model):
|
|
|
33
33
|
|
|
34
34
|
if TYPE_CHECKING:
|
|
35
35
|
from endoreg_db.models import ExaminationIndication, Finding, FindingClassification
|
|
36
|
-
finding_classifications: models.QuerySet['FindingClassification']
|
|
37
|
-
indications: models.QuerySet[ExaminationIndication]
|
|
38
|
-
findings: models.QuerySet["Finding"]
|
|
39
|
-
exam_reqset_links: models.QuerySet["ExaminationRequirementSet"]
|
|
40
36
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
37
|
+
@property
|
|
38
|
+
def finding_classifications(self) -> "models.manager.RelatedManager[FindingClassification]": ...
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def indications(self) -> "models.manager.RelatedManager[ExaminationIndication]": ...
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def findings(self) -> "models.manager.RelatedManager[Finding]": ...
|
|
48
45
|
|
|
46
|
+
@property
|
|
47
|
+
def exam_reqset_links(self) -> "models.manager.RelatedManager[ExaminationRequirementSet]": ...
|
|
49
48
|
|
|
50
49
|
@property
|
|
51
50
|
def links(self) -> "RequirementLinks":
|
|
@@ -61,7 +60,7 @@ class Examination(models.Model):
|
|
|
61
60
|
examinations=[self],
|
|
62
61
|
findings=list(self.findings.all()),
|
|
63
62
|
finding_classifications=list(self.finding_classifications.all()),
|
|
64
|
-
examination_indications=list(self.indications.all())
|
|
63
|
+
examination_indications=list(self.indications.all()),
|
|
65
64
|
)
|
|
66
65
|
|
|
67
66
|
def __str__(self) -> str:
|
|
@@ -108,12 +107,13 @@ class ExaminationRequirementSetManager(models.Manager):
|
|
|
108
107
|
def get_by_natural_key(self, name: str) -> "ExaminationRequirementSet":
|
|
109
108
|
return self.get(name=name)
|
|
110
109
|
|
|
111
|
-
|
|
110
|
+
|
|
112
111
|
class ExaminationRequirementSet(models.Model):
|
|
113
112
|
"""
|
|
114
113
|
Through table for Examination ↔ RequirementSet link.
|
|
115
114
|
Lets you store per-link metadata (order, default, etc.)
|
|
116
115
|
"""
|
|
116
|
+
|
|
117
117
|
examinations = models.ManyToManyField(
|
|
118
118
|
"Examination",
|
|
119
119
|
related_name="exam_reqset_links",
|
|
@@ -126,7 +126,7 @@ class ExaminationRequirementSet(models.Model):
|
|
|
126
126
|
# )
|
|
127
127
|
# Optional metadata
|
|
128
128
|
enabled_by_default = models.BooleanField(default=False)
|
|
129
|
-
|
|
129
|
+
|
|
130
130
|
name = models.CharField(max_length=100, unique=True)
|
|
131
131
|
|
|
132
132
|
objects = ExaminationRequirementSetManager()
|
|
@@ -136,7 +136,7 @@ class ExaminationRequirementSet(models.Model):
|
|
|
136
136
|
|
|
137
137
|
# def __str__(self) -> str:
|
|
138
138
|
# return f"{self.examination} ↔ {self.requirement_set} (prio={self.priority})"
|
|
139
|
-
|
|
139
|
+
|
|
140
140
|
def natural_key(self) -> tuple:
|
|
141
141
|
"""
|
|
142
142
|
Returns the natural key for the ExaminationRequirementSet.
|
|
@@ -145,4 +145,3 @@ class ExaminationRequirementSet(models.Model):
|
|
|
145
145
|
tuple: The natural key consisting of the name.
|
|
146
146
|
"""
|
|
147
147
|
return (self.name,)
|
|
148
|
-
|