endoreg-db 0.8.9.2__py3-none-any.whl → 0.8.9.10__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/admin.py +10 -5
- endoreg_db/apps.py +4 -7
- endoreg_db/authz/auth.py +1 -0
- endoreg_db/authz/backends.py +1 -1
- endoreg_db/authz/management/commands/list_routes.py +2 -0
- endoreg_db/authz/middleware.py +8 -7
- endoreg_db/authz/permissions.py +21 -10
- endoreg_db/authz/policy.py +14 -19
- endoreg_db/authz/views_auth.py +14 -10
- endoreg_db/codemods/rename_datetime_fields.py +8 -1
- endoreg_db/exceptions.py +5 -2
- endoreg_db/forms/__init__.py +0 -1
- endoreg_db/forms/examination_form.py +4 -3
- endoreg_db/forms/patient_finding_intervention_form.py +30 -8
- endoreg_db/forms/patient_form.py +9 -13
- endoreg_db/forms/questionnaires/__init__.py +1 -1
- endoreg_db/forms/settings/__init__.py +4 -1
- endoreg_db/forms/unit.py +2 -1
- endoreg_db/helpers/count_db.py +17 -14
- endoreg_db/helpers/default_objects.py +2 -1
- endoreg_db/helpers/download_segmentation_model.py +4 -3
- endoreg_db/helpers/interact.py +0 -5
- endoreg_db/helpers/test_video_helper.py +33 -25
- endoreg_db/import_files/__init__.py +1 -1
- endoreg_db/import_files/context/__init__.py +1 -1
- endoreg_db/import_files/context/default_sensitive_meta.py +11 -9
- endoreg_db/import_files/context/ensure_center.py +4 -4
- endoreg_db/import_files/context/file_lock.py +3 -3
- endoreg_db/import_files/context/import_context.py +11 -12
- endoreg_db/import_files/context/validate_directories.py +1 -0
- endoreg_db/import_files/file_storage/create_report_file.py +57 -34
- endoreg_db/import_files/file_storage/create_video_file.py +64 -35
- endoreg_db/import_files/file_storage/sensitive_meta_storage.py +5 -2
- endoreg_db/import_files/file_storage/state_management.py +89 -122
- endoreg_db/import_files/file_storage/storage.py +5 -1
- endoreg_db/import_files/processing/report_processing/report_anonymization.py +24 -19
- endoreg_db/import_files/processing/sensitive_meta_adapter.py +3 -3
- endoreg_db/import_files/processing/video_processing/video_anonymization.py +18 -18
- endoreg_db/import_files/pseudonymization/k_anonymity.py +8 -9
- endoreg_db/import_files/pseudonymization/k_pseudonymity.py +16 -5
- endoreg_db/import_files/report_import_service.py +36 -30
- endoreg_db/import_files/video_import_service.py +27 -23
- endoreg_db/logger_conf.py +56 -40
- endoreg_db/management/__init__.py +1 -1
- endoreg_db/management/commands/__init__.py +1 -1
- endoreg_db/management/commands/check_auth.py +45 -38
- endoreg_db/management/commands/create_model_meta_from_huggingface.py +53 -2
- endoreg_db/management/commands/create_multilabel_model_meta.py +54 -19
- endoreg_db/management/commands/fix_missing_patient_data.py +105 -71
- endoreg_db/management/commands/fix_video_paths.py +75 -54
- endoreg_db/management/commands/import_report.py +1 -3
- endoreg_db/management/commands/list_routes.py +2 -0
- endoreg_db/management/commands/load_ai_model_data.py +8 -2
- endoreg_db/management/commands/load_ai_model_label_data.py +0 -1
- endoreg_db/management/commands/load_center_data.py +3 -3
- endoreg_db/management/commands/load_distribution_data.py +35 -38
- endoreg_db/management/commands/load_endoscope_data.py +0 -3
- endoreg_db/management/commands/load_examination_data.py +20 -4
- endoreg_db/management/commands/load_finding_data.py +18 -3
- endoreg_db/management/commands/load_gender_data.py +17 -24
- endoreg_db/management/commands/load_green_endoscopy_wuerzburg_data.py +95 -85
- endoreg_db/management/commands/load_information_source.py +0 -3
- endoreg_db/management/commands/load_lab_value_data.py +14 -3
- endoreg_db/management/commands/load_legacy_data.py +303 -0
- endoreg_db/management/commands/load_name_data.py +1 -2
- endoreg_db/management/commands/load_pdf_type_data.py +4 -8
- endoreg_db/management/commands/load_profession_data.py +0 -1
- endoreg_db/management/commands/load_report_reader_flag_data.py +0 -4
- endoreg_db/management/commands/load_requirement_data.py +6 -2
- endoreg_db/management/commands/load_unit_data.py +0 -4
- endoreg_db/management/commands/load_user_groups.py +5 -7
- endoreg_db/management/commands/model_input.py +169 -0
- endoreg_db/management/commands/register_ai_model.py +22 -16
- endoreg_db/management/commands/setup_endoreg_db.py +110 -32
- endoreg_db/management/commands/storage_management.py +14 -8
- endoreg_db/management/commands/summarize_db_content.py +154 -63
- endoreg_db/management/commands/train_image_multilabel_model.py +144 -0
- endoreg_db/management/commands/validate_video_files.py +82 -50
- endoreg_db/management/commands/video_validation.py +4 -6
- endoreg_db/migrations/0001_initial.py +112 -63
- endoreg_db/models/__init__.py +8 -0
- endoreg_db/models/administration/ai/active_model.py +5 -5
- endoreg_db/models/administration/ai/ai_model.py +41 -18
- endoreg_db/models/administration/ai/model_type.py +1 -0
- endoreg_db/models/administration/case/case.py +22 -22
- endoreg_db/models/administration/center/__init__.py +5 -5
- endoreg_db/models/administration/center/center.py +6 -2
- endoreg_db/models/administration/center/center_resource.py +18 -4
- endoreg_db/models/administration/center/center_shift.py +3 -1
- endoreg_db/models/administration/center/center_waste.py +6 -2
- endoreg_db/models/administration/person/__init__.py +1 -1
- endoreg_db/models/administration/person/employee/__init__.py +1 -1
- endoreg_db/models/administration/person/employee/employee_type.py +3 -1
- endoreg_db/models/administration/person/examiner/__init__.py +1 -1
- endoreg_db/models/administration/person/examiner/examiner.py +10 -2
- endoreg_db/models/administration/person/names/first_name.py +6 -4
- endoreg_db/models/administration/person/names/last_name.py +4 -3
- endoreg_db/models/administration/person/patient/__init__.py +1 -1
- endoreg_db/models/administration/person/patient/patient.py +0 -1
- endoreg_db/models/administration/person/patient/patient_external_id.py +0 -1
- endoreg_db/models/administration/person/person.py +1 -1
- endoreg_db/models/administration/product/__init__.py +7 -6
- endoreg_db/models/administration/product/product.py +6 -2
- endoreg_db/models/administration/product/product_group.py +9 -7
- endoreg_db/models/administration/product/product_material.py +9 -2
- endoreg_db/models/administration/product/reference_product.py +64 -15
- endoreg_db/models/administration/qualification/qualification.py +3 -1
- endoreg_db/models/administration/shift/shift.py +3 -1
- endoreg_db/models/administration/shift/shift_type.py +12 -4
- endoreg_db/models/aidataset/__init__.py +5 -0
- endoreg_db/models/aidataset/aidataset.py +193 -0
- endoreg_db/models/label/__init__.py +1 -1
- endoreg_db/models/label/label.py +10 -2
- endoreg_db/models/label/label_set.py +3 -1
- endoreg_db/models/label/label_video_segment/_create_from_video.py +6 -2
- endoreg_db/models/label/label_video_segment/label_video_segment.py +148 -44
- endoreg_db/models/media/__init__.py +12 -5
- endoreg_db/models/media/frame/__init__.py +1 -1
- endoreg_db/models/media/frame/frame.py +34 -8
- endoreg_db/models/media/pdf/__init__.py +2 -1
- endoreg_db/models/media/pdf/raw_pdf.py +11 -4
- endoreg_db/models/media/pdf/report_file.py +6 -2
- endoreg_db/models/media/pdf/report_reader/__init__.py +3 -3
- endoreg_db/models/media/pdf/report_reader/report_reader_flag.py +15 -5
- endoreg_db/models/media/video/create_from_file.py +20 -41
- endoreg_db/models/media/video/pipe_1.py +75 -30
- endoreg_db/models/media/video/pipe_2.py +37 -12
- endoreg_db/models/media/video/video_file.py +36 -24
- endoreg_db/models/media/video/video_file_ai.py +235 -70
- endoreg_db/models/media/video/video_file_anonymize.py +240 -65
- endoreg_db/models/media/video/video_file_frames/_bulk_create_frames.py +6 -1
- endoreg_db/models/media/video/video_file_frames/_create_frame_object.py +3 -1
- endoreg_db/models/media/video/video_file_frames/_delete_frames.py +30 -9
- endoreg_db/models/media/video/video_file_frames/_extract_frames.py +95 -29
- endoreg_db/models/media/video/video_file_frames/_get_frame.py +13 -3
- endoreg_db/models/media/video/video_file_frames/_get_frame_path.py +4 -1
- endoreg_db/models/media/video/video_file_frames/_get_frame_paths.py +15 -3
- endoreg_db/models/media/video/video_file_frames/_get_frame_range.py +15 -3
- endoreg_db/models/media/video/video_file_frames/_get_frames.py +7 -2
- endoreg_db/models/media/video/video_file_frames/_initialize_frames.py +109 -23
- endoreg_db/models/media/video/video_file_frames/_manage_frame_range.py +111 -27
- endoreg_db/models/media/video/video_file_frames/_mark_frames_extracted_status.py +46 -13
- endoreg_db/models/media/video/video_file_io.py +85 -33
- endoreg_db/models/media/video/video_file_meta/__init__.py +6 -6
- endoreg_db/models/media/video/video_file_meta/get_crop_template.py +17 -4
- endoreg_db/models/media/video/video_file_meta/get_endo_roi.py +28 -7
- endoreg_db/models/media/video/video_file_meta/get_fps.py +46 -13
- endoreg_db/models/media/video/video_file_meta/initialize_video_specs.py +81 -20
- endoreg_db/models/media/video/video_file_meta/text_meta.py +61 -20
- endoreg_db/models/media/video/video_file_meta/video_meta.py +40 -12
- endoreg_db/models/media/video/video_file_segments.py +118 -27
- endoreg_db/models/media/video/video_metadata.py +25 -6
- endoreg_db/models/media/video/video_processing.py +54 -15
- endoreg_db/models/medical/__init__.py +3 -13
- endoreg_db/models/medical/contraindication/__init__.py +3 -1
- endoreg_db/models/medical/disease.py +18 -6
- endoreg_db/models/medical/event.py +6 -2
- endoreg_db/models/medical/examination/__init__.py +5 -1
- endoreg_db/models/medical/examination/examination.py +22 -6
- endoreg_db/models/medical/examination/examination_indication.py +23 -7
- endoreg_db/models/medical/examination/examination_time.py +6 -2
- endoreg_db/models/medical/finding/__init__.py +3 -1
- endoreg_db/models/medical/finding/finding.py +37 -12
- endoreg_db/models/medical/finding/finding_classification.py +27 -8
- endoreg_db/models/medical/finding/finding_intervention.py +19 -6
- endoreg_db/models/medical/finding/finding_type.py +3 -1
- endoreg_db/models/medical/hardware/__init__.py +1 -1
- endoreg_db/models/medical/hardware/endoscope.py +14 -2
- endoreg_db/models/medical/laboratory/__init__.py +1 -1
- endoreg_db/models/medical/laboratory/lab_value.py +139 -39
- endoreg_db/models/medical/medication/__init__.py +7 -3
- endoreg_db/models/medical/medication/medication.py +3 -1
- endoreg_db/models/medical/medication/medication_indication.py +3 -1
- endoreg_db/models/medical/medication/medication_indication_type.py +11 -3
- endoreg_db/models/medical/medication/medication_intake_time.py +3 -1
- endoreg_db/models/medical/medication/medication_schedule.py +3 -1
- endoreg_db/models/medical/patient/__init__.py +2 -10
- endoreg_db/models/medical/patient/medication_examples.py +3 -14
- endoreg_db/models/medical/patient/patient_disease.py +17 -5
- endoreg_db/models/medical/patient/patient_event.py +12 -4
- endoreg_db/models/medical/patient/patient_examination.py +52 -15
- endoreg_db/models/medical/patient/patient_examination_indication.py +15 -4
- endoreg_db/models/medical/patient/patient_finding.py +105 -29
- endoreg_db/models/medical/patient/patient_finding_classification.py +41 -12
- endoreg_db/models/medical/patient/patient_finding_intervention.py +11 -3
- endoreg_db/models/medical/patient/patient_lab_sample.py +6 -2
- endoreg_db/models/medical/patient/patient_lab_value.py +42 -10
- endoreg_db/models/medical/patient/patient_medication.py +25 -7
- endoreg_db/models/medical/patient/patient_medication_schedule.py +34 -10
- endoreg_db/models/metadata/model_meta.py +40 -12
- endoreg_db/models/metadata/model_meta_logic.py +51 -16
- endoreg_db/models/metadata/sensitive_meta.py +65 -28
- endoreg_db/models/metadata/sensitive_meta_logic.py +28 -26
- endoreg_db/models/metadata/video_meta.py +146 -39
- endoreg_db/models/metadata/video_prediction_logic.py +70 -21
- endoreg_db/models/metadata/video_prediction_meta.py +80 -27
- endoreg_db/models/operation_log.py +63 -0
- endoreg_db/models/other/__init__.py +10 -10
- endoreg_db/models/other/distribution/__init__.py +9 -7
- endoreg_db/models/other/distribution/base_value_distribution.py +3 -1
- endoreg_db/models/other/distribution/date_value_distribution.py +19 -5
- endoreg_db/models/other/distribution/multiple_categorical_value_distribution.py +3 -1
- endoreg_db/models/other/distribution/numeric_value_distribution.py +34 -9
- endoreg_db/models/other/emission/__init__.py +1 -1
- endoreg_db/models/other/emission/emission_factor.py +9 -3
- endoreg_db/models/other/information_source.py +15 -5
- endoreg_db/models/other/material.py +3 -1
- endoreg_db/models/other/transport_route.py +3 -1
- endoreg_db/models/other/unit.py +6 -2
- endoreg_db/models/report/report.py +0 -1
- endoreg_db/models/requirement/requirement.py +84 -27
- endoreg_db/models/requirement/requirement_error.py +5 -6
- endoreg_db/models/requirement/requirement_evaluation/__init__.py +1 -1
- endoreg_db/models/requirement/requirement_evaluation/evaluate_with_dependencies.py +8 -8
- endoreg_db/models/requirement/requirement_evaluation/get_values.py +3 -3
- endoreg_db/models/requirement/requirement_evaluation/requirement_type_parser.py +24 -8
- endoreg_db/models/requirement/requirement_operator.py +28 -8
- endoreg_db/models/requirement/requirement_set.py +34 -11
- endoreg_db/models/state/__init__.py +1 -0
- endoreg_db/models/state/audit_ledger.py +9 -2
- endoreg_db/models/{media → state}/processing_history/__init__.py +1 -3
- endoreg_db/models/state/processing_history/processing_history.py +136 -0
- endoreg_db/models/state/raw_pdf.py +0 -1
- endoreg_db/models/state/video.py +2 -4
- endoreg_db/models/utils.py +4 -2
- endoreg_db/queries/__init__.py +2 -6
- endoreg_db/queries/annotations/__init__.py +1 -3
- endoreg_db/queries/annotations/legacy.py +37 -26
- endoreg_db/root_urls.py +3 -4
- endoreg_db/schemas/examination_evaluation.py +3 -0
- endoreg_db/serializers/Frames_NICE_and_PARIS_classifications.py +249 -163
- endoreg_db/serializers/__init__.py +2 -8
- endoreg_db/serializers/administration/__init__.py +1 -2
- endoreg_db/serializers/administration/ai/__init__.py +0 -1
- endoreg_db/serializers/administration/ai/active_model.py +3 -1
- endoreg_db/serializers/administration/ai/ai_model.py +5 -3
- endoreg_db/serializers/administration/ai/model_type.py +3 -1
- endoreg_db/serializers/administration/center.py +7 -2
- endoreg_db/serializers/administration/gender.py +4 -2
- endoreg_db/serializers/anonymization.py +13 -13
- endoreg_db/serializers/evaluation/examination_evaluation.py +0 -1
- endoreg_db/serializers/examination/__init__.py +1 -1
- endoreg_db/serializers/examination/base.py +12 -13
- endoreg_db/serializers/examination/dropdown.py +6 -7
- endoreg_db/serializers/examination_serializer.py +3 -6
- endoreg_db/serializers/finding/__init__.py +1 -1
- endoreg_db/serializers/finding/finding.py +14 -7
- endoreg_db/serializers/finding_classification/__init__.py +3 -3
- endoreg_db/serializers/finding_classification/choice.py +3 -3
- endoreg_db/serializers/finding_classification/classification.py +2 -4
- endoreg_db/serializers/label_video_segment/__init__.py +5 -3
- endoreg_db/serializers/{label → label_video_segment}/image_classification_annotation.py +5 -5
- endoreg_db/serializers/label_video_segment/label/__init__.py +6 -0
- endoreg_db/serializers/{label → label_video_segment/label}/label.py +1 -1
- endoreg_db/serializers/label_video_segment/label_video_segment.py +338 -228
- endoreg_db/serializers/meta/__init__.py +1 -2
- endoreg_db/serializers/meta/sensitive_meta_detail.py +28 -13
- endoreg_db/serializers/meta/sensitive_meta_update.py +51 -46
- endoreg_db/serializers/meta/sensitive_meta_verification.py +19 -16
- endoreg_db/serializers/misc/__init__.py +2 -2
- endoreg_db/serializers/misc/file_overview.py +11 -7
- endoreg_db/serializers/misc/stats.py +10 -8
- endoreg_db/serializers/misc/translatable_field_mix_in.py +6 -6
- endoreg_db/serializers/misc/upload_job.py +32 -29
- endoreg_db/serializers/patient/__init__.py +2 -1
- endoreg_db/serializers/patient/patient.py +32 -15
- endoreg_db/serializers/patient/patient_dropdown.py +11 -3
- endoreg_db/serializers/patient_examination/__init__.py +1 -1
- endoreg_db/serializers/patient_examination/patient_examination.py +67 -40
- endoreg_db/serializers/patient_finding/__init__.py +1 -1
- endoreg_db/serializers/patient_finding/patient_finding.py +2 -1
- endoreg_db/serializers/patient_finding/patient_finding_classification.py +17 -9
- endoreg_db/serializers/patient_finding/patient_finding_detail.py +26 -17
- endoreg_db/serializers/patient_finding/patient_finding_intervention.py +7 -5
- endoreg_db/serializers/patient_finding/patient_finding_list.py +10 -11
- endoreg_db/serializers/patient_finding/patient_finding_write.py +36 -27
- endoreg_db/serializers/pdf/__init__.py +1 -3
- endoreg_db/serializers/requirements/requirement_schema.py +1 -6
- endoreg_db/serializers/sensitive_meta_serializer.py +100 -81
- endoreg_db/serializers/video/__init__.py +2 -2
- endoreg_db/serializers/video/{segmentation.py → video_file.py} +66 -47
- endoreg_db/serializers/video/video_file_brief.py +6 -2
- endoreg_db/serializers/video/video_file_detail.py +36 -23
- endoreg_db/serializers/video/video_file_list.py +4 -2
- endoreg_db/serializers/video/video_processing_history.py +54 -50
- endoreg_db/services/__init__.py +1 -1
- endoreg_db/services/anonymization.py +2 -2
- endoreg_db/services/examination_evaluation.py +40 -17
- endoreg_db/services/model_meta_from_hf.py +76 -0
- endoreg_db/services/polling_coordinator.py +101 -70
- endoreg_db/services/pseudonym_service.py +27 -22
- endoreg_db/services/report_import.py +6 -3
- endoreg_db/services/segment_sync.py +75 -59
- endoreg_db/services/video_import.py +6 -7
- endoreg_db/urls/__init__.py +2 -2
- endoreg_db/urls/ai.py +7 -25
- endoreg_db/urls/anonymization.py +61 -15
- endoreg_db/urls/auth.py +4 -4
- endoreg_db/urls/classification.py +4 -9
- endoreg_db/urls/examination.py +27 -18
- endoreg_db/urls/media.py +27 -34
- endoreg_db/urls/patient.py +11 -7
- endoreg_db/urls/requirements.py +3 -1
- endoreg_db/urls/root_urls.py +2 -3
- endoreg_db/urls/stats.py +24 -16
- endoreg_db/urls/upload.py +3 -11
- endoreg_db/utils/__init__.py +14 -15
- endoreg_db/utils/ai/__init__.py +1 -1
- endoreg_db/utils/ai/data_loader_for_model_input.py +262 -0
- endoreg_db/utils/ai/data_loader_for_model_training.py +262 -0
- endoreg_db/utils/ai/get.py +2 -1
- endoreg_db/utils/ai/inference_dataset.py +14 -15
- endoreg_db/utils/ai/model_training/config.py +117 -0
- endoreg_db/utils/ai/model_training/dataset.py +74 -0
- endoreg_db/utils/ai/model_training/losses.py +68 -0
- endoreg_db/utils/ai/model_training/metrics.py +78 -0
- endoreg_db/utils/ai/model_training/model_backbones.py +155 -0
- endoreg_db/utils/ai/model_training/model_gastronet_resnet.py +118 -0
- endoreg_db/utils/ai/model_training/trainer_gastronet_multilabel.py +771 -0
- endoreg_db/utils/ai/multilabel_classification_net.py +21 -6
- endoreg_db/utils/ai/predict.py +4 -4
- endoreg_db/utils/ai/preprocess.py +19 -11
- endoreg_db/utils/calc_duration_seconds.py +4 -4
- endoreg_db/utils/case_generator/lab_sample_factory.py +3 -4
- endoreg_db/utils/check_video_files.py +74 -47
- endoreg_db/utils/cropping.py +10 -9
- endoreg_db/utils/dataloader.py +11 -3
- endoreg_db/utils/dates.py +3 -4
- endoreg_db/utils/defaults/set_default_center.py +7 -6
- endoreg_db/utils/env.py +6 -2
- endoreg_db/utils/extract_specific_frames.py +24 -9
- endoreg_db/utils/file_operations.py +30 -18
- endoreg_db/utils/fix_video_path_direct.py +57 -41
- endoreg_db/utils/frame_anonymization_utils.py +157 -157
- endoreg_db/utils/hashs.py +3 -18
- endoreg_db/utils/links/requirement_link.py +96 -52
- endoreg_db/utils/ocr.py +30 -25
- endoreg_db/utils/operation_log.py +61 -0
- endoreg_db/utils/parse_and_generate_yaml.py +12 -13
- endoreg_db/utils/paths.py +6 -6
- endoreg_db/utils/permissions.py +40 -24
- endoreg_db/utils/pipelines/process_video_dir.py +50 -26
- endoreg_db/utils/product/sum_emissions.py +5 -3
- endoreg_db/utils/product/sum_weights.py +4 -2
- endoreg_db/utils/pydantic_models/__init__.py +3 -4
- endoreg_db/utils/requirement_operator_logic/_old/lab_value_operators.py +207 -107
- endoreg_db/utils/requirement_operator_logic/_old/model_evaluators.py +252 -65
- endoreg_db/utils/requirement_operator_logic/new_operator_logic.py +27 -10
- endoreg_db/utils/setup_config.py +21 -5
- endoreg_db/utils/storage.py +3 -1
- endoreg_db/utils/translation.py +19 -15
- endoreg_db/utils/uuid.py +1 -0
- endoreg_db/utils/validate_endo_roi.py +12 -4
- endoreg_db/utils/validate_subcategory_dict.py +26 -24
- endoreg_db/utils/validate_video_detailed.py +207 -149
- endoreg_db/utils/video/__init__.py +7 -3
- endoreg_db/utils/video/extract_frames.py +30 -18
- endoreg_db/utils/video/names.py +11 -6
- endoreg_db/utils/video/streaming_processor.py +175 -101
- endoreg_db/utils/video/video_splitter.py +30 -19
- endoreg_db/views/Frames_NICE_and_PARIS_classifications_views.py +59 -50
- endoreg_db/views/__init__.py +0 -20
- endoreg_db/views/anonymization/__init__.py +6 -2
- endoreg_db/views/anonymization/media_management.py +2 -6
- endoreg_db/views/anonymization/overview.py +34 -1
- endoreg_db/views/anonymization/validate.py +79 -18
- endoreg_db/views/auth/__init__.py +1 -1
- endoreg_db/views/auth/keycloak.py +16 -14
- endoreg_db/views/examination/__init__.py +12 -15
- endoreg_db/views/examination/examination.py +5 -5
- endoreg_db/views/examination/examination_manifest_cache.py +5 -5
- endoreg_db/views/examination/get_finding_classification_choices.py +8 -5
- endoreg_db/views/examination/get_finding_classifications.py +9 -7
- endoreg_db/views/examination/get_findings.py +8 -10
- endoreg_db/views/examination/get_instruments.py +3 -2
- endoreg_db/views/examination/get_interventions.py +1 -1
- endoreg_db/views/finding/__init__.py +2 -2
- endoreg_db/views/finding/finding.py +58 -54
- endoreg_db/views/finding/get_classifications.py +1 -1
- endoreg_db/views/finding/get_interventions.py +1 -1
- endoreg_db/views/finding_classification/__init__.py +5 -5
- endoreg_db/views/finding_classification/finding_classification.py +5 -6
- endoreg_db/views/finding_classification/get_classification_choices.py +3 -4
- endoreg_db/views/media/__init__.py +13 -13
- endoreg_db/views/media/pdf_media.py +9 -9
- endoreg_db/views/media/sensitive_metadata.py +10 -7
- endoreg_db/views/media/video_media.py +4 -4
- endoreg_db/views/meta/__init__.py +1 -1
- endoreg_db/views/meta/sensitive_meta_list.py +20 -22
- endoreg_db/views/meta/sensitive_meta_verification.py +14 -11
- endoreg_db/views/misc/__init__.py +6 -34
- endoreg_db/views/misc/center.py +2 -1
- endoreg_db/views/misc/csrf.py +2 -1
- endoreg_db/views/misc/gender.py +2 -1
- endoreg_db/views/misc/stats.py +141 -106
- endoreg_db/views/patient/__init__.py +1 -3
- endoreg_db/views/patient/patient.py +141 -99
- endoreg_db/views/patient_examination/__init__.py +5 -5
- endoreg_db/views/patient_examination/patient_examination.py +43 -42
- endoreg_db/views/patient_examination/patient_examination_create.py +10 -15
- endoreg_db/views/patient_examination/patient_examination_detail.py +12 -15
- endoreg_db/views/patient_examination/patient_examination_list.py +21 -17
- endoreg_db/views/patient_examination/video.py +114 -80
- endoreg_db/views/patient_finding/__init__.py +1 -1
- endoreg_db/views/patient_finding/patient_finding.py +17 -10
- endoreg_db/views/patient_finding/patient_finding_optimized.py +127 -95
- endoreg_db/views/patient_finding_classification/__init__.py +1 -1
- endoreg_db/views/patient_finding_classification/pfc_create.py +35 -27
- endoreg_db/views/report/reimport.py +1 -1
- endoreg_db/views/report/report_stream.py +5 -8
- endoreg_db/views/requirement/__init__.py +2 -1
- endoreg_db/views/requirement/evaluate.py +7 -9
- endoreg_db/views/requirement/lookup.py +2 -3
- endoreg_db/views/requirement/lookup_store.py +0 -1
- endoreg_db/views/requirement/requirement_utils.py +2 -4
- endoreg_db/views/stats/__init__.py +4 -4
- endoreg_db/views/stats/stats_views.py +152 -115
- endoreg_db/views/video/__init__.py +18 -27
- endoreg_db/views/{ai → video/ai}/__init__.py +2 -2
- endoreg_db/views/{ai → video/ai}/label.py +20 -16
- endoreg_db/views/video/correction.py +5 -6
- endoreg_db/views/video/reimport.py +134 -99
- endoreg_db/views/video/segments_crud.py +134 -44
- endoreg_db/views/video/video_apply_mask.py +13 -12
- endoreg_db/views/video/video_correction.py +2 -1
- endoreg_db/views/video/video_download_processed.py +15 -15
- endoreg_db/views/video/video_meta_stats.py +7 -6
- endoreg_db/views/video/video_processing_history.py +3 -2
- endoreg_db/views/video/video_remove_frames.py +13 -12
- endoreg_db/views/video/video_stream.py +110 -82
- {endoreg_db-0.8.9.2.dist-info → endoreg_db-0.8.9.10.dist-info}/METADATA +9 -3
- {endoreg_db-0.8.9.2.dist-info → endoreg_db-0.8.9.10.dist-info}/RECORD +434 -431
- endoreg_db/management/commands/import_fallback_video.py +0 -203
- endoreg_db/management/commands/import_video.py +0 -422
- endoreg_db/management/commands/import_video_with_classification.py +0 -367
- endoreg_db/models/media/processing_history/processing_history.py +0 -96
- endoreg_db/serializers/label/__init__.py +0 -7
- endoreg_db/serializers/label_video_segment/_lvs_create.py +0 -149
- endoreg_db/serializers/label_video_segment/_lvs_update.py +0 -138
- endoreg_db/serializers/label_video_segment/_lvs_validate.py +0 -149
- endoreg_db/serializers/label_video_segment/label_video_segment_annotation.py +0 -99
- endoreg_db/serializers/label_video_segment/label_video_segment_update.py +0 -163
- endoreg_db/services/__old/pdf_import.py +0 -1487
- endoreg_db/services/__old/video_import.py +0 -1306
- endoreg_db/tasks/upload_tasks.py +0 -216
- endoreg_db/tasks/video_ingest.py +0 -161
- endoreg_db/tasks/video_processing_tasks.py +0 -327
- endoreg_db/views/misc/translation.py +0 -182
- {endoreg_db-0.8.9.2.dist-info → endoreg_db-0.8.9.10.dist-info}/WHEEL +0 -0
- {endoreg_db-0.8.9.2.dist-info → endoreg_db-0.8.9.10.dist-info}/licenses/LICENSE +0 -0
|
@@ -10,20 +10,22 @@ from endoreg_db.authz.permissions import PolicyPermission
|
|
|
10
10
|
from endoreg_db.models import Patient
|
|
11
11
|
from endoreg_db.serializers.patient import PatientSerializer
|
|
12
12
|
from endoreg_db.models.medical.patient.patient_examination import PatientExamination
|
|
13
|
-
|
|
13
|
+
|
|
14
|
+
|
|
14
15
|
@staff_member_required # Ensures only staff members can access the page
|
|
15
16
|
def start_examination(request):
|
|
16
|
-
return render(request,
|
|
17
|
+
return render(request, "admin/start_examination.html") # Loads the simple HTML page
|
|
17
18
|
|
|
18
19
|
|
|
19
|
-
#TODO Review this view
|
|
20
|
+
# TODO Review this view
|
|
20
21
|
class PatientViewSet(viewsets.ModelViewSet):
|
|
21
22
|
"""API endpoint for managing patients."""
|
|
23
|
+
|
|
22
24
|
queryset = Patient.objects.all()
|
|
23
25
|
serializer_class = PatientSerializer
|
|
24
26
|
permission_classes = [PolicyPermission]
|
|
25
|
-
#permission_classes = [PolicyPermission]
|
|
26
|
-
|
|
27
|
+
# permission_classes = [PolicyPermission]
|
|
28
|
+
|
|
27
29
|
def perform_create(self, serializer):
|
|
28
30
|
"""Erweiterte Validierung beim Erstellen eines Patienten"""
|
|
29
31
|
try:
|
|
@@ -31,16 +33,18 @@ class PatientViewSet(viewsets.ModelViewSet):
|
|
|
31
33
|
patient = serializer.save()
|
|
32
34
|
return patient
|
|
33
35
|
except Exception as e:
|
|
34
|
-
raise serializers.ValidationError(
|
|
35
|
-
|
|
36
|
+
raise serializers.ValidationError(
|
|
37
|
+
f"Fehler beim Erstellen des Patienten: {str(e)}"
|
|
38
|
+
)
|
|
39
|
+
|
|
36
40
|
def update(self, request, *args, **kwargs):
|
|
37
41
|
"""Erweiterte Logik für das Aktualisieren von Patienten"""
|
|
38
42
|
try:
|
|
39
43
|
return super().update(request, *args, **kwargs)
|
|
40
44
|
except Exception as e:
|
|
41
45
|
return Response(
|
|
42
|
-
{"error": f"Fehler beim Aktualisieren des Patienten: {str(e)}"},
|
|
43
|
-
status=status.HTTP_400_BAD_REQUEST
|
|
46
|
+
{"error": f"Fehler beim Aktualisieren des Patienten: {str(e)}"},
|
|
47
|
+
status=status.HTTP_400_BAD_REQUEST,
|
|
44
48
|
)
|
|
45
49
|
|
|
46
50
|
def destroy(self, request, *args, **kwargs):
|
|
@@ -48,53 +52,71 @@ class PatientViewSet(viewsets.ModelViewSet):
|
|
|
48
52
|
Delete a patient with proper error handling and cascade protection.
|
|
49
53
|
"""
|
|
50
54
|
patient = self.get_object()
|
|
51
|
-
|
|
55
|
+
|
|
52
56
|
try:
|
|
53
57
|
with transaction.atomic():
|
|
54
58
|
# Check if patient has related examinations
|
|
55
|
-
examination_count =
|
|
59
|
+
examination_count = (
|
|
60
|
+
patient.patient_examinations.count()
|
|
61
|
+
if hasattr(patient, "patient_examinations")
|
|
62
|
+
else 0
|
|
63
|
+
)
|
|
56
64
|
finding_count = 0
|
|
57
|
-
|
|
65
|
+
|
|
58
66
|
if examination_count > 0:
|
|
59
67
|
finding_count = sum(
|
|
60
|
-
exam.patient_findings.count()
|
|
68
|
+
exam.patient_findings.count()
|
|
69
|
+
if hasattr(exam, "patient_findings")
|
|
70
|
+
else 0
|
|
61
71
|
for exam in patient.patient_examinations.all()
|
|
62
72
|
)
|
|
63
|
-
|
|
64
|
-
return Response(
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
73
|
+
|
|
74
|
+
return Response(
|
|
75
|
+
{
|
|
76
|
+
"error": "Patient cannot be deleted",
|
|
77
|
+
"reason": f"Patient has {examination_count} examination(s) and {finding_count} finding(s).",
|
|
78
|
+
"detail": "Please remove all related examinations and findings before deleting the patient.",
|
|
79
|
+
},
|
|
80
|
+
status=status.HTTP_409_CONFLICT,
|
|
81
|
+
)
|
|
82
|
+
|
|
70
83
|
# Check if this is a real person (additional protection)
|
|
71
|
-
if hasattr(patient,
|
|
72
|
-
return Response(
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
84
|
+
if hasattr(patient, "is_real_person") and patient.is_real_person:
|
|
85
|
+
return Response(
|
|
86
|
+
{
|
|
87
|
+
"error": "Cannot delete real patient",
|
|
88
|
+
"reason": "This patient is marked as a real person.",
|
|
89
|
+
"detail": "Real patient data cannot be deleted for data protection reasons.",
|
|
90
|
+
},
|
|
91
|
+
status=status.HTTP_403_FORBIDDEN,
|
|
92
|
+
)
|
|
93
|
+
|
|
78
94
|
# Perform the deletion
|
|
79
95
|
patient_name = f"{patient.first_name} {patient.last_name}"
|
|
80
96
|
patient.delete()
|
|
81
|
-
|
|
82
|
-
return Response(
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
97
|
+
|
|
98
|
+
return Response(
|
|
99
|
+
{
|
|
100
|
+
"message": f'Patient "{patient_name}" has been successfully deleted.'
|
|
101
|
+
},
|
|
102
|
+
status=status.HTTP_200_OK,
|
|
103
|
+
)
|
|
104
|
+
|
|
86
105
|
except Exception as e:
|
|
87
|
-
return Response(
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
106
|
+
return Response(
|
|
107
|
+
{
|
|
108
|
+
"error": "Patient deletion failed",
|
|
109
|
+
"reason": "Patient has protected related objects.",
|
|
110
|
+
"detail": str(e),
|
|
111
|
+
},
|
|
112
|
+
status=status.HTTP_409_CONFLICT,
|
|
113
|
+
)
|
|
92
114
|
except Exception as e:
|
|
93
115
|
return Response(
|
|
94
|
-
{"error": f"Fehler beim Löschen des Patienten: {str(e)}"},
|
|
95
|
-
status=status.HTTP_400_BAD_REQUEST
|
|
116
|
+
{"error": f"Fehler beim Löschen des Patienten: {str(e)}"},
|
|
117
|
+
status=status.HTTP_400_BAD_REQUEST,
|
|
96
118
|
)
|
|
97
|
-
|
|
119
|
+
|
|
98
120
|
def check_pe_exist(self, request, pk=None):
|
|
99
121
|
"""Check if a patient examination exists.
|
|
100
122
|
|
|
@@ -111,101 +133,121 @@ class PatientViewSet(viewsets.ModelViewSet):
|
|
|
111
133
|
except PatientExamination.DoesNotExist:
|
|
112
134
|
return Response({"exists": False}, status=status.HTTP_404_NOT_FOUND)
|
|
113
135
|
|
|
114
|
-
@action(detail=True, methods=[
|
|
136
|
+
@action(detail=True, methods=["get"])
|
|
115
137
|
def check_deletion_safety(self, request, pk=None):
|
|
116
138
|
"""
|
|
117
139
|
Check if a patient can be safely deleted.
|
|
118
140
|
Returns information about related objects.
|
|
119
141
|
"""
|
|
120
142
|
patient = self.get_object()
|
|
121
|
-
|
|
122
|
-
examination_count =
|
|
123
|
-
|
|
124
|
-
|
|
143
|
+
|
|
144
|
+
examination_count = (
|
|
145
|
+
patient.patient_examinations.count()
|
|
146
|
+
if hasattr(patient, "patient_examinations")
|
|
147
|
+
else 0
|
|
148
|
+
)
|
|
149
|
+
examinations = (
|
|
150
|
+
patient.patient_examinations.all()
|
|
151
|
+
if hasattr(patient, "patient_examinations")
|
|
152
|
+
else []
|
|
153
|
+
)
|
|
154
|
+
|
|
125
155
|
finding_count = sum(
|
|
126
|
-
exam.patient_findings.count() if hasattr(exam,
|
|
156
|
+
exam.patient_findings.count() if hasattr(exam, "patient_findings") else 0
|
|
127
157
|
for exam in examinations
|
|
128
158
|
)
|
|
129
159
|
video_count = sum(
|
|
130
|
-
1 for exam in examinations
|
|
131
|
-
if hasattr(exam, 'video') and exam.video
|
|
160
|
+
1 for exam in examinations if hasattr(exam, "video") and exam.video
|
|
132
161
|
)
|
|
133
162
|
report_count = sum(
|
|
134
|
-
exam.raw_pdf_files.count() if hasattr(exam,
|
|
163
|
+
exam.raw_pdf_files.count() if hasattr(exam, "raw_pdf_files") else 0
|
|
135
164
|
for exam in examinations
|
|
136
165
|
)
|
|
137
|
-
|
|
138
|
-
is_real_person = hasattr(patient,
|
|
166
|
+
|
|
167
|
+
is_real_person = hasattr(patient, "is_real_person") and patient.is_real_person
|
|
139
168
|
can_delete = examination_count == 0 and not is_real_person
|
|
140
|
-
|
|
169
|
+
|
|
141
170
|
warnings = []
|
|
142
171
|
if is_real_person:
|
|
143
|
-
warnings.append(
|
|
172
|
+
warnings.append("This patient is marked as a real person")
|
|
144
173
|
if examination_count > 0:
|
|
145
|
-
warnings.append(f
|
|
174
|
+
warnings.append(f"Patient has {examination_count} examination(s)")
|
|
146
175
|
if finding_count > 0:
|
|
147
|
-
warnings.append(f
|
|
148
|
-
|
|
149
|
-
return Response(
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
176
|
+
warnings.append(f"Patient has {finding_count} finding(s)")
|
|
177
|
+
|
|
178
|
+
return Response(
|
|
179
|
+
{
|
|
180
|
+
"can_delete": can_delete,
|
|
181
|
+
"is_real_person": is_real_person,
|
|
182
|
+
"related_objects": {
|
|
183
|
+
"examinations": examination_count,
|
|
184
|
+
"findings": finding_count,
|
|
185
|
+
"videos": video_count,
|
|
186
|
+
"reports": report_count,
|
|
187
|
+
},
|
|
188
|
+
"warnings": warnings,
|
|
189
|
+
}
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
@action(detail=False, methods=["get"])
|
|
162
193
|
def patient_count(self, request):
|
|
163
194
|
"""Gibt die Anzahl der Patienten zurück"""
|
|
164
195
|
count = Patient.objects.count()
|
|
165
196
|
return Response({"count": count})
|
|
166
|
-
|
|
167
|
-
@action(detail=True, methods=[
|
|
197
|
+
|
|
198
|
+
@action(detail=True, methods=["post"], url_path="pseudonym")
|
|
168
199
|
def generate_pseudonym(self, request, pk=None):
|
|
169
200
|
"""
|
|
170
201
|
Generate a pseudonym hash for an existing patient.
|
|
171
|
-
|
|
202
|
+
|
|
172
203
|
This endpoint generates a deterministic hash based on the patient's
|
|
173
204
|
personal data (name, dob, center) using server-side logic without
|
|
174
205
|
exposing any secrets to the frontend.
|
|
175
206
|
"""
|
|
176
|
-
from endoreg_db.services.pseudonym_service import
|
|
177
|
-
|
|
207
|
+
from endoreg_db.services.pseudonym_service import (
|
|
208
|
+
generate_patient_pseudonym,
|
|
209
|
+
validate_patient_for_pseudonym,
|
|
210
|
+
)
|
|
211
|
+
|
|
178
212
|
patient = self.get_object()
|
|
179
|
-
|
|
213
|
+
|
|
180
214
|
try:
|
|
181
215
|
# Validate that patient has required fields
|
|
182
216
|
missing_fields = validate_patient_for_pseudonym(patient)
|
|
183
217
|
if missing_fields:
|
|
184
|
-
return Response(
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
218
|
+
return Response(
|
|
219
|
+
{
|
|
220
|
+
"error": "Missing required fields for pseudonym generation",
|
|
221
|
+
"missing_fields": missing_fields,
|
|
222
|
+
"detail": f"Please provide: {', '.join(missing_fields)}",
|
|
223
|
+
},
|
|
224
|
+
status=status.HTTP_400_BAD_REQUEST,
|
|
225
|
+
)
|
|
226
|
+
|
|
190
227
|
# Generate the pseudonym
|
|
191
228
|
patient_hash, persisted = generate_patient_pseudonym(patient)
|
|
192
|
-
|
|
193
|
-
return Response(
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
229
|
+
|
|
230
|
+
return Response(
|
|
231
|
+
{
|
|
232
|
+
"patient_id": patient.id,
|
|
233
|
+
"patient_hash": patient_hash,
|
|
234
|
+
"source": "server",
|
|
235
|
+
"persisted": persisted,
|
|
236
|
+
"message": "Pseudonym generated successfully",
|
|
237
|
+
},
|
|
238
|
+
status=status.HTTP_200_OK,
|
|
239
|
+
)
|
|
240
|
+
|
|
201
241
|
except ValueError as e:
|
|
202
|
-
return Response(
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
242
|
+
return Response(
|
|
243
|
+
{"error": "Pseudonym generation failed", "detail": str(e)},
|
|
244
|
+
status=status.HTTP_400_BAD_REQUEST,
|
|
245
|
+
)
|
|
206
246
|
except Exception as e:
|
|
207
|
-
return Response(
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
247
|
+
return Response(
|
|
248
|
+
{
|
|
249
|
+
"error": "Internal server error during pseudonym generation",
|
|
250
|
+
"detail": str(e),
|
|
251
|
+
},
|
|
252
|
+
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
253
|
+
)
|
|
@@ -4,8 +4,8 @@ from .patient_examination_list import PatientExaminationListView
|
|
|
4
4
|
from .patient_examination import PatientExaminationViewSet
|
|
5
5
|
|
|
6
6
|
__all__ = [
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
]
|
|
7
|
+
"ExaminationCreateView",
|
|
8
|
+
"PatientExaminationDetailView",
|
|
9
|
+
"PatientExaminationListView",
|
|
10
|
+
"PatientExaminationViewSet",
|
|
11
|
+
]
|
|
@@ -8,24 +8,26 @@ from endoreg_db.serializers.patient_examination import (
|
|
|
8
8
|
)
|
|
9
9
|
from endoreg_db.serializers.examination import ExaminationDropdownSerializer
|
|
10
10
|
|
|
11
|
+
|
|
11
12
|
class PatientExaminationViewSet(viewsets.ModelViewSet):
|
|
12
13
|
"""
|
|
13
14
|
ViewSet für PatientExamination mit vollständiger CRUD-Unterstützung
|
|
14
15
|
"""
|
|
15
|
-
|
|
16
|
+
|
|
17
|
+
queryset = PatientExamination.objects.all().select_related("patient", "examination")
|
|
16
18
|
serializer_class = PatientExaminationSerializer
|
|
17
|
-
|
|
19
|
+
|
|
18
20
|
def get_queryset(self):
|
|
19
21
|
"""Optimierte Abfrage mit besserer Performance"""
|
|
20
|
-
return
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
)
|
|
25
|
-
|
|
22
|
+
return (
|
|
23
|
+
PatientExamination.objects.select_related("patient", "examination")
|
|
24
|
+
.prefetch_related("patient_findings", "indications")
|
|
25
|
+
.order_by("-date_start", "-id")
|
|
26
|
+
)
|
|
27
|
+
|
|
26
28
|
def get_patient_examination_ids(self):
|
|
27
29
|
"""Hilfsmethode zum Abrufen mehrerer PatientExamination IDs"""
|
|
28
|
-
return PatientExamination.objects.filter(all=True).values_list(
|
|
30
|
+
return PatientExamination.objects.filter(all=True).values_list("id", flat=True)
|
|
29
31
|
|
|
30
32
|
def get_patient_examination_by_id(self, pk):
|
|
31
33
|
"""Hilfsmethode zum Abrufen einer PatientExamination nach ID"""
|
|
@@ -33,42 +35,41 @@ class PatientExaminationViewSet(viewsets.ModelViewSet):
|
|
|
33
35
|
return None
|
|
34
36
|
else:
|
|
35
37
|
return PatientExamination.objects.select_related(
|
|
36
|
-
|
|
38
|
+
"patient", "examination"
|
|
37
39
|
).get(pk=pk)
|
|
38
40
|
|
|
39
|
-
|
|
40
|
-
@action(detail=False, methods=['get'])
|
|
41
|
+
@action(detail=False, methods=["get"])
|
|
41
42
|
def patients_dropdown(self, request):
|
|
42
43
|
"""
|
|
43
44
|
Endpoint für Patient-Dropdown-Daten
|
|
44
45
|
GET /api/patient-examinations/patients_dropdown/
|
|
45
46
|
"""
|
|
46
|
-
patients = Patient.objects.all().order_by(
|
|
47
|
+
patients = Patient.objects.all().order_by("first_name", "last_name")
|
|
47
48
|
serializer = PatientDropdownSerializer(patients, many=True)
|
|
48
49
|
return Response(serializer.data)
|
|
49
|
-
|
|
50
|
-
@action(detail=False, methods=[
|
|
50
|
+
|
|
51
|
+
@action(detail=False, methods=["get"])
|
|
51
52
|
def examinations_dropdown(self, request):
|
|
52
53
|
"""
|
|
53
54
|
Endpoint für Examination-Dropdown-Daten
|
|
54
55
|
GET /api/patient-examinations/examinations_dropdown/
|
|
55
56
|
"""
|
|
56
|
-
examinations = Examination.objects.all().order_by(
|
|
57
|
+
examinations = Examination.objects.all().order_by("name")
|
|
57
58
|
serializer = ExaminationDropdownSerializer(examinations, many=True)
|
|
58
59
|
return Response(serializer.data)
|
|
59
|
-
|
|
60
|
-
@action(detail=False, methods=[
|
|
60
|
+
|
|
61
|
+
@action(detail=False, methods=["get"])
|
|
61
62
|
def recent(self, request):
|
|
62
63
|
"""
|
|
63
64
|
Endpoint für die letzten PatientExaminations
|
|
64
65
|
GET /api/patient-examinations/recent/
|
|
65
66
|
"""
|
|
66
|
-
limit = int(request.query_params.get(
|
|
67
|
+
limit = int(request.query_params.get("limit", 10))
|
|
67
68
|
recent_examinations = self.get_queryset()[:limit]
|
|
68
69
|
serializer = self.get_serializer(recent_examinations, many=True)
|
|
69
70
|
return Response(serializer.data)
|
|
70
|
-
|
|
71
|
-
@action(detail=True, methods=[
|
|
71
|
+
|
|
72
|
+
@action(detail=True, methods=["get"])
|
|
72
73
|
def details(self, request, pk=None):
|
|
73
74
|
"""
|
|
74
75
|
Detaillierte Informationen über eine PatientExamination
|
|
@@ -76,13 +77,15 @@ class PatientExaminationViewSet(viewsets.ModelViewSet):
|
|
|
76
77
|
"""
|
|
77
78
|
examination = self.get_object()
|
|
78
79
|
data = {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
"examination": PatientExaminationSerializer(examination).data,
|
|
81
|
+
"findings": examination.get_findings().count(),
|
|
82
|
+
"indications": examination.get_indications().count(),
|
|
83
|
+
"patient_age_at_examination": examination.get_patient_age_at_examination()
|
|
84
|
+
if examination.date_start
|
|
85
|
+
else None,
|
|
83
86
|
}
|
|
84
87
|
return Response(data)
|
|
85
|
-
|
|
88
|
+
|
|
86
89
|
def create(self, request, *args, **kwargs):
|
|
87
90
|
"""
|
|
88
91
|
Überschreibt die create-Methode für bessere Fehlerbehandlung
|
|
@@ -93,36 +96,34 @@ class PatientExaminationViewSet(viewsets.ModelViewSet):
|
|
|
93
96
|
self.perform_create(serializer)
|
|
94
97
|
headers = self.get_success_headers(serializer.data)
|
|
95
98
|
return Response(
|
|
96
|
-
serializer.data,
|
|
97
|
-
status=status.HTTP_201_CREATED,
|
|
98
|
-
headers=headers
|
|
99
|
+
serializer.data, status=status.HTTP_201_CREATED, headers=headers
|
|
99
100
|
)
|
|
100
101
|
except Exception as e:
|
|
101
102
|
return Response(
|
|
102
|
-
{
|
|
103
|
-
status=status.HTTP_400_BAD_REQUEST
|
|
103
|
+
{"error": f"Fehler beim Erstellen der Untersuchung: {str(e)}"},
|
|
104
|
+
status=status.HTTP_400_BAD_REQUEST,
|
|
104
105
|
)
|
|
105
106
|
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
|
106
|
-
|
|
107
|
+
|
|
107
108
|
def update(self, request, *args, **kwargs):
|
|
108
109
|
"""
|
|
109
110
|
Überschreibt die update-Methode für bessere Fehlerbehandlung
|
|
110
111
|
"""
|
|
111
|
-
partial = kwargs.pop(
|
|
112
|
+
partial = kwargs.pop("partial", False)
|
|
112
113
|
instance = self.get_object()
|
|
113
114
|
serializer = self.get_serializer(instance, data=request.data, partial=partial)
|
|
114
|
-
|
|
115
|
+
|
|
115
116
|
if serializer.is_valid():
|
|
116
117
|
try:
|
|
117
118
|
self.perform_update(serializer)
|
|
118
119
|
return Response(serializer.data)
|
|
119
120
|
except Exception as e:
|
|
120
121
|
return Response(
|
|
121
|
-
{
|
|
122
|
-
status=status.HTTP_400_BAD_REQUEST
|
|
122
|
+
{"error": f"Fehler beim Aktualisieren der Untersuchung: {str(e)}"},
|
|
123
|
+
status=status.HTTP_400_BAD_REQUEST,
|
|
123
124
|
)
|
|
124
125
|
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
|
125
|
-
|
|
126
|
+
|
|
126
127
|
def get_findings_for_examination(self, request, pk=None):
|
|
127
128
|
"""
|
|
128
129
|
Endpoint to retrieve findings for a specific PatientExamination
|
|
@@ -131,10 +132,10 @@ class PatientExaminationViewSet(viewsets.ModelViewSet):
|
|
|
131
132
|
examination = self.get_patient_examination_by_id(pk)
|
|
132
133
|
if not examination:
|
|
133
134
|
return Response(
|
|
134
|
-
{
|
|
135
|
-
status=status.HTTP_404_NOT_FOUND
|
|
135
|
+
{"error": "PatientExamination nicht gefunden"},
|
|
136
|
+
status=status.HTTP_404_NOT_FOUND,
|
|
136
137
|
)
|
|
137
|
-
|
|
138
|
+
|
|
138
139
|
findings = PatientExaminationSerializer.get_
|
|
139
|
-
finding_data = [{
|
|
140
|
-
return Response(finding_data)
|
|
140
|
+
finding_data = [{"id": f.id, "name": str(f)} for f in findings]
|
|
141
|
+
return Response(finding_data)
|
|
@@ -6,8 +6,10 @@ from rest_framework.response import Response
|
|
|
6
6
|
from endoreg_db.utils.permissions import EnvironmentAwarePermission
|
|
7
7
|
|
|
8
8
|
import logging
|
|
9
|
+
|
|
9
10
|
logger = logging.getLogger(__name__)
|
|
10
11
|
|
|
12
|
+
|
|
11
13
|
class ExaminationCreateView(generics.CreateAPIView):
|
|
12
14
|
"""
|
|
13
15
|
Create new PatientExamination instances.
|
|
@@ -16,17 +18,16 @@ class ExaminationCreateView(generics.CreateAPIView):
|
|
|
16
18
|
Expected payload:
|
|
17
19
|
{
|
|
18
20
|
"patient": "patient_hash_string", # or patient_id integer
|
|
19
|
-
"examination": "examination_name", # examination name string
|
|
21
|
+
"examination": "examination_name", # examination name string
|
|
20
22
|
"date_start": "2024-01-15",
|
|
21
23
|
}
|
|
22
24
|
"""
|
|
25
|
+
|
|
23
26
|
serializer_class = PatientExaminationSerializer
|
|
24
27
|
permission_classes = [EnvironmentAwarePermission]
|
|
25
28
|
|
|
26
|
-
|
|
27
29
|
@transaction.atomic
|
|
28
30
|
def create(self, request, *args, **kwargs):
|
|
29
|
-
|
|
30
31
|
try:
|
|
31
32
|
logger.info(f"Creating examination with data: {request.data}")
|
|
32
33
|
|
|
@@ -38,26 +39,20 @@ class ExaminationCreateView(generics.CreateAPIView):
|
|
|
38
39
|
instance = serializer.save()
|
|
39
40
|
|
|
40
41
|
response_data = serializer.data
|
|
41
|
-
response_data[
|
|
42
|
+
response_data["message"] = "Examination created successfully"
|
|
42
43
|
|
|
43
44
|
logger.info(f"Examination created successfully with ID: {instance.id}")
|
|
44
45
|
return Response(response_data, status=status.HTTP_201_CREATED)
|
|
45
46
|
else:
|
|
46
47
|
logger.warning(f"Validation errors: {serializer.errors}")
|
|
47
48
|
return Response(
|
|
48
|
-
{
|
|
49
|
-
|
|
50
|
-
'details': serializer.errors
|
|
51
|
-
},
|
|
52
|
-
status=status.HTTP_400_BAD_REQUEST
|
|
49
|
+
{"error": "Validation failed", "details": serializer.errors},
|
|
50
|
+
status=status.HTTP_400_BAD_REQUEST,
|
|
53
51
|
)
|
|
54
52
|
|
|
55
53
|
except Exception as e:
|
|
56
54
|
logger.error(f"Error creating examination: {str(e)}")
|
|
57
55
|
return Response(
|
|
58
|
-
{
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
},
|
|
62
|
-
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
|
63
|
-
)
|
|
56
|
+
{"error": "Failed to create examination", "message": str(e)},
|
|
57
|
+
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
58
|
+
)
|
|
@@ -8,15 +8,18 @@ from rest_framework.response import Response
|
|
|
8
8
|
from endoreg_db.utils.permissions import DEBUG_PERMISSIONS
|
|
9
9
|
|
|
10
10
|
import logging
|
|
11
|
+
|
|
11
12
|
logger = logging.getLogger(__name__)
|
|
12
13
|
|
|
14
|
+
|
|
13
15
|
class PatientExaminationDetailView(generics.RetrieveUpdateAPIView):
|
|
14
16
|
"""
|
|
15
17
|
Retrieve and update PatientExamination instances.
|
|
16
18
|
GET /api/examinations/{id}/
|
|
17
19
|
PATCH /api/examinations/{id}/
|
|
18
20
|
"""
|
|
19
|
-
|
|
21
|
+
|
|
22
|
+
queryset = PatientExamination.objects.select_related("patient", "examination")
|
|
20
23
|
serializer_class = PatientExaminationSerializer
|
|
21
24
|
permission_classes = DEBUG_PERMISSIONS
|
|
22
25
|
|
|
@@ -28,8 +31,8 @@ class PatientExaminationDetailView(generics.RetrieveUpdateAPIView):
|
|
|
28
31
|
except Exception as e:
|
|
29
32
|
logger.error(f"Error retrieving examination: {str(e)}")
|
|
30
33
|
return Response(
|
|
31
|
-
{
|
|
32
|
-
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
|
34
|
+
{"error": "Failed to retrieve examination"},
|
|
35
|
+
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
33
36
|
)
|
|
34
37
|
|
|
35
38
|
@transaction.atomic
|
|
@@ -42,25 +45,19 @@ class PatientExaminationDetailView(generics.RetrieveUpdateAPIView):
|
|
|
42
45
|
updated_instance = serializer.save()
|
|
43
46
|
|
|
44
47
|
response_data = serializer.data
|
|
45
|
-
response_data[
|
|
48
|
+
response_data["message"] = "Examination updated successfully"
|
|
46
49
|
|
|
47
50
|
logger.info(f"Examination {instance.id} updated successfully")
|
|
48
51
|
return Response(response_data, status=status.HTTP_200_OK)
|
|
49
52
|
else:
|
|
50
53
|
return Response(
|
|
51
|
-
{
|
|
52
|
-
|
|
53
|
-
'details': serializer.errors
|
|
54
|
-
},
|
|
55
|
-
status=status.HTTP_400_BAD_REQUEST
|
|
54
|
+
{"error": "Validation failed", "details": serializer.errors},
|
|
55
|
+
status=status.HTTP_400_BAD_REQUEST,
|
|
56
56
|
)
|
|
57
57
|
|
|
58
58
|
except Exception as e:
|
|
59
59
|
logger.error(f"Error updating examination: {str(e)}")
|
|
60
60
|
return Response(
|
|
61
|
-
{
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
},
|
|
65
|
-
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
|
66
|
-
)
|
|
61
|
+
{"error": "Failed to update examination", "message": str(e)},
|
|
62
|
+
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
63
|
+
)
|