endoreg-db 0.3.4__py3-none-any.whl → 0.3.5__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.
Files changed (198) hide show
  1. endoreg_db/data/__init__.py +50 -1
  2. endoreg_db/data/case_template/rule/00_patient_lab_sample_add_default_value.yaml +167 -0
  3. endoreg_db/data/case_template/rule/01_patient-set-age.yaml +8 -0
  4. endoreg_db/data/case_template/rule/01_patient-set-gender.yaml +9 -0
  5. endoreg_db/data/case_template/rule/11_create_patient_lab_sample.yaml +23 -0
  6. endoreg_db/data/case_template/rule/12_create-patient_medication-anticoagulation.yaml +19 -0
  7. endoreg_db/data/case_template/rule/13_create-patient_medication_schedule-anticoagulation.yaml +19 -0
  8. endoreg_db/data/case_template/rule/19_create_patient.yaml +17 -0
  9. endoreg_db/data/case_template/rule_type/base_types.yaml +35 -0
  10. endoreg_db/data/case_template/rule_value_type/base_types.yaml +59 -0
  11. endoreg_db/data/case_template/template/base.yaml +8 -0
  12. endoreg_db/data/case_template/template_type/pre_endoscopy.yaml +3 -0
  13. endoreg_db/data/case_template/tmp/_rule_value +13 -0
  14. endoreg_db/data/case_template/tmp/rule/01_atrial_fibrillation.yaml +21 -0
  15. endoreg_db/data/case_template/tmp/rule/02_create_object.yaml +10 -0
  16. endoreg_db/data/case_template/tmp/template/atrial_fibrillation_low_risk.yaml +7 -0
  17. endoreg_db/data/center/data.yaml +8 -0
  18. endoreg_db/data/center_resource/green_endoscopy_dashboard_CenterResource.yaml +144 -0
  19. endoreg_db/data/center_waste/green_endoscopy_dashboard_CenterWaste.yaml +48 -0
  20. endoreg_db/data/disease/cardiovascular.yaml +37 -0
  21. endoreg_db/data/disease/hepatology.yaml +5 -0
  22. endoreg_db/data/disease/misc.yaml +6 -0
  23. endoreg_db/data/disease/renal.yaml +5 -0
  24. endoreg_db/data/disease_classification/chronic_kidney_disease.yaml +6 -0
  25. endoreg_db/data/disease_classification/coronary_vessel_disease.yaml +6 -0
  26. endoreg_db/data/disease_classification_choice/chronic_kidney_disease.yaml +41 -0
  27. endoreg_db/data/disease_classification_choice/coronary_vessel_disease.yaml +20 -0
  28. endoreg_db/data/distribution/date/patient.yaml +7 -0
  29. endoreg_db/data/distribution/single_categorical/patient.yaml +7 -0
  30. endoreg_db/data/emission_factor/green_endoscopy_dashboard_EmissionFactor.yaml +132 -0
  31. endoreg_db/data/event/cardiology.yaml +28 -0
  32. endoreg_db/data/event/neurology.yaml +14 -0
  33. endoreg_db/data/event/surgery.yaml +13 -0
  34. endoreg_db/data/event/thrombembolism.yaml +20 -0
  35. endoreg_db/data/examination/examinations/data.yaml +49 -0
  36. endoreg_db/data/gender/data.yaml +18 -0
  37. endoreg_db/data/information_source/medication.yaml +6 -0
  38. endoreg_db/data/lab_value/cardiac_enzymes.yaml +31 -0
  39. endoreg_db/data/lab_value/coagulation.yaml +49 -0
  40. endoreg_db/data/lab_value/electrolytes.yaml +190 -0
  41. endoreg_db/data/lab_value/gastrointestinal_function.yaml +121 -0
  42. endoreg_db/data/lab_value/hematology.yaml +169 -0
  43. endoreg_db/data/lab_value/hormones.yaml +53 -0
  44. endoreg_db/data/lab_value/lipids.yaml +44 -0
  45. endoreg_db/data/lab_value/misc.yaml +30 -0
  46. endoreg_db/data/lab_value/renal_function.yaml +11 -0
  47. endoreg_db/data/material/material.yaml +91 -0
  48. endoreg_db/data/medication/anticoagulation.yaml +65 -0
  49. endoreg_db/data/medication/tah.yaml +70 -0
  50. endoreg_db/data/medication_indication/anticoagulation.yaml +120 -0
  51. endoreg_db/data/medication_indication_type/data.yaml +11 -0
  52. endoreg_db/data/medication_indication_type/thrombembolism.yaml +41 -0
  53. endoreg_db/data/medication_intake_time/base.yaml +31 -0
  54. endoreg_db/data/medication_schedule/apixaban.yaml +95 -0
  55. endoreg_db/data/medication_schedule/ass.yaml +12 -0
  56. endoreg_db/data/medication_schedule/enoxaparin.yaml +26 -0
  57. endoreg_db/data/patient_lab_sample_type/generic.yaml +6 -0
  58. endoreg_db/data/product/green_endoscopy_dashboard_Product.yaml +66 -0
  59. endoreg_db/data/product_group/green_endoscopy_dashboard_ProductGroup.yaml +33 -0
  60. endoreg_db/data/product_material/green_endoscopy_dashboard_ProductMaterial.yaml +308 -0
  61. endoreg_db/data/product_weight/green_endoscopy_dashboard_ProductWeight.yaml +88 -0
  62. endoreg_db/data/reference_product/green_endoscopy_dashboard_ReferenceProduct.yaml +55 -0
  63. endoreg_db/data/resource/green_endoscopy_dashboard_Resource.yaml +15 -0
  64. endoreg_db/data/tmp/chronic_kidney_disease.yaml +0 -0
  65. endoreg_db/data/tmp/congestive_heart_failure.yaml +0 -0
  66. endoreg_db/data/transport_route/green_endoscopy_dashboard_TransportRoute.yaml +12 -0
  67. endoreg_db/data/unit/concentration.yaml +92 -0
  68. endoreg_db/data/unit/length.yaml +4 -4
  69. endoreg_db/data/unit/misc.yaml +20 -0
  70. endoreg_db/data/unit/rate.yaml +6 -0
  71. endoreg_db/data/unit/time.yaml +13 -0
  72. endoreg_db/data/unit/volume.yaml +13 -4
  73. endoreg_db/data/unit/weight.yaml +11 -4
  74. endoreg_db/data/waste/data.yaml +12 -0
  75. endoreg_db/management/commands/load_base_db_data.py +58 -1
  76. endoreg_db/management/commands/load_disease_classification_choices_data.py +41 -0
  77. endoreg_db/management/commands/load_disease_classification_data.py +41 -0
  78. endoreg_db/management/commands/load_disease_data.py +40 -0
  79. endoreg_db/management/commands/load_distribution_data.py +66 -0
  80. endoreg_db/management/commands/load_event_data.py +41 -0
  81. endoreg_db/management/commands/load_g_play_data.py +113 -0
  82. endoreg_db/management/commands/load_gender_data.py +44 -0
  83. endoreg_db/management/commands/load_green_endoscopy_wuerzburg_data.py +133 -0
  84. endoreg_db/management/commands/load_lab_value_data.py +50 -0
  85. endoreg_db/management/commands/load_medication_data.py +41 -0
  86. endoreg_db/management/commands/load_medication_indication_data.py +63 -0
  87. endoreg_db/management/commands/load_medication_indication_type_data.py +41 -0
  88. endoreg_db/management/commands/load_medication_intake_time_data.py +41 -0
  89. endoreg_db/management/commands/load_medication_schedule_data.py +55 -0
  90. endoreg_db/migrations/0025_event_alter_rawpdffile_file_patientevent.py +42 -0
  91. endoreg_db/migrations/0026_disease_diseaseclassification_and_more.py +166 -0
  92. endoreg_db/migrations/0027_labvalue_abbreviation_labvalue_default_normal_range_and_more.py +38 -0
  93. endoreg_db/migrations/0028_alter_unit_abbreviation.py +18 -0
  94. endoreg_db/migrations/0029_medicationintaketime_and_more.py +75 -0
  95. endoreg_db/migrations/0030_medicationindicationtype_and_more.py +101 -0
  96. endoreg_db/migrations/0031_rename_adapt_to_liver_function_medication_adapt_to_age_and_more.py +38 -0
  97. endoreg_db/migrations/0032_alter_medicationschedule_therapy_duration_d.py +18 -0
  98. endoreg_db/migrations/0033_medicationindication_sources.py +18 -0
  99. endoreg_db/migrations/0034_alter_rawpdffile_file.py +20 -0
  100. endoreg_db/migrations/0035_alter_medicationindication_sources.py +18 -0
  101. endoreg_db/migrations/0036_alter_rawpdffile_file.py +20 -0
  102. endoreg_db/migrations/0037_alter_medicationindication_sources.py +18 -0
  103. endoreg_db/migrations/0038_emissionfactor_material_product_productgroup_and_more.py +164 -0
  104. endoreg_db/migrations/0039_referenceproduct_name.py +19 -0
  105. endoreg_db/migrations/0040_quizanswertype_quizquestiontype_quizquestion_and_more.py +50 -0
  106. endoreg_db/migrations/0041_gender_patientmedication_medication_indication_and_more.py +40 -0
  107. endoreg_db/migrations/0042_casetemplateruletype_casetemplaterulevalue_and_more.py +74 -0
  108. endoreg_db/migrations/0043_casetemplatetype_name_de_casetemplatetype_name_en.py +23 -0
  109. endoreg_db/migrations/0044_casetemplateruletype_name_de_and_more.py +23 -0
  110. endoreg_db/migrations/0045_casetemplaterulevalue_value_type.py +19 -0
  111. endoreg_db/migrations/0046_casetemplaterulevalue_target_field.py +18 -0
  112. endoreg_db/migrations/0047_casetemplaterule_target_model.py +18 -0
  113. endoreg_db/migrations/0048_remove_casetemplaterule_chained_rules_and_more.py +22 -0
  114. endoreg_db/migrations/0049_remove_casetemplaterule_rule_values.py +17 -0
  115. endoreg_db/migrations/0050_casetemplaterule_rule_values.py +18 -0
  116. endoreg_db/migrations/0051_remove_casetemplaterule_calling_rules_and_more.py +27 -0
  117. endoreg_db/migrations/0052_rename_case_template_type_casetemplate_template_type.py +18 -0
  118. endoreg_db/migrations/0053_patientlabsampletype_patientlabsample_and_more.py +38 -0
  119. endoreg_db/migrations/0054_multiplecategoricalvaluedistribution_and_more.py +69 -0
  120. endoreg_db/migrations/0055_remove_casetemplaterule_rule_values_and_more.py +59 -0
  121. endoreg_db/migrations/0056_datevaluedistribution_and_more.py +32 -0
  122. endoreg_db/migrations/0057_remove_datevaluedistribution_max_date_and_more.py +72 -0
  123. endoreg_db/migrations/0058_datevaluedistribution_description_and_more.py +28 -0
  124. endoreg_db/migrations/0059_casetemplaterule_rule_values.py +18 -0
  125. endoreg_db/migrations/0060_labvalue__default_date_value_distribution_and_more.py +44 -0
  126. endoreg_db/migrations/0061_remove_patientlabvalue_date_patientlabvalue_datetime.py +24 -0
  127. endoreg_db/migrations/0062_labvalue_numeric_precision.py +18 -0
  128. endoreg_db/migrations/0063_alter_labvalue_numeric_precision.py +18 -0
  129. endoreg_db/migrations/0064_casetemplaterule_extra_parameters_and_more.py +23 -0
  130. endoreg_db/migrations/0065_rename__date_value_distribution_casetemplaterule_date_value_distribution_and_more.py +58 -0
  131. endoreg_db/migrations/0066_alter_patientlabvalue_patient_and_more.py +29 -0
  132. endoreg_db/migrations/0067_alter_medicationindication_indication_type.py +19 -0
  133. endoreg_db/models/__init__.py +28 -11
  134. endoreg_db/models/case_template/__init__.py +6 -0
  135. endoreg_db/models/case_template/case_template.py +81 -0
  136. endoreg_db/models/case_template/case_template_rule.py +276 -0
  137. endoreg_db/models/case_template/case_template_rule_value.py +73 -0
  138. endoreg_db/models/case_template/case_template_type.py +28 -0
  139. endoreg_db/models/center/__init__.py +4 -0
  140. endoreg_db/models/center/center_product.py +34 -0
  141. endoreg_db/models/center/center_resource.py +19 -0
  142. endoreg_db/models/center/center_waste.py +11 -0
  143. endoreg_db/models/data_file/import_classes/raw_pdf.py +4 -1
  144. endoreg_db/models/data_file/metadata/video_meta.py +4 -3
  145. endoreg_db/models/disease.py +56 -0
  146. endoreg_db/models/emission/__init__.py +1 -0
  147. endoreg_db/models/emission/emission_factor.py +20 -0
  148. endoreg_db/models/event.py +22 -0
  149. endoreg_db/models/information_source.py +7 -0
  150. endoreg_db/models/laboratory/__init__.py +1 -0
  151. endoreg_db/models/laboratory/lab_value.py +102 -0
  152. endoreg_db/models/medication/__init__.py +1 -0
  153. endoreg_db/models/medication/medication.py +148 -0
  154. endoreg_db/models/other/__init__.py +5 -0
  155. endoreg_db/models/other/distribution.py +215 -0
  156. endoreg_db/models/other/material.py +16 -0
  157. endoreg_db/models/other/resource.py +18 -0
  158. endoreg_db/models/other/transport_route.py +21 -0
  159. endoreg_db/models/other/waste.py +20 -0
  160. endoreg_db/models/persons/__init__.py +3 -2
  161. endoreg_db/models/persons/gender.py +22 -0
  162. endoreg_db/models/persons/patient/__init__.py +8 -0
  163. endoreg_db/models/persons/patient/case/__init__.py +0 -0
  164. endoreg_db/models/persons/patient/case/case.py +30 -0
  165. endoreg_db/models/persons/patient/patient.py +216 -0
  166. endoreg_db/models/persons/patient/patient_disease.py +16 -0
  167. endoreg_db/models/persons/patient/patient_event.py +22 -0
  168. endoreg_db/models/persons/patient/patient_lab_sample.py +106 -0
  169. endoreg_db/models/persons/patient/patient_lab_value.py +176 -0
  170. endoreg_db/models/persons/patient/patient_medication.py +44 -0
  171. endoreg_db/models/persons/patient/patient_medication_schedule.py +28 -0
  172. endoreg_db/models/persons/person.py +1 -4
  173. endoreg_db/models/persons/portal_user_information.py +0 -2
  174. endoreg_db/models/product/__init__.py +5 -0
  175. endoreg_db/models/product/product.py +97 -0
  176. endoreg_db/models/product/product_group.py +19 -0
  177. endoreg_db/models/product/product_material.py +24 -0
  178. endoreg_db/models/product/product_weight.py +26 -0
  179. endoreg_db/models/product/reference_product.py +99 -0
  180. endoreg_db/models/quiz/__init__.py +2 -0
  181. endoreg_db/models/quiz/quiz_answer.py +41 -0
  182. endoreg_db/models/quiz/quiz_question.py +54 -0
  183. endoreg_db/models/rules/__init__.py +5 -0
  184. endoreg_db/models/rules/rule.py +24 -0
  185. endoreg_db/models/rules/rule_applicator.py +224 -0
  186. endoreg_db/models/rules/rule_attribute_dtype.py +19 -0
  187. endoreg_db/models/rules/rule_type.py +22 -0
  188. endoreg_db/models/rules/ruleset.py +19 -0
  189. endoreg_db/models/unit.py +6 -4
  190. endoreg_db/utils/dataloader.py +13 -106
  191. {endoreg_db-0.3.4.dist-info → endoreg_db-0.3.5.dist-info}/METADATA +1 -1
  192. endoreg_db-0.3.5.dist-info/RECORD +357 -0
  193. endoreg_db/models/persons/patient.py +0 -58
  194. endoreg_db/models.py +0 -3
  195. endoreg_db-0.3.4.dist-info/RECORD +0 -185
  196. /endoreg_db/models/{center.py → center/center.py} +0 -0
  197. {endoreg_db-0.3.4.dist-info → endoreg_db-0.3.5.dist-info}/LICENSE +0 -0
  198. {endoreg_db-0.3.4.dist-info → endoreg_db-0.3.5.dist-info}/WHEEL +0 -0
@@ -0,0 +1,19 @@
1
+ from os import name
2
+ from django.db import models
3
+
4
+ class CenterResource(models.Model):
5
+ name = models.CharField(max_length=255, null=True)
6
+ center = models.ForeignKey("Center", on_delete=models.CASCADE)
7
+ name_de = models.CharField(max_length=255, null=True)
8
+ name_en = models.CharField(max_length=255, null=True)
9
+ quantity = models.FloatField()
10
+ resource = models.ForeignKey("Resource", on_delete=models.CASCADE)
11
+ transport_emission_factor = models.ForeignKey("EmissionFactor", on_delete=models.SET_NULL, null=True,
12
+ related_name="center_resource_transport_emission_factor")
13
+ use_emission_factor = models.ForeignKey("EmissionFactor", on_delete=models.SET_NULL, null=True,
14
+ related_name="center_resource_use_emission_factor")
15
+ year = models.IntegerField()
16
+ unit = models.ForeignKey("Unit", on_delete=models.SET_NULL, null=True)
17
+
18
+ def __str__(self):
19
+ return self.center.name + " - " + self.resource.name + " (" + str(self.year) + ")"
@@ -0,0 +1,11 @@
1
+ from django.db import models
2
+
3
+ class CenterWaste(models.Model):
4
+ center = models.ForeignKey("Center", on_delete=models.CASCADE)
5
+ year = models.IntegerField()
6
+ waste = models.ForeignKey("Waste", on_delete=models.CASCADE)
7
+ quantity = models.FloatField()
8
+ unit = models.ForeignKey("Unit", on_delete=models.SET_NULL, null=True)
9
+ emission_factor = models.ForeignKey("EmissionFactor", on_delete=models.SET_NULL, null=True)
10
+
11
+
@@ -25,11 +25,14 @@ logger = logging.getLogger('pdf_import')
25
25
 
26
26
  import shutil
27
27
 
28
+ # get pdf location from settings, default to ~/erc_data/raw_pdf and create if not exists
29
+ PSEUDO_DIR_RAW_PDF = getattr(settings, 'PSEUDO_DIR_RAW_PDF', settings.BASE_DIR / 'erc_data/raw_pdf')
30
+
28
31
  class RawPdfFile(models.Model):
29
32
  file = models.FileField(
30
33
  upload_to='raw_pdf/',
31
34
  validators=[FileExtensionValidator(allowed_extensions=['pdf'])],
32
- storage=FileSystemStorage(location=settings.PSEUDO_DIR_RAW_PDF.resolve().as_posix()),
35
+ storage=FileSystemStorage(location=PSEUDO_DIR_RAW_PDF.resolve().as_posix()),
33
36
  )
34
37
 
35
38
  pdf_hash = models.CharField(max_length=255, unique=True)
@@ -79,9 +79,10 @@ class FFMpegMeta(models.Model):
79
79
  def create_from_file(cls, file_path: Path):
80
80
  """Creates an FFMpegMeta instance from a video file using ffmpeg probe."""
81
81
  try:
82
- probe = ffmpeg.probe(str(file_path))
83
- except ffmpeg.Error as e:
84
- print(e.stderr)
82
+ probe = ffmpeg.probe(file_path.resolve().as_posix())
83
+ except: # ffmpeg.Error as e:
84
+ # print(e.stderr)
85
+ print(f"Error while probing {file_path}")
85
86
  return None
86
87
 
87
88
  video_stream = next((stream for stream in probe['streams'] if stream['codec_type'] == 'video'), None)
@@ -0,0 +1,56 @@
1
+ from django.db import models
2
+
3
+ class DiseaseManager(models.Manager):
4
+ def get_by_natural_key(self, name):
5
+ return self.get(name=name)
6
+
7
+ class Disease(models.Model):
8
+ name = models.CharField(max_length=255, unique=True)
9
+ name_de = models.CharField(max_length=255, blank=True, null=True)
10
+ name_en = models.CharField(max_length=255, blank=True, null=True)
11
+
12
+ objects = DiseaseManager()
13
+
14
+ def natural_key(self):
15
+ return (self.name,)
16
+
17
+ def __str__(self):
18
+ return self.name
19
+
20
+ class DiseaseClassificationManager(models.Manager):
21
+ def get_by_natural_key(self, name):
22
+ return self.get(name=name)
23
+
24
+ class DiseaseClassification(models.Model):
25
+ name = models.CharField(max_length=255, unique=True)
26
+ name_de = models.CharField(max_length=255, blank=True, null=True)
27
+ name_en = models.CharField(max_length=255, blank=True, null=True)
28
+
29
+ disease = models.ForeignKey(Disease, on_delete=models.CASCADE)
30
+
31
+ objects = DiseaseClassificationManager()
32
+
33
+ def natural_key(self):
34
+ return (self.name,)
35
+
36
+ def __str__(self):
37
+ return self.name
38
+
39
+ class DiseaseClassificationChoiceManager(models.Manager):
40
+ def get_by_natural_key(self, name):
41
+ return self.get(name=name)
42
+
43
+ class DiseaseClassificationChoice(models.Model):
44
+ name = models.CharField(max_length=255, unique=True)
45
+ name_de = models.CharField(max_length=255, blank=True, null=True)
46
+ name_en = models.CharField(max_length=255, blank=True, null=True)
47
+
48
+ disease_classification = models.ForeignKey(DiseaseClassification, on_delete=models.CASCADE)
49
+
50
+ objects = DiseaseClassificationChoiceManager()
51
+
52
+ def natural_key(self):
53
+ return (self.name,)
54
+
55
+ def __str__(self):
56
+ return self.name
@@ -0,0 +1 @@
1
+ from .emission_factor import EmissionFactor
@@ -0,0 +1,20 @@
1
+ from django.db import models
2
+
3
+ class EmissionFactorManager(models.Manager):
4
+ def get_by_natural_key(self, name):
5
+ return self.get(name=name)
6
+
7
+ class EmissionFactor(models.Model):
8
+ objects = EmissionFactorManager()
9
+
10
+ name = models.CharField(max_length=255)
11
+ name_de = models.CharField(max_length=255, null=True)
12
+ name_en = models.CharField(max_length=255, null=True)
13
+ unit = models.ForeignKey("Unit", on_delete=models.SET_NULL, null=True)
14
+ value = models.FloatField()
15
+
16
+ def natural_key(self):
17
+ return (self.name,)
18
+
19
+ def __str__(self):
20
+ return self.name
@@ -0,0 +1,22 @@
1
+ from django.db import models
2
+
3
+ class Event(models.Model):
4
+ """
5
+ A class representing an event.
6
+
7
+ Attributes:
8
+ name (str): The name of the event.
9
+ name_de (str): The German name of the event.
10
+ name_en (str): The English name of the event.
11
+ description (str): A description of the event.
12
+ """
13
+ name = models.CharField(max_length=100, unique=True)
14
+ name_de = models.CharField(max_length=100, blank=True, null=True)
15
+ name_en = models.CharField(max_length=100, blank=True, null=True)
16
+ description = models.TextField(blank=True, null=True)
17
+
18
+ def natural_key(self):
19
+ return (self.name,)
20
+
21
+ def __str__(self):
22
+ return self.name
@@ -18,5 +18,12 @@ class InformationSource(models.Model):
18
18
  name_de = models.CharField(max_length=100, blank=True, null=True)
19
19
  name_en = models.CharField(max_length=100, blank=True, null=True)
20
20
 
21
+ url = models.URLField(blank=True, null=True)
22
+ description = models.TextField(blank=True, null=True)
23
+ date = models.DateField(blank=True, null=True)
24
+
25
+ def natural_key(self):
26
+ return (self.name,)
27
+
21
28
  def __str__(self):
22
29
  return self.name
@@ -0,0 +1 @@
1
+ from .lab_value import LabValue
@@ -0,0 +1,102 @@
1
+ from django.db import models
2
+ import warnings
3
+
4
+ LANG = "de"
5
+
6
+ class LabValueManager(models.Manager):
7
+ def get_by_natural_key(self, name):
8
+ return self.get(name=name)
9
+
10
+ class LabValue(models.Model):
11
+ name = models.CharField(max_length=255, unique=True)
12
+ name_de = models.CharField(max_length=255, blank=True, null=True)
13
+ name_en = models.CharField(max_length=255, blank=True, null=True)
14
+ abbreviation = models.CharField(max_length=10, blank=True, null=True)
15
+ default_unit = models.ForeignKey('Unit', on_delete=models.CASCADE, blank=True, null=True)
16
+ numeric_precision = models.IntegerField(default=3)
17
+ default_single_categorical_value_distribution = models.ForeignKey(
18
+ 'SingleCategoricalValueDistribution',
19
+ on_delete=models.CASCADE,
20
+ blank=True, null=True,
21
+ related_name='default_single_categorical_value_distribution'
22
+ )
23
+ default_numerical_value_distribution = models.ForeignKey(
24
+ 'NumericValueDistribution',
25
+ on_delete=models.CASCADE,
26
+ blank=True, null=True,
27
+ related_name='default_numerical_value_distribution'
28
+ )
29
+ default_multiple_categorical_value_distribution = models.ForeignKey(
30
+ 'MultipleCategoricalValueDistribution',
31
+ on_delete=models.CASCADE,
32
+ blank=True, null=True,
33
+ related_name='default_multiple_categorical_value_distribution'
34
+ )
35
+ default_date_value_distribution = models.ForeignKey(
36
+ 'DateValueDistribution',
37
+ on_delete=models.CASCADE,
38
+ blank=True, null=True,
39
+ related_name='default_date_value_distribution'
40
+ )
41
+ default_normal_range = models.JSONField(blank=True, null=True)
42
+ normal_range_age_dependent = models.BooleanField(default=False)
43
+ normal_range_gender_dependent = models.BooleanField(default=False)
44
+ normal_range_special_case = models.BooleanField(default=False)
45
+ objects = LabValueManager()
46
+
47
+ def natural_key(self):
48
+ return (self.name,)
49
+
50
+ def __str__(self):
51
+ return self.name
52
+
53
+ def get_default_default_distribution(self):
54
+ if self.default_single_categorical_value_distribution:
55
+ return self.default_single_categorical_value_distribution
56
+ elif self.default_numerical_value_distribution:
57
+ return self.default_numerical_value_distribution
58
+ elif self.default_multiple_categorical_value_distribution:
59
+ return self.default_multiple_categorical_value_distribution
60
+ elif self.default_date_value_distribution:
61
+ return self.default_date_value_distribution
62
+ else:
63
+ warnings.warn("No default distribution set for lab value")
64
+ return None
65
+
66
+ def get_normal_range(self, age=None, gender=None):
67
+ age_dependent = self.normal_range_age_dependent
68
+ gender_dependent = self.normal_range_gender_dependent
69
+ special_case = self.normal_range_special_case
70
+
71
+ min_value = None
72
+ max_value = None
73
+
74
+ if not age_dependent and \
75
+ not gender_dependent and \
76
+ not special_case:
77
+ min_value = self.default_normal_range.get('min', None)
78
+ max_value = self.default_normal_range.get('max', None)
79
+
80
+ if age_dependent:
81
+ # get normal range for age)
82
+ warnings.warn("Age dependent normal range not implemented yet")
83
+ pass
84
+
85
+ if gender_dependent:
86
+ if not gender:
87
+ warnings.warn("Calling get_normal_range with gender_dependent=True requires gender to be set, choosing by random")
88
+ # set gender to either "male" or "female"
89
+ from random import choice
90
+ choices = ["male", "female"]
91
+ gender = choice(choices)
92
+
93
+ default_range_dict = self.default_normal_range.get(gender, {})
94
+ min_value = default_range_dict.get('min', None)
95
+ max_value = default_range_dict.get('max', None)
96
+
97
+ if special_case:
98
+ # get normal range for special case
99
+ warnings.warn("Special case normal range not implemented yet")
100
+
101
+ return min_value, max_value
102
+
@@ -0,0 +1 @@
1
+ from .medication import *
@@ -0,0 +1,148 @@
1
+ from django.db import models
2
+
3
+ class MedicationManager(models.Manager):
4
+ def get_by_natural_key(self, name):
5
+ return self.get(name=name)
6
+
7
+ class Medication(models.Model):
8
+ name = models.CharField(max_length=255, unique=True)
9
+ name_de = models.CharField(max_length=255, blank=True, null=True)
10
+ name_en = models.CharField(max_length=255, blank=True, null=True)
11
+ adapt_to_renal_function = models.BooleanField(default = False)
12
+ adapt_to_hepatic_function = models.BooleanField(default=False)
13
+ adapt_to_indication = models.BooleanField(default=False)
14
+ adapt_to_age = models.BooleanField(default=False)
15
+ adapt_to_weight = models.BooleanField(default=False)
16
+ adapt_to_risk = models.BooleanField(default=False)
17
+ default_unit = models.ForeignKey('Unit', on_delete=models.CASCADE)
18
+
19
+
20
+ objects = MedicationManager()
21
+
22
+ def natural_key(self):
23
+ return (self.name,)
24
+
25
+ def __str__(self):
26
+ return self.name
27
+
28
+ class MedicationScheduleManager(models.Manager):
29
+ def get_by_natural_key(self, name):
30
+ return self.get(name=name)
31
+
32
+ class MedicationSchedule(models.Model):
33
+ name = models.CharField(max_length=255)
34
+ name_de = models.CharField(max_length=255, blank=True, null=True)
35
+ name_en = models.CharField(max_length=255, blank=True, null=True)
36
+ description = models.TextField(blank=True, null=True)
37
+ medication = models.ForeignKey("Medication", on_delete=models.CASCADE)
38
+ unit = models.ForeignKey("Unit", on_delete=models.CASCADE)
39
+ therapy_duration_d = models.FloatField(blank=True, null=True)
40
+ dose = models.FloatField()
41
+ intake_times = models.ManyToManyField(
42
+ "MedicationIntakeTime",
43
+ )
44
+
45
+ objects = MedicationScheduleManager()
46
+
47
+ def natural_key(self):
48
+ return (self.name,)
49
+
50
+ def __str__(self):
51
+ return self.name
52
+
53
+
54
+ class MedicationIntakeTimeManager(models.Manager):
55
+ def get_by_natural_key(self, name):
56
+ return self.get(name=name)
57
+
58
+ class MedicationIntakeTime(models.Model):
59
+ name = models.CharField(max_length=255)
60
+ name_de = models.CharField(max_length=255, blank=True, null=True)
61
+ name_en = models.CharField(max_length=255, blank=True, null=True)
62
+ repeats = models.CharField(max_length=20, default = "daily")
63
+ time = models.TimeField()
64
+
65
+ objects = MedicationIntakeTimeManager()
66
+
67
+ def natural_key(self):
68
+ return (self.name,)
69
+
70
+ def __str__(self):
71
+ return self.name
72
+
73
+ # IMPLEMENT MEDICATION INDICATION TYPE
74
+ class MedicationIndicationTypeManager(models.Manager):
75
+ def get_by_natural_key(self, name):
76
+ return self.get(name=name)
77
+
78
+ class MedicationIndicationType(models.Model):
79
+ name = models.CharField(max_length=255, unique=True)
80
+ name_de = models.CharField(max_length=255, blank=True, null=True)
81
+ name_en = models.CharField(max_length=255, blank=True, null=True)
82
+
83
+ objects = MedicationIndicationTypeManager()
84
+
85
+ def natural_key(self):
86
+ return (self.name,)
87
+
88
+ def __str__(self):
89
+ return self.name
90
+
91
+ @classmethod
92
+ def get_random_indication_by_type(cls, name) -> "MedicationIndication":
93
+ return cls.objects.get(name=name).medication_indications.order_by('?').first()
94
+
95
+
96
+ def get_random_medication_indication(self):
97
+ from endoreg_db.models import MedicationIndication
98
+ return MedicationIndication.objects.filter(indication_type=self).order_by('?').first()
99
+
100
+
101
+ class MedicationIndicationManager(models.Manager):
102
+ def get_by_natural_key(self, name):
103
+ return self.get(name=name)
104
+
105
+ class MedicationIndication(models.Model):
106
+ name = models.CharField(max_length=255, unique=True)
107
+ indication_type = models.ForeignKey(
108
+ "MedicationIndicationType", on_delete=models.CASCADE, related_name="medication_indications"
109
+ )
110
+ medication_schedules = models.ManyToManyField(
111
+ "MedicationSchedule"
112
+ )
113
+ diseases = models.ManyToManyField(
114
+ "Disease"
115
+ )
116
+ events = models.ManyToManyField(
117
+ "Event"
118
+ )
119
+ classification_choices = models.ManyToManyField(
120
+ "DiseaseClassificationChoice"
121
+ )
122
+ sources = models.ManyToManyField(
123
+ "InformationSource"
124
+ )
125
+
126
+ def get_indication_links(self):
127
+ links = {
128
+ "medication_schedules": self.medication_schedules,
129
+ "diseases": self.diseases,
130
+ "events": self.events,
131
+ "classification_choices": self.classification_choices
132
+ }
133
+
134
+ objects = MedicationIndicationManager()
135
+
136
+ def natural_key(self):
137
+ return (self.name,)
138
+
139
+ def __str__(self):
140
+ return self.name
141
+
142
+ def create_patient_medication_schedules(self, patient):
143
+ from endoreg_db.models import PatientMedicationSchedule
144
+ for medication_schedule in self.medication_schedules.all():
145
+ PatientMedicationSchedule.objects.create(
146
+ patient=patient,
147
+ medication_schedule=medication_schedule
148
+ )
@@ -0,0 +1,5 @@
1
+ from .material import Material
2
+ from .resource import Resource
3
+ from .transport_route import TransportRoute
4
+ from .waste import Waste
5
+ from .distribution import *
@@ -0,0 +1,215 @@
1
+ from django.db import models
2
+ import numpy as np
3
+ from scipy.stats import skewnorm
4
+
5
+ class BaseValueDistribution(models.Model):
6
+ """
7
+ Abstract base class for value distributions.
8
+ """
9
+ name = models.CharField(max_length=100)
10
+
11
+ class Meta:
12
+ abstract = True
13
+
14
+ def generate_value(self):
15
+ """
16
+ Generate a value based on the distribution rules.
17
+ Must be implemented by subclasses.
18
+ """
19
+ raise NotImplementedError("Subclasses must implement this method")
20
+
21
+ def natural_key(self):
22
+ return (self.name,)
23
+
24
+ class NumericValueDistributionManager(models.Manager):
25
+ def get_by_natural_key(self, name):
26
+ return self.get(name=name)
27
+
28
+ class NumericValueDistribution(BaseValueDistribution):
29
+ """
30
+ Numeric value distribution model.
31
+ Supports uniform, normal, and skewed normal distributions with hard limits.
32
+ """
33
+ objects = NumericValueDistributionManager()
34
+ DISTRIBUTION_CHOICES = [
35
+ ('uniform', 'Uniform'),
36
+ ('normal', 'Normal'),
37
+ ('skewed_normal', 'Skewed Normal'),
38
+ ]
39
+
40
+ distribution_type = models.CharField(max_length=20, choices=DISTRIBUTION_CHOICES)
41
+ min_value = models.FloatField()
42
+ max_value = models.FloatField()
43
+ mean = models.FloatField(null=True, blank=True)
44
+ std_dev = models.FloatField(null=True, blank=True)
45
+ skewness = models.FloatField(null=True, blank=True)
46
+
47
+ def generate_value(self):
48
+ if self.distribution_type == 'uniform':
49
+ return np.random.uniform(self.min_value, self.max_value)
50
+ elif self.distribution_type == 'normal':
51
+ value = np.random.normal(self.mean, self.std_dev)
52
+ return np.clip(value, self.min_value, self.max_value)
53
+ elif self.distribution_type == 'skewed_normal':
54
+ value = skewnorm.rvs(a=self.skewness, loc=self.mean, scale=self.std_dev)
55
+ return np.clip(value, self.min_value, self.max_value)
56
+ else:
57
+ raise ValueError("Unsupported distribution type")
58
+
59
+
60
+ class SingleCategoricalValueDistributionManager(models.Manager):
61
+ def get_by_natural_key(self, name):
62
+ return self.get(name=name)
63
+
64
+ class SingleCategoricalValueDistribution(BaseValueDistribution):
65
+ """
66
+ Single categorical value distribution model.
67
+ Assigns a single value based on specified probabilities.
68
+ """
69
+ objects = SingleCategoricalValueDistributionManager()
70
+ categories = models.JSONField() # { "category": "probability", ... }
71
+
72
+ def generate_value(self):
73
+ categories, probabilities = zip(*self.categories.items())
74
+ return np.random.choice(categories, p=probabilities)
75
+
76
+
77
+ class MultipleCategoricalValueDistributionManager(models.Manager):
78
+ def get_by_natural_key(self, name):
79
+ return self.get(name=name)
80
+
81
+ class MultipleCategoricalValueDistribution(BaseValueDistribution):
82
+ """
83
+ Multiple categorical value distribution model.
84
+ Assigns a specific number or varying number of values based on probabilities.
85
+ """
86
+ objects = MultipleCategoricalValueDistributionManager()
87
+ categories = models.JSONField() # { "category": "probability", ... }
88
+ min_count = models.IntegerField()
89
+ max_count = models.IntegerField()
90
+ count_distribution_type = models.CharField(max_length=20, choices=[('uniform', 'Uniform'), ('normal', 'Normal')])
91
+ count_mean = models.FloatField(null=True, blank=True)
92
+ count_std_dev = models.FloatField(null=True, blank=True)
93
+
94
+ def generate_value(self):
95
+ if self.count_distribution_type == 'uniform':
96
+ count = np.random.randint(self.min_count, self.max_count + 1)
97
+ elif self.count_distribution_type == 'normal':
98
+ count = int(np.random.normal(self.count_mean, self.count_std_dev))
99
+ count = np.clip(count, self.min_count, self.max_count)
100
+ else:
101
+ raise ValueError("Unsupported count distribution type")
102
+
103
+ categories, probabilities = zip(*self.categories.items())
104
+ return list(np.random.choice(categories, size=count, p=probabilities))
105
+
106
+
107
+ class DateValueDistributionManager(models.Manager):
108
+ def get_by_natural_key(self, name):
109
+ return self.get(name=name)
110
+
111
+ from datetime import date, timedelta
112
+ class DateValueDistribution(BaseValueDistribution):
113
+ """
114
+ Assign date values based on specified distribution.
115
+ Expects distribution_type (uniform, normal) and mode (date, timedelta) and based on this either
116
+ date_min, date_max, date_mean, date_std_dev or
117
+ timedelta_days_min, timedelta_days_max, timedelta_days_mean, timedelta_days_std_dev
118
+ """
119
+ objects = DateValueDistributionManager()
120
+ name = models.CharField(max_length=100)
121
+ name_de = models.CharField(max_length=100, blank=True, null=True)
122
+ name_en = models.CharField(max_length=100, blank=True, null=True)
123
+ description = models.TextField(blank=True, null=True)
124
+ DISTRIBUTION_CHOICES = [
125
+ ('uniform', 'Uniform'),
126
+ ('normal', 'Normal'),
127
+ ]
128
+ MODE_CHOICES = [
129
+ ('date', 'Date'),
130
+ ('timedelta', 'Timedelta'),
131
+ ]
132
+
133
+ distribution_type = models.CharField(max_length=20, choices=DISTRIBUTION_CHOICES)
134
+ mode = models.CharField(max_length=20, choices=MODE_CHOICES)
135
+
136
+ # Date-related fields
137
+ date_min = models.DateField(blank=True, null=True)
138
+ date_max = models.DateField(blank=True, null=True)
139
+ date_mean = models.DateField(blank=True, null=True)
140
+ date_std_dev = models.IntegerField(blank=True, null=True) # Standard deviation in days
141
+
142
+ # Timedelta-related fields
143
+ timedelta_days_min = models.IntegerField(blank=True, null=True)
144
+ timedelta_days_max = models.IntegerField(blank=True, null=True)
145
+ timedelta_days_mean = models.IntegerField(blank=True, null=True)
146
+ timedelta_days_std_dev = models.IntegerField(blank=True, null=True)
147
+
148
+ def generate_value(self):
149
+ if self.mode == 'date':
150
+ return self._generate_date_value()
151
+ elif self.mode == 'timedelta':
152
+ return self._generate_timedelta_value()
153
+ else:
154
+ raise ValueError("Unsupported mode")
155
+
156
+ def _generate_date_value(self):
157
+ #UNTESTED
158
+ if self.distribution_type == 'uniform':
159
+ start_date = self.date_min.toordinal()
160
+ end_date = self.date_max.toordinal()
161
+ random_ordinal = np.random.randint(start_date, end_date)
162
+ return date.fromordinal(random_ordinal)
163
+ elif self.distribution_type == 'normal':
164
+ mean_ordinal = self.date_mean.toordinal()
165
+ std_dev_days = self.date_std_dev
166
+ random_ordinal = int(np.random.normal(mean_ordinal, std_dev_days))
167
+ random_ordinal = np.clip(random_ordinal, self.date_min.toordinal(), self.date_max.toordinal())
168
+ return date.fromordinal(random_ordinal)
169
+ else:
170
+ raise ValueError("Unsupported distribution type")
171
+
172
+ def _generate_timedelta_value(self):
173
+ if self.distribution_type == 'uniform':
174
+ random_days = np.random.randint(self.timedelta_days_min, self.timedelta_days_max + 1)
175
+
176
+
177
+ elif self.distribution_type == 'normal':
178
+ random_days = int(np.random.normal(self.timedelta_days_mean, self.timedelta_days_std_dev))
179
+ random_days = np.clip(random_days, self.timedelta_days_min, self.timedelta_days_max)
180
+
181
+ else:
182
+ raise ValueError("Unsupported distribution type")
183
+
184
+ current_date = date.today()
185
+ generated_date = current_date - timedelta(days=random_days)
186
+ print(generated_date)
187
+ return(generated_date)
188
+
189
+ # Example Usage
190
+ # Numeric distribution for age
191
+ # age_distribution = NumericValueDistribution.objects.create(
192
+ # name='Age Distribution',
193
+ # distribution_type='normal',
194
+ # min_value=0,
195
+ # max_value=100,
196
+ # mean=50,
197
+ # std_dev=15
198
+ # )
199
+
200
+ # # Single categorical distribution for gender
201
+ # gender_distribution = SingleCategoricalValueDistribution.objects.create(
202
+ # name='Gender Distribution',
203
+ # categories={'male': 0.5, 'female': 0.5}
204
+ # )
205
+
206
+ # # Multiple categorical distribution for symptoms
207
+ # symptoms_distribution = MultipleCategoricalValueDistribution.objects.create(
208
+ # name='Symptoms Distribution',
209
+ # categories={'fever': 0.3, 'cough': 0.4, 'fatigue': 0.2, 'nausea': 0.1},
210
+ # min_count=1,
211
+ # max_count=3,
212
+ # count_distribution_type='normal',
213
+ # count_mean=2,
214
+ # count_std_dev=0.5
215
+ # )
@@ -0,0 +1,16 @@
1
+ from django.db import models
2
+
3
+ class MaterialManager(models.Manager):
4
+ def get_by_natural_key(self, name):
5
+ return self.get(name=name)
6
+
7
+ class Material(models.Model):
8
+ objects = MaterialManager()
9
+
10
+ name = models.CharField(max_length=255)
11
+ name_de = models.CharField(max_length=255, null=True)
12
+ name_en = models.CharField(max_length=255, null=True)
13
+ emission_factor = models.ForeignKey("EmissionFactor", on_delete=models.SET_NULL, null=True)
14
+
15
+ def natural_key(self):
16
+ return (self.name,)