endoreg-db 0.8.8.9__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.

Files changed (453) hide show
  1. endoreg_db/admin.py +10 -5
  2. endoreg_db/apps.py +4 -7
  3. endoreg_db/authz/auth.py +1 -0
  4. endoreg_db/authz/backends.py +1 -1
  5. endoreg_db/authz/management/commands/list_routes.py +2 -0
  6. endoreg_db/authz/middleware.py +8 -7
  7. endoreg_db/authz/permissions.py +21 -10
  8. endoreg_db/authz/policy.py +14 -19
  9. endoreg_db/authz/views_auth.py +14 -10
  10. endoreg_db/codemods/rename_datetime_fields.py +8 -1
  11. endoreg_db/exceptions.py +5 -2
  12. endoreg_db/forms/__init__.py +0 -1
  13. endoreg_db/forms/examination_form.py +4 -3
  14. endoreg_db/forms/patient_finding_intervention_form.py +30 -8
  15. endoreg_db/forms/patient_form.py +9 -13
  16. endoreg_db/forms/questionnaires/__init__.py +1 -1
  17. endoreg_db/forms/settings/__init__.py +4 -1
  18. endoreg_db/forms/unit.py +2 -1
  19. endoreg_db/helpers/count_db.py +17 -14
  20. endoreg_db/helpers/default_objects.py +2 -1
  21. endoreg_db/helpers/download_segmentation_model.py +4 -3
  22. endoreg_db/helpers/interact.py +0 -5
  23. endoreg_db/helpers/test_video_helper.py +33 -25
  24. endoreg_db/import_files/__init__.py +1 -1
  25. endoreg_db/import_files/context/__init__.py +1 -1
  26. endoreg_db/import_files/context/default_sensitive_meta.py +11 -9
  27. endoreg_db/import_files/context/ensure_center.py +4 -4
  28. endoreg_db/import_files/context/file_lock.py +3 -3
  29. endoreg_db/import_files/context/import_context.py +11 -12
  30. endoreg_db/import_files/context/validate_directories.py +1 -0
  31. endoreg_db/import_files/file_storage/create_report_file.py +57 -34
  32. endoreg_db/import_files/file_storage/create_video_file.py +64 -35
  33. endoreg_db/import_files/file_storage/sensitive_meta_storage.py +5 -2
  34. endoreg_db/import_files/file_storage/state_management.py +146 -83
  35. endoreg_db/import_files/file_storage/storage.py +5 -1
  36. endoreg_db/import_files/processing/report_processing/report_anonymization.py +24 -19
  37. endoreg_db/import_files/processing/sensitive_meta_adapter.py +3 -3
  38. endoreg_db/import_files/processing/video_processing/video_anonymization.py +18 -18
  39. endoreg_db/import_files/pseudonymization/k_anonymity.py +8 -9
  40. endoreg_db/import_files/pseudonymization/k_pseudonymity.py +16 -5
  41. endoreg_db/import_files/report_import_service.py +36 -30
  42. endoreg_db/import_files/video_import_service.py +27 -23
  43. endoreg_db/logger_conf.py +56 -40
  44. endoreg_db/management/__init__.py +1 -1
  45. endoreg_db/management/commands/__init__.py +1 -1
  46. endoreg_db/management/commands/check_auth.py +45 -38
  47. endoreg_db/management/commands/create_model_meta_from_huggingface.py +53 -2
  48. endoreg_db/management/commands/create_multilabel_model_meta.py +54 -19
  49. endoreg_db/management/commands/fix_missing_patient_data.py +105 -71
  50. endoreg_db/management/commands/fix_video_paths.py +75 -54
  51. endoreg_db/management/commands/import_report.py +1 -3
  52. endoreg_db/management/commands/list_routes.py +2 -0
  53. endoreg_db/management/commands/load_ai_model_data.py +8 -2
  54. endoreg_db/management/commands/load_ai_model_label_data.py +0 -1
  55. endoreg_db/management/commands/load_center_data.py +3 -3
  56. endoreg_db/management/commands/load_distribution_data.py +35 -38
  57. endoreg_db/management/commands/load_endoscope_data.py +0 -3
  58. endoreg_db/management/commands/load_examination_data.py +20 -4
  59. endoreg_db/management/commands/load_finding_data.py +18 -3
  60. endoreg_db/management/commands/load_gender_data.py +17 -24
  61. endoreg_db/management/commands/load_green_endoscopy_wuerzburg_data.py +95 -85
  62. endoreg_db/management/commands/load_information_source.py +0 -3
  63. endoreg_db/management/commands/load_lab_value_data.py +14 -3
  64. endoreg_db/management/commands/load_legacy_data.py +303 -0
  65. endoreg_db/management/commands/load_name_data.py +1 -2
  66. endoreg_db/management/commands/load_pdf_type_data.py +4 -8
  67. endoreg_db/management/commands/load_profession_data.py +0 -1
  68. endoreg_db/management/commands/load_report_reader_flag_data.py +0 -4
  69. endoreg_db/management/commands/load_requirement_data.py +6 -2
  70. endoreg_db/management/commands/load_unit_data.py +0 -4
  71. endoreg_db/management/commands/load_user_groups.py +5 -7
  72. endoreg_db/management/commands/model_input.py +169 -0
  73. endoreg_db/management/commands/register_ai_model.py +22 -16
  74. endoreg_db/management/commands/setup_endoreg_db.py +110 -32
  75. endoreg_db/management/commands/storage_management.py +14 -8
  76. endoreg_db/management/commands/summarize_db_content.py +154 -63
  77. endoreg_db/management/commands/train_image_multilabel_model.py +144 -0
  78. endoreg_db/management/commands/validate_video_files.py +82 -50
  79. endoreg_db/management/commands/video_validation.py +4 -6
  80. endoreg_db/migrations/0001_initial.py +112 -63
  81. endoreg_db/migrations/__init__.py +0 -0
  82. endoreg_db/models/__init__.py +8 -0
  83. endoreg_db/models/administration/ai/active_model.py +5 -5
  84. endoreg_db/models/administration/ai/ai_model.py +41 -18
  85. endoreg_db/models/administration/ai/model_type.py +1 -0
  86. endoreg_db/models/administration/case/case.py +22 -22
  87. endoreg_db/models/administration/center/__init__.py +5 -5
  88. endoreg_db/models/administration/center/center.py +6 -2
  89. endoreg_db/models/administration/center/center_resource.py +18 -4
  90. endoreg_db/models/administration/center/center_shift.py +3 -1
  91. endoreg_db/models/administration/center/center_waste.py +6 -2
  92. endoreg_db/models/administration/person/__init__.py +1 -1
  93. endoreg_db/models/administration/person/employee/__init__.py +1 -1
  94. endoreg_db/models/administration/person/employee/employee_type.py +3 -1
  95. endoreg_db/models/administration/person/examiner/__init__.py +1 -1
  96. endoreg_db/models/administration/person/examiner/examiner.py +10 -2
  97. endoreg_db/models/administration/person/names/first_name.py +6 -4
  98. endoreg_db/models/administration/person/names/last_name.py +4 -3
  99. endoreg_db/models/administration/person/patient/__init__.py +1 -1
  100. endoreg_db/models/administration/person/patient/patient.py +0 -1
  101. endoreg_db/models/administration/person/patient/patient_external_id.py +0 -1
  102. endoreg_db/models/administration/person/person.py +1 -1
  103. endoreg_db/models/administration/product/__init__.py +7 -6
  104. endoreg_db/models/administration/product/product.py +6 -2
  105. endoreg_db/models/administration/product/product_group.py +9 -7
  106. endoreg_db/models/administration/product/product_material.py +9 -2
  107. endoreg_db/models/administration/product/reference_product.py +64 -15
  108. endoreg_db/models/administration/qualification/qualification.py +3 -1
  109. endoreg_db/models/administration/shift/shift.py +3 -1
  110. endoreg_db/models/administration/shift/shift_type.py +12 -4
  111. endoreg_db/models/aidataset/__init__.py +5 -0
  112. endoreg_db/models/aidataset/aidataset.py +193 -0
  113. endoreg_db/models/label/__init__.py +1 -1
  114. endoreg_db/models/label/label.py +10 -2
  115. endoreg_db/models/label/label_set.py +3 -1
  116. endoreg_db/models/label/label_video_segment/_create_from_video.py +6 -2
  117. endoreg_db/models/label/label_video_segment/label_video_segment.py +148 -44
  118. endoreg_db/models/media/__init__.py +12 -5
  119. endoreg_db/models/media/frame/__init__.py +1 -1
  120. endoreg_db/models/media/frame/frame.py +34 -8
  121. endoreg_db/models/media/pdf/__init__.py +2 -1
  122. endoreg_db/models/media/pdf/raw_pdf.py +11 -4
  123. endoreg_db/models/media/pdf/report_file.py +6 -2
  124. endoreg_db/models/media/pdf/report_reader/__init__.py +3 -3
  125. endoreg_db/models/media/pdf/report_reader/report_reader_flag.py +15 -5
  126. endoreg_db/models/media/video/create_from_file.py +20 -41
  127. endoreg_db/models/media/video/pipe_1.py +75 -30
  128. endoreg_db/models/media/video/pipe_2.py +37 -12
  129. endoreg_db/models/media/video/video_file.py +36 -24
  130. endoreg_db/models/media/video/video_file_ai.py +235 -70
  131. endoreg_db/models/media/video/video_file_anonymize.py +240 -65
  132. endoreg_db/models/media/video/video_file_frames/_bulk_create_frames.py +6 -1
  133. endoreg_db/models/media/video/video_file_frames/_create_frame_object.py +3 -1
  134. endoreg_db/models/media/video/video_file_frames/_delete_frames.py +30 -9
  135. endoreg_db/models/media/video/video_file_frames/_extract_frames.py +95 -29
  136. endoreg_db/models/media/video/video_file_frames/_get_frame.py +13 -3
  137. endoreg_db/models/media/video/video_file_frames/_get_frame_path.py +4 -1
  138. endoreg_db/models/media/video/video_file_frames/_get_frame_paths.py +15 -3
  139. endoreg_db/models/media/video/video_file_frames/_get_frame_range.py +15 -3
  140. endoreg_db/models/media/video/video_file_frames/_get_frames.py +7 -2
  141. endoreg_db/models/media/video/video_file_frames/_initialize_frames.py +109 -23
  142. endoreg_db/models/media/video/video_file_frames/_manage_frame_range.py +111 -27
  143. endoreg_db/models/media/video/video_file_frames/_mark_frames_extracted_status.py +46 -13
  144. endoreg_db/models/media/video/video_file_io.py +85 -33
  145. endoreg_db/models/media/video/video_file_meta/__init__.py +6 -6
  146. endoreg_db/models/media/video/video_file_meta/get_crop_template.py +17 -4
  147. endoreg_db/models/media/video/video_file_meta/get_endo_roi.py +28 -7
  148. endoreg_db/models/media/video/video_file_meta/get_fps.py +46 -13
  149. endoreg_db/models/media/video/video_file_meta/initialize_video_specs.py +81 -20
  150. endoreg_db/models/media/video/video_file_meta/text_meta.py +61 -20
  151. endoreg_db/models/media/video/video_file_meta/video_meta.py +40 -12
  152. endoreg_db/models/media/video/video_file_segments.py +118 -27
  153. endoreg_db/models/media/video/video_metadata.py +25 -6
  154. endoreg_db/models/media/video/video_processing.py +54 -15
  155. endoreg_db/models/medical/__init__.py +3 -13
  156. endoreg_db/models/medical/contraindication/__init__.py +3 -1
  157. endoreg_db/models/medical/disease.py +18 -6
  158. endoreg_db/models/medical/event.py +6 -2
  159. endoreg_db/models/medical/examination/__init__.py +5 -1
  160. endoreg_db/models/medical/examination/examination.py +22 -6
  161. endoreg_db/models/medical/examination/examination_indication.py +23 -7
  162. endoreg_db/models/medical/examination/examination_time.py +6 -2
  163. endoreg_db/models/medical/finding/__init__.py +3 -1
  164. endoreg_db/models/medical/finding/finding.py +37 -12
  165. endoreg_db/models/medical/finding/finding_classification.py +27 -8
  166. endoreg_db/models/medical/finding/finding_intervention.py +19 -6
  167. endoreg_db/models/medical/finding/finding_type.py +3 -1
  168. endoreg_db/models/medical/hardware/__init__.py +1 -1
  169. endoreg_db/models/medical/hardware/endoscope.py +14 -2
  170. endoreg_db/models/medical/laboratory/__init__.py +1 -1
  171. endoreg_db/models/medical/laboratory/lab_value.py +139 -39
  172. endoreg_db/models/medical/medication/__init__.py +7 -3
  173. endoreg_db/models/medical/medication/medication.py +3 -1
  174. endoreg_db/models/medical/medication/medication_indication.py +3 -1
  175. endoreg_db/models/medical/medication/medication_indication_type.py +11 -3
  176. endoreg_db/models/medical/medication/medication_intake_time.py +3 -1
  177. endoreg_db/models/medical/medication/medication_schedule.py +3 -1
  178. endoreg_db/models/medical/patient/__init__.py +2 -10
  179. endoreg_db/models/medical/patient/medication_examples.py +3 -14
  180. endoreg_db/models/medical/patient/patient_disease.py +17 -5
  181. endoreg_db/models/medical/patient/patient_event.py +12 -4
  182. endoreg_db/models/medical/patient/patient_examination.py +52 -15
  183. endoreg_db/models/medical/patient/patient_examination_indication.py +15 -4
  184. endoreg_db/models/medical/patient/patient_finding.py +105 -29
  185. endoreg_db/models/medical/patient/patient_finding_classification.py +41 -12
  186. endoreg_db/models/medical/patient/patient_finding_intervention.py +11 -3
  187. endoreg_db/models/medical/patient/patient_lab_sample.py +6 -2
  188. endoreg_db/models/medical/patient/patient_lab_value.py +42 -10
  189. endoreg_db/models/medical/patient/patient_medication.py +25 -7
  190. endoreg_db/models/medical/patient/patient_medication_schedule.py +34 -10
  191. endoreg_db/models/metadata/model_meta.py +40 -12
  192. endoreg_db/models/metadata/model_meta_logic.py +51 -16
  193. endoreg_db/models/metadata/sensitive_meta.py +65 -28
  194. endoreg_db/models/metadata/sensitive_meta_logic.py +28 -26
  195. endoreg_db/models/metadata/video_meta.py +146 -39
  196. endoreg_db/models/metadata/video_prediction_logic.py +70 -21
  197. endoreg_db/models/metadata/video_prediction_meta.py +80 -27
  198. endoreg_db/models/operation_log.py +63 -0
  199. endoreg_db/models/other/__init__.py +10 -10
  200. endoreg_db/models/other/distribution/__init__.py +9 -7
  201. endoreg_db/models/other/distribution/base_value_distribution.py +3 -1
  202. endoreg_db/models/other/distribution/date_value_distribution.py +19 -5
  203. endoreg_db/models/other/distribution/multiple_categorical_value_distribution.py +3 -1
  204. endoreg_db/models/other/distribution/numeric_value_distribution.py +34 -9
  205. endoreg_db/models/other/emission/__init__.py +1 -1
  206. endoreg_db/models/other/emission/emission_factor.py +9 -3
  207. endoreg_db/models/other/information_source.py +15 -5
  208. endoreg_db/models/other/material.py +3 -1
  209. endoreg_db/models/other/transport_route.py +3 -1
  210. endoreg_db/models/other/unit.py +6 -2
  211. endoreg_db/models/report/report.py +0 -1
  212. endoreg_db/models/requirement/requirement.py +84 -27
  213. endoreg_db/models/requirement/requirement_error.py +5 -6
  214. endoreg_db/models/requirement/requirement_evaluation/__init__.py +1 -1
  215. endoreg_db/models/requirement/requirement_evaluation/evaluate_with_dependencies.py +8 -8
  216. endoreg_db/models/requirement/requirement_evaluation/get_values.py +3 -3
  217. endoreg_db/models/requirement/requirement_evaluation/requirement_type_parser.py +24 -8
  218. endoreg_db/models/requirement/requirement_operator.py +28 -8
  219. endoreg_db/models/requirement/requirement_set.py +34 -11
  220. endoreg_db/models/state/__init__.py +1 -0
  221. endoreg_db/models/state/audit_ledger.py +9 -2
  222. endoreg_db/models/{media → state}/processing_history/__init__.py +1 -3
  223. endoreg_db/models/state/processing_history/processing_history.py +136 -0
  224. endoreg_db/models/state/raw_pdf.py +0 -1
  225. endoreg_db/models/state/video.py +2 -3
  226. endoreg_db/models/utils.py +4 -2
  227. endoreg_db/queries/__init__.py +2 -6
  228. endoreg_db/queries/annotations/__init__.py +1 -3
  229. endoreg_db/queries/annotations/legacy.py +37 -26
  230. endoreg_db/root_urls.py +3 -4
  231. endoreg_db/schemas/examination_evaluation.py +3 -0
  232. endoreg_db/serializers/Frames_NICE_and_PARIS_classifications.py +249 -163
  233. endoreg_db/serializers/__init__.py +2 -8
  234. endoreg_db/serializers/administration/__init__.py +1 -2
  235. endoreg_db/serializers/administration/ai/__init__.py +0 -1
  236. endoreg_db/serializers/administration/ai/active_model.py +3 -1
  237. endoreg_db/serializers/administration/ai/ai_model.py +5 -3
  238. endoreg_db/serializers/administration/ai/model_type.py +3 -1
  239. endoreg_db/serializers/administration/center.py +7 -2
  240. endoreg_db/serializers/administration/gender.py +4 -2
  241. endoreg_db/serializers/anonymization.py +13 -13
  242. endoreg_db/serializers/evaluation/examination_evaluation.py +0 -1
  243. endoreg_db/serializers/examination/__init__.py +1 -1
  244. endoreg_db/serializers/examination/base.py +12 -13
  245. endoreg_db/serializers/examination/dropdown.py +6 -7
  246. endoreg_db/serializers/examination_serializer.py +3 -6
  247. endoreg_db/serializers/finding/__init__.py +1 -1
  248. endoreg_db/serializers/finding/finding.py +14 -7
  249. endoreg_db/serializers/finding_classification/__init__.py +3 -3
  250. endoreg_db/serializers/finding_classification/choice.py +3 -3
  251. endoreg_db/serializers/finding_classification/classification.py +2 -4
  252. endoreg_db/serializers/label_video_segment/__init__.py +5 -3
  253. endoreg_db/serializers/{label → label_video_segment}/image_classification_annotation.py +5 -5
  254. endoreg_db/serializers/label_video_segment/label/__init__.py +6 -0
  255. endoreg_db/serializers/{label → label_video_segment/label}/label.py +1 -1
  256. endoreg_db/serializers/label_video_segment/label_video_segment.py +338 -228
  257. endoreg_db/serializers/meta/__init__.py +1 -2
  258. endoreg_db/serializers/meta/sensitive_meta_detail.py +28 -13
  259. endoreg_db/serializers/meta/sensitive_meta_update.py +51 -46
  260. endoreg_db/serializers/meta/sensitive_meta_verification.py +19 -16
  261. endoreg_db/serializers/misc/__init__.py +2 -2
  262. endoreg_db/serializers/misc/file_overview.py +11 -7
  263. endoreg_db/serializers/misc/stats.py +10 -8
  264. endoreg_db/serializers/misc/translatable_field_mix_in.py +6 -6
  265. endoreg_db/serializers/misc/upload_job.py +32 -29
  266. endoreg_db/serializers/patient/__init__.py +2 -1
  267. endoreg_db/serializers/patient/patient.py +32 -15
  268. endoreg_db/serializers/patient/patient_dropdown.py +11 -3
  269. endoreg_db/serializers/patient_examination/__init__.py +1 -1
  270. endoreg_db/serializers/patient_examination/patient_examination.py +67 -40
  271. endoreg_db/serializers/patient_finding/__init__.py +1 -1
  272. endoreg_db/serializers/patient_finding/patient_finding.py +2 -1
  273. endoreg_db/serializers/patient_finding/patient_finding_classification.py +17 -9
  274. endoreg_db/serializers/patient_finding/patient_finding_detail.py +26 -17
  275. endoreg_db/serializers/patient_finding/patient_finding_intervention.py +7 -5
  276. endoreg_db/serializers/patient_finding/patient_finding_list.py +10 -11
  277. endoreg_db/serializers/patient_finding/patient_finding_write.py +36 -27
  278. endoreg_db/serializers/pdf/__init__.py +1 -3
  279. endoreg_db/serializers/requirements/requirement_schema.py +1 -6
  280. endoreg_db/serializers/sensitive_meta_serializer.py +100 -81
  281. endoreg_db/serializers/video/__init__.py +2 -2
  282. endoreg_db/serializers/video/{segmentation.py → video_file.py} +66 -47
  283. endoreg_db/serializers/video/video_file_brief.py +6 -2
  284. endoreg_db/serializers/video/video_file_detail.py +36 -23
  285. endoreg_db/serializers/video/video_file_list.py +4 -2
  286. endoreg_db/serializers/video/video_processing_history.py +54 -50
  287. endoreg_db/services/__init__.py +1 -1
  288. endoreg_db/services/anonymization.py +2 -2
  289. endoreg_db/services/examination_evaluation.py +40 -17
  290. endoreg_db/services/model_meta_from_hf.py +76 -0
  291. endoreg_db/services/polling_coordinator.py +101 -70
  292. endoreg_db/services/pseudonym_service.py +27 -22
  293. endoreg_db/services/report_import.py +6 -3
  294. endoreg_db/services/segment_sync.py +75 -59
  295. endoreg_db/services/video_import.py +6 -7
  296. endoreg_db/urls/__init__.py +2 -2
  297. endoreg_db/urls/ai.py +7 -25
  298. endoreg_db/urls/anonymization.py +61 -15
  299. endoreg_db/urls/auth.py +4 -4
  300. endoreg_db/urls/classification.py +4 -9
  301. endoreg_db/urls/examination.py +27 -18
  302. endoreg_db/urls/media.py +27 -34
  303. endoreg_db/urls/patient.py +11 -7
  304. endoreg_db/urls/requirements.py +3 -1
  305. endoreg_db/urls/root_urls.py +2 -3
  306. endoreg_db/urls/stats.py +24 -16
  307. endoreg_db/urls/upload.py +3 -11
  308. endoreg_db/utils/__init__.py +14 -15
  309. endoreg_db/utils/ai/__init__.py +1 -1
  310. endoreg_db/utils/ai/data_loader_for_model_input.py +262 -0
  311. endoreg_db/utils/ai/data_loader_for_model_training.py +262 -0
  312. endoreg_db/utils/ai/get.py +2 -1
  313. endoreg_db/utils/ai/inference_dataset.py +14 -15
  314. endoreg_db/utils/ai/model_training/config.py +117 -0
  315. endoreg_db/utils/ai/model_training/dataset.py +74 -0
  316. endoreg_db/utils/ai/model_training/losses.py +68 -0
  317. endoreg_db/utils/ai/model_training/metrics.py +78 -0
  318. endoreg_db/utils/ai/model_training/model_backbones.py +155 -0
  319. endoreg_db/utils/ai/model_training/model_gastronet_resnet.py +118 -0
  320. endoreg_db/utils/ai/model_training/trainer_gastronet_multilabel.py +771 -0
  321. endoreg_db/utils/ai/multilabel_classification_net.py +21 -6
  322. endoreg_db/utils/ai/predict.py +4 -4
  323. endoreg_db/utils/ai/preprocess.py +19 -11
  324. endoreg_db/utils/calc_duration_seconds.py +4 -4
  325. endoreg_db/utils/case_generator/lab_sample_factory.py +3 -4
  326. endoreg_db/utils/check_video_files.py +74 -47
  327. endoreg_db/utils/cropping.py +10 -9
  328. endoreg_db/utils/dataloader.py +11 -3
  329. endoreg_db/utils/dates.py +3 -4
  330. endoreg_db/utils/defaults/set_default_center.py +7 -6
  331. endoreg_db/utils/env.py +6 -2
  332. endoreg_db/utils/extract_specific_frames.py +24 -9
  333. endoreg_db/utils/file_operations.py +30 -18
  334. endoreg_db/utils/fix_video_path_direct.py +57 -41
  335. endoreg_db/utils/frame_anonymization_utils.py +157 -157
  336. endoreg_db/utils/hashs.py +3 -18
  337. endoreg_db/utils/links/requirement_link.py +96 -52
  338. endoreg_db/utils/ocr.py +30 -25
  339. endoreg_db/utils/operation_log.py +61 -0
  340. endoreg_db/utils/parse_and_generate_yaml.py +12 -13
  341. endoreg_db/utils/paths.py +6 -6
  342. endoreg_db/utils/permissions.py +40 -24
  343. endoreg_db/utils/pipelines/process_video_dir.py +50 -26
  344. endoreg_db/utils/product/sum_emissions.py +5 -3
  345. endoreg_db/utils/product/sum_weights.py +4 -2
  346. endoreg_db/utils/pydantic_models/__init__.py +3 -4
  347. endoreg_db/utils/requirement_operator_logic/_old/lab_value_operators.py +207 -107
  348. endoreg_db/utils/requirement_operator_logic/_old/model_evaluators.py +252 -65
  349. endoreg_db/utils/requirement_operator_logic/new_operator_logic.py +27 -10
  350. endoreg_db/utils/setup_config.py +21 -5
  351. endoreg_db/utils/storage.py +3 -1
  352. endoreg_db/utils/translation.py +19 -15
  353. endoreg_db/utils/uuid.py +1 -0
  354. endoreg_db/utils/validate_endo_roi.py +12 -4
  355. endoreg_db/utils/validate_subcategory_dict.py +26 -24
  356. endoreg_db/utils/validate_video_detailed.py +207 -149
  357. endoreg_db/utils/video/__init__.py +7 -3
  358. endoreg_db/utils/video/extract_frames.py +30 -18
  359. endoreg_db/utils/video/ffmpeg_wrapper.py +217 -52
  360. endoreg_db/utils/video/names.py +11 -6
  361. endoreg_db/utils/video/streaming_processor.py +175 -101
  362. endoreg_db/utils/video/video_splitter.py +30 -19
  363. endoreg_db/views/Frames_NICE_and_PARIS_classifications_views.py +59 -50
  364. endoreg_db/views/__init__.py +0 -20
  365. endoreg_db/views/anonymization/__init__.py +6 -2
  366. endoreg_db/views/anonymization/media_management.py +2 -6
  367. endoreg_db/views/anonymization/overview.py +34 -1
  368. endoreg_db/views/anonymization/validate.py +79 -18
  369. endoreg_db/views/auth/__init__.py +1 -1
  370. endoreg_db/views/auth/keycloak.py +16 -14
  371. endoreg_db/views/examination/__init__.py +12 -15
  372. endoreg_db/views/examination/examination.py +5 -5
  373. endoreg_db/views/examination/examination_manifest_cache.py +5 -5
  374. endoreg_db/views/examination/get_finding_classification_choices.py +8 -5
  375. endoreg_db/views/examination/get_finding_classifications.py +9 -7
  376. endoreg_db/views/examination/get_findings.py +8 -10
  377. endoreg_db/views/examination/get_instruments.py +3 -2
  378. endoreg_db/views/examination/get_interventions.py +1 -1
  379. endoreg_db/views/finding/__init__.py +2 -2
  380. endoreg_db/views/finding/finding.py +58 -54
  381. endoreg_db/views/finding/get_classifications.py +1 -1
  382. endoreg_db/views/finding/get_interventions.py +1 -1
  383. endoreg_db/views/finding_classification/__init__.py +5 -5
  384. endoreg_db/views/finding_classification/finding_classification.py +5 -6
  385. endoreg_db/views/finding_classification/get_classification_choices.py +3 -4
  386. endoreg_db/views/media/__init__.py +13 -13
  387. endoreg_db/views/media/pdf_media.py +9 -9
  388. endoreg_db/views/media/sensitive_metadata.py +10 -7
  389. endoreg_db/views/media/video_media.py +4 -4
  390. endoreg_db/views/meta/__init__.py +1 -1
  391. endoreg_db/views/meta/sensitive_meta_list.py +20 -22
  392. endoreg_db/views/meta/sensitive_meta_verification.py +14 -11
  393. endoreg_db/views/misc/__init__.py +6 -34
  394. endoreg_db/views/misc/center.py +2 -1
  395. endoreg_db/views/misc/csrf.py +2 -1
  396. endoreg_db/views/misc/gender.py +2 -1
  397. endoreg_db/views/misc/stats.py +141 -106
  398. endoreg_db/views/patient/__init__.py +1 -3
  399. endoreg_db/views/patient/patient.py +141 -99
  400. endoreg_db/views/patient_examination/__init__.py +5 -5
  401. endoreg_db/views/patient_examination/patient_examination.py +43 -42
  402. endoreg_db/views/patient_examination/patient_examination_create.py +10 -15
  403. endoreg_db/views/patient_examination/patient_examination_detail.py +12 -15
  404. endoreg_db/views/patient_examination/patient_examination_list.py +21 -17
  405. endoreg_db/views/patient_examination/video.py +114 -80
  406. endoreg_db/views/patient_finding/__init__.py +1 -1
  407. endoreg_db/views/patient_finding/patient_finding.py +17 -10
  408. endoreg_db/views/patient_finding/patient_finding_optimized.py +127 -95
  409. endoreg_db/views/patient_finding_classification/__init__.py +1 -1
  410. endoreg_db/views/patient_finding_classification/pfc_create.py +35 -27
  411. endoreg_db/views/report/reimport.py +1 -1
  412. endoreg_db/views/report/report_stream.py +5 -8
  413. endoreg_db/views/requirement/__init__.py +2 -1
  414. endoreg_db/views/requirement/evaluate.py +7 -9
  415. endoreg_db/views/requirement/lookup.py +2 -3
  416. endoreg_db/views/requirement/lookup_store.py +0 -1
  417. endoreg_db/views/requirement/requirement_utils.py +2 -4
  418. endoreg_db/views/stats/__init__.py +4 -4
  419. endoreg_db/views/stats/stats_views.py +152 -115
  420. endoreg_db/views/video/__init__.py +18 -27
  421. endoreg_db/views/{ai → video/ai}/__init__.py +2 -2
  422. endoreg_db/views/{ai → video/ai}/label.py +20 -16
  423. endoreg_db/views/video/correction.py +5 -6
  424. endoreg_db/views/video/reimport.py +134 -99
  425. endoreg_db/views/video/segments_crud.py +134 -44
  426. endoreg_db/views/video/video_apply_mask.py +13 -12
  427. endoreg_db/views/video/video_correction.py +2 -1
  428. endoreg_db/views/video/video_download_processed.py +15 -15
  429. endoreg_db/views/video/video_meta_stats.py +7 -6
  430. endoreg_db/views/video/video_processing_history.py +3 -2
  431. endoreg_db/views/video/video_remove_frames.py +13 -12
  432. endoreg_db/views/video/video_stream.py +110 -82
  433. {endoreg_db-0.8.8.9.dist-info → endoreg_db-0.8.9.10.dist-info}/METADATA +9 -3
  434. {endoreg_db-0.8.8.9.dist-info → endoreg_db-0.8.9.10.dist-info}/RECORD +436 -433
  435. endoreg_db/import_files/processing/video_processing/video_cleanup_on_error.py +0 -119
  436. endoreg_db/management/commands/import_fallback_video.py +0 -203
  437. endoreg_db/management/commands/import_video.py +0 -422
  438. endoreg_db/management/commands/import_video_with_classification.py +0 -367
  439. endoreg_db/models/media/processing_history/processing_history.py +0 -96
  440. endoreg_db/serializers/label/__init__.py +0 -7
  441. endoreg_db/serializers/label_video_segment/_lvs_create.py +0 -149
  442. endoreg_db/serializers/label_video_segment/_lvs_update.py +0 -138
  443. endoreg_db/serializers/label_video_segment/_lvs_validate.py +0 -149
  444. endoreg_db/serializers/label_video_segment/label_video_segment_annotation.py +0 -99
  445. endoreg_db/serializers/label_video_segment/label_video_segment_update.py +0 -163
  446. endoreg_db/services/__old/pdf_import.py +0 -1487
  447. endoreg_db/services/__old/video_import.py +0 -1306
  448. endoreg_db/tasks/upload_tasks.py +0 -216
  449. endoreg_db/tasks/video_ingest.py +0 -161
  450. endoreg_db/tasks/video_processing_tasks.py +0 -327
  451. endoreg_db/views/misc/translation.py +0 -182
  452. {endoreg_db-0.8.8.9.dist-info → endoreg_db-0.8.9.10.dist-info}/WHEEL +0 -0
  453. {endoreg_db-0.8.8.9.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
- from rest_framework.permissions import IsAuthenticated
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, 'admin/start_examination.html') # Loads the simple HTML page
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(f"Fehler beim Erstellen des Patienten: {str(e)}")
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 = patient.patient_examinations.count() if hasattr(patient, 'patient_examinations') else 0
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() if hasattr(exam, 'patient_findings') else 0
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
- 'error': 'Patient cannot be deleted',
66
- 'reason': f'Patient has {examination_count} examination(s) and {finding_count} finding(s).',
67
- 'detail': 'Please remove all related examinations and findings before deleting the patient.'
68
- }, status=status.HTTP_409_CONFLICT)
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, 'is_real_person') and patient.is_real_person:
72
- return Response({
73
- 'error': 'Cannot delete real patient',
74
- 'reason': 'This patient is marked as a real person.',
75
- 'detail': 'Real patient data cannot be deleted for data protection reasons.'
76
- }, status=status.HTTP_403_FORBIDDEN)
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
- 'message': f'Patient "{patient_name}" has been successfully deleted.'
84
- }, status=status.HTTP_200_OK)
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
- 'error': 'Patient deletion failed',
89
- 'reason': 'Patient has protected related objects.',
90
- 'detail': str(e)
91
- }, status=status.HTTP_409_CONFLICT)
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=['get'])
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 = patient.patient_examinations.count() if hasattr(patient, 'patient_examinations') else 0
123
- examinations = patient.patient_examinations.all() if hasattr(patient, 'patient_examinations') else []
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, 'patient_findings') else 0
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, 'raw_pdf_files') else 0
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, 'is_real_person') and patient.is_real_person
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('This patient is marked as a real person')
172
+ warnings.append("This patient is marked as a real person")
144
173
  if examination_count > 0:
145
- warnings.append(f'Patient has {examination_count} examination(s)')
174
+ warnings.append(f"Patient has {examination_count} examination(s)")
146
175
  if finding_count > 0:
147
- warnings.append(f'Patient has {finding_count} finding(s)')
148
-
149
- return Response({
150
- 'can_delete': can_delete,
151
- 'is_real_person': is_real_person,
152
- 'related_objects': {
153
- 'examinations': examination_count,
154
- 'findings': finding_count,
155
- 'videos': video_count,
156
- 'reports': report_count
157
- },
158
- 'warnings': warnings
159
- })
160
-
161
- @action(detail=False, methods=['get'])
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=['post'], url_path='pseudonym')
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 generate_patient_pseudonym, validate_patient_for_pseudonym
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
- 'error': 'Missing required fields for pseudonym generation',
186
- 'missing_fields': missing_fields,
187
- 'detail': f'Please provide: {", ".join(missing_fields)}'
188
- }, status=status.HTTP_400_BAD_REQUEST)
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
- 'patient_id': patient.id,
195
- 'patient_hash': patient_hash,
196
- 'source': 'server',
197
- 'persisted': persisted,
198
- 'message': 'Pseudonym generated successfully'
199
- }, status=status.HTTP_200_OK)
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
- 'error': 'Pseudonym generation failed',
204
- 'detail': str(e)
205
- }, status=status.HTTP_400_BAD_REQUEST)
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
- 'error': 'Internal server error during pseudonym generation',
209
- 'detail': str(e)
210
- }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
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
- 'ExaminationCreateView',
8
- 'PatientExaminationDetailView',
9
- 'PatientExaminationListView',
10
- 'PatientExaminationViewSet'
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
- queryset = PatientExamination.objects.all().select_related('patient', 'examination')
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 PatientExamination.objects.select_related(
21
- 'patient', 'examination'
22
- ).prefetch_related(
23
- 'patient_findings', 'indications'
24
- ).order_by('-date_start', '-id')
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('id', flat=True)
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
- 'patient', 'examination'
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('first_name', 'last_name')
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=['get'])
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('name')
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=['get'])
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('limit', 10))
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=['get'])
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
- 'examination': PatientExaminationSerializer(examination).data,
80
- 'findings': examination.get_findings().count(),
81
- 'indications': examination.get_indications().count(),
82
- 'patient_age_at_examination': examination.get_patient_age_at_examination() if examination.date_start else None,
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
- {'error': f'Fehler beim Erstellen der Untersuchung: {str(e)}'},
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('partial', False)
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
- {'error': f'Fehler beim Aktualisieren der Untersuchung: {str(e)}'},
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
- {'error': 'PatientExamination nicht gefunden'},
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 = [{'id': f.id, 'name': str(f)} for f in findings]
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['message'] = 'Examination created successfully'
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
- 'error': 'Validation failed',
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
- 'error': 'Failed to create examination',
60
- 'message': str(e)
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
- queryset = PatientExamination.objects.select_related('patient', 'examination')
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
- {'error': 'Failed to retrieve examination'},
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['message'] = 'Examination updated successfully'
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
- 'error': 'Validation failed',
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
- 'error': 'Failed to update examination',
63
- 'message': str(e)
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
+ )