endoreg-db 0.8.6.1__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_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 +3 -3
- 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 +110 -182
- 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_2.py +8 -9
- endoreg_db/models/media/video/video_file.py +150 -108
- 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 +125 -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 +192 -173
- 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 +0 -2
- 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/file_overview.py +11 -99
- 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/services/anonymization.py +75 -73
- endoreg_db/services/lookup_service.py +37 -24
- endoreg_db/services/pdf_import.py +166 -68
- endoreg_db/services/storage_aware_video_processor.py +140 -114
- endoreg_db/services/video_import.py +193 -283
- endoreg_db/urls/__init__.py +7 -20
- endoreg_db/urls/media.py +108 -67
- 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 +0 -10
- 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 -152
- 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 +2 -3
- endoreg_db/views/meta/sensitive_meta_detail.py +0 -63
- endoreg_db/views/patient/patient.py +5 -4
- endoreg_db/views/pdf/pdf_stream.py +20 -21
- endoreg_db/views/pdf/reimport.py +11 -32
- endoreg_db/views/requirement/evaluate.py +188 -187
- endoreg_db/views/requirement/lookup.py +17 -3
- endoreg_db/views/requirement/requirement_utils.py +89 -0
- endoreg_db/views/video/__init__.py +0 -2
- endoreg_db/views/video/correction.py +2 -2
- {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.0.dist-info}/METADATA +7 -3
- {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.0.dist-info}/RECORD +341 -245
- endoreg_db/models/administration/permissions/__init__.py +0 -44
- 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/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.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/{models/media/video/refactor_plan.md → views/pdf/pdf_stream_views.py} +0 -0
- {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.0.dist-info}/WHEEL +0 -0
- {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
from django.db import models
|
|
3
|
-
from faker import Faker
|
|
1
|
+
import logging
|
|
4
2
|
import random
|
|
5
|
-
from datetime import datetime
|
|
3
|
+
from datetime import date, datetime
|
|
6
4
|
from typing import TYPE_CHECKING, List, Optional # Added List
|
|
7
|
-
|
|
5
|
+
|
|
6
|
+
from django.db import models
|
|
8
7
|
from django.utils import timezone # Add this import
|
|
8
|
+
from faker import Faker
|
|
9
|
+
|
|
10
|
+
from ..person import Person
|
|
9
11
|
|
|
10
12
|
# Import RequirementLinks and Disease for the links property
|
|
11
13
|
|
|
@@ -13,23 +15,22 @@ logger = logging.getLogger("patient")
|
|
|
13
15
|
|
|
14
16
|
if TYPE_CHECKING:
|
|
15
17
|
from endoreg_db.models import (
|
|
18
|
+
AnonymExaminationReport,
|
|
19
|
+
AnonymHistologyReport,
|
|
20
|
+
Center,
|
|
16
21
|
ExaminationIndication,
|
|
17
|
-
PatientEvent, PatientDisease,
|
|
18
22
|
Gender,
|
|
23
|
+
PatientDisease,
|
|
24
|
+
PatientEvent,
|
|
19
25
|
PatientExamination,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
AnonymHistologyReport, RawPdfFile,
|
|
23
|
-
# Added for links property
|
|
24
|
-
Medication,
|
|
26
|
+
PatientExternalID,
|
|
27
|
+
PatientLabValue,
|
|
25
28
|
PatientMedication,
|
|
26
|
-
|
|
27
|
-
MedicationIntakeTime,
|
|
28
|
-
PatientLabValue, # Assuming self.lab_values are PatientLabValue instances
|
|
29
|
-
LabValue # If RequirementLinks expects actual LabValue instances
|
|
29
|
+
RawPdfFile,
|
|
30
30
|
)
|
|
31
31
|
from endoreg_db.utils.links.requirement_link import RequirementLinks
|
|
32
32
|
|
|
33
|
+
|
|
33
34
|
class Patient(Person):
|
|
34
35
|
"""
|
|
35
36
|
A class representing a patient.
|
|
@@ -44,31 +45,47 @@ class Patient(Person):
|
|
|
44
45
|
|
|
45
46
|
"""
|
|
46
47
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
"Gender", on_delete=models.SET_NULL, null=True, blank=True
|
|
53
|
-
)
|
|
54
|
-
center = models.ForeignKey( # type: ignore[assignment]
|
|
55
|
-
"Center", on_delete=models.SET_NULL, null=True, blank=True
|
|
56
|
-
)
|
|
48
|
+
first_name = models.CharField(max_length=100)
|
|
49
|
+
last_name = models.CharField(max_length=100)
|
|
50
|
+
dob = models.DateField(null=True, blank=True)
|
|
51
|
+
gender = models.ForeignKey("Gender", on_delete=models.SET_NULL, null=True, blank=True)
|
|
52
|
+
center = models.ForeignKey("Center", on_delete=models.SET_NULL, null=True, blank=True)
|
|
57
53
|
patient_hash = models.CharField(max_length=255, blank=True, null=True)
|
|
58
|
-
|
|
54
|
+
|
|
59
55
|
objects = models.Manager() # Default manager
|
|
60
56
|
|
|
61
57
|
if TYPE_CHECKING:
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
58
|
+
from django.db.models.manager import RelatedManager
|
|
59
|
+
|
|
60
|
+
first_name: models.CharField[str]
|
|
61
|
+
last_name: models.CharField[str]
|
|
62
|
+
dob: models.DateField[date | None]
|
|
63
|
+
gender: models.ForeignKey["Gender | None"]
|
|
64
|
+
center: models.ForeignKey["Center | None"]
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def events(self) -> RelatedManager[PatientEvent]: ...
|
|
68
|
+
|
|
69
|
+
@property
|
|
70
|
+
def diseases(self) -> RelatedManager[PatientDisease]: ...
|
|
71
|
+
|
|
72
|
+
@property
|
|
73
|
+
def patient_examinations(self) -> RelatedManager[PatientExamination]: ...
|
|
74
|
+
|
|
75
|
+
@property
|
|
76
|
+
def anonymexaminationreport_set(self) -> RelatedManager[AnonymExaminationReport]: ...
|
|
77
|
+
|
|
78
|
+
@property
|
|
79
|
+
def anonymhistologyreport_set(self) -> RelatedManager[AnonymHistologyReport]: ...
|
|
80
|
+
|
|
81
|
+
@property
|
|
82
|
+
def external_ids(self) -> RelatedManager[PatientExternalID]: ...
|
|
83
|
+
|
|
84
|
+
@property
|
|
85
|
+
def patientmedication_set(self) -> RelatedManager[PatientMedication]: ...
|
|
86
|
+
|
|
87
|
+
@property
|
|
88
|
+
def lab_values(self) -> RelatedManager[PatientLabValue]: ...
|
|
72
89
|
|
|
73
90
|
def __str__(self):
|
|
74
91
|
return f"{self.first_name} {self.last_name} ({self.dob})"
|
|
@@ -77,12 +94,13 @@ class Patient(Person):
|
|
|
77
94
|
def get_or_create_pseudo_patient_by_hash(
|
|
78
95
|
cls,
|
|
79
96
|
patient_hash: str,
|
|
80
|
-
center: "Center" = None,
|
|
81
|
-
gender: "Gender | str" = None, # Allow string type hint
|
|
82
|
-
birth_month: int = None,
|
|
83
|
-
birth_year: int = None,
|
|
97
|
+
center: Optional["Center"] = None,
|
|
98
|
+
gender: Optional["Gender | str"] = None, # Allow string type hint
|
|
99
|
+
birth_month: Optional[int] = None,
|
|
100
|
+
birth_year: Optional[int] = None,
|
|
84
101
|
):
|
|
85
|
-
from endoreg_db.utils import
|
|
102
|
+
from endoreg_db.utils import create_mock_patient_name, random_day_by_year
|
|
103
|
+
|
|
86
104
|
from ....other import Gender # Import Gender model
|
|
87
105
|
|
|
88
106
|
created = False
|
|
@@ -96,9 +114,7 @@ class Patient(Person):
|
|
|
96
114
|
# If no patient with the given hash exists, create a new pseudo patient
|
|
97
115
|
assert center, "Center must be provided to create a new pseudo patient"
|
|
98
116
|
assert gender, "Gender must be provided to create a new pseudo patient"
|
|
99
|
-
assert birth_month,
|
|
100
|
-
"Birth month must be provided to create a new pseudo patient"
|
|
101
|
-
)
|
|
117
|
+
assert birth_month, "Birth month must be provided to create a new pseudo patient"
|
|
102
118
|
assert birth_year, "Birth year must be provided to create a new pseudo patient"
|
|
103
119
|
|
|
104
120
|
# Ensure gender is a Gender object
|
|
@@ -130,9 +146,8 @@ class Patient(Person):
|
|
|
130
146
|
|
|
131
147
|
return patient, created
|
|
132
148
|
|
|
133
|
-
def get_dob(self) ->
|
|
134
|
-
|
|
135
|
-
return dob
|
|
149
|
+
def get_dob(self) -> date | None:
|
|
150
|
+
return self.dob
|
|
136
151
|
|
|
137
152
|
def get_patient_examinations(self): # field: self.patient_examinations
|
|
138
153
|
"""Returns all patient examinations for this patient ordered by date (most recent is first)."""
|
|
@@ -146,10 +161,9 @@ class Patient(Person):
|
|
|
146
161
|
save: bool = True,
|
|
147
162
|
) -> "PatientExamination":
|
|
148
163
|
"""Creates a patient examination for this patient."""
|
|
164
|
+
from ....medical import Examination, PatientExamination
|
|
149
165
|
|
|
150
166
|
if examination_name_str:
|
|
151
|
-
from ....medical import Examination, PatientExamination
|
|
152
|
-
|
|
153
167
|
examination = Examination.objects.get(name=examination_name_str)
|
|
154
168
|
patient_examination = PatientExamination(
|
|
155
169
|
patient=self,
|
|
@@ -159,21 +173,17 @@ class Patient(Person):
|
|
|
159
173
|
)
|
|
160
174
|
|
|
161
175
|
else:
|
|
162
|
-
patient_examination = PatientExamination(
|
|
163
|
-
patient=self, date_start=date_start, date_end=date_end
|
|
164
|
-
)
|
|
176
|
+
patient_examination = PatientExamination(patient=self, date_start=date_start, date_end=date_end)
|
|
165
177
|
|
|
166
178
|
if save:
|
|
167
179
|
patient_examination.save()
|
|
168
180
|
|
|
169
181
|
return patient_examination
|
|
170
182
|
|
|
171
|
-
def create_examination_by_indication(
|
|
172
|
-
self, indication: "ExaminationIndication", date_start: datetime = None, date_end: datetime = None
|
|
173
|
-
):
|
|
183
|
+
def create_examination_by_indication(self, indication: "ExaminationIndication", date_start: Optional[datetime] = None, date_end: Optional[datetime] = None):
|
|
174
184
|
from ....medical import (
|
|
175
|
-
PatientExaminationIndication,
|
|
176
185
|
PatientExamination,
|
|
186
|
+
PatientExaminationIndication,
|
|
177
187
|
)
|
|
178
188
|
|
|
179
189
|
examination = indication.get_examination()
|
|
@@ -187,9 +197,7 @@ class Patient(Person):
|
|
|
187
197
|
|
|
188
198
|
patient_examination.save()
|
|
189
199
|
|
|
190
|
-
patient_examination_indication = PatientExaminationIndication.objects.create(
|
|
191
|
-
patient_examination=patient_examination, examination_indication=indication
|
|
192
|
-
)
|
|
200
|
+
patient_examination_indication = PatientExaminationIndication.objects.create(patient_examination=patient_examination, examination_indication=indication)
|
|
193
201
|
patient_examination_indication.save()
|
|
194
202
|
|
|
195
203
|
return patient_examination, patient_examination_indication
|
|
@@ -197,13 +205,13 @@ class Patient(Person):
|
|
|
197
205
|
def create_event(
|
|
198
206
|
self,
|
|
199
207
|
event_name_str: str,
|
|
200
|
-
date_start: datetime = None,
|
|
201
|
-
date_end: datetime = None,
|
|
202
|
-
description: str = None,
|
|
208
|
+
date_start: Optional[datetime] = None,
|
|
209
|
+
date_end: Optional[datetime] = None,
|
|
210
|
+
description: Optional[str] = None,
|
|
203
211
|
):
|
|
204
212
|
"""
|
|
205
213
|
Creates a patient event with the specified event name and start date.
|
|
206
|
-
|
|
214
|
+
|
|
207
215
|
If no start date is provided, the current datetime is used. Returns the created PatientEvent instance.
|
|
208
216
|
"""
|
|
209
217
|
from ....medical import Event, PatientEvent
|
|
@@ -224,16 +232,17 @@ class Patient(Person):
|
|
|
224
232
|
def create_examination_by_pdf(self, pdf: "RawPdfFile"):
|
|
225
233
|
"""
|
|
226
234
|
Creates a patient examination and associates it with the provided PDF report file.
|
|
227
|
-
|
|
235
|
+
|
|
228
236
|
The examination is created for this patient, saved, and linked to the given RawPdfFile instance. The PDF's examination field is updated and saved. Returns the created examination instance.
|
|
229
|
-
|
|
237
|
+
|
|
230
238
|
Args:
|
|
231
239
|
pdf: The RawPdfFile to associate with the new examination.
|
|
232
|
-
|
|
240
|
+
|
|
233
241
|
Returns:
|
|
234
242
|
The created PatientExamination instance.
|
|
235
243
|
"""
|
|
236
244
|
from ....medical import PatientExamination
|
|
245
|
+
|
|
237
246
|
patient_examination = PatientExamination(patient=self)
|
|
238
247
|
patient_examination.save()
|
|
239
248
|
pdf.examination = patient_examination
|
|
@@ -264,9 +273,7 @@ class Patient(Person):
|
|
|
264
273
|
return gender_obj
|
|
265
274
|
|
|
266
275
|
@classmethod
|
|
267
|
-
def get_random_age(
|
|
268
|
-
cls, min_age=55, max_age=90, mean_age=65, std_age=10, distribution="normal"
|
|
269
|
-
):
|
|
276
|
+
def get_random_age(cls, min_age=55, max_age=90, mean_age=65, std_age=10, distribution="normal"):
|
|
270
277
|
"""
|
|
271
278
|
Get a random age based on the given distribution.
|
|
272
279
|
|
|
@@ -346,11 +353,17 @@ class Patient(Person):
|
|
|
346
353
|
last_name=last_name,
|
|
347
354
|
dob=dob,
|
|
348
355
|
gender=gender,
|
|
349
|
-
center=center_obj,
|
|
356
|
+
center=center_obj, # Assign the center object
|
|
350
357
|
)
|
|
351
358
|
# No need to call save() again after create()
|
|
352
359
|
return patient
|
|
353
360
|
|
|
361
|
+
@property
|
|
362
|
+
def age_safe(self) -> int:
|
|
363
|
+
age = self.age()
|
|
364
|
+
assert age is not None, "Patient age is not set."
|
|
365
|
+
return age
|
|
366
|
+
|
|
354
367
|
def age(self) -> int | None:
|
|
355
368
|
"""
|
|
356
369
|
Get the age of the patient.
|
|
@@ -362,11 +375,7 @@ class Patient(Person):
|
|
|
362
375
|
dob = self.dob
|
|
363
376
|
# Ensure dob is not None before calculation
|
|
364
377
|
if dob:
|
|
365
|
-
age = (
|
|
366
|
-
current_date.year
|
|
367
|
-
- dob.year
|
|
368
|
-
- ((current_date.month, current_date.day) < (dob.month, dob.day))
|
|
369
|
-
)
|
|
378
|
+
age = current_date.year - dob.year - ((current_date.month, current_date.day) < (dob.month, dob.day))
|
|
370
379
|
return age
|
|
371
380
|
return None # Or handle the case where dob is None appropriately
|
|
372
381
|
|
|
@@ -390,17 +399,11 @@ class Patient(Person):
|
|
|
390
399
|
|
|
391
400
|
if isinstance(sample_type, str):
|
|
392
401
|
sample_type = PatientLabSampleType.objects.get(name=sample_type)
|
|
393
|
-
assert sample_type is not None,
|
|
394
|
-
f"Sample type with name '{sample_type}' not found."
|
|
395
|
-
)
|
|
402
|
+
assert sample_type is not None, f"Sample type with name '{sample_type}' not found."
|
|
396
403
|
elif not isinstance(sample_type, PatientLabSampleType):
|
|
397
|
-
raise ValueError(
|
|
398
|
-
"Sample type must be either a string or a PatientLabSampleType object."
|
|
399
|
-
)
|
|
404
|
+
raise ValueError("Sample type must be either a string or a PatientLabSampleType object.")
|
|
400
405
|
|
|
401
|
-
patient_lab_sample = PatientLabSample.objects.create(
|
|
402
|
-
patient=self, sample_type=sample_type, date=date
|
|
403
|
-
)
|
|
406
|
+
patient_lab_sample = PatientLabSample.objects.create(patient=self, sample_type=sample_type, date=date)
|
|
404
407
|
|
|
405
408
|
return patient_lab_sample
|
|
406
409
|
|
|
@@ -411,50 +414,50 @@ class Patient(Person):
|
|
|
411
414
|
as a RequirementLinks object. For a Patient, this includes their diseases, associated classification choices,
|
|
412
415
|
all their lab values, and medication information.
|
|
413
416
|
"""
|
|
414
|
-
from endoreg_db.utils.links.requirement_link import RequirementLinks
|
|
415
417
|
from endoreg_db.models.medical.disease import Disease, DiseaseClassificationChoice
|
|
416
|
-
|
|
418
|
+
|
|
417
419
|
# Imports for medication related models
|
|
418
420
|
from endoreg_db.models.medical.medication.medication import Medication
|
|
419
421
|
from endoreg_db.models.medical.medication.medication_indication import MedicationIndication
|
|
420
422
|
from endoreg_db.models.medical.medication.medication_intake_time import MedicationIntakeTime
|
|
423
|
+
from endoreg_db.utils.links.requirement_link import RequirementLinks
|
|
421
424
|
# PatientMedication objects are retrieved via self.patientmedication_set
|
|
422
425
|
# PatientLabValue objects are retrieved via self.lab_values
|
|
423
426
|
|
|
424
|
-
patient_disease_instances = list(self.diseases.all())
|
|
427
|
+
patient_disease_instances = list(self.diseases.all()) # These are PatientDisease model instances
|
|
425
428
|
actual_diseases: List[Disease] = []
|
|
426
429
|
all_classification_choices: List[DiseaseClassificationChoice] = []
|
|
427
430
|
|
|
428
431
|
for pd_instance in patient_disease_instances:
|
|
429
|
-
if pd_instance.disease:
|
|
432
|
+
if pd_instance.disease: # pd_instance.disease is a Disease instance
|
|
430
433
|
actual_diseases.append(pd_instance.disease)
|
|
431
434
|
all_classification_choices.extend(list(pd_instance.classification_choices.all()))
|
|
432
|
-
|
|
435
|
+
|
|
433
436
|
# Assuming self.lab_values is a related manager for PatientLabValue instances
|
|
434
|
-
patient_lab_value_instances = list(self.lab_values.all())
|
|
437
|
+
patient_lab_value_instances = list(self.lab_values.all()) # These are PatientLabValue model instances
|
|
435
438
|
|
|
436
439
|
# Medication information
|
|
437
440
|
# self.patientmedication_set gives a QuerySet of PatientMedication
|
|
438
|
-
patient_medication_instances = list(self.patientmedication_set.all())
|
|
439
|
-
|
|
441
|
+
patient_medication_instances = list(self.patientmedication_set.all())
|
|
442
|
+
|
|
440
443
|
actual_medications: List[Medication] = []
|
|
441
444
|
med_indications: List[MedicationIndication] = []
|
|
442
445
|
med_intake_times: List[MedicationIntakeTime] = []
|
|
443
446
|
|
|
444
447
|
for pm_instance in patient_medication_instances:
|
|
445
|
-
if pm_instance.medication:
|
|
448
|
+
if pm_instance.medication: # pm_instance.medication is a Medication instance
|
|
446
449
|
actual_medications.append(pm_instance.medication)
|
|
447
|
-
if pm_instance.medication_indication:
|
|
450
|
+
if pm_instance.medication_indication: # pm_instance.medication_indication is a MedicationIndication instance
|
|
448
451
|
med_indications.append(pm_instance.medication_indication)
|
|
449
|
-
med_intake_times.extend(list(pm_instance.intake_times.all()))
|
|
452
|
+
med_intake_times.extend(list(pm_instance.intake_times.all())) # pm_instance.intake_times is a ManyRelatedManager for MedicationIntakeTime
|
|
450
453
|
|
|
451
454
|
return RequirementLinks(
|
|
452
|
-
diseases=list(set(actual_diseases)),
|
|
453
|
-
patient_diseases=patient_disease_instances,
|
|
454
|
-
disease_classification_choices=list(set(all_classification_choices)),
|
|
455
|
+
diseases=list(set(actual_diseases)),
|
|
456
|
+
patient_diseases=patient_disease_instances,
|
|
457
|
+
disease_classification_choices=list(set(all_classification_choices)),
|
|
455
458
|
patient_lab_values=patient_lab_value_instances,
|
|
456
|
-
medications=list(set(actual_medications)),
|
|
459
|
+
medications=list(set(actual_medications)),
|
|
457
460
|
patient_medications=patient_medication_instances,
|
|
458
461
|
medication_indications=list(set(med_indications)),
|
|
459
|
-
medication_intake_times=list(set(med_intake_times))
|
|
462
|
+
medication_intake_times=list(set(med_intake_times)),
|
|
460
463
|
)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING
|
|
2
|
+
|
|
3
|
+
from django.db import models # Add this import
|
|
4
|
+
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
from endoreg_db.models import (
|
|
7
|
+
Patient,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class PatientExternalID(models.Model):
|
|
12
|
+
"""
|
|
13
|
+
A class representing the identifier of external datasources.
|
|
14
|
+
Attributes:
|
|
15
|
+
external_id (str): The external ID value.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
external_id: models.CharField = models.CharField(max_length=255)
|
|
19
|
+
patient = models.ForeignKey(
|
|
20
|
+
"Patient",
|
|
21
|
+
on_delete=models.CASCADE,
|
|
22
|
+
related_name="external_ids",
|
|
23
|
+
)
|
|
24
|
+
origin = models.CharField(max_length=255)
|
|
25
|
+
|
|
26
|
+
class Meta:
|
|
27
|
+
constraints = [
|
|
28
|
+
models.UniqueConstraint(
|
|
29
|
+
fields=("origin", "external_id"),
|
|
30
|
+
name="uniq_patient_external_id_per_origin",
|
|
31
|
+
)
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
if TYPE_CHECKING:
|
|
35
|
+
patient: models.ForeignKey["Patient"]
|
|
36
|
+
origin: models.CharField[str]
|
|
37
|
+
|
|
@@ -22,6 +22,10 @@ class Person(models.Model):
|
|
|
22
22
|
phone = models.CharField(max_length=255, blank=True, null=True)
|
|
23
23
|
is_real_person = models.BooleanField(default=True)
|
|
24
24
|
|
|
25
|
+
post_code = models.CharField(max_length=20, blank=True, null=True)
|
|
26
|
+
city = models.CharField(max_length=255, blank=True, null=True)
|
|
27
|
+
street = models.CharField(max_length=255, blank=True, null=True)
|
|
28
|
+
|
|
25
29
|
@abstractmethod
|
|
26
30
|
def __str__(self):
|
|
27
31
|
pass
|
|
@@ -1,24 +1,28 @@
|
|
|
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
6
|
from endoreg_db.models import PortalUserInfo
|
|
6
7
|
|
|
8
|
+
|
|
7
9
|
class ProfessionManager(models.Manager):
|
|
8
10
|
def get_by_natural_key(self, name):
|
|
9
11
|
return self.get(name=name)
|
|
10
12
|
|
|
13
|
+
|
|
11
14
|
class Profession(models.Model):
|
|
12
15
|
objects = ProfessionManager()
|
|
13
16
|
name = models.CharField(max_length=100)
|
|
14
17
|
description = models.TextField(blank=True, null=True)
|
|
15
18
|
|
|
16
|
-
|
|
17
19
|
if TYPE_CHECKING:
|
|
18
|
-
|
|
20
|
+
|
|
21
|
+
@property
|
|
22
|
+
def portal_user_infos(self) -> models.QuerySet["PortalUserInfo"]: ...
|
|
19
23
|
|
|
20
24
|
def __str__(self):
|
|
21
25
|
"""
|
|
22
26
|
Return the profession's name as its string representation.
|
|
23
27
|
"""
|
|
24
|
-
return str(self.name)
|
|
28
|
+
return str(self.name)
|
|
@@ -1,17 +1,21 @@
|
|
|
1
|
-
from django.db import models
|
|
2
1
|
from typing import TYPE_CHECKING
|
|
2
|
+
|
|
3
|
+
from django.db import models
|
|
4
|
+
|
|
3
5
|
# models.py in your main app
|
|
4
6
|
|
|
5
7
|
if TYPE_CHECKING:
|
|
6
|
-
from ..profession import Profession
|
|
7
|
-
from endoreg_db.models import Examiner
|
|
8
8
|
from django.contrib.auth.models import User
|
|
9
9
|
|
|
10
|
+
from endoreg_db.models import Examiner
|
|
11
|
+
|
|
12
|
+
from ..profession import Profession
|
|
13
|
+
|
|
10
14
|
|
|
11
15
|
class PortalUserInfo(models.Model):
|
|
12
16
|
user = models.OneToOneField("auth.User", on_delete=models.CASCADE)
|
|
13
17
|
profession = models.ForeignKey(
|
|
14
|
-
|
|
18
|
+
"endoreg_db.Profession",
|
|
15
19
|
on_delete=models.CASCADE,
|
|
16
20
|
blank=True,
|
|
17
21
|
null=True,
|
|
@@ -29,9 +33,9 @@ class PortalUserInfo(models.Model):
|
|
|
29
33
|
)
|
|
30
34
|
|
|
31
35
|
if TYPE_CHECKING:
|
|
32
|
-
user: "User"
|
|
33
|
-
profession: "Profession"
|
|
34
|
-
examiner: "Examiner"
|
|
36
|
+
user: models.OneToOneField["User"]
|
|
37
|
+
profession: models.ForeignKey["Profession|None"]
|
|
38
|
+
examiner: models.OneToOneField["Examiner|None"]
|
|
35
39
|
|
|
36
40
|
def __str__(self):
|
|
37
41
|
return self.user.username
|
|
@@ -1,20 +1,23 @@
|
|
|
1
|
-
from django.db import models
|
|
2
1
|
from typing import TYPE_CHECKING
|
|
3
2
|
|
|
3
|
+
from django.db import models
|
|
4
|
+
|
|
4
5
|
from endoreg_db.utils.product.sum_emissions import sum_emissions
|
|
5
6
|
from endoreg_db.utils.product.sum_weights import sum_weights
|
|
6
7
|
|
|
7
8
|
if TYPE_CHECKING:
|
|
8
9
|
from ...other.transport_route import TransportRoute
|
|
9
10
|
from .product_group import ProductGroup
|
|
10
|
-
from .reference_product import ReferenceProduct
|
|
11
11
|
from .product_material import ProductMaterial
|
|
12
|
+
from .reference_product import ReferenceProduct
|
|
12
13
|
# from .product_weight import ProductWeight
|
|
13
14
|
|
|
15
|
+
|
|
14
16
|
class ProductManager(models.Manager):
|
|
15
17
|
def get_by_natural_key(self, name):
|
|
16
18
|
return self.get(name=name)
|
|
17
|
-
|
|
19
|
+
|
|
20
|
+
|
|
18
21
|
class Product(models.Model):
|
|
19
22
|
objects = ProductManager()
|
|
20
23
|
|
|
@@ -29,15 +32,14 @@ class Product(models.Model):
|
|
|
29
32
|
)
|
|
30
33
|
|
|
31
34
|
if TYPE_CHECKING:
|
|
32
|
-
transport_route: "TransportRoute"
|
|
33
|
-
product_group: "ProductGroup"
|
|
35
|
+
transport_route: models.ForeignKey["TransportRoute|None"]
|
|
36
|
+
product_group: models.ForeignKey["ProductGroup|None"]
|
|
34
37
|
reference_products: models.QuerySet["ReferenceProduct"]
|
|
35
38
|
product_product_materials: models.QuerySet["ProductMaterial"]
|
|
36
39
|
|
|
37
|
-
|
|
38
40
|
def natural_key(self):
|
|
39
41
|
return (self.name,)
|
|
40
|
-
|
|
42
|
+
|
|
41
43
|
def __str__(self):
|
|
42
44
|
result = f"{self.name}"
|
|
43
45
|
if self.product_group:
|
|
@@ -49,41 +51,44 @@ class Product(models.Model):
|
|
|
49
51
|
result += f"{self.transport_route})"
|
|
50
52
|
else:
|
|
51
53
|
result += "no transport route)"
|
|
52
|
-
|
|
54
|
+
|
|
53
55
|
return result
|
|
54
|
-
|
|
56
|
+
|
|
55
57
|
def _calculate_material_metric(self, component: str, calculation_func):
|
|
56
58
|
"""Helper method to calculate weight or emission for materials of a specific component."""
|
|
57
|
-
from .product_material import ProductMaterial
|
|
59
|
+
from .product_material import ProductMaterial # Import locally to avoid circular dependency issues at module level
|
|
60
|
+
|
|
58
61
|
materials = ProductMaterial.objects.filter(product=self, component=component)
|
|
59
62
|
return calculation_func(materials)
|
|
60
63
|
|
|
61
64
|
def get_product_weight(self):
|
|
62
65
|
"""Get the product weight, prioritizing material definitions."""
|
|
63
66
|
from .product_material import ProductMaterial
|
|
67
|
+
|
|
64
68
|
# Check if there are specific material definitions for the product component
|
|
65
69
|
if ProductMaterial.objects.filter(product=self, component="product").exists():
|
|
66
70
|
return self.get_product_material_weight()
|
|
67
|
-
|
|
71
|
+
|
|
68
72
|
# Fallback: check if there is a direct product weight defined (Not implemented yet)
|
|
69
73
|
# TODO: Implement logic for ProductWeight lookup
|
|
70
|
-
return None
|
|
74
|
+
return None # Or appropriate default/error
|
|
71
75
|
|
|
72
76
|
def get_package_weight(self):
|
|
73
77
|
"""Get the package weight, prioritizing material definitions."""
|
|
74
78
|
from .product_material import ProductMaterial
|
|
79
|
+
|
|
75
80
|
# Check if there are specific material definitions for the package component
|
|
76
81
|
if ProductMaterial.objects.filter(product=self, component="package").exists():
|
|
77
82
|
return self.get_package_material_weight()
|
|
78
|
-
|
|
83
|
+
|
|
79
84
|
# Fallback: check if there is a direct package weight defined (Not implemented yet)
|
|
80
85
|
# TODO: Implement logic for PackageWeight lookup (if different from ProductWeight)
|
|
81
|
-
return None
|
|
86
|
+
return None # Or appropriate default/error
|
|
82
87
|
|
|
83
88
|
def get_product_material_weight(self):
|
|
84
89
|
"""Calculate the total weight based on defined product materials."""
|
|
85
90
|
return self._calculate_material_metric("product", sum_weights)
|
|
86
|
-
|
|
91
|
+
|
|
87
92
|
def get_package_material_weight(self):
|
|
88
93
|
"""Calculate the total weight based on defined package materials."""
|
|
89
94
|
return self._calculate_material_metric("package", sum_weights)
|
|
@@ -1,54 +1,53 @@
|
|
|
1
|
-
from django.db import models
|
|
2
1
|
from typing import TYPE_CHECKING
|
|
3
2
|
|
|
3
|
+
from django.db import models
|
|
4
|
+
|
|
4
5
|
from endoreg_db.models.other.unit import Unit
|
|
5
6
|
|
|
6
7
|
if TYPE_CHECKING:
|
|
7
|
-
from ...other.
|
|
8
|
+
from ...other.material import Material
|
|
8
9
|
from ...other.unit import Unit
|
|
9
10
|
from .product import Product
|
|
10
|
-
|
|
11
|
+
|
|
11
12
|
|
|
12
13
|
class ProductMaterial(models.Model):
|
|
13
14
|
component = models.CharField(max_length=255)
|
|
14
15
|
material = models.ForeignKey(
|
|
15
16
|
"Material",
|
|
16
17
|
on_delete=models.CASCADE,
|
|
17
|
-
related_name="material_product_materials",
|
|
18
|
+
related_name="material_product_materials", # Changed related_name
|
|
18
19
|
)
|
|
19
20
|
product = models.ForeignKey(
|
|
20
21
|
"Product",
|
|
21
22
|
on_delete=models.CASCADE,
|
|
22
|
-
related_name="product_product_materials"
|
|
23
|
+
related_name="product_product_materials", # Changed related_name
|
|
23
24
|
)
|
|
24
25
|
unit = models.ForeignKey(
|
|
25
26
|
"Unit",
|
|
26
27
|
on_delete=models.CASCADE,
|
|
27
|
-
related_name="unit_product_materials",
|
|
28
|
+
related_name="unit_product_materials", # Changed related_name
|
|
28
29
|
)
|
|
29
30
|
quantity = models.FloatField()
|
|
30
31
|
|
|
31
32
|
if TYPE_CHECKING:
|
|
32
|
-
product: "Product"
|
|
33
|
-
material: "Material"
|
|
34
|
-
unit: "Unit"
|
|
35
|
-
emission_factor: "EmissionFactor"
|
|
33
|
+
product: models.ForeignKey["Product"]
|
|
34
|
+
material: models.ForeignKey["Material"]
|
|
35
|
+
unit: models.ForeignKey["Unit"]
|
|
36
36
|
|
|
37
37
|
def get_emission(self) -> tuple[float, Unit]:
|
|
38
38
|
emission_factor = self.material.emission_factor
|
|
39
39
|
if emission_factor is None:
|
|
40
40
|
raise Exception("No emission factor for material " + self.material.name + " found.")
|
|
41
|
-
|
|
41
|
+
|
|
42
42
|
# make sure product_material.unit is the same as emission_factor.unit
|
|
43
|
-
if self.unit
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
if self.unit is not None and emission_factor.unit is not None:
|
|
44
|
+
if self.unit != emission_factor.unit:
|
|
45
|
+
raise Exception("Unit mismatch: " + self.unit.name + " != " + emission_factor.unit.name)
|
|
46
|
+
|
|
46
47
|
emmision_value = emission_factor.value * self.quantity
|
|
48
|
+
assert isinstance(emission_factor.unit, Unit)
|
|
47
49
|
emission_unit = emission_factor.unit
|
|
48
50
|
return emmision_value, emission_unit
|
|
49
|
-
|
|
51
|
+
|
|
50
52
|
def __str__(self) -> str:
|
|
51
53
|
return f"{self.product.name} - {self.material.name} - {self.quantity} {self.unit.name}"
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|