endoreg-db 0.5.3__py3-none-any.whl → 0.6.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of endoreg-db might be problematic. Click here for more details.
- endoreg_db/admin.py +90 -1
- endoreg_db/case_generator/case_generator.py +159 -0
- endoreg_db/case_generator/lab_sample_factory.py +33 -0
- endoreg_db/case_generator/utils.py +30 -0
- endoreg_db/data/__init__.py +50 -4
- endoreg_db/data/ai_model/data.yaml +7 -0
- endoreg_db/data/{label → ai_model_label}/label/data.yaml +27 -1
- endoreg_db/data/ai_model_label/label-set/data.yaml +21 -0
- endoreg_db/data/ai_model_meta/default_multilabel_classification.yaml +5 -0
- endoreg_db/data/ai_model_video_segmentation_label/base_segmentation.yaml +176 -0
- endoreg_db/data/ai_model_video_segmentation_labelset/data.yaml +20 -0
- endoreg_db/data/center/data.yaml +35 -5
- endoreg_db/data/contraindication/bleeding.yaml +11 -0
- endoreg_db/data/distribution/numeric/data.yaml +14 -0
- endoreg_db/data/endoscope/data.yaml +93 -0
- endoreg_db/data/examination_indication/endoscopy.yaml +8 -0
- endoreg_db/data/examination_indication_classification/endoscopy.yaml +8 -0
- endoreg_db/data/examination_indication_classification_choice/endoscopy.yaml +101 -0
- endoreg_db/data/finding/data.yaml +141 -0
- endoreg_db/data/finding_intervention/endoscopy.yaml +138 -0
- endoreg_db/data/finding_intervention_type/endoscopy.yaml +15 -0
- endoreg_db/data/finding_location_classification/colonoscopy.yaml +46 -0
- endoreg_db/data/finding_location_classification_choice/colonoscopy.yaml +240 -0
- endoreg_db/data/finding_morphology_classification/colonoscopy.yaml +48 -0
- endoreg_db/data/finding_morphology_classification_choice/colon_lesion_circularity_default.yaml +34 -0
- endoreg_db/data/finding_morphology_classification_choice/colon_lesion_nice.yaml +20 -0
- endoreg_db/data/finding_morphology_classification_choice/colon_lesion_paris.yaml +65 -0
- endoreg_db/data/finding_morphology_classification_choice/colon_lesion_planarity_default.yaml +56 -0
- endoreg_db/data/finding_morphology_classification_choice/colon_lesion_surface_intact_default.yaml +39 -0
- endoreg_db/data/finding_morphology_classification_choice/colonoscopy_size.yaml +57 -0
- endoreg_db/data/finding_morphology_classification_type/colonoscopy.yaml +79 -0
- endoreg_db/data/finding_type/data.yaml +30 -0
- endoreg_db/data/gender/data.yaml +17 -0
- endoreg_db/data/lab_value/cardiac_enzymes.yaml +7 -1
- endoreg_db/data/lab_value/coagulation.yaml +6 -1
- endoreg_db/data/lab_value/electrolytes.yaml +39 -1
- endoreg_db/data/lab_value/gastrointestinal_function.yaml +12 -0
- endoreg_db/data/lab_value/hematology.yaml +17 -2
- endoreg_db/data/lab_value/hormones.yaml +6 -0
- endoreg_db/data/lab_value/lipids.yaml +12 -3
- endoreg_db/data/lab_value/misc.yaml +5 -2
- endoreg_db/data/lab_value/renal_function.yaml +2 -1
- endoreg_db/data/lx_client_tag/base.yaml +54 -0
- endoreg_db/data/lx_client_type/base.yaml +30 -0
- endoreg_db/data/lx_permission/base.yaml +24 -0
- endoreg_db/data/lx_permission/endoreg.yaml +52 -0
- endoreg_db/data/medication_indication/anticoagulation.yaml +44 -49
- endoreg_db/data/names_first/first_names.yaml +51 -0
- endoreg_db/data/names_last/last_names.yaml +51 -0
- endoreg_db/data/network_device/data.yaml +30 -0
- endoreg_db/data/organ/data.yaml +29 -0
- endoreg_db/data/pdf_type/data.yaml +2 -1
- endoreg_db/data/report_reader_flag/ukw-examination-generic.yaml +4 -0
- endoreg_db/forms/__init__.py +3 -1
- endoreg_db/forms/examination_form.py +11 -0
- endoreg_db/forms/patient_finding_intervention_form.py +19 -0
- endoreg_db/forms/patient_form.py +26 -0
- endoreg_db/management/commands/__init__.py +0 -0
- endoreg_db/management/commands/load_ai_model_data.py +57 -23
- endoreg_db/management/commands/load_ai_model_label_data.py +59 -0
- endoreg_db/management/commands/load_base_db_data.py +160 -118
- endoreg_db/management/commands/{load_endoscope_type_data.py → load_contraindication_data.py} +3 -7
- endoreg_db/management/commands/load_disease_data.py +29 -7
- endoreg_db/management/commands/load_endoscope_data.py +68 -0
- endoreg_db/management/commands/load_examination_indication_data.py +65 -0
- endoreg_db/management/commands/load_finding_data.py +171 -0
- endoreg_db/management/commands/load_lab_value_data.py +3 -3
- endoreg_db/management/commands/load_lx_data.py +64 -0
- endoreg_db/management/commands/load_medication_data.py +83 -21
- endoreg_db/management/commands/load_name_data.py +37 -0
- endoreg_db/management/commands/{load_endoscopy_processor_data.py → load_organ_data.py} +7 -9
- endoreg_db/migrations/0001_initial.py +1206 -728
- endoreg_db/migrations/0002_alter_frame_image_alter_rawframe_image.py +23 -0
- endoreg_db/migrations/0003_alter_frame_image_alter_rawframe_image.py +23 -0
- endoreg_db/migrations/0004_alter_rawvideofile_file_alter_video_file.py +25 -0
- endoreg_db/migrations/0005_rawvideofile_frame_count_and_more.py +33 -0
- endoreg_db/migrations/0006_frame_extracted_rawframe_extracted.py +23 -0
- endoreg_db/migrations/0007_rename_pseudo_patient_video_patient_and_more.py +24 -0
- endoreg_db/migrations/0008_remove_reportfile_patient_examination_and_more.py +48 -0
- endoreg_db/models/__init__.py +331 -28
- endoreg_db/models/ai_model/__init__.py +1 -0
- endoreg_db/models/ai_model/ai_model.py +103 -0
- endoreg_db/models/ai_model/lightning/__init__.py +3 -0
- endoreg_db/models/ai_model/lightning/inference_dataset.py +53 -0
- endoreg_db/models/ai_model/lightning/multilabel_classification_net.py +155 -0
- endoreg_db/models/ai_model/lightning/postprocess.py +53 -0
- endoreg_db/models/ai_model/lightning/predict.py +172 -0
- endoreg_db/models/ai_model/lightning/prediction_visualizer.py +55 -0
- endoreg_db/models/ai_model/lightning/preprocess.py +68 -0
- endoreg_db/models/ai_model/lightning/run_visualizer.py +21 -0
- endoreg_db/models/ai_model/model_meta.py +232 -6
- endoreg_db/models/ai_model/model_type.py +13 -3
- endoreg_db/models/annotation/__init__.py +31 -2
- endoreg_db/models/annotation/anonymized_image_annotation.py +73 -18
- endoreg_db/models/annotation/binary_classification_annotation_task.py +94 -57
- endoreg_db/models/annotation/image_classification.py +73 -14
- endoreg_db/models/annotation/video_segmentation_annotation.py +52 -0
- endoreg_db/models/annotation/video_segmentation_labelset.py +20 -0
- endoreg_db/models/case/__init__.py +1 -0
- endoreg_db/models/{persons/patient/case → case}/case.py +4 -0
- endoreg_db/models/case_template/__init__.py +10 -1
- endoreg_db/models/case_template/case_template.py +57 -13
- endoreg_db/models/case_template/case_template_rule.py +5 -5
- endoreg_db/models/case_template/case_template_rule_value.py +19 -4
- endoreg_db/models/center/__init__.py +7 -0
- endoreg_db/models/center/center.py +31 -5
- endoreg_db/models/center/center_product.py +0 -1
- endoreg_db/models/center/center_resource.py +16 -2
- endoreg_db/models/center/center_waste.py +6 -1
- endoreg_db/models/contraindication/__init__.py +21 -0
- endoreg_db/models/data_file/__init__.py +38 -5
- endoreg_db/models/data_file/base_classes/__init__.py +6 -1
- endoreg_db/models/data_file/base_classes/abstract_frame.py +64 -15
- endoreg_db/models/data_file/base_classes/abstract_pdf.py +136 -0
- endoreg_db/models/data_file/base_classes/abstract_video.py +744 -138
- endoreg_db/models/data_file/base_classes/frame_helpers.py +17 -0
- endoreg_db/models/data_file/base_classes/prepare_bulk_frames.py +19 -0
- endoreg_db/models/data_file/base_classes/utils.py +80 -0
- endoreg_db/models/data_file/frame.py +22 -38
- endoreg_db/models/data_file/import_classes/__init__.py +4 -18
- endoreg_db/models/data_file/import_classes/raw_pdf.py +162 -90
- endoreg_db/models/data_file/import_classes/raw_video.py +239 -294
- endoreg_db/models/data_file/metadata/__init__.py +10 -0
- endoreg_db/models/data_file/metadata/pdf_meta.py +4 -0
- endoreg_db/models/data_file/metadata/sensitive_meta.py +265 -6
- endoreg_db/models/data_file/metadata/video_meta.py +116 -50
- endoreg_db/models/data_file/report_file.py +30 -63
- endoreg_db/models/data_file/video/__init__.py +6 -2
- endoreg_db/models/data_file/video/video.py +187 -16
- endoreg_db/models/data_file/video_segment.py +162 -55
- endoreg_db/models/disease.py +25 -2
- endoreg_db/models/emission/__init__.py +5 -1
- endoreg_db/models/emission/emission_factor.py +71 -6
- endoreg_db/models/event.py +51 -0
- endoreg_db/models/examination/__init__.py +6 -1
- endoreg_db/models/examination/examination.py +53 -12
- endoreg_db/models/examination/examination_indication.py +170 -0
- endoreg_db/models/examination/examination_time.py +31 -5
- endoreg_db/models/examination/examination_time_type.py +28 -4
- endoreg_db/models/examination/examination_type.py +28 -6
- endoreg_db/models/finding/__init__.py +11 -0
- endoreg_db/models/finding/finding.py +75 -0
- endoreg_db/models/finding/finding_intervention.py +60 -0
- endoreg_db/models/finding/finding_location_classification.py +94 -0
- endoreg_db/models/finding/finding_morphology_classification.py +89 -0
- endoreg_db/models/finding/finding_type.py +22 -0
- endoreg_db/models/hardware/endoscope.py +16 -0
- endoreg_db/models/hardware/endoscopy_processor.py +31 -19
- endoreg_db/models/label/label.py +35 -7
- endoreg_db/models/laboratory/lab_value.py +12 -3
- endoreg_db/models/logging/__init__.py +8 -1
- endoreg_db/models/lx/__init__.py +4 -0
- endoreg_db/models/lx/client.py +57 -0
- endoreg_db/models/lx/identity.py +34 -0
- endoreg_db/models/lx/permission.py +18 -0
- endoreg_db/models/lx/user.py +16 -0
- endoreg_db/models/medication/__init__.py +19 -1
- endoreg_db/models/medication/medication.py +7 -122
- endoreg_db/models/medication/medication_indication.py +50 -0
- endoreg_db/models/medication/medication_indication_type.py +34 -0
- endoreg_db/models/medication/medication_intake_time.py +26 -0
- endoreg_db/models/medication/medication_schedule.py +37 -0
- endoreg_db/models/network/__init__.py +7 -1
- endoreg_db/models/network/network_device.py +13 -8
- endoreg_db/models/organ/__init__.py +38 -0
- endoreg_db/models/other/__init__.py +19 -1
- endoreg_db/models/other/distribution/__init__.py +44 -0
- endoreg_db/models/other/distribution/base_value_distribution.py +20 -0
- endoreg_db/models/other/distribution/date_value_distribution.py +91 -0
- endoreg_db/models/other/distribution/multiple_categorical_value_distribution.py +32 -0
- endoreg_db/models/other/distribution/numeric_value_distribution.py +97 -0
- endoreg_db/models/other/distribution/single_categorical_value_distribution.py +22 -0
- endoreg_db/models/other/distribution.py +1 -211
- endoreg_db/models/other/material.py +4 -0
- endoreg_db/models/other/transport_route.py +2 -1
- endoreg_db/models/patient/__init__.py +24 -0
- endoreg_db/models/patient/patient_examination.py +182 -0
- endoreg_db/models/patient/patient_finding.py +143 -0
- endoreg_db/models/patient/patient_finding_intervention.py +26 -0
- endoreg_db/models/patient/patient_finding_location.py +120 -0
- endoreg_db/models/patient/patient_finding_morphology.py +166 -0
- endoreg_db/models/persons/__init__.py +29 -2
- endoreg_db/models/persons/examiner/examiner.py +48 -4
- endoreg_db/models/persons/patient/__init__.py +1 -1
- endoreg_db/models/persons/patient/patient.py +227 -54
- endoreg_db/models/persons/patient/patient_disease.py +6 -0
- endoreg_db/models/persons/patient/patient_event.py +31 -1
- endoreg_db/models/persons/patient/patient_examination_indication.py +32 -0
- endoreg_db/models/persons/patient/patient_lab_sample.py +4 -2
- endoreg_db/models/persons/patient/patient_lab_value.py +37 -16
- endoreg_db/models/persons/patient/patient_medication.py +27 -12
- endoreg_db/models/persons/patient/patient_medication_schedule.py +62 -2
- endoreg_db/models/prediction/__init__.py +7 -1
- endoreg_db/models/prediction/image_classification.py +20 -6
- endoreg_db/models/prediction/video_prediction_meta.py +151 -89
- endoreg_db/models/product/__init__.py +10 -1
- endoreg_db/models/product/product.py +15 -2
- endoreg_db/models/product/product_group.py +8 -0
- endoreg_db/models/product/product_material.py +4 -0
- endoreg_db/models/product/product_weight.py +12 -0
- endoreg_db/models/product/reference_product.py +19 -3
- endoreg_db/models/quiz/__init__.py +8 -1
- endoreg_db/models/report_reader/__init__.py +6 -1
- endoreg_db/serializers/__init__.py +1 -1
- endoreg_db/serializers/annotation.py +2 -5
- endoreg_db/serializers/frame.py +1 -5
- endoreg_db/serializers/patient.py +26 -3
- endoreg_db/serializers/prediction.py +2 -7
- endoreg_db/serializers/raw_video_meta_validation.py +13 -0
- endoreg_db/serializers/video.py +6 -13
- endoreg_db/serializers/video_segmentation.py +492 -0
- endoreg_db/templates/admin/patient_finding_intervention.html +253 -0
- endoreg_db/templates/admin/start_examination.html +12 -0
- endoreg_db/templates/timeline.html +176 -0
- endoreg_db/urls.py +173 -0
- endoreg_db/utils/__init__.py +36 -1
- endoreg_db/utils/dataloader.py +45 -19
- endoreg_db/utils/dates.py +39 -0
- endoreg_db/utils/hashs.py +122 -4
- endoreg_db/utils/names.py +74 -0
- endoreg_db/utils/parse_and_generate_yaml.py +46 -0
- endoreg_db/utils/pydantic_models/__init__.py +6 -0
- endoreg_db/utils/pydantic_models/db_config.py +57 -0
- endoreg_db/utils/validate_endo_roi.py +19 -0
- endoreg_db/utils/validate_subcategory_dict.py +91 -0
- endoreg_db/utils/video/__init__.py +13 -0
- endoreg_db/utils/video/extract_frames.py +121 -0
- endoreg_db/utils/video/transcode_videofile.py +111 -0
- endoreg_db/views/__init__.py +2 -0
- endoreg_db/views/csrf.py +7 -0
- endoreg_db/views/patient_views.py +90 -0
- endoreg_db/views/raw_video_meta_validation_views.py +38 -0
- endoreg_db/views/report_views.py +96 -0
- endoreg_db/views/video_segmentation_views.py +149 -0
- endoreg_db/views/views_for_timeline.py +46 -0
- endoreg_db/views.py +0 -3
- endoreg_db-0.6.1.dist-info/METADATA +151 -0
- endoreg_db-0.6.1.dist-info/RECORD +420 -0
- {endoreg_db-0.5.3.dist-info → endoreg_db-0.6.1.dist-info}/WHEEL +1 -1
- endoreg_db/data/active_model/data.yaml +0 -3
- endoreg_db/data/label/label-set/data.yaml +0 -18
- endoreg_db/management/commands/delete_legacy_images.py +0 -19
- endoreg_db/management/commands/delete_legacy_videos.py +0 -17
- endoreg_db/management/commands/extract_legacy_video_frames.py +0 -18
- endoreg_db/management/commands/import_legacy_images.py +0 -94
- endoreg_db/management/commands/import_legacy_videos.py +0 -76
- endoreg_db/management/commands/load_label_data.py +0 -67
- endoreg_db/migrations/0002_anonymizedimagelabel_anonymousimageannotation_and_more.py +0 -55
- endoreg_db/migrations/0003_anonymousimageannotation_original_image_url_and_more.py +0 -39
- endoreg_db/migrations/0004_alter_rawpdffile_file.py +0 -20
- endoreg_db/migrations/0005_uploadedfile_alter_rawpdffile_file_anonymizedfile.py +0 -40
- endoreg_db/migrations/0006_alter_rawpdffile_file.py +0 -20
- endoreg_db/migrations/0007_networkdevicelogentry_datetime_and_more.py +0 -43
- endoreg_db/migrations/0008_networkdevicelogentry_aglnet_ip_and_more.py +0 -28
- endoreg_db/migrations/0009_alter_networkdevicelogentry_vpn_service_status.py +0 -18
- endoreg_db/migrations/0010_remove_networkdevicelogentry_hostname.py +0 -17
- endoreg_db/models/legacy_data/__init__.py +0 -3
- endoreg_db/models/legacy_data/image.py +0 -34
- endoreg_db/models/patient_examination/__init__.py +0 -35
- endoreg_db/utils/video_metadata.py +0 -87
- endoreg_db-0.5.3.dist-info/METADATA +0 -28
- endoreg_db-0.5.3.dist-info/RECORD +0 -319
- /endoreg_db/{models/persons/patient/case → case_generator}/__init__.py +0 -0
- /endoreg_db/data/{label → ai_model_label}/label-type/data.yaml +0 -0
- /endoreg_db/data/{model_type → ai_model_type}/data.yaml +0 -0
- /endoreg_db/{data/distribution/numeric/.init → management/__init__.py} +0 -0
- /endoreg_db/management/commands/{load_report_reader_flag.py → load_report_reader_flag_data.py} +0 -0
- {endoreg_db-0.5.3.dist-info → endoreg_db-0.6.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
from ..person import Person
|
|
2
2
|
from django import forms
|
|
3
3
|
from django.forms import DateInput
|
|
4
|
-
from
|
|
5
|
-
from ...patient_examination import PatientExamination
|
|
4
|
+
from ...patient import PatientExamination
|
|
6
5
|
from ...data_file import ReportFile
|
|
7
6
|
from django.db import models
|
|
8
7
|
from faker import Faker
|
|
9
8
|
import random
|
|
10
9
|
from datetime import datetime
|
|
10
|
+
from icecream import ic
|
|
11
|
+
from typing import TYPE_CHECKING
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from endoreg_db.models import Center, Gender
|
|
15
|
+
|
|
11
16
|
|
|
12
17
|
class Patient(Person):
|
|
13
18
|
"""
|
|
@@ -22,33 +27,196 @@ class Patient(Person):
|
|
|
22
27
|
phone (str): The phone number of the patient.
|
|
23
28
|
|
|
24
29
|
"""
|
|
25
|
-
|
|
26
|
-
|
|
30
|
+
|
|
31
|
+
# -----gc-08-dev--changings---
|
|
32
|
+
first_name = models.CharField(max_length=100)
|
|
33
|
+
last_name = models.CharField(max_length=100)
|
|
34
|
+
dob = models.DateField(null=True, blank=True)
|
|
35
|
+
gender = models.ForeignKey(
|
|
36
|
+
"Gender", on_delete=models.SET_NULL, null=True, blank=True
|
|
37
|
+
)
|
|
38
|
+
center = models.ForeignKey(
|
|
39
|
+
"Center", on_delete=models.SET_NULL, null=True, blank=True
|
|
40
|
+
)
|
|
41
|
+
patient_hash = models.CharField(max_length=255, blank=True, null=True)
|
|
27
42
|
|
|
28
43
|
def __str__(self):
|
|
29
|
-
return self.first_name
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
44
|
+
return f"{self.first_name} {self.last_name} ({self.dob})"
|
|
45
|
+
|
|
46
|
+
@classmethod
|
|
47
|
+
def get_or_create_pseudo_patient_by_hash(
|
|
48
|
+
cls,
|
|
49
|
+
patient_hash: str,
|
|
50
|
+
center: "Center" = None,
|
|
51
|
+
gender: "Gender" = None,
|
|
52
|
+
birth_month: int = None,
|
|
53
|
+
birth_year: int = None,
|
|
54
|
+
):
|
|
55
|
+
from endoreg_db.utils import random_day_by_year, create_mock_patient_name
|
|
56
|
+
|
|
57
|
+
created = False
|
|
58
|
+
|
|
59
|
+
existing_pathient = cls.objects.filter(patient_hash=patient_hash).first()
|
|
60
|
+
if existing_pathient:
|
|
61
|
+
ic(f"Patient with hash {patient_hash} already exists")
|
|
62
|
+
ic(f"Returning existing patient: {existing_pathient}")
|
|
63
|
+
return existing_pathient, created
|
|
64
|
+
|
|
65
|
+
# If no patient with the given hash exists, create a new pseudo patient
|
|
66
|
+
assert center, "Center must be provided to create a new pseudo patient"
|
|
67
|
+
assert gender, "Gender must be provided to create a new pseudo patient"
|
|
68
|
+
assert birth_month, (
|
|
69
|
+
"Birth month must be provided to create a new pseudo patient"
|
|
70
|
+
)
|
|
71
|
+
assert birth_year, "Birth year must be provided to create a new pseudo patient"
|
|
72
|
+
|
|
73
|
+
pseudo_dob = random_day_by_year(birth_year)
|
|
74
|
+
gender_name = gender.name
|
|
75
|
+
first_name, last_name = create_mock_patient_name(gender_name)
|
|
76
|
+
|
|
77
|
+
ic(f"Creating pseudo patient with hash {patient_hash}")
|
|
78
|
+
ic(f"Generated name: {first_name} {last_name}")
|
|
79
|
+
|
|
80
|
+
patient = cls.objects.create(
|
|
81
|
+
first_name=first_name,
|
|
82
|
+
last_name=last_name,
|
|
83
|
+
dob=pseudo_dob,
|
|
84
|
+
patient_hash=patient_hash,
|
|
85
|
+
is_real_person=False,
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
patient.save()
|
|
89
|
+
created = True
|
|
90
|
+
|
|
91
|
+
return patient, created
|
|
92
|
+
|
|
93
|
+
def export_patient_examinations(self):
|
|
94
|
+
"""
|
|
95
|
+
Get all associated PatientExaminations, ReportFiles, and Videos for the patient.
|
|
96
|
+
"""
|
|
97
|
+
from endoreg_db.models import PatientExamination, ReportFile, Video
|
|
98
|
+
|
|
99
|
+
patient_examinations = PatientExamination.objects.filter(patient=self)
|
|
100
|
+
report_files, videos = [], []
|
|
101
|
+
for patient_examination in patient_examinations:
|
|
102
|
+
rr = patient_examination.reportfile_set.all()
|
|
103
|
+
vv = patient_examination.videos.all()
|
|
104
|
+
|
|
105
|
+
report_files.extend(rr)
|
|
106
|
+
videos.extend(vv)
|
|
107
|
+
|
|
108
|
+
return patient_examinations, report_files, videos
|
|
109
|
+
|
|
110
|
+
def get_dob(self) -> datetime.date:
|
|
111
|
+
dob: datetime.date = self.dob
|
|
112
|
+
return dob
|
|
113
|
+
|
|
114
|
+
def get_unmatched_report_files(
|
|
115
|
+
self,
|
|
116
|
+
): # field: self.report_files; filter: report_file.patient_examination = None
|
|
117
|
+
"""Returns all report files for this patient that are not matched to a patient examination."""
|
|
33
118
|
|
|
34
119
|
return self.reportfile_set.filter(patient_examination=None)
|
|
35
120
|
|
|
36
|
-
def get_unmatched_video_files(
|
|
37
|
-
|
|
121
|
+
def get_unmatched_video_files(
|
|
122
|
+
self,
|
|
123
|
+
): # field: self.videos; filter: video.patient_examination = None
|
|
124
|
+
"""Returns all video files for this patient that are not matched to a patient examination."""
|
|
38
125
|
return self.videos.filter(patient_examination=None)
|
|
39
126
|
|
|
40
|
-
def get_patient_examinations(self):
|
|
41
|
-
|
|
42
|
-
return self.patient_examinations.order_by(
|
|
43
|
-
|
|
44
|
-
def
|
|
45
|
-
|
|
127
|
+
def get_patient_examinations(self): # field: self.patient_examinations
|
|
128
|
+
"""Returns all patient examinations for this patient ordered by date (most recent is first)."""
|
|
129
|
+
return self.patient_examinations.order_by("-date")
|
|
130
|
+
|
|
131
|
+
def create_examination(
|
|
132
|
+
self,
|
|
133
|
+
examination_name_str: str = None,
|
|
134
|
+
date_start: datetime = None,
|
|
135
|
+
date_end: datetime = None,
|
|
136
|
+
):
|
|
137
|
+
"""Creates a patient examination for this patient."""
|
|
138
|
+
|
|
139
|
+
if examination_name_str:
|
|
140
|
+
from endoreg_db.models import Examination
|
|
141
|
+
|
|
142
|
+
examination = Examination.objects.get(name=examination_name_str)
|
|
143
|
+
patient_examination = PatientExamination(
|
|
144
|
+
patient=self,
|
|
145
|
+
examination=examination,
|
|
146
|
+
date_start=date_start,
|
|
147
|
+
date_end=date_end,
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
else:
|
|
151
|
+
patient_examination = PatientExamination(
|
|
152
|
+
patient=self, date_start=date_start, date_end=date_end
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
patient_examination.save()
|
|
156
|
+
|
|
157
|
+
return patient_examination
|
|
158
|
+
|
|
159
|
+
def create_examination_by_indication(
|
|
160
|
+
self, indication, date_start: datetime = None, date_end: datetime = None
|
|
161
|
+
):
|
|
162
|
+
from endoreg_db.models import (
|
|
163
|
+
ExaminationIndication,
|
|
164
|
+
Examination,
|
|
165
|
+
PatientExaminationIndication,
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
assert isinstance(indication, ExaminationIndication)
|
|
169
|
+
|
|
170
|
+
examination = indication.get_examination()
|
|
171
|
+
|
|
172
|
+
assert isinstance(examination, Examination)
|
|
173
|
+
|
|
174
|
+
patient_examination = PatientExamination.objects.create(
|
|
175
|
+
patient=self,
|
|
176
|
+
examination=examination,
|
|
177
|
+
date_start=date_start,
|
|
178
|
+
date_end=date_end,
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
patient_examination.save()
|
|
182
|
+
|
|
183
|
+
patient_examination_indication = PatientExaminationIndication.objects.create(
|
|
184
|
+
patient_examination=patient_examination, examination_indication=indication
|
|
185
|
+
)
|
|
186
|
+
patient_examination_indication.save()
|
|
187
|
+
|
|
188
|
+
return patient_examination, patient_examination_indication
|
|
189
|
+
|
|
190
|
+
def create_event(
|
|
191
|
+
self,
|
|
192
|
+
event_name_str: str,
|
|
193
|
+
date_start: datetime = None,
|
|
194
|
+
date_end: datetime = None,
|
|
195
|
+
description: str = None,
|
|
196
|
+
):
|
|
197
|
+
from endoreg_db.models import Event, PatientEvent
|
|
198
|
+
|
|
199
|
+
event = Event.objects.get(name=event_name_str)
|
|
200
|
+
|
|
201
|
+
if not date_start:
|
|
202
|
+
date_start = datetime.now()
|
|
203
|
+
|
|
204
|
+
patient_event = PatientEvent.objects.create(
|
|
205
|
+
patient=self,
|
|
206
|
+
event=event,
|
|
207
|
+
date_start=date_start,
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
return patient_event
|
|
211
|
+
|
|
212
|
+
def create_examination_by_report_file(self, report_file: ReportFile):
|
|
213
|
+
"""Creates a patient examination for this patient based on the given report file."""
|
|
46
214
|
patient_examination = PatientExamination(patient=self, report_file=report_file)
|
|
47
215
|
patient_examination.save()
|
|
48
216
|
return patient_examination
|
|
49
|
-
|
|
217
|
+
|
|
50
218
|
@classmethod
|
|
51
|
-
def get_random_gender(
|
|
219
|
+
def get_random_gender(cls, p_male=0.5, p_female=0.5):
|
|
52
220
|
"""
|
|
53
221
|
Get a Gender object by name (male, female) from the database with given probability.
|
|
54
222
|
|
|
@@ -57,33 +225,28 @@ class Patient(Person):
|
|
|
57
225
|
:return: Gender object selected based on given probabilities.
|
|
58
226
|
"""
|
|
59
227
|
from endoreg_db.models import Gender
|
|
60
|
-
|
|
228
|
+
|
|
61
229
|
# Extract names and probabilities
|
|
62
230
|
gender_names = ["male", "female"]
|
|
63
|
-
probabilities = [
|
|
64
|
-
|
|
231
|
+
probabilities = [p_male, p_female]
|
|
232
|
+
|
|
65
233
|
# Debug: print the names and probabilities
|
|
66
|
-
print(f"Gender names: {gender_names}")
|
|
67
|
-
print(f"Probabilities: {probabilities}")
|
|
68
|
-
|
|
234
|
+
# print(f"Gender names: {gender_names}")
|
|
235
|
+
# print(f"Probabilities: {probabilities}")
|
|
236
|
+
|
|
69
237
|
# Select a gender based on the given probabilities
|
|
70
238
|
selected_gender = random.choices(gender_names, probabilities)[0]
|
|
71
239
|
# Debug: print the selected gender
|
|
72
|
-
print(f"Selected gender: {selected_gender}")
|
|
73
|
-
|
|
240
|
+
# print(f"Selected gender: {selected_gender}")
|
|
241
|
+
|
|
74
242
|
# Fetch the corresponding Gender object from the database
|
|
75
243
|
gender_obj = Gender.objects.get(name=selected_gender)
|
|
76
|
-
|
|
77
|
-
return gender_obj
|
|
78
244
|
|
|
245
|
+
return gender_obj
|
|
79
246
|
|
|
80
247
|
@classmethod
|
|
81
|
-
def get_random_age(
|
|
82
|
-
|
|
83
|
-
max_age = 90,
|
|
84
|
-
mean_age = 65,
|
|
85
|
-
std_age = 10,
|
|
86
|
-
distribution = "normal"
|
|
248
|
+
def get_random_age(
|
|
249
|
+
cls, min_age=55, max_age=90, mean_age=65, std_age=10, distribution="normal"
|
|
87
250
|
):
|
|
88
251
|
"""
|
|
89
252
|
Get a random age based on the given distribution.
|
|
@@ -99,11 +262,11 @@ class Patient(Person):
|
|
|
99
262
|
age = int(random.normalvariate(mean_age, std_age))
|
|
100
263
|
else:
|
|
101
264
|
age = int(random.uniform(min_age, max_age))
|
|
102
|
-
|
|
265
|
+
|
|
103
266
|
return age
|
|
104
|
-
|
|
267
|
+
|
|
105
268
|
@classmethod
|
|
106
|
-
def get_dob_from_age(
|
|
269
|
+
def get_dob_from_age(cls, age, current_date=None):
|
|
107
270
|
"""
|
|
108
271
|
Get a date of birth based on the given age and current date.
|
|
109
272
|
|
|
@@ -119,24 +282,24 @@ class Patient(Person):
|
|
|
119
282
|
# randomize the day and month by adding a random number of days (0-364) to the date
|
|
120
283
|
|
|
121
284
|
return dob
|
|
122
|
-
|
|
285
|
+
|
|
123
286
|
@classmethod
|
|
124
|
-
def get_random_name_for_gender(
|
|
287
|
+
def get_random_name_for_gender(cls, gender_obj, locale="de_DE"):
|
|
125
288
|
gender = gender_obj.name
|
|
126
289
|
fake = Faker(locale)
|
|
127
|
-
|
|
290
|
+
|
|
128
291
|
if gender == "male":
|
|
129
292
|
first_name = fake.first_name_male()
|
|
130
293
|
last_name = fake.last_name_male()
|
|
131
294
|
|
|
132
|
-
else:
|
|
295
|
+
else:
|
|
133
296
|
first_name = fake.first_name_female()
|
|
134
297
|
last_name = fake.last_name_female()
|
|
135
298
|
|
|
136
299
|
return last_name, first_name
|
|
137
|
-
|
|
300
|
+
|
|
138
301
|
@classmethod
|
|
139
|
-
def create_generic(
|
|
302
|
+
def create_generic(cls, center="gplay_case_generator"):
|
|
140
303
|
"""
|
|
141
304
|
Create a generic patient with random attributes.
|
|
142
305
|
|
|
@@ -144,6 +307,7 @@ class Patient(Person):
|
|
|
144
307
|
:return: The created patient.
|
|
145
308
|
"""
|
|
146
309
|
from endoreg_db.models import Center
|
|
310
|
+
|
|
147
311
|
gender = Patient.get_random_gender()
|
|
148
312
|
last_name, first_name = Patient.get_random_name_for_gender(gender)
|
|
149
313
|
|
|
@@ -155,7 +319,8 @@ class Patient(Person):
|
|
|
155
319
|
patient = Patient.objects.create(
|
|
156
320
|
first_name=first_name,
|
|
157
321
|
last_name=last_name,
|
|
158
|
-
dob=dob
|
|
322
|
+
dob=dob,
|
|
323
|
+
gender=gender,
|
|
159
324
|
)
|
|
160
325
|
patient.save()
|
|
161
326
|
return patient
|
|
@@ -169,7 +334,11 @@ class Patient(Person):
|
|
|
169
334
|
# calculate correct age based on current date including day and month
|
|
170
335
|
current_date = datetime.now()
|
|
171
336
|
dob = self.dob
|
|
172
|
-
age =
|
|
337
|
+
age = (
|
|
338
|
+
current_date.year
|
|
339
|
+
- dob.year
|
|
340
|
+
- ((current_date.month, current_date.day) < (dob.month, dob.day))
|
|
341
|
+
)
|
|
173
342
|
return age
|
|
174
343
|
|
|
175
344
|
def create_lab_sample(self, sample_type="generic", date=None, save=True):
|
|
@@ -182,19 +351,22 @@ class Patient(Person):
|
|
|
182
351
|
:return: The created lab sample.
|
|
183
352
|
"""
|
|
184
353
|
from endoreg_db.models import PatientLabSample, PatientLabSampleType
|
|
354
|
+
|
|
185
355
|
if date is None:
|
|
186
356
|
date = datetime.now()
|
|
187
357
|
|
|
188
358
|
if isinstance(sample_type, str):
|
|
189
359
|
sample_type = PatientLabSampleType.objects.get(name=sample_type)
|
|
190
|
-
assert sample_type is not None,
|
|
360
|
+
assert sample_type is not None, (
|
|
361
|
+
f"Sample type with name '{sample_type}' not found."
|
|
362
|
+
) #
|
|
191
363
|
elif not isinstance(sample_type, PatientLabSampleType):
|
|
192
|
-
raise ValueError(
|
|
193
|
-
|
|
364
|
+
raise ValueError(
|
|
365
|
+
"Sample type must be either a string or a PatientLabSampleType object."
|
|
366
|
+
)
|
|
367
|
+
|
|
194
368
|
patient_lab_sample = PatientLabSample.objects.create(
|
|
195
|
-
patient=self,
|
|
196
|
-
sample_type=sample_type,
|
|
197
|
-
date=date
|
|
369
|
+
patient=self, sample_type=sample_type, date=date
|
|
198
370
|
)
|
|
199
371
|
|
|
200
372
|
if save:
|
|
@@ -202,15 +374,16 @@ class Patient(Person):
|
|
|
202
374
|
|
|
203
375
|
return patient_lab_sample
|
|
204
376
|
|
|
377
|
+
|
|
205
378
|
class PatientForm(forms.ModelForm):
|
|
206
379
|
class Meta:
|
|
207
380
|
model = Patient
|
|
208
|
-
fields =
|
|
381
|
+
fields = "__all__"
|
|
209
382
|
widgets = {
|
|
210
|
-
|
|
383
|
+
"dob": DateInput(attrs={"type": "date"}),
|
|
211
384
|
}
|
|
212
385
|
|
|
213
386
|
def __init__(self, *args, **kwargs):
|
|
214
387
|
super().__init__(*args, **kwargs)
|
|
215
388
|
for field in self.fields.values():
|
|
216
|
-
field.widget.attrs[
|
|
389
|
+
field.widget.attrs["class"] = "form-control"
|
|
@@ -8,9 +8,15 @@ class PatientDisease(models.Model):
|
|
|
8
8
|
classification_choices = models.ManyToManyField("DiseaseClassificationChoice")
|
|
9
9
|
start_date = models.DateField(blank=True, null=True)
|
|
10
10
|
end_date = models.DateField(blank=True, null=True)
|
|
11
|
+
numerical_descriptors = models.JSONField(default=dict)
|
|
12
|
+
subcategories = models.JSONField(default=dict)
|
|
11
13
|
|
|
12
14
|
last_update = models.DateTimeField(auto_now=True)
|
|
13
15
|
|
|
14
16
|
def __str__(self):
|
|
15
17
|
return f"{self.patient} - {self.disease}"
|
|
16
18
|
|
|
19
|
+
class Meta:
|
|
20
|
+
# unique_together = ('patient', 'disease', 'start_date')
|
|
21
|
+
verbose_name = 'Patient Disease'
|
|
22
|
+
verbose_name_plural = 'Patient Diseases'
|
|
@@ -15,8 +15,38 @@ class PatientEvent(models.Model):
|
|
|
15
15
|
date_start = models.DateField()
|
|
16
16
|
date_end = models.DateField(blank=True, null=True)
|
|
17
17
|
description = models.TextField(blank=True, null=True)
|
|
18
|
+
classification_choice = models.ForeignKey(
|
|
19
|
+
"EventClassificationChoice", on_delete=models.CASCADE, blank=True, null=True
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
subcategories = models.JSONField(default=dict)
|
|
23
|
+
numerical_descriptors = models.JSONField(default=dict)
|
|
18
24
|
|
|
19
25
|
last_update = models.DateTimeField(auto_now=True)
|
|
20
26
|
|
|
21
27
|
def __str__(self):
|
|
22
|
-
return str(self.date_start) + ": " + self.event
|
|
28
|
+
return str(self.date_start) + ": " + self.event.name
|
|
29
|
+
|
|
30
|
+
def set_subcategories_from_classification_choice(self):
|
|
31
|
+
"""
|
|
32
|
+
Sets the subcategories for this event from the classification choice.
|
|
33
|
+
"""
|
|
34
|
+
from endoreg_db.models import EventClassificationChoice
|
|
35
|
+
if self.classification_choice:
|
|
36
|
+
self.classification_choice:EventClassificationChoice
|
|
37
|
+
self.subcategories = self.classification_choice.subcategories
|
|
38
|
+
self.save()
|
|
39
|
+
|
|
40
|
+
return self.subcategories
|
|
41
|
+
|
|
42
|
+
def set_numerical_descriptors_from_classification_choice(self):
|
|
43
|
+
"""
|
|
44
|
+
Sets the numerical descriptors for this event from the classification choice.
|
|
45
|
+
"""
|
|
46
|
+
from endoreg_db.models import EventClassificationChoice
|
|
47
|
+
if self.classification_choice:
|
|
48
|
+
self.classification_choice:EventClassificationChoice
|
|
49
|
+
self.numerical_descriptors = self.classification_choice.numerical_descriptors
|
|
50
|
+
self.save()
|
|
51
|
+
|
|
52
|
+
return self.numerical_descriptors
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from django.db import models
|
|
2
|
+
|
|
3
|
+
class PatientExaminationIndication(models.Model):
|
|
4
|
+
'''A model to store the indication for a patient examination.'''
|
|
5
|
+
patient_examination = models.ForeignKey('PatientExamination', on_delete=models.CASCADE, related_name='indications')
|
|
6
|
+
examination_indication = models.ForeignKey('ExaminationIndication', on_delete=models.CASCADE)
|
|
7
|
+
indication_choice = models.ForeignKey('ExaminationIndicationClassificationChoice', on_delete=models.CASCADE, blank=True, null=True)
|
|
8
|
+
|
|
9
|
+
def __str__(self):
|
|
10
|
+
return f"{self.patient_examination} - {self.examination_indication}"
|
|
11
|
+
|
|
12
|
+
def get_examination(self):
|
|
13
|
+
from endoreg_db.models import Examination
|
|
14
|
+
pe = self.get_patient_examination()
|
|
15
|
+
e: Examination = pe.examination
|
|
16
|
+
|
|
17
|
+
return e
|
|
18
|
+
|
|
19
|
+
def get_patient_examination(self):
|
|
20
|
+
from endoreg_db.models import PatientExamination
|
|
21
|
+
pe: PatientExamination = self.patient_examination
|
|
22
|
+
return pe
|
|
23
|
+
|
|
24
|
+
def get_choices(self):
|
|
25
|
+
from endoreg_db.models import (
|
|
26
|
+
ExaminationIndicationClassificationChoice,
|
|
27
|
+
ExaminationIndication
|
|
28
|
+
)
|
|
29
|
+
examination_indication:ExaminationIndication = self.examination_indication
|
|
30
|
+
choices = [_ for _ in examination_indication.get_choices()]
|
|
31
|
+
return choices
|
|
32
|
+
|
|
@@ -58,10 +58,12 @@ class PatientLabSample(models.Model):
|
|
|
58
58
|
date = models.DateTimeField()
|
|
59
59
|
|
|
60
60
|
def __str__(self):
|
|
61
|
-
|
|
61
|
+
|
|
62
|
+
formatted_datetime = self.date.strftime('%Y-%m-%d %H:%M')
|
|
63
|
+
return f"{self.patient} - {self.sample_type} - {formatted_datetime} ()"
|
|
62
64
|
|
|
63
65
|
def get_values(self):
|
|
64
|
-
return self.values
|
|
66
|
+
return self.values.all()
|
|
65
67
|
|
|
66
68
|
@classmethod
|
|
67
69
|
def create_by_patient(cls, patient=None, sample_type=None, date=None, save = True):
|
|
@@ -30,7 +30,11 @@ class PatientLabValue(models.Model):
|
|
|
30
30
|
unit = models.ForeignKey('Unit', on_delete=models.CASCADE, blank=True, null=True)
|
|
31
31
|
|
|
32
32
|
@classmethod
|
|
33
|
-
def create_lab_value_by_sample(
|
|
33
|
+
def create_lab_value_by_sample(
|
|
34
|
+
cls, sample=None, lab_value_name=None,
|
|
35
|
+
value=None, value_str=None,
|
|
36
|
+
unit=None
|
|
37
|
+
):
|
|
34
38
|
from endoreg_db.models import LabValue
|
|
35
39
|
patient = sample.patient
|
|
36
40
|
lab_value = LabValue.objects.get(name=lab_value_name)
|
|
@@ -51,10 +55,26 @@ class PatientLabValue(models.Model):
|
|
|
51
55
|
return pat_lab_val
|
|
52
56
|
|
|
53
57
|
def __str__(self):
|
|
54
|
-
|
|
55
|
-
|
|
58
|
+
formatted_datetime = self.datetime.strftime('%Y-%m-%d %H:%M')
|
|
59
|
+
# normal_range = self.get_normal_range()
|
|
60
|
+
norm_range_string = f'[{self.normal_range.get("min", "")} - {self.normal_range.get("max", "")}]'
|
|
61
|
+
_str = f'{self.lab_value} - {self.value} {self.unit} - {norm_range_string} ({formatted_datetime})'
|
|
56
62
|
return _str
|
|
57
63
|
|
|
64
|
+
def get_normal_range(self):
|
|
65
|
+
from endoreg_db.models import LabValue, Patient
|
|
66
|
+
lab_value:LabValue = self.lab_value
|
|
67
|
+
patient:Patient = self.patient
|
|
68
|
+
|
|
69
|
+
age = patient.age()
|
|
70
|
+
gender = patient.gender
|
|
71
|
+
|
|
72
|
+
normal_range_dict = lab_value.get_normal_range(
|
|
73
|
+
age,gender
|
|
74
|
+
)
|
|
75
|
+
return normal_range_dict
|
|
76
|
+
|
|
77
|
+
|
|
58
78
|
def set_min_norm_value(self, value, save = True):
|
|
59
79
|
self.normal_range["min"] = value
|
|
60
80
|
if save:
|
|
@@ -66,13 +86,11 @@ class PatientLabValue(models.Model):
|
|
|
66
86
|
self.save()
|
|
67
87
|
|
|
68
88
|
def set_norm_values_from_default(self):
|
|
69
|
-
age = self.patient.age()
|
|
70
|
-
gender = self.patient.gender
|
|
71
|
-
min_value, max_value = self.lab_value.get_normal_range(age=age, gender=gender)
|
|
72
|
-
self.set_min_norm_value(min_value, save = False)
|
|
73
|
-
self.set_max_norm_value(max_value, save = False)
|
|
74
|
-
self.save()
|
|
75
89
|
|
|
90
|
+
normal_range_dict = self.get_normal_range()
|
|
91
|
+
self.set_min_norm_value(normal_range_dict["min"], save = False)
|
|
92
|
+
self.set_max_norm_value(normal_range_dict["max"], save = False)
|
|
93
|
+
self.save()
|
|
76
94
|
|
|
77
95
|
def set_unit_from_default(self):
|
|
78
96
|
self.unit = self.lab_value.default_unit
|
|
@@ -109,8 +127,8 @@ class PatientLabValue(models.Model):
|
|
|
109
127
|
|
|
110
128
|
patient:Patient = self.patient
|
|
111
129
|
|
|
112
|
-
dob = patient.dob
|
|
113
|
-
gender:Gender = patient.gender
|
|
130
|
+
dob = patient.dob #TODO: age specific norm values
|
|
131
|
+
gender:Gender = patient.gender # TODO: gender specific norm values
|
|
114
132
|
lab_value:LabValue = self.lab_value
|
|
115
133
|
|
|
116
134
|
assert self.lab_value, "Lab value must be set to set value by distribution"
|
|
@@ -121,7 +139,7 @@ class PatientLabValue(models.Model):
|
|
|
121
139
|
|
|
122
140
|
if not distribution:
|
|
123
141
|
warnings.warn(
|
|
124
|
-
"No distribution set for lab value, assuming uniform numeric distribution based on normal values"
|
|
142
|
+
f"No distribution set for lab value {lab_value}, assuming uniform numeric distribution based on normal values"
|
|
125
143
|
)
|
|
126
144
|
|
|
127
145
|
if not self.normal_range.get("min", None) or not self.normal_range.get("max", None):
|
|
@@ -133,12 +151,12 @@ class PatientLabValue(models.Model):
|
|
|
133
151
|
_name = "auto-" + self.lab_value.name + "-distribution-default-uniform"
|
|
134
152
|
distribution = NumericValueDistribution(
|
|
135
153
|
name = _name,
|
|
136
|
-
|
|
137
|
-
|
|
154
|
+
min_descriptor = _min,
|
|
155
|
+
max_max_desciptor = _max,
|
|
138
156
|
distribution_type = "uniform"
|
|
139
157
|
)
|
|
140
158
|
|
|
141
|
-
value = distribution.generate_value()
|
|
159
|
+
value = distribution.generate_value(lab_value=lab_value)
|
|
142
160
|
self.value = value
|
|
143
161
|
if save:
|
|
144
162
|
self.save()
|
|
@@ -153,7 +171,10 @@ class PatientLabValue(models.Model):
|
|
|
153
171
|
return value
|
|
154
172
|
|
|
155
173
|
elif isinstance(distribution, NumericValueDistribution):
|
|
156
|
-
value = distribution.generate_value(
|
|
174
|
+
value = distribution.generate_value(
|
|
175
|
+
lab_value=lab_value,
|
|
176
|
+
patient=patient
|
|
177
|
+
)
|
|
157
178
|
self.value = value
|
|
158
179
|
if save:
|
|
159
180
|
self.save()
|
|
@@ -8,11 +8,25 @@ class PatientMedication(models.Model):
|
|
|
8
8
|
related_name="patient_medications", null=True
|
|
9
9
|
)
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
'
|
|
11
|
+
medication = models.ForeignKey(
|
|
12
|
+
'Medication', on_delete=models.CASCADE,
|
|
13
|
+
blank=True,
|
|
14
|
+
related_name='patient_medications'
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
intake_times = models.ManyToManyField(
|
|
18
|
+
'MedicationIntakeTime',
|
|
19
|
+
related_name='patient_medications',
|
|
20
|
+
blank=True,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
unit = models.ForeignKey(
|
|
24
|
+
'Unit', on_delete=models.CASCADE,
|
|
25
|
+
null=True, blank=True
|
|
26
|
+
)
|
|
27
|
+
dosage = models.JSONField(
|
|
28
|
+
null=True, blank=True
|
|
13
29
|
)
|
|
14
|
-
unit = models.ForeignKey('Unit', on_delete=models.CASCADE)
|
|
15
|
-
dosage = models.JSONField()
|
|
16
30
|
active = models.BooleanField(default=True)
|
|
17
31
|
|
|
18
32
|
objects = models.Manager()
|
|
@@ -27,18 +41,19 @@ class PatientMedication(models.Model):
|
|
|
27
41
|
medication_indication: MedicationIndication
|
|
28
42
|
patient_medication = cls.objects.create(patient=patient, medication_indication=medication_indication)
|
|
29
43
|
patient_medication.save()
|
|
30
|
-
patient_medication.set_schedules_from_indication()
|
|
31
44
|
|
|
32
45
|
return patient_medication
|
|
33
46
|
|
|
34
|
-
def set_schedules_from_indication(self):
|
|
35
|
-
schedules = self.medication_indication.medication_schedules.all()
|
|
36
|
-
self.medication_schedules.set(schedules)
|
|
37
|
-
self.save()
|
|
38
47
|
|
|
39
48
|
def __str__(self):
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
49
|
+
intake_times = self.intake_times.all()
|
|
50
|
+
out = f"{self.medication} (Indication {self.medication_indication}) - "
|
|
51
|
+
out += f"{self.dosage} - {self.unit} - "
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
for intake_time in intake_times:
|
|
55
|
+
out += f"{intake_time} - "
|
|
56
|
+
|
|
57
|
+
return out
|
|
43
58
|
|
|
44
59
|
|