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
|
@@ -1,22 +1,26 @@
|
|
|
1
|
-
from django.db import models
|
|
2
1
|
from typing import TYPE_CHECKING
|
|
3
2
|
|
|
3
|
+
from django.db import models
|
|
4
|
+
|
|
4
5
|
if TYPE_CHECKING:
|
|
5
|
-
from .patient_examination import PatientExamination
|
|
6
6
|
from ..examination import (
|
|
7
7
|
ExaminationIndication,
|
|
8
8
|
ExaminationIndicationClassificationChoice,
|
|
9
9
|
)
|
|
10
|
+
from .patient_examination import PatientExamination
|
|
11
|
+
|
|
12
|
+
|
|
10
13
|
class PatientExaminationIndication(models.Model):
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
"""A model to store the indication for a patient examination."""
|
|
15
|
+
|
|
16
|
+
patient_examination = models.ForeignKey("PatientExamination", on_delete=models.CASCADE, related_name="indications")
|
|
17
|
+
examination_indication = models.ForeignKey("ExaminationIndication", on_delete=models.CASCADE)
|
|
18
|
+
indication_choice = models.ForeignKey("ExaminationIndicationClassificationChoice", on_delete=models.CASCADE, blank=True, null=True)
|
|
15
19
|
|
|
16
20
|
if TYPE_CHECKING:
|
|
17
|
-
patient_examination: "PatientExamination"
|
|
18
|
-
examination_indication: "ExaminationIndication"
|
|
19
|
-
indication_choice: "ExaminationIndicationClassificationChoice"
|
|
21
|
+
patient_examination: models.ForeignKey["PatientExamination"]
|
|
22
|
+
examination_indication: models.ForeignKey["ExaminationIndication"]
|
|
23
|
+
indication_choice: models.ForeignKey["ExaminationIndicationClassificationChoice|None"]
|
|
20
24
|
|
|
21
25
|
def __str__(self):
|
|
22
26
|
return f"{self.patient_examination} - {self.examination_indication}"
|
|
@@ -26,19 +30,17 @@ class PatientExaminationIndication(models.Model):
|
|
|
26
30
|
e = pe.examination
|
|
27
31
|
|
|
28
32
|
return e
|
|
29
|
-
|
|
33
|
+
|
|
30
34
|
def get_patient_examination(self):
|
|
31
35
|
pe = self.patient_examination
|
|
32
36
|
return pe
|
|
33
|
-
|
|
37
|
+
|
|
34
38
|
def get_patient(self):
|
|
35
39
|
pe = self.get_patient_examination()
|
|
36
40
|
patient = pe.patient
|
|
37
41
|
return patient
|
|
38
|
-
|
|
39
|
-
def get_choices(self):
|
|
40
42
|
|
|
43
|
+
def get_choices(self):
|
|
41
44
|
examination_indication = self.examination_indication
|
|
42
45
|
choices = [_ for _ in examination_indication.get_choices()]
|
|
43
46
|
return choices
|
|
44
|
-
|
|
@@ -1,71 +1,73 @@
|
|
|
1
|
-
from
|
|
1
|
+
from typing import TYPE_CHECKING
|
|
2
|
+
|
|
2
3
|
from django.core.exceptions import ValidationError
|
|
4
|
+
from django.db import models
|
|
3
5
|
from django.utils import timezone
|
|
4
|
-
from typing import TYPE_CHECKING
|
|
5
6
|
|
|
6
7
|
if TYPE_CHECKING:
|
|
7
8
|
from endoreg_db.models import (
|
|
8
|
-
PatientExamination,
|
|
9
9
|
Finding,
|
|
10
|
-
PatientFindingIntervention,
|
|
11
|
-
PatientFindingClassification,
|
|
12
10
|
LabelVideoSegment,
|
|
11
|
+
PatientExamination,
|
|
12
|
+
PatientFindingClassification,
|
|
13
|
+
PatientFindingIntervention,
|
|
13
14
|
)
|
|
14
15
|
from endoreg_db.utils.links.requirement_link import RequirementLinks
|
|
15
|
-
|
|
16
|
+
|
|
17
|
+
|
|
16
18
|
class PatientFinding(models.Model):
|
|
17
|
-
patient_examination = models.ForeignKey(
|
|
18
|
-
finding = models.ForeignKey(
|
|
19
|
-
|
|
19
|
+
patient_examination = models.ForeignKey("PatientExamination", on_delete=models.CASCADE, related_name="patient_findings")
|
|
20
|
+
finding = models.ForeignKey("Finding", on_delete=models.CASCADE, related_name="finding_patient_findings")
|
|
21
|
+
|
|
20
22
|
# Audit-Felder für medizinische Nachverfolgung
|
|
21
23
|
created_at = models.DateTimeField(auto_now_add=True)
|
|
22
24
|
updated_at = models.DateTimeField(auto_now=True)
|
|
23
|
-
created_by = models.ForeignKey(
|
|
24
|
-
updated_by = models.ForeignKey(
|
|
25
|
-
|
|
25
|
+
created_by = models.ForeignKey("auth.User", on_delete=models.PROTECT, related_name="created_findings", null=True, blank=True)
|
|
26
|
+
updated_by = models.ForeignKey("auth.User", on_delete=models.PROTECT, related_name="updated_findings", null=True, blank=True)
|
|
27
|
+
|
|
26
28
|
# Soft Delete für historische Daten
|
|
27
29
|
is_active = models.BooleanField(default=True, help_text="Deaktiviert statt gelöscht für Audit-Trail")
|
|
28
30
|
deactivated_at = models.DateTimeField(null=True, blank=True)
|
|
29
|
-
deactivated_by = models.ForeignKey(
|
|
30
|
-
|
|
31
|
+
deactivated_by = models.ForeignKey("auth.User", on_delete=models.PROTECT, related_name="deactivated_findings", null=True, blank=True)
|
|
32
|
+
|
|
31
33
|
if TYPE_CHECKING:
|
|
32
|
-
patient_examination: "PatientExamination"
|
|
33
|
-
finding: "Finding"
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
video_segments
|
|
34
|
+
patient_examination: models.ForeignKey["PatientExamination"]
|
|
35
|
+
finding: models.ForeignKey["Finding"]
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
def video_segments(self) -> models.manager.RelatedManager["LabelVideoSegment"]: ...
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def interventions(self) -> models.manager.RelatedManager["PatientFindingIntervention"]: ...
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def classifications(self) -> models.manager.RelatedManager["PatientFindingClassification"]: ...
|
|
37
45
|
|
|
38
46
|
class Meta:
|
|
39
|
-
verbose_name =
|
|
40
|
-
verbose_name_plural =
|
|
41
|
-
ordering = [
|
|
42
|
-
|
|
47
|
+
verbose_name = "Patient Finding"
|
|
48
|
+
verbose_name_plural = "Patient Findings"
|
|
49
|
+
ordering = ["patient_examination", "finding"]
|
|
50
|
+
|
|
43
51
|
# Wichtige Constraints für Datenintegrität
|
|
44
52
|
constraints = [
|
|
45
53
|
models.UniqueConstraint(
|
|
46
|
-
fields=[
|
|
47
|
-
condition=models.Q(is_active=True),
|
|
48
|
-
name='unique_active_finding_per_examination'
|
|
54
|
+
fields=["patient_examination", "finding"], condition=models.Q(is_active=True), name="unique_active_finding_per_examination"
|
|
49
55
|
),
|
|
50
56
|
models.CheckConstraint(
|
|
51
|
-
check=models.Q(
|
|
52
|
-
deactivated_at__isnull=True,
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
is_active=False
|
|
58
|
-
),
|
|
59
|
-
name='deactivation_fields_consistency'
|
|
60
|
-
)
|
|
57
|
+
check=models.Q( # called .check in future?
|
|
58
|
+
deactivated_at__isnull=True, deactivated_by__isnull=True
|
|
59
|
+
)
|
|
60
|
+
| models.Q(deactivated_at__isnull=False, deactivated_by__isnull=False, is_active=False),
|
|
61
|
+
name="deactivation_fields_consistency",
|
|
62
|
+
),
|
|
61
63
|
]
|
|
62
|
-
|
|
64
|
+
|
|
63
65
|
# Performance-optimierte Indizes
|
|
64
66
|
indexes = [
|
|
65
|
-
models.Index(fields=[
|
|
66
|
-
models.Index(fields=[
|
|
67
|
-
models.Index(fields=[
|
|
68
|
-
models.Index(fields=[
|
|
67
|
+
models.Index(fields=["patient_examination", "finding"]),
|
|
68
|
+
models.Index(fields=["patient_examination", "is_active"]),
|
|
69
|
+
models.Index(fields=["created_at"]),
|
|
70
|
+
models.Index(fields=["finding", "is_active"]),
|
|
69
71
|
]
|
|
70
72
|
|
|
71
73
|
@property
|
|
@@ -80,61 +82,56 @@ class PatientFinding(models.Model):
|
|
|
80
82
|
def clean(self):
|
|
81
83
|
"""
|
|
82
84
|
Validates the patient finding against business rules before saving.
|
|
83
|
-
|
|
85
|
+
|
|
84
86
|
Ensures that the selected finding is allowed for the associated examination and that all required findings are present. Raises a ValidationError if the finding is not permitted or required findings are missing.
|
|
85
87
|
"""
|
|
86
88
|
super().clean()
|
|
87
|
-
|
|
89
|
+
|
|
88
90
|
# Prüfe ob Finding für diese Examination erlaubt ist
|
|
89
91
|
if self.finding and self.patient_examination:
|
|
90
|
-
available_findings = self.patient_examination.
|
|
92
|
+
available_findings = self.patient_examination.examination_safe.get_available_findings()
|
|
91
93
|
if self.finding not in available_findings:
|
|
92
|
-
raise ValidationError(
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
94
|
+
raise ValidationError(
|
|
95
|
+
{"finding": f'Finding "{self.finding.name}" ist nicht für Examination "{self.patient_examination.examination_safe.name}" erlaubt.'}
|
|
96
|
+
)
|
|
97
|
+
|
|
96
98
|
# Prüfe Required Findings Logic
|
|
97
99
|
if self.finding and self.patient_examination:
|
|
98
100
|
self._validate_required_findings()
|
|
99
|
-
|
|
100
|
-
# This avoids validation errors on partial updates
|
|
101
|
+
|
|
102
|
+
# This avoids validation errors on partial updates
|
|
101
103
|
def save(self, *args, **kwargs):
|
|
102
104
|
"""
|
|
103
105
|
Validates the model instance before saving, unless performing a partial update.
|
|
104
|
-
|
|
106
|
+
|
|
105
107
|
Performs full model validation with `full_clean()` before saving, except when `update_fields` is specified for a partial update.
|
|
106
108
|
"""
|
|
107
|
-
if not kwargs.get(
|
|
109
|
+
if not kwargs.get("update_fields"):
|
|
108
110
|
self.full_clean()
|
|
109
111
|
super().save(*args, **kwargs)
|
|
110
112
|
|
|
111
|
-
|
|
112
113
|
def _validate_required_findings(self):
|
|
113
114
|
"""Validiert Required vs Optional Finding Constraints"""
|
|
114
115
|
examination = self.patient_examination.examination
|
|
115
|
-
|
|
116
|
+
|
|
116
117
|
# Hole Required Findings für diese Examination
|
|
117
|
-
required_findings = getattr(examination,
|
|
118
|
+
required_findings = getattr(examination, "required_findings", None)
|
|
118
119
|
if required_findings and required_findings.exists():
|
|
119
120
|
# Prüfe ob alle Required Findings vorhanden sind
|
|
120
|
-
existing_findings = self.patient_examination.patient_findings.filter(
|
|
121
|
-
|
|
122
|
-
).values_list('finding', flat=True)
|
|
123
|
-
|
|
121
|
+
existing_findings = self.patient_examination.patient_findings.filter(is_active=True).values_list("finding", flat=True)
|
|
122
|
+
|
|
124
123
|
missing_required = required_findings.exclude(id__in=existing_findings)
|
|
125
124
|
if missing_required.exists() and self.finding not in required_findings.all():
|
|
126
|
-
missing_names =
|
|
127
|
-
raise ValidationError(
|
|
128
|
-
f'Erforderliche Findings fehlen: {missing_names}'
|
|
129
|
-
)
|
|
125
|
+
missing_names = ", ".join([f.name for f in missing_required])
|
|
126
|
+
raise ValidationError(f"Erforderliche Findings fehlen: {missing_names}")
|
|
130
127
|
|
|
131
128
|
def deactivate(self, user=None, reason=None):
|
|
132
129
|
"""Soft Delete mit Audit-Trail"""
|
|
133
130
|
self.is_active = False
|
|
134
131
|
self.deactivated_at = timezone.now()
|
|
135
132
|
self.deactivated_by = user
|
|
136
|
-
self.save(update_fields=[
|
|
137
|
-
|
|
133
|
+
self.save(update_fields=["is_active", "deactivated_at", "deactivated_by"])
|
|
134
|
+
|
|
138
135
|
# Deaktiviere auch abhängige Objekte
|
|
139
136
|
self.locations.update(is_active=False, deactivated_at=timezone.now())
|
|
140
137
|
self.morphologies.update(is_active=False, deactivated_at=timezone.now())
|
|
@@ -143,7 +140,7 @@ class PatientFinding(models.Model):
|
|
|
143
140
|
def reactivate(self, user=None):
|
|
144
141
|
"""
|
|
145
142
|
Reactivates a previously deactivated patient finding after validating its state.
|
|
146
|
-
|
|
143
|
+
|
|
147
144
|
If validation passes, sets the finding as active, clears deactivation fields, updates the user, and saves changes. Raises a ValidationError if reactivation is not allowed.
|
|
148
145
|
"""
|
|
149
146
|
if not self.is_active:
|
|
@@ -154,57 +151,50 @@ class PatientFinding(models.Model):
|
|
|
154
151
|
self.deactivated_at = None
|
|
155
152
|
self.deactivated_by = None
|
|
156
153
|
self.updated_by = user
|
|
157
|
-
self.save(update_fields=[
|
|
154
|
+
self.save(update_fields=["is_active", "deactivated_at", "deactivated_by", "updated_by"])
|
|
158
155
|
except ValidationError as e:
|
|
159
|
-
raise ValidationError(f
|
|
160
|
-
|
|
156
|
+
raise ValidationError(f"Reaktivierung nicht möglich: {e}")
|
|
161
157
|
|
|
162
158
|
def get_interventions(self):
|
|
163
159
|
"""
|
|
164
160
|
Retrieve all active interventions associated with this patient finding.
|
|
165
|
-
|
|
161
|
+
|
|
166
162
|
Returns:
|
|
167
163
|
QuerySet: Active related interventions with intervention details prefetched.
|
|
168
164
|
"""
|
|
169
|
-
return self.interventions.filter(is_active=True).select_related(
|
|
165
|
+
return self.interventions.filter(is_active=True).select_related("intervention")
|
|
170
166
|
|
|
171
167
|
def add_classification(
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
168
|
+
self,
|
|
169
|
+
classification_id,
|
|
170
|
+
classification_choice_id,
|
|
171
|
+
user=None,
|
|
172
|
+
) -> "PatientFindingClassification":
|
|
173
|
+
"""
|
|
174
|
+
Add a classification choice to this patient finding after validating its association.
|
|
175
|
+
|
|
176
|
+
Parameters:
|
|
177
|
+
classification_id: The ID of the classification to add.
|
|
178
|
+
classification_choice_id: The ID of the classification choice to associate.
|
|
179
|
+
user: Optional user performing the action.
|
|
180
|
+
|
|
181
|
+
Returns:
|
|
182
|
+
PatientFindingClassification: The created or existing active classification association.
|
|
183
|
+
|
|
184
|
+
Raises:
|
|
185
|
+
ValidationError: If the classification does not exist or the choice is not valid for the classification.
|
|
177
186
|
"""
|
|
178
|
-
Add a classification choice to this patient finding after validating its association.
|
|
179
|
-
|
|
180
|
-
Parameters:
|
|
181
|
-
classification_id: The ID of the classification to add.
|
|
182
|
-
classification_choice_id: The ID of the classification choice to associate.
|
|
183
|
-
user: Optional user performing the action.
|
|
184
|
-
|
|
185
|
-
Returns:
|
|
186
|
-
PatientFindingClassification: The created or existing active classification association.
|
|
187
|
-
|
|
188
|
-
Raises:
|
|
189
|
-
ValidationError: If the classification does not exist or the choice is not valid for the classification.
|
|
190
|
-
"""
|
|
191
|
-
from .patient_finding_classification import PatientFindingClassification
|
|
192
187
|
from ..finding import FindingClassification, FindingClassificationChoice
|
|
188
|
+
from .patient_finding_classification import PatientFindingClassification
|
|
193
189
|
|
|
194
190
|
try:
|
|
195
191
|
classification = FindingClassification.objects.get(id=classification_id)
|
|
196
192
|
classification_choice = FindingClassificationChoice.objects.filter(id=classification_choice_id).first()
|
|
197
193
|
|
|
198
194
|
if not classification.choices.filter(id=classification_choice_id).exists():
|
|
199
|
-
raise ValidationError(
|
|
200
|
-
f'Classification Choice {classification_choice_id} gehört nicht zu Classification {classification_id}'
|
|
201
|
-
)
|
|
195
|
+
raise ValidationError(f"Classification Choice {classification_choice_id} gehört nicht zu Classification {classification_id}")
|
|
202
196
|
|
|
203
|
-
existing = self.classifications.filter(
|
|
204
|
-
classification=classification,
|
|
205
|
-
classification_choice=classification_choice,
|
|
206
|
-
is_active=True
|
|
207
|
-
).first()
|
|
197
|
+
existing = self.classifications.filter(classification=classification, classification_choice=classification_choice, is_active=True).first()
|
|
208
198
|
|
|
209
199
|
if existing:
|
|
210
200
|
return existing
|
|
@@ -218,54 +208,50 @@ class PatientFinding(models.Model):
|
|
|
218
208
|
return patient_finding_classification
|
|
219
209
|
|
|
220
210
|
except FindingClassification.DoesNotExist:
|
|
221
|
-
raise ValidationError(f
|
|
211
|
+
raise ValidationError(f"Classification {classification_id} nicht gefunden")
|
|
222
212
|
|
|
223
213
|
def add_intervention(self, intervention_id, state="pending", date=None, user=None):
|
|
224
214
|
"""
|
|
225
215
|
Add an intervention to the patient finding after validating its existence.
|
|
226
|
-
|
|
216
|
+
|
|
227
217
|
Parameters:
|
|
228
218
|
intervention_id (int): The ID of the intervention to add.
|
|
229
219
|
state (str, optional): The state of the intervention. Defaults to "pending".
|
|
230
220
|
date (datetime, optional): The date of the intervention. Defaults to the current time if not provided.
|
|
231
221
|
user (User, optional): The user creating the intervention.
|
|
232
|
-
|
|
222
|
+
|
|
233
223
|
Returns:
|
|
234
224
|
PatientFindingIntervention: The created intervention instance.
|
|
235
|
-
|
|
225
|
+
|
|
236
226
|
Raises:
|
|
237
227
|
ValidationError: If the specified intervention does not exist.
|
|
238
228
|
"""
|
|
239
|
-
from .patient_finding_intervention import PatientFindingIntervention
|
|
240
229
|
from ..finding import FindingIntervention
|
|
241
|
-
|
|
230
|
+
from .patient_finding_intervention import PatientFindingIntervention
|
|
231
|
+
|
|
242
232
|
try:
|
|
243
233
|
intervention = FindingIntervention.objects.get(id=intervention_id)
|
|
244
|
-
|
|
234
|
+
|
|
245
235
|
patient_finding_intervention = PatientFindingIntervention.objects.create(
|
|
246
|
-
patient_finding=self,
|
|
247
|
-
intervention=intervention,
|
|
248
|
-
state=state,
|
|
249
|
-
date=date or timezone.now(),
|
|
250
|
-
created_by=user
|
|
236
|
+
patient_finding=self, intervention=intervention, state=state, date=date or timezone.now(), created_by=user
|
|
251
237
|
)
|
|
252
|
-
|
|
238
|
+
|
|
253
239
|
return patient_finding_intervention
|
|
254
|
-
|
|
240
|
+
|
|
255
241
|
except FindingIntervention.DoesNotExist:
|
|
256
|
-
raise ValidationError(f
|
|
242
|
+
raise ValidationError(f"Intervention {intervention_id} nicht gefunden")
|
|
257
243
|
|
|
258
244
|
def add_video_segment(self, video_segment):
|
|
259
245
|
"""
|
|
260
246
|
Associates a video segment with this patient finding.
|
|
261
|
-
|
|
247
|
+
|
|
262
248
|
Parameters:
|
|
263
|
-
|
|
264
|
-
|
|
249
|
+
video_segment: The video segment instance to add.
|
|
250
|
+
|
|
265
251
|
Returns:
|
|
266
|
-
|
|
252
|
+
The added video segment instance.
|
|
267
253
|
"""
|
|
268
|
-
self.video_segments.add(video_segment)
|
|
254
|
+
self.video_segments.add(video_segment) # TODO
|
|
269
255
|
return video_segment
|
|
270
256
|
|
|
271
257
|
# Manager für active/inactive Objekte
|
|
@@ -273,36 +259,32 @@ class PatientFinding(models.Model):
|
|
|
273
259
|
def active_classifications(self):
|
|
274
260
|
"""
|
|
275
261
|
Return all active classifications associated with this patient finding.
|
|
276
|
-
|
|
262
|
+
|
|
277
263
|
Returns:
|
|
278
|
-
|
|
264
|
+
QuerySet: Active related classifications where `is_active` is True.
|
|
279
265
|
"""
|
|
280
266
|
return self.classifications.filter(is_active=True)
|
|
281
|
-
|
|
267
|
+
|
|
282
268
|
@property
|
|
283
269
|
def locations(self):
|
|
284
270
|
"""
|
|
285
271
|
Return all classifications of this patient finding that are of type "location".
|
|
286
|
-
|
|
272
|
+
|
|
287
273
|
Returns:
|
|
288
|
-
|
|
274
|
+
QuerySet: Classifications related to this finding filtered by the "location" classification type.
|
|
289
275
|
"""
|
|
290
|
-
classifications = self.classifications.filter(
|
|
291
|
-
classification__classification_types__name__iexact="location"
|
|
292
|
-
)
|
|
276
|
+
classifications = self.classifications.filter(classification__classification_types__name__iexact="location")
|
|
293
277
|
return classifications
|
|
294
278
|
|
|
295
279
|
@property
|
|
296
280
|
def morphologies(self):
|
|
297
281
|
"""
|
|
298
282
|
Return all classifications of this patient finding that are of type "morphology".
|
|
299
|
-
|
|
283
|
+
|
|
300
284
|
Returns:
|
|
301
|
-
|
|
285
|
+
QuerySet: Classifications related to this finding filtered by the "morphology" classification type.
|
|
302
286
|
"""
|
|
303
|
-
classifications = self.classifications.filter(
|
|
304
|
-
classification__classification_types__name__iexact="morphology"
|
|
305
|
-
)
|
|
287
|
+
classifications = self.classifications.filter(classification__classification_types__name__iexact="morphology")
|
|
306
288
|
return classifications
|
|
307
289
|
|
|
308
290
|
@property
|
|
@@ -314,39 +296,40 @@ class PatientFinding(models.Model):
|
|
|
314
296
|
"""
|
|
315
297
|
Aggregates and returns all related model instances relevant for requirement evaluation
|
|
316
298
|
as a RequirementLinks object.
|
|
317
|
-
|
|
299
|
+
|
|
318
300
|
This property provides access to:
|
|
319
301
|
- The finding associated with this patient finding
|
|
320
302
|
- All active finding classifications and their choices
|
|
321
303
|
- All active finding interventions
|
|
322
304
|
- The patient examination and patient
|
|
323
305
|
"""
|
|
306
|
+
from typing import List, cast
|
|
307
|
+
|
|
324
308
|
from endoreg_db.utils.links.requirement_link import RequirementLinks
|
|
325
|
-
|
|
326
|
-
|
|
309
|
+
|
|
327
310
|
# Get the base finding
|
|
328
311
|
findings_list = [self.finding] if self.finding else []
|
|
329
|
-
|
|
312
|
+
|
|
330
313
|
# Get all active finding classifications and their choices
|
|
331
314
|
finding_classifications_list = []
|
|
332
315
|
finding_classification_choices_list = []
|
|
333
|
-
|
|
316
|
+
|
|
334
317
|
for pf_classification in self.active_classifications:
|
|
335
318
|
if pf_classification.classification:
|
|
336
319
|
finding_classifications_list.append(pf_classification.classification)
|
|
337
320
|
if pf_classification.classification_choice:
|
|
338
321
|
finding_classification_choices_list.append(pf_classification.classification_choice)
|
|
339
|
-
|
|
322
|
+
|
|
340
323
|
# Get all active finding interventions
|
|
341
324
|
finding_interventions_list = []
|
|
342
325
|
for pf_intervention in self.active_interventions:
|
|
343
326
|
if pf_intervention.intervention:
|
|
344
327
|
finding_interventions_list.append(pf_intervention.intervention)
|
|
345
|
-
|
|
328
|
+
|
|
346
329
|
# Include patient examination and patient for context
|
|
347
330
|
patient_examinations_list = [self.patient_examination] if self.patient_examination else []
|
|
348
331
|
patient_findings_list = cast("List[PatientFinding]", [self]) # Include self for direct patient finding evaluations
|
|
349
|
-
|
|
332
|
+
|
|
350
333
|
return RequirementLinks(
|
|
351
334
|
findings=findings_list,
|
|
352
335
|
finding_classifications=finding_classifications_list,
|