meta-edc 0.3.26__py3-none-any.whl → 0.3.28__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.
- meta_dashboard/views/subject/dashboard/dashboard_view.py +1 -0
- {meta_edc-0.3.26.dist-info → meta_edc-0.3.28.dist-info}/METADATA +3 -2
- {meta_edc-0.3.26.dist-info → meta_edc-0.3.28.dist-info}/RECORD +25 -15
- meta_reports/admin/__init__.py +1 -0
- meta_reports/admin/unmanaged/__init__.py +4 -1
- meta_reports/admin/unmanaged/missing_screening_ogtt_admin/__init__.py +2 -0
- meta_reports/admin/unmanaged/missing_screening_ogtt_admin/note_model_admin.py +53 -0
- meta_reports/admin/unmanaged/{missing_screening_ogtt_admin.py → missing_screening_ogtt_admin/unmanaged_model_admin.py} +32 -7
- meta_reports/forms/__init__.py +1 -0
- meta_reports/forms/missing_ogtt_note_form.py +33 -0
- meta_reports/migrations/0034_auto_20240823_1642.py +54 -0
- meta_reports/migrations/0035_historicalmissingogttnote_missingogttnote.py +457 -0
- meta_reports/migrations/0036_historicalmissingogttnote_fasting_and_more.py +86 -0
- meta_reports/migrations/0037_historicalmissingogttnote_result_status_and_more.py +51 -0
- meta_reports/migrations/0038_alter_historicalmissingogttnote_fasting_and_more.py +33 -0
- meta_reports/models/__init__.py +2 -0
- meta_reports/models/dbviews/__init__.py +1 -1
- meta_reports/models/dbviews/missing_screening_ogtt/__init__.py +1 -0
- meta_reports/models/dbviews/missing_screening_ogtt/note_model.py +57 -0
- meta_reports/models/dbviews/missing_screening_ogtt/unmanaged_model.py +0 -2
- meta_reports/models/dbviews/missing_screening_ogtt/view_definition.py +6 -6
- {meta_edc-0.3.26.dist-info → meta_edc-0.3.28.dist-info}/AUTHORS +0 -0
- {meta_edc-0.3.26.dist-info → meta_edc-0.3.28.dist-info}/LICENSE +0 -0
- {meta_edc-0.3.26.dist-info → meta_edc-0.3.28.dist-info}/WHEEL +0 -0
- {meta_edc-0.3.26.dist-info → meta_edc-0.3.28.dist-info}/top_level.txt +0 -0
@@ -17,6 +17,7 @@ class DashboardView(SubjectDashboardView):
|
|
17
17
|
history_button_label = _("Audit")
|
18
18
|
|
19
19
|
def get_context_data(self, **kwargs) -> dict[str, Any]:
|
20
|
+
"""Add message if subject reaches DM Endpoint."""
|
20
21
|
context = super().get_context_data(**kwargs)
|
21
22
|
try:
|
22
23
|
Endpoints.objects.get(subject_identifier=self.subject_identifier)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: meta-edc
|
3
|
-
Version: 0.3.
|
3
|
+
Version: 0.3.28
|
4
4
|
Summary: META Trial EDC (http://www.isrctn.com/ISRCTN76157257)
|
5
5
|
Home-page: https://github.com/meta-trial/meta-edc
|
6
6
|
Author: Erik van Widenfelt
|
@@ -10,6 +10,7 @@ Keywords: django edc META EDC,clinicedc,clinical trials
|
|
10
10
|
Classifier: Environment :: Web Environment
|
11
11
|
Classifier: Framework :: Django
|
12
12
|
Classifier: Framework :: Django :: 4.2
|
13
|
+
Classifier: Framework :: Django :: 5.1
|
13
14
|
Classifier: Intended Audience :: Developers
|
14
15
|
Classifier: Intended Audience :: Science/Research
|
15
16
|
Classifier: Operating System :: OS Independent
|
@@ -19,7 +20,7 @@ Requires-Python: >=3.12
|
|
19
20
|
Description-Content-Type: text/x-rst
|
20
21
|
License-File: LICENSE
|
21
22
|
License-File: AUTHORS
|
22
|
-
Requires-Dist: edc ==0.6.
|
23
|
+
Requires-Dist: edc ==0.6.5
|
23
24
|
Requires-Dist: edc-microscopy
|
24
25
|
Requires-Dist: beautifulsoup4
|
25
26
|
Requires-Dist: edc-analytics
|
@@ -204,7 +204,7 @@ meta_dashboard/views/screening/__init__.py,sha256=bjnvZdqdonOW_DPFs1MR2GQv2x4oqA
|
|
204
204
|
meta_dashboard/views/screening/listboard_view.py,sha256=DF42XR3ftCHO4vd3cuxtq5ir2NqOmQHGQV6cGObr7is,578
|
205
205
|
meta_dashboard/views/subject/__init__.py,sha256=s7l0halOqlqscWdMD_r98V4VKeEsgchhY3eAgs0EI3k,81
|
206
206
|
meta_dashboard/views/subject/dashboard/__init__.py,sha256=1961drFBW7OVhglUAL4OGFxLOU0tN3jOGMvO7Oone8U,42
|
207
|
-
meta_dashboard/views/subject/dashboard/dashboard_view.py,sha256=
|
207
|
+
meta_dashboard/views/subject/dashboard/dashboard_view.py,sha256=inFSVxZDnNghGJlEYIVK0Xy3mtSmPUEoJWj4D6yYU3o,1388
|
208
208
|
meta_dashboard/views/subject/listboard/__init__.py,sha256=WHtaM6dXPN7vtnROBOutMO9zEBVIkx3T0RPJdbq4sq4,49
|
209
209
|
meta_dashboard/views/subject/listboard/listboard_view.py,sha256=bQ5fPqbbkVvPNrmNvIGNZ_GoRIkqUFHk6T7p1dkjr_Y,601
|
210
210
|
meta_data_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -433,18 +433,22 @@ meta_reports/death_report.py,sha256=mJw08jMxOWIAtsKQN8zCP64HIrxW1fb48D9OXqEMpM0,
|
|
433
433
|
meta_reports/pdf_report.py,sha256=9lWnRc_BNieDFXC4VgA0QHK6g_ct58u8tupPRsbRvV0,2395
|
434
434
|
meta_reports/tasks.py,sha256=wPzfm99Hox1AIvt1KxYg1r6g9v8ta2AHOHesoN6AxEk,370
|
435
435
|
meta_reports/urls.py,sha256=_c6AMrK4U5MsyFSU2JSPNfiZlbhuw24C7CyPNYpqGd0,206
|
436
|
-
meta_reports/admin/__init__.py,sha256=
|
436
|
+
meta_reports/admin/__init__.py,sha256=OOVq30qqC5s7SVkWGO-AVHVOeyIrCXcfBGcpahAOrIo,344
|
437
437
|
meta_reports/admin/endpoints_admin.py,sha256=L4mDLNIkR6203RI3ImBYel2kevaH_Nwa6KMYuoDwyNU,518
|
438
438
|
meta_reports/admin/endpoints_all_admin.py,sha256=_czdezZf9fSjwZJmO-3HbmdXrXP6nk8-HdiweqUzPRE,476
|
439
439
|
meta_reports/admin/list_filters.py,sha256=pByBzz9-qGwqBfdZFlByxJUZDTJQXOTWfNLjmK8KF00,870
|
440
440
|
meta_reports/admin/modeladmin_mixins.py,sha256=YgzUjGlzG5S3i8daVaexBpZ8WAEPBjlhktsRIvOkyo4,3752
|
441
|
-
meta_reports/admin/unmanaged/__init__.py,sha256=
|
441
|
+
meta_reports/admin/unmanaged/__init__.py,sha256=56wDkwrBBt-50mQNHK9UiIRZAOBpsKk4Ui5PwWvb-Nk,471
|
442
442
|
meta_reports/admin/unmanaged/glucose_summary_admin.py,sha256=NqnDKx5l0Q-2xxRGdnf50DaRX1Sn8-DC0jHSk96LkRo,4005
|
443
|
-
meta_reports/admin/unmanaged/missing_screening_ogtt_admin.py,sha256=rpT5j4DsIB_475B2joeDwCd3kOtgiMR0eJBroVwIFGA,1836
|
444
443
|
meta_reports/admin/unmanaged/patient_history_missing_baseline_cd4_admin.py,sha256=XyroEqxlX816xrdi0IVSelNPxPBWi96niKa-MQVGkck,2058
|
445
444
|
meta_reports/admin/unmanaged/unattended_three_in_row2_admin.py,sha256=0r13KRr0gsH2osmSlffRV11SpSBpWM612AYl-GOoYm0,1347
|
446
445
|
meta_reports/admin/unmanaged/unattended_three_in_row_admin.py,sha256=i_-H3pMXRjssf8jFw8gJ8_b0FaM4tX2AI4xfHQDyssU,1121
|
447
446
|
meta_reports/admin/unmanaged/unattended_two_in_row_admin.py,sha256=tbnga05uTMgdK8ULsKYV7IuyhyPe0e-JpbMm6etU6Pk,1062
|
447
|
+
meta_reports/admin/unmanaged/missing_screening_ogtt_admin/__init__.py,sha256=UZMypicuUuZ2jD2Rf0hcDUi-oBUf7_3fgyV5KacIJtE,117
|
448
|
+
meta_reports/admin/unmanaged/missing_screening_ogtt_admin/note_model_admin.py,sha256=RcksbJ9HinK71iN9Pr_xMp-voj17pBqjLZpfMTJ7300,1357
|
449
|
+
meta_reports/admin/unmanaged/missing_screening_ogtt_admin/unmanaged_model_admin.py,sha256=1pWmmqk6LADkPWqyxcS8nwC-KwMjuN8O7fmG_AbcA3g,2644
|
450
|
+
meta_reports/forms/__init__.py,sha256=F5AIupgum2dWL1_HqQCjLkrpMzjQ2dbo065hlkXBTNY,56
|
451
|
+
meta_reports/forms/missing_ogtt_note_form.py,sha256=nUG5uNqE-U6KtY9m-S48bricyERKHd95GkWn364oT1Q,1445
|
448
452
|
meta_reports/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
449
453
|
meta_reports/management/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
450
454
|
meta_reports/management/commands/generate_endpoints.py,sha256=LcQyLb5cinYUq9kmUTZOin08-sP_hzM7ve8chEq9M1I,348
|
@@ -481,18 +485,24 @@ meta_reports/migrations/0030_auto_20240822_1637.py,sha256=StGg7ifQj7fF18BC0j_lGl
|
|
481
485
|
meta_reports/migrations/0031_endpointsproxy.py,sha256=8yeRLRF6j0nWpNZxlsDc-V7qlUubOz7z9fSqQm6XBQM,629
|
482
486
|
meta_reports/migrations/0032_alter_endpointsproxy_options.py,sha256=07lWYABDDwKtd3rmPmNoRhu3y7Q-J74HUTq9kLx-jV4,539
|
483
487
|
meta_reports/migrations/0033_auto_20240823_0012.py,sha256=4N1fvwzjt2EWaXrqjt3vL47OvfuHxC7G9pPzR2OKiJo,8777
|
488
|
+
meta_reports/migrations/0034_auto_20240823_1642.py,sha256=XcuAbFJ8tokZSE6o_iXBxvqAncFehCQE7s_afJjl3Qo,6601
|
489
|
+
meta_reports/migrations/0035_historicalmissingogttnote_missingogttnote.py,sha256=Pv2J7K9Auw1Y_gFKvkdL05i-hO_8xMT3xa-6K5aA6do,18235
|
490
|
+
meta_reports/migrations/0036_historicalmissingogttnote_fasting_and_more.py,sha256=sr0xr1MslT-jXD_mNr59IY3R1QPcq5Bpa6vc67VHBY4,3167
|
491
|
+
meta_reports/migrations/0037_historicalmissingogttnote_result_status_and_more.py,sha256=FdGYLdu4zTxoDO9PCI2wlDS43fxfNGtynCKYABs5cAg,1600
|
492
|
+
meta_reports/migrations/0038_alter_historicalmissingogttnote_fasting_and_more.py,sha256=-HljbT033-M0XZanZfcEA8jXmW3vhLoigdEC3hE5jOs,1010
|
484
493
|
meta_reports/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
485
|
-
meta_reports/models/__init__.py,sha256=
|
494
|
+
meta_reports/models/__init__.py,sha256=mdSLwykOHh_Y9QSS9HeTes8SDie_Y4aRU8yYXehTjpA,303
|
486
495
|
meta_reports/models/endpoints.py,sha256=HfxQuKkzu883xbTeVfIEktN-ARoGe1qC6KgEAzRtV5E,925
|
487
496
|
meta_reports/models/endpoints_proxy.py,sha256=3h3JGaPmnJedFPVWGrk4idV4YtdihqiCI5W7QomwG4E,318
|
488
497
|
meta_reports/models/dbviews/README,sha256=GdeboB7Xqb-Qo_rE1ondcxP8Ps93MIjLzCePQCePig0,686
|
489
|
-
meta_reports/models/dbviews/__init__.py,sha256=
|
498
|
+
meta_reports/models/dbviews/__init__.py,sha256=tE_j0PeMl-r97-KNATY9tdQYiw0sNH39s8E2PAyk2Q4,388
|
490
499
|
meta_reports/models/dbviews/glucose_summary/__init__.py,sha256=Tfgjso4TpxMCidAdRJp8g1Ykqqa43yWlQSotzAaORAo,93
|
491
500
|
meta_reports/models/dbviews/glucose_summary/unmanaged_model.py,sha256=uqhD5JLXtyQ94zpG5Puxodjzli3quE4GgiFi7en6EeM,1055
|
492
501
|
meta_reports/models/dbviews/glucose_summary/view_definition.py,sha256=f_lUpaKRMa1Z0y8Y7DPB2qbHEPeEXBDXr2FnM5yD55s,4029
|
493
|
-
meta_reports/models/dbviews/missing_screening_ogtt/__init__.py,sha256=
|
494
|
-
meta_reports/models/dbviews/missing_screening_ogtt/
|
495
|
-
meta_reports/models/dbviews/missing_screening_ogtt/
|
502
|
+
meta_reports/models/dbviews/missing_screening_ogtt/__init__.py,sha256=7uX_2HfVU-3G1O_xecfGnE5_pcX5eceiRaapeDQtzIw,105
|
503
|
+
meta_reports/models/dbviews/missing_screening_ogtt/note_model.py,sha256=JHItVS11WDFg3lTe7ayH9T7Epd-VvXXD_79FssrmAwc,1813
|
504
|
+
meta_reports/models/dbviews/missing_screening_ogtt/unmanaged_model.py,sha256=_XFzpOiMoxr-F0ebKNEnyXqS6dnb3P5tBRnZlbrQ2x8,1346
|
505
|
+
meta_reports/models/dbviews/missing_screening_ogtt/view_definition.py,sha256=2f7A0VLcb5ZGee8Us3SPLeExayCTXrGlCHt3j7072HY,2638
|
496
506
|
meta_reports/models/dbviews/patient_history_missing_baseline_cd4/__init__.py,sha256=eIyKY9mdIE3-J2vtQtY7MOg_RQkwKj7aserwO5PBNQQ,62
|
497
507
|
meta_reports/models/dbviews/patient_history_missing_baseline_cd4/unmanaged_model.py,sha256=7TbSZJLdprIO8FvVq5a_MUXgiEvqAZ5NrirQVfH8Fnk,957
|
498
508
|
meta_reports/models/dbviews/patient_history_missing_baseline_cd4/view_definition.py,sha256=AlraPbMyJ_bdfb2sBPbNT-CP_dUK8nSFh9bH1j3DTmw,2066
|
@@ -1089,9 +1099,9 @@ tests/etc/user-rsa-restricted-private.pem,sha256=CUcHW9bznWdmmASN00hCzvxFPAFl4N2
|
|
1089
1099
|
tests/etc/user-rsa-restricted-public.pem,sha256=mt84djoL-uHw6Wc5SJh0zml6VzXulnf8eQSFg7-fheg,450
|
1090
1100
|
tests/etc/user-salt-local.key,sha256=x5anBw9fvbHurczouT3CjrkWb_xs7Ypm1htIJsgiuiw,256
|
1091
1101
|
tests/etc/user-salt-restricted.key,sha256=pxmpcfBRNB-4C6wTvHXz-9fOfJgKIFOjaAF8ZFfa4q4,256
|
1092
|
-
meta_edc-0.3.
|
1093
|
-
meta_edc-0.3.
|
1094
|
-
meta_edc-0.3.
|
1095
|
-
meta_edc-0.3.
|
1096
|
-
meta_edc-0.3.
|
1097
|
-
meta_edc-0.3.
|
1102
|
+
meta_edc-0.3.28.dist-info/AUTHORS,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1103
|
+
meta_edc-0.3.28.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
1104
|
+
meta_edc-0.3.28.dist-info/METADATA,sha256=01QtxWazwkpcrqvp_W9kznFwV9OEdJQyfrztvCcVGUI,2810
|
1105
|
+
meta_edc-0.3.28.dist-info/WHEEL,sha256=Mdi9PDNwEZptOjTlUcAth7XJDFtKrHYaQMPulZeBCiQ,91
|
1106
|
+
meta_edc-0.3.28.dist-info/top_level.txt,sha256=RkzjNXwRq2kg_uZ_1bDwPUntijSXoY2YBqtByDwvvrc,244
|
1107
|
+
meta_edc-0.3.28.dist-info/RECORD,,
|
meta_reports/admin/__init__.py
CHANGED
@@ -2,6 +2,7 @@ from .endpoints_admin import EndpointsAdmin
|
|
2
2
|
from .endpoints_all_admin import EndpointsAllAdmin
|
3
3
|
from .unmanaged import (
|
4
4
|
GlucoseSummaryAdmin,
|
5
|
+
MissingOgttNoteModelAdmin,
|
5
6
|
MissingScreeningOgttAdmin,
|
6
7
|
PatientHistoryMissingBaselineCd4Admin,
|
7
8
|
UnattendedThreeInRow2Admin,
|
@@ -1,5 +1,8 @@
|
|
1
1
|
from .glucose_summary_admin import GlucoseSummaryAdmin
|
2
|
-
from .missing_screening_ogtt_admin import
|
2
|
+
from .missing_screening_ogtt_admin import (
|
3
|
+
MissingOgttNoteModelAdmin,
|
4
|
+
MissingScreeningOgttAdmin,
|
5
|
+
)
|
3
6
|
from .patient_history_missing_baseline_cd4_admin import (
|
4
7
|
PatientHistoryMissingBaselineCd4Admin,
|
5
8
|
)
|
@@ -0,0 +1,53 @@
|
|
1
|
+
from django.contrib import admin
|
2
|
+
from django_audit_fields import audit_fieldset_tuple
|
3
|
+
from edc_qareports.modeladmin_mixins import NoteModelAdminMixin
|
4
|
+
|
5
|
+
from ....admin_site import meta_reports_admin
|
6
|
+
from ....forms import MissingOgttNoteForm
|
7
|
+
from ....models import MissingOgttNote
|
8
|
+
|
9
|
+
|
10
|
+
@admin.register(MissingOgttNote, site=meta_reports_admin)
|
11
|
+
class MissingOgttNoteModelAdmin(
|
12
|
+
NoteModelAdminMixin,
|
13
|
+
admin.ModelAdmin,
|
14
|
+
):
|
15
|
+
"""A modeladmin class for the Note model."""
|
16
|
+
|
17
|
+
form = MissingOgttNoteForm
|
18
|
+
note_template_name = "edc_qareports/qa_report_note.html"
|
19
|
+
|
20
|
+
fieldsets = (
|
21
|
+
(
|
22
|
+
None,
|
23
|
+
{"fields": ("subject_identifier", "report_datetime", "result_status")},
|
24
|
+
),
|
25
|
+
(
|
26
|
+
"OGTT",
|
27
|
+
{
|
28
|
+
"fields": (
|
29
|
+
"fasting",
|
30
|
+
"ogtt_base_datetime",
|
31
|
+
"ogtt_datetime",
|
32
|
+
"ogtt_value",
|
33
|
+
"ogtt_units",
|
34
|
+
)
|
35
|
+
},
|
36
|
+
),
|
37
|
+
(
|
38
|
+
"Note",
|
39
|
+
{
|
40
|
+
"fields": (
|
41
|
+
"note",
|
42
|
+
"report_model",
|
43
|
+
)
|
44
|
+
},
|
45
|
+
),
|
46
|
+
audit_fieldset_tuple,
|
47
|
+
)
|
48
|
+
|
49
|
+
radio_fields = {
|
50
|
+
"ogtt_units": admin.VERTICAL,
|
51
|
+
"result_status": admin.VERTICAL,
|
52
|
+
"fasting": admin.VERTICAL,
|
53
|
+
}
|
@@ -4,12 +4,19 @@ from django.urls import reverse
|
|
4
4
|
from django.utils.translation import gettext as _
|
5
5
|
from edc_model_admin.dashboard import ModelAdminDashboardMixin
|
6
6
|
from edc_model_admin.mixins import TemplatesModelAdminMixin
|
7
|
+
from edc_qareports.modeladmin_mixins import (
|
8
|
+
NoteStatusListFilter as BaseNoteStatusListFilter,
|
9
|
+
)
|
7
10
|
from edc_qareports.modeladmin_mixins import QaReportModelAdminMixin
|
8
11
|
from edc_sites.admin import SiteModelAdminMixin
|
9
12
|
from edc_visit_schedule.admin import ScheduleStatusListFilter
|
10
13
|
|
11
|
-
from
|
12
|
-
from
|
14
|
+
from ....admin_site import meta_reports_admin
|
15
|
+
from ....models import NOTE_STATUSES, MissingScreeningOgtt
|
16
|
+
|
17
|
+
|
18
|
+
class NoteStatusListFilter(BaseNoteStatusListFilter):
|
19
|
+
note_model_status_choices = NOTE_STATUSES
|
13
20
|
|
14
21
|
|
15
22
|
@admin.register(MissingScreeningOgtt, site=meta_reports_admin)
|
@@ -20,13 +27,19 @@ class MissingScreeningOgttAdmin(
|
|
20
27
|
TemplatesModelAdminMixin,
|
21
28
|
admin.ModelAdmin,
|
22
29
|
):
|
23
|
-
|
30
|
+
note_model = "meta_reports.missingogttnote"
|
31
|
+
note_status_list_filter = NoteStatusListFilter
|
32
|
+
note_template = "edc_qareports/columns/notes_column.html"
|
33
|
+
include_note_column = True
|
34
|
+
|
35
|
+
ordering = ["site", "subject_identifier"]
|
36
|
+
|
24
37
|
list_display = [
|
25
38
|
"dashboard",
|
26
|
-
"
|
39
|
+
"subject_identifier",
|
27
40
|
"site",
|
28
|
-
"
|
29
|
-
"
|
41
|
+
"screening_date",
|
42
|
+
"fbg_date",
|
30
43
|
"fbg_value",
|
31
44
|
"ogtt_value",
|
32
45
|
"repeated",
|
@@ -46,7 +59,7 @@ class MissingScreeningOgttAdmin(
|
|
46
59
|
"p3_ltfu",
|
47
60
|
]
|
48
61
|
|
49
|
-
search_fields = ["
|
62
|
+
search_fields = ["subject_identifier"]
|
50
63
|
|
51
64
|
def dashboard(self, obj=None, label=None) -> str:
|
52
65
|
url = self.get_subject_dashboard_url(obj=obj)
|
@@ -57,3 +70,15 @@ class MissingScreeningOgttAdmin(
|
|
57
70
|
)
|
58
71
|
context = dict(title=_("Go to subject screening"), url=url, label=label)
|
59
72
|
return render_to_string("dashboard_button.html", context=context)
|
73
|
+
|
74
|
+
@admin.display(description="Screen date", ordering="screening_datetime")
|
75
|
+
def screening_date(self, obj):
|
76
|
+
if obj.screening_datetime:
|
77
|
+
return obj.screening_datetime.date()
|
78
|
+
return None
|
79
|
+
|
80
|
+
@admin.display(description="Fbg date", ordering="fbg_datetime")
|
81
|
+
def fbg_date(self, obj):
|
82
|
+
if obj.fbg_datetime:
|
83
|
+
return obj.fbg_datetime.date()
|
84
|
+
return None
|
@@ -0,0 +1 @@
|
|
1
|
+
from .missing_ogtt_note_form import MissingOgttNoteForm
|
@@ -0,0 +1,33 @@
|
|
1
|
+
from django import forms
|
2
|
+
from edc_constants.constants import NO, YES
|
3
|
+
from edc_form_validators import FormValidator, FormValidatorMixin
|
4
|
+
from edc_glucose.form_validators import OgttFormValidatorMixin
|
5
|
+
from edc_glucose.utils import validate_glucose_as_millimoles_per_liter
|
6
|
+
|
7
|
+
from ..models import MissingOgttNote
|
8
|
+
|
9
|
+
|
10
|
+
class MissingOgttNoteFormValidator(OgttFormValidatorMixin, FormValidator):
|
11
|
+
|
12
|
+
def clean(self):
|
13
|
+
self.applicable_if(YES, field="result_status", field_applicable="fasting")
|
14
|
+
self.required_if(YES, NO, field="fasting", field_required="ogtt_base_datetime")
|
15
|
+
self.required_if(YES, NO, field="fasting", field_required="ogtt_datetime")
|
16
|
+
self.required_if(YES, NO, field="fasting", field_required="ogtt_value")
|
17
|
+
self.applicable_if(YES, NO, field="fasting", field_applicable="ogtt_units")
|
18
|
+
validate_glucose_as_millimoles_per_liter("ogtt", self.cleaned_data)
|
19
|
+
self.validate_ogtt_dates()
|
20
|
+
self.validate_ogtt_time_interval()
|
21
|
+
|
22
|
+
|
23
|
+
class MissingOgttNoteForm(FormValidatorMixin, forms.ModelForm):
|
24
|
+
form_validator_cls = MissingOgttNoteFormValidator
|
25
|
+
|
26
|
+
class Meta:
|
27
|
+
model = MissingOgttNote
|
28
|
+
fields = "__all__"
|
29
|
+
help_text = {"subject_identifier": "(read-only)", "name": "(read-only)"}
|
30
|
+
widgets = {
|
31
|
+
"report_model": forms.TextInput(attrs={"readonly": "readonly"}),
|
32
|
+
"subject_identifier": forms.TextInput(attrs={"readonly": "readonly"}),
|
33
|
+
}
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# Generated by Django 5.0.8 on 2024-08-23 13:42
|
2
|
+
|
3
|
+
import django_db_views.migration_functions
|
4
|
+
import django_db_views.operations
|
5
|
+
from django.db import migrations
|
6
|
+
|
7
|
+
|
8
|
+
class Migration(migrations.Migration):
|
9
|
+
|
10
|
+
dependencies = [
|
11
|
+
("meta_reports", "0033_auto_20240823_0012"),
|
12
|
+
]
|
13
|
+
|
14
|
+
operations = [
|
15
|
+
django_db_views.operations.ViewRunPython(
|
16
|
+
code=django_db_views.migration_functions.ForwardViewMigration(
|
17
|
+
"# noqa\n select *, uuid() as id, now() as created,\n 'meta_reports.missing_screening_ogtt_view' as report_model\n from (\n select screening_identifier, site_id, report_datetime as 'screening_datetime', fbg_datetime,\n converted_fbg_value as fbg_value, converted_ogtt_value as ogtt_value, repeat_glucose_performed as repeated,\n p3_ltfu, fbg2_value, ogtt2_value, fbg2_datetime, ogtt2_datetime, consented,\n screening_identifier as subject_identifier, id as original_id\n from meta_screening_subjectscreening\n where converted_fbg_value is not null and converted_ogtt_value is null and unsuitable_agreed != \"Yes\"\n ) as A\n order by screening_identifier",
|
18
|
+
"missing_screening_ogtt_view",
|
19
|
+
engine="django.db.backends.mysql",
|
20
|
+
),
|
21
|
+
reverse_code=django_db_views.migration_functions.BackwardViewMigration(
|
22
|
+
"# noqa\n select *, uuid() as id, now() as created,\n 'meta_reports.missing_screening_ogtt_view' as report_model\n from (\n select screening_identifier, site_id, report_datetime as 'screening_datetime', fbg_datetime,\n converted_fbg_value as fbg_value, converted_ogtt_value as ogtt_value, repeat_glucose_performed as repeated,\n p3_ltfu, fbg2_value, ogtt2_value, fbg2_datetime, ogtt2_datetime, consented, \"\" as subject_identifier,\n id as original_id\n from meta_screening_subjectscreening\n where converted_fbg_value is not null and converted_ogtt_value is null and unsuitable_agreed != \"Yes\"\n ) as A\n order by screening_identifier",
|
23
|
+
"missing_screening_ogtt_view",
|
24
|
+
engine="django.db.backends.mysql",
|
25
|
+
),
|
26
|
+
atomic=False,
|
27
|
+
),
|
28
|
+
django_db_views.operations.ViewRunPython(
|
29
|
+
code=django_db_views.migration_functions.ForwardViewMigration(
|
30
|
+
"# noqa\n select *, get_random_uuid() as id, now() as created,\n 'meta_reports.missing_screening_ogtt_view' as report_model\n from (\n select screening_identifier, site_id, report_datetime as 'screening_datetime', fbg_datetime,\n converted_fbg_value as fbg_value, converted_ogtt_value as ogtt_value, repeat_glucose_performed as repeated,\n p3_ltfu, fbg2_value, ogtt2_value, fbg2_datetime, ogtt2_datetime, consented,\n screening_identifier as subject_identifier, id as original_id\n from meta_screening_subjectscreening\n where converted_fbg_value is not null and converted_ogtt_value is null and unsuitable_agreed != \"Yes\"\n ) as A\n order by screening_identifier",
|
31
|
+
"missing_screening_ogtt_view",
|
32
|
+
engine="django.db.backends.postgresql",
|
33
|
+
),
|
34
|
+
reverse_code=django_db_views.migration_functions.BackwardViewMigration(
|
35
|
+
"# noqa\n select *, get_random_uuid() as id, now() as created,\n 'meta_reports.missing_screening_ogtt_view' as report_model\n from (\n select screening_identifier, site_id, report_datetime as 'screening_datetime', fbg_datetime,\n converted_fbg_value as fbg_value, converted_ogtt_value as ogtt_value, repeat_glucose_performed as repeated,\n p3_ltfu, fbg2_value, ogtt2_value, fbg2_datetime, ogtt2_datetime, consented, \"\" as subject_identifier,\n id as original_id\n from meta_screening_subjectscreening\n where converted_fbg_value is not null and converted_ogtt_value is null and unsuitable_agreed != \"Yes\"\n ) as A\n order by screening_identifier",
|
36
|
+
"missing_screening_ogtt_view",
|
37
|
+
engine="django.db.backends.postgresql",
|
38
|
+
),
|
39
|
+
atomic=False,
|
40
|
+
),
|
41
|
+
django_db_views.operations.ViewRunPython(
|
42
|
+
code=django_db_views.migration_functions.ForwardViewMigration(
|
43
|
+
"# noqa\nSELECT *, lower(\n hex(randomblob(4)) || '-' || hex(randomblob(2)) || '-' || '4' ||\n substr(hex( randomblob(2)), 2) || '-' ||\n substr('AB89', 1 + (abs(random()) % 4) , 1) ||\n substr(hex(randomblob(2)), 2) || '-' ||\n hex(randomblob(6))\n ) as id, datetime() as `created`,\n 'meta_reports.missing_screening_ogtt_view' as report_model\n from (\n select screening_identifier, site_id, report_datetime as 'screening_datetime', fbg_datetime,\n converted_fbg_value as fbg_value, converted_ogtt_value as ogtt_value, fbg2_value, ogtt2_value,\n repeat_glucose_performed as repeated, p3_ltfu, fbg2_datetime, ogtt2_datetime, consented,\n screening_identifier as subject_identifier, id as original_id\n from meta_screening_subjectscreening\n where converted_fbg_value is not null and converted_ogtt_value is null and unsuitable_agreed != \"Yes\"\n ) as A\n order by screening_identifier",
|
44
|
+
"missing_screening_ogtt_view",
|
45
|
+
engine="django.db.backends.sqlite3",
|
46
|
+
),
|
47
|
+
reverse_code=django_db_views.migration_functions.BackwardViewMigration(
|
48
|
+
"# noqa\nSELECT *, lower(\n hex(randomblob(4)) || '-' || hex(randomblob(2)) || '-' || '4' ||\n substr(hex( randomblob(2)), 2) || '-' ||\n substr('AB89', 1 + (abs(random()) % 4) , 1) ||\n substr(hex(randomblob(2)), 2) || '-' ||\n hex(randomblob(6))\n ) as id, datetime() as `created`,\n 'meta_reports.missing_screening_ogtt_view' as report_model\n from (\n select screening_identifier, site_id, report_datetime as 'screening_datetime', fbg_datetime,\n converted_fbg_value as fbg_value, converted_ogtt_value as ogtt_value, fbg2_value, ogtt2_value,\n repeat_glucose_performed as repeated, p3_ltfu, fbg2_datetime, ogtt2_datetime, consented, \"\" as subject_identifier,\n id as original_id\n from meta_screening_subjectscreening\n where converted_fbg_value is not null and converted_ogtt_value is null and unsuitable_agreed != \"Yes\"\n ) as A\n order by screening_identifier",
|
49
|
+
"missing_screening_ogtt_view",
|
50
|
+
engine="django.db.backends.sqlite3",
|
51
|
+
),
|
52
|
+
atomic=False,
|
53
|
+
),
|
54
|
+
]
|
@@ -0,0 +1,457 @@
|
|
1
|
+
# Generated by Django 5.0.8 on 2024-08-23 13:59
|
2
|
+
|
3
|
+
import _socket
|
4
|
+
import django.db.models.deletion
|
5
|
+
import django.db.models.manager
|
6
|
+
import django_audit_fields.fields.hostname_modification_field
|
7
|
+
import django_audit_fields.fields.userfield
|
8
|
+
import django_audit_fields.fields.uuid_auto_field
|
9
|
+
import django_audit_fields.models.audit_model_mixin
|
10
|
+
import django_revision.revision_field
|
11
|
+
import edc_model.validators.date
|
12
|
+
import edc_sites.managers
|
13
|
+
import edc_utils.date
|
14
|
+
import simple_history.models
|
15
|
+
import uuid
|
16
|
+
from django.conf import settings
|
17
|
+
from django.db import migrations, models
|
18
|
+
|
19
|
+
|
20
|
+
class Migration(migrations.Migration):
|
21
|
+
|
22
|
+
dependencies = [
|
23
|
+
("meta_reports", "0034_auto_20240823_1642"),
|
24
|
+
("sites", "0002_alter_domain_unique"),
|
25
|
+
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
26
|
+
]
|
27
|
+
|
28
|
+
operations = [
|
29
|
+
migrations.CreateModel(
|
30
|
+
name="HistoricalMissingOgttNote",
|
31
|
+
fields=[
|
32
|
+
(
|
33
|
+
"revision",
|
34
|
+
django_revision.revision_field.RevisionField(
|
35
|
+
blank=True,
|
36
|
+
editable=False,
|
37
|
+
help_text="System field. Git repository tag:branch:commit.",
|
38
|
+
max_length=75,
|
39
|
+
null=True,
|
40
|
+
verbose_name="Revision",
|
41
|
+
),
|
42
|
+
),
|
43
|
+
(
|
44
|
+
"created",
|
45
|
+
models.DateTimeField(
|
46
|
+
blank=True, default=django_audit_fields.models.audit_model_mixin.utcnow
|
47
|
+
),
|
48
|
+
),
|
49
|
+
(
|
50
|
+
"modified",
|
51
|
+
models.DateTimeField(
|
52
|
+
blank=True, default=django_audit_fields.models.audit_model_mixin.utcnow
|
53
|
+
),
|
54
|
+
),
|
55
|
+
(
|
56
|
+
"user_created",
|
57
|
+
django_audit_fields.fields.userfield.UserField(
|
58
|
+
blank=True,
|
59
|
+
help_text="Updated by admin.save_model",
|
60
|
+
max_length=50,
|
61
|
+
verbose_name="user created",
|
62
|
+
),
|
63
|
+
),
|
64
|
+
(
|
65
|
+
"user_modified",
|
66
|
+
django_audit_fields.fields.userfield.UserField(
|
67
|
+
blank=True,
|
68
|
+
help_text="Updated by admin.save_model",
|
69
|
+
max_length=50,
|
70
|
+
verbose_name="user modified",
|
71
|
+
),
|
72
|
+
),
|
73
|
+
(
|
74
|
+
"hostname_created",
|
75
|
+
models.CharField(
|
76
|
+
blank=True,
|
77
|
+
default=_socket.gethostname,
|
78
|
+
help_text="System field. (modified on create only)",
|
79
|
+
max_length=60,
|
80
|
+
verbose_name="Hostname created",
|
81
|
+
),
|
82
|
+
),
|
83
|
+
(
|
84
|
+
"hostname_modified",
|
85
|
+
django_audit_fields.fields.hostname_modification_field.HostnameModificationField(
|
86
|
+
blank=True,
|
87
|
+
help_text="System field. (modified on every save)",
|
88
|
+
max_length=50,
|
89
|
+
verbose_name="Hostname modified",
|
90
|
+
),
|
91
|
+
),
|
92
|
+
(
|
93
|
+
"device_created",
|
94
|
+
models.CharField(blank=True, max_length=10, verbose_name="Device created"),
|
95
|
+
),
|
96
|
+
(
|
97
|
+
"device_modified",
|
98
|
+
models.CharField(
|
99
|
+
blank=True, max_length=10, verbose_name="Device modified"
|
100
|
+
),
|
101
|
+
),
|
102
|
+
(
|
103
|
+
"locale_created",
|
104
|
+
models.CharField(
|
105
|
+
blank=True,
|
106
|
+
help_text="Auto-updated by Modeladmin",
|
107
|
+
max_length=10,
|
108
|
+
null=True,
|
109
|
+
verbose_name="Locale created",
|
110
|
+
),
|
111
|
+
),
|
112
|
+
(
|
113
|
+
"locale_modified",
|
114
|
+
models.CharField(
|
115
|
+
blank=True,
|
116
|
+
help_text="Auto-updated by Modeladmin",
|
117
|
+
max_length=10,
|
118
|
+
null=True,
|
119
|
+
verbose_name="Locale modified",
|
120
|
+
),
|
121
|
+
),
|
122
|
+
(
|
123
|
+
"id",
|
124
|
+
django_audit_fields.fields.uuid_auto_field.UUIDAutoField(
|
125
|
+
blank=True,
|
126
|
+
db_index=True,
|
127
|
+
editable=False,
|
128
|
+
help_text="System auto field. UUID primary key.",
|
129
|
+
),
|
130
|
+
),
|
131
|
+
("subject_identifier", models.CharField(db_index=True, max_length=50)),
|
132
|
+
("report_model", models.CharField(max_length=150)),
|
133
|
+
("report_datetime", models.DateTimeField(default=edc_utils.date.get_utcnow)),
|
134
|
+
("note", models.TextField(blank=True, null=True)),
|
135
|
+
(
|
136
|
+
"ogtt_base_datetime",
|
137
|
+
models.DateTimeField(
|
138
|
+
blank=True,
|
139
|
+
help_text="(glucose solution given)",
|
140
|
+
null=True,
|
141
|
+
validators=[edc_model.validators.date.datetime_not_future],
|
142
|
+
verbose_name="Date/time oral glucose solution given",
|
143
|
+
),
|
144
|
+
),
|
145
|
+
(
|
146
|
+
"ogtt_value",
|
147
|
+
models.DecimalField(
|
148
|
+
blank=True,
|
149
|
+
decimal_places=2,
|
150
|
+
help_text="A `HIGH` reading may be entered as 9999.99",
|
151
|
+
max_digits=8,
|
152
|
+
null=True,
|
153
|
+
verbose_name="Blood glucose measure 2hrs <u>after</u> oral glucose solution given",
|
154
|
+
),
|
155
|
+
),
|
156
|
+
(
|
157
|
+
"ogtt_quantifier",
|
158
|
+
models.CharField(
|
159
|
+
choices=[
|
160
|
+
("=", "="),
|
161
|
+
(">", ">"),
|
162
|
+
(">=", ">="),
|
163
|
+
("<", "<"),
|
164
|
+
("<=", "<="),
|
165
|
+
],
|
166
|
+
default="=",
|
167
|
+
max_length=10,
|
168
|
+
),
|
169
|
+
),
|
170
|
+
(
|
171
|
+
"ogtt_units",
|
172
|
+
models.CharField(
|
173
|
+
choices=[
|
174
|
+
("mg/dL", "mg/dL"),
|
175
|
+
("mmol/L", "mmol/L (millimoles/L)"),
|
176
|
+
("N/A", "Not applicable"),
|
177
|
+
],
|
178
|
+
default="N/A",
|
179
|
+
max_length=15,
|
180
|
+
verbose_name="Units (Blood glucose 2hrs after...)",
|
181
|
+
),
|
182
|
+
),
|
183
|
+
(
|
184
|
+
"ogtt_datetime",
|
185
|
+
models.DateTimeField(
|
186
|
+
blank=True,
|
187
|
+
help_text="(2 hours after glucose solution given)",
|
188
|
+
null=True,
|
189
|
+
validators=[edc_model.validators.date.datetime_not_future],
|
190
|
+
verbose_name="Date/time blood glucose measured 2hrs <u>after</u> oral glucose solution given",
|
191
|
+
),
|
192
|
+
),
|
193
|
+
(
|
194
|
+
"status",
|
195
|
+
models.CharField(
|
196
|
+
choices=[
|
197
|
+
("done", "Done"),
|
198
|
+
("PENDING", "Data is pending"),
|
199
|
+
("not_available", "Data not available"),
|
200
|
+
],
|
201
|
+
default="done",
|
202
|
+
max_length=25,
|
203
|
+
),
|
204
|
+
),
|
205
|
+
(
|
206
|
+
"history_id",
|
207
|
+
models.UUIDField(
|
208
|
+
default=uuid.uuid4, editable=False, primary_key=True, serialize=False
|
209
|
+
),
|
210
|
+
),
|
211
|
+
("history_date", models.DateTimeField(db_index=True)),
|
212
|
+
("history_change_reason", models.CharField(max_length=100, null=True)),
|
213
|
+
(
|
214
|
+
"history_type",
|
215
|
+
models.CharField(
|
216
|
+
choices=[("+", "Created"), ("~", "Changed"), ("-", "Deleted")],
|
217
|
+
max_length=1,
|
218
|
+
),
|
219
|
+
),
|
220
|
+
(
|
221
|
+
"history_user",
|
222
|
+
models.ForeignKey(
|
223
|
+
null=True,
|
224
|
+
on_delete=django.db.models.deletion.SET_NULL,
|
225
|
+
related_name="+",
|
226
|
+
to=settings.AUTH_USER_MODEL,
|
227
|
+
),
|
228
|
+
),
|
229
|
+
(
|
230
|
+
"site",
|
231
|
+
models.ForeignKey(
|
232
|
+
blank=True,
|
233
|
+
db_constraint=False,
|
234
|
+
null=True,
|
235
|
+
on_delete=django.db.models.deletion.DO_NOTHING,
|
236
|
+
related_name="+",
|
237
|
+
to="sites.site",
|
238
|
+
),
|
239
|
+
),
|
240
|
+
],
|
241
|
+
options={
|
242
|
+
"verbose_name": "historical Screening: Missing OGTT Note",
|
243
|
+
"verbose_name_plural": "historical Screening: Missing OGTT Notes",
|
244
|
+
"ordering": ("-history_date", "-history_id"),
|
245
|
+
"get_latest_by": ("history_date", "history_id"),
|
246
|
+
},
|
247
|
+
bases=(simple_history.models.HistoricalChanges, models.Model),
|
248
|
+
),
|
249
|
+
migrations.CreateModel(
|
250
|
+
name="MissingOgttNote",
|
251
|
+
fields=[
|
252
|
+
(
|
253
|
+
"revision",
|
254
|
+
django_revision.revision_field.RevisionField(
|
255
|
+
blank=True,
|
256
|
+
editable=False,
|
257
|
+
help_text="System field. Git repository tag:branch:commit.",
|
258
|
+
max_length=75,
|
259
|
+
null=True,
|
260
|
+
verbose_name="Revision",
|
261
|
+
),
|
262
|
+
),
|
263
|
+
(
|
264
|
+
"created",
|
265
|
+
models.DateTimeField(
|
266
|
+
blank=True, default=django_audit_fields.models.audit_model_mixin.utcnow
|
267
|
+
),
|
268
|
+
),
|
269
|
+
(
|
270
|
+
"modified",
|
271
|
+
models.DateTimeField(
|
272
|
+
blank=True, default=django_audit_fields.models.audit_model_mixin.utcnow
|
273
|
+
),
|
274
|
+
),
|
275
|
+
(
|
276
|
+
"user_created",
|
277
|
+
django_audit_fields.fields.userfield.UserField(
|
278
|
+
blank=True,
|
279
|
+
help_text="Updated by admin.save_model",
|
280
|
+
max_length=50,
|
281
|
+
verbose_name="user created",
|
282
|
+
),
|
283
|
+
),
|
284
|
+
(
|
285
|
+
"user_modified",
|
286
|
+
django_audit_fields.fields.userfield.UserField(
|
287
|
+
blank=True,
|
288
|
+
help_text="Updated by admin.save_model",
|
289
|
+
max_length=50,
|
290
|
+
verbose_name="user modified",
|
291
|
+
),
|
292
|
+
),
|
293
|
+
(
|
294
|
+
"hostname_created",
|
295
|
+
models.CharField(
|
296
|
+
blank=True,
|
297
|
+
default=_socket.gethostname,
|
298
|
+
help_text="System field. (modified on create only)",
|
299
|
+
max_length=60,
|
300
|
+
verbose_name="Hostname created",
|
301
|
+
),
|
302
|
+
),
|
303
|
+
(
|
304
|
+
"hostname_modified",
|
305
|
+
django_audit_fields.fields.hostname_modification_field.HostnameModificationField(
|
306
|
+
blank=True,
|
307
|
+
help_text="System field. (modified on every save)",
|
308
|
+
max_length=50,
|
309
|
+
verbose_name="Hostname modified",
|
310
|
+
),
|
311
|
+
),
|
312
|
+
(
|
313
|
+
"device_created",
|
314
|
+
models.CharField(blank=True, max_length=10, verbose_name="Device created"),
|
315
|
+
),
|
316
|
+
(
|
317
|
+
"device_modified",
|
318
|
+
models.CharField(
|
319
|
+
blank=True, max_length=10, verbose_name="Device modified"
|
320
|
+
),
|
321
|
+
),
|
322
|
+
(
|
323
|
+
"locale_created",
|
324
|
+
models.CharField(
|
325
|
+
blank=True,
|
326
|
+
help_text="Auto-updated by Modeladmin",
|
327
|
+
max_length=10,
|
328
|
+
null=True,
|
329
|
+
verbose_name="Locale created",
|
330
|
+
),
|
331
|
+
),
|
332
|
+
(
|
333
|
+
"locale_modified",
|
334
|
+
models.CharField(
|
335
|
+
blank=True,
|
336
|
+
help_text="Auto-updated by Modeladmin",
|
337
|
+
max_length=10,
|
338
|
+
null=True,
|
339
|
+
verbose_name="Locale modified",
|
340
|
+
),
|
341
|
+
),
|
342
|
+
(
|
343
|
+
"id",
|
344
|
+
django_audit_fields.fields.uuid_auto_field.UUIDAutoField(
|
345
|
+
blank=True,
|
346
|
+
editable=False,
|
347
|
+
help_text="System auto field. UUID primary key.",
|
348
|
+
primary_key=True,
|
349
|
+
serialize=False,
|
350
|
+
),
|
351
|
+
),
|
352
|
+
("subject_identifier", models.CharField(max_length=50, unique=True)),
|
353
|
+
("report_model", models.CharField(max_length=150)),
|
354
|
+
("report_datetime", models.DateTimeField(default=edc_utils.date.get_utcnow)),
|
355
|
+
("note", models.TextField(blank=True, null=True)),
|
356
|
+
(
|
357
|
+
"ogtt_base_datetime",
|
358
|
+
models.DateTimeField(
|
359
|
+
blank=True,
|
360
|
+
help_text="(glucose solution given)",
|
361
|
+
null=True,
|
362
|
+
validators=[edc_model.validators.date.datetime_not_future],
|
363
|
+
verbose_name="Date/time oral glucose solution given",
|
364
|
+
),
|
365
|
+
),
|
366
|
+
(
|
367
|
+
"ogtt_value",
|
368
|
+
models.DecimalField(
|
369
|
+
blank=True,
|
370
|
+
decimal_places=2,
|
371
|
+
help_text="A `HIGH` reading may be entered as 9999.99",
|
372
|
+
max_digits=8,
|
373
|
+
null=True,
|
374
|
+
verbose_name="Blood glucose measure 2hrs <u>after</u> oral glucose solution given",
|
375
|
+
),
|
376
|
+
),
|
377
|
+
(
|
378
|
+
"ogtt_quantifier",
|
379
|
+
models.CharField(
|
380
|
+
choices=[
|
381
|
+
("=", "="),
|
382
|
+
(">", ">"),
|
383
|
+
(">=", ">="),
|
384
|
+
("<", "<"),
|
385
|
+
("<=", "<="),
|
386
|
+
],
|
387
|
+
default="=",
|
388
|
+
max_length=10,
|
389
|
+
),
|
390
|
+
),
|
391
|
+
(
|
392
|
+
"ogtt_units",
|
393
|
+
models.CharField(
|
394
|
+
choices=[
|
395
|
+
("mg/dL", "mg/dL"),
|
396
|
+
("mmol/L", "mmol/L (millimoles/L)"),
|
397
|
+
("N/A", "Not applicable"),
|
398
|
+
],
|
399
|
+
default="N/A",
|
400
|
+
max_length=15,
|
401
|
+
verbose_name="Units (Blood glucose 2hrs after...)",
|
402
|
+
),
|
403
|
+
),
|
404
|
+
(
|
405
|
+
"ogtt_datetime",
|
406
|
+
models.DateTimeField(
|
407
|
+
blank=True,
|
408
|
+
help_text="(2 hours after glucose solution given)",
|
409
|
+
null=True,
|
410
|
+
validators=[edc_model.validators.date.datetime_not_future],
|
411
|
+
verbose_name="Date/time blood glucose measured 2hrs <u>after</u> oral glucose solution given",
|
412
|
+
),
|
413
|
+
),
|
414
|
+
(
|
415
|
+
"status",
|
416
|
+
models.CharField(
|
417
|
+
choices=[
|
418
|
+
("done", "Done"),
|
419
|
+
("PENDING", "Data is pending"),
|
420
|
+
("not_available", "Data not available"),
|
421
|
+
],
|
422
|
+
default="done",
|
423
|
+
max_length=25,
|
424
|
+
),
|
425
|
+
),
|
426
|
+
(
|
427
|
+
"site",
|
428
|
+
models.ForeignKey(
|
429
|
+
null=True,
|
430
|
+
on_delete=django.db.models.deletion.PROTECT,
|
431
|
+
related_name="+",
|
432
|
+
to="sites.site",
|
433
|
+
),
|
434
|
+
),
|
435
|
+
],
|
436
|
+
options={
|
437
|
+
"verbose_name": "Screening: Missing OGTT Note",
|
438
|
+
"verbose_name_plural": "Screening: Missing OGTT Notes",
|
439
|
+
"abstract": False,
|
440
|
+
"default_permissions": ("add", "change", "delete", "view", "export", "import"),
|
441
|
+
"default_manager_name": "objects",
|
442
|
+
"indexes": [
|
443
|
+
models.Index(
|
444
|
+
fields=["modified", "created"], name="meta_report_modifie_4a4894_idx"
|
445
|
+
),
|
446
|
+
models.Index(
|
447
|
+
fields=["user_modified", "user_created"],
|
448
|
+
name="meta_report_user_mo_5b8129_idx",
|
449
|
+
),
|
450
|
+
],
|
451
|
+
},
|
452
|
+
managers=[
|
453
|
+
("on_site", edc_sites.managers.CurrentSiteManager()),
|
454
|
+
("objects", django.db.models.manager.Manager()),
|
455
|
+
],
|
456
|
+
),
|
457
|
+
]
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# Generated by Django 5.0.8 on 2024-08-23 14:26
|
2
|
+
|
3
|
+
import django.core.validators
|
4
|
+
from django.db import migrations, models
|
5
|
+
|
6
|
+
|
7
|
+
class Migration(migrations.Migration):
|
8
|
+
|
9
|
+
dependencies = [
|
10
|
+
("meta_reports", "0035_historicalmissingogttnote_missingogttnote"),
|
11
|
+
]
|
12
|
+
|
13
|
+
operations = [
|
14
|
+
migrations.AddField(
|
15
|
+
model_name="historicalmissingogttnote",
|
16
|
+
name="fasting",
|
17
|
+
field=models.CharField(
|
18
|
+
choices=[("Yes", "Yes"), ("No", "No")],
|
19
|
+
max_length=15,
|
20
|
+
null=True,
|
21
|
+
verbose_name="Did the participant fast?",
|
22
|
+
),
|
23
|
+
),
|
24
|
+
migrations.AddField(
|
25
|
+
model_name="historicalmissingogttnote",
|
26
|
+
name="fasting_duration_delta",
|
27
|
+
field=models.DurationField(
|
28
|
+
blank=True,
|
29
|
+
help_text="system calculated to microseconds. (hours=microseconds/3.6e+9)",
|
30
|
+
null=True,
|
31
|
+
),
|
32
|
+
),
|
33
|
+
migrations.AddField(
|
34
|
+
model_name="historicalmissingogttnote",
|
35
|
+
name="fasting_duration_str",
|
36
|
+
field=models.CharField(
|
37
|
+
blank=True,
|
38
|
+
help_text="As reported by patient. Duration of fast. Format is `HHhMMm`. For example 1h23m, 12h7m, etc",
|
39
|
+
max_length=8,
|
40
|
+
null=True,
|
41
|
+
validators=[
|
42
|
+
django.core.validators.RegexValidator(
|
43
|
+
"^([0-9]{1,3}h([0-5]?[0-9]m)?)$",
|
44
|
+
message="Invalid format. Expected something like 1h20m, 11h5m, etc. No spaces allowed.",
|
45
|
+
)
|
46
|
+
],
|
47
|
+
verbose_name="How long have they fasted in hours and/or minutes?",
|
48
|
+
),
|
49
|
+
),
|
50
|
+
migrations.AddField(
|
51
|
+
model_name="missingogttnote",
|
52
|
+
name="fasting",
|
53
|
+
field=models.CharField(
|
54
|
+
choices=[("Yes", "Yes"), ("No", "No")],
|
55
|
+
max_length=15,
|
56
|
+
null=True,
|
57
|
+
verbose_name="Did the participant fast?",
|
58
|
+
),
|
59
|
+
),
|
60
|
+
migrations.AddField(
|
61
|
+
model_name="missingogttnote",
|
62
|
+
name="fasting_duration_delta",
|
63
|
+
field=models.DurationField(
|
64
|
+
blank=True,
|
65
|
+
help_text="system calculated to microseconds. (hours=microseconds/3.6e+9)",
|
66
|
+
null=True,
|
67
|
+
),
|
68
|
+
),
|
69
|
+
migrations.AddField(
|
70
|
+
model_name="missingogttnote",
|
71
|
+
name="fasting_duration_str",
|
72
|
+
field=models.CharField(
|
73
|
+
blank=True,
|
74
|
+
help_text="As reported by patient. Duration of fast. Format is `HHhMMm`. For example 1h23m, 12h7m, etc",
|
75
|
+
max_length=8,
|
76
|
+
null=True,
|
77
|
+
validators=[
|
78
|
+
django.core.validators.RegexValidator(
|
79
|
+
"^([0-9]{1,3}h([0-5]?[0-9]m)?)$",
|
80
|
+
message="Invalid format. Expected something like 1h20m, 11h5m, etc. No spaces allowed.",
|
81
|
+
)
|
82
|
+
],
|
83
|
+
verbose_name="How long have they fasted in hours and/or minutes?",
|
84
|
+
),
|
85
|
+
),
|
86
|
+
]
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# Generated by Django 5.0.8 on 2024-08-23 14:40
|
2
|
+
|
3
|
+
from django.db import migrations, models
|
4
|
+
|
5
|
+
|
6
|
+
class Migration(migrations.Migration):
|
7
|
+
|
8
|
+
dependencies = [
|
9
|
+
("meta_reports", "0036_historicalmissingogttnote_fasting_and_more"),
|
10
|
+
]
|
11
|
+
|
12
|
+
operations = [
|
13
|
+
migrations.AddField(
|
14
|
+
model_name="historicalmissingogttnote",
|
15
|
+
name="result_status",
|
16
|
+
field=models.CharField(
|
17
|
+
choices=[("Yes", "Yes"), ("No", "No")],
|
18
|
+
default="Yes",
|
19
|
+
max_length=25,
|
20
|
+
verbose_name="Is the OGTT result available",
|
21
|
+
),
|
22
|
+
),
|
23
|
+
migrations.AddField(
|
24
|
+
model_name="missingogttnote",
|
25
|
+
name="result_status",
|
26
|
+
field=models.CharField(
|
27
|
+
choices=[("Yes", "Yes"), ("No", "No")],
|
28
|
+
default="Yes",
|
29
|
+
max_length=25,
|
30
|
+
verbose_name="Is the OGTT result available",
|
31
|
+
),
|
32
|
+
),
|
33
|
+
migrations.AlterField(
|
34
|
+
model_name="historicalmissingogttnote",
|
35
|
+
name="status",
|
36
|
+
field=models.CharField(
|
37
|
+
choices=[("COMPLETE", "Complete"), ("not_available", "Not available")],
|
38
|
+
default="done",
|
39
|
+
max_length=25,
|
40
|
+
),
|
41
|
+
),
|
42
|
+
migrations.AlterField(
|
43
|
+
model_name="missingogttnote",
|
44
|
+
name="status",
|
45
|
+
field=models.CharField(
|
46
|
+
choices=[("COMPLETE", "Complete"), ("not_available", "Not available")],
|
47
|
+
default="done",
|
48
|
+
max_length=25,
|
49
|
+
),
|
50
|
+
),
|
51
|
+
]
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# Generated by Django 5.0.8 on 2024-08-23 15:06
|
2
|
+
|
3
|
+
from django.db import migrations, models
|
4
|
+
|
5
|
+
|
6
|
+
class Migration(migrations.Migration):
|
7
|
+
|
8
|
+
dependencies = [
|
9
|
+
("meta_reports", "0037_historicalmissingogttnote_result_status_and_more"),
|
10
|
+
]
|
11
|
+
|
12
|
+
operations = [
|
13
|
+
migrations.AlterField(
|
14
|
+
model_name="historicalmissingogttnote",
|
15
|
+
name="fasting",
|
16
|
+
field=models.CharField(
|
17
|
+
choices=[("Yes", "Yes"), ("No", "No"), ("N/A", "Not applicable")],
|
18
|
+
default="N/A",
|
19
|
+
max_length=15,
|
20
|
+
verbose_name="Did the participant fast?",
|
21
|
+
),
|
22
|
+
),
|
23
|
+
migrations.AlterField(
|
24
|
+
model_name="missingogttnote",
|
25
|
+
name="fasting",
|
26
|
+
field=models.CharField(
|
27
|
+
choices=[("Yes", "Yes"), ("No", "No"), ("N/A", "Not applicable")],
|
28
|
+
default="N/A",
|
29
|
+
max_length=15,
|
30
|
+
verbose_name="Did the participant fast?",
|
31
|
+
),
|
32
|
+
),
|
33
|
+
]
|
meta_reports/models/__init__.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
from .glucose_summary import GlucoseSummary
|
2
|
-
from .missing_screening_ogtt import MissingScreeningOgtt
|
2
|
+
from .missing_screening_ogtt import NOTE_STATUSES, MissingOgttNote, MissingScreeningOgtt
|
3
3
|
from .patient_history_missing_baseline_cd4 import PatientHistoryMissingBaselineCd4
|
4
4
|
from .unattended_three_in_row import UnattendedThreeInRow
|
5
5
|
from .unattended_three_in_row2 import UnattendedThreeInRow2
|
@@ -0,0 +1,57 @@
|
|
1
|
+
from django.db import models
|
2
|
+
from edc_constants.choices import YES_NO, YES_NO_NA
|
3
|
+
from edc_constants.constants import COMPLETE, DONE, NOT_APPLICABLE, NOT_AVAILABLE, YES
|
4
|
+
from edc_glucose.model_mixins import (
|
5
|
+
fasting_model_mixin_factory,
|
6
|
+
ogtt_model_mixin_factory,
|
7
|
+
)
|
8
|
+
from edc_identifier.model_mixins import UniqueSubjectIdentifierFieldMixin
|
9
|
+
from edc_model.models import BaseUuidModel, HistoricalRecords
|
10
|
+
from edc_qareports.model_mixins import NoteModelMixin
|
11
|
+
|
12
|
+
NOTE_STATUSES = (
|
13
|
+
(COMPLETE, "Complete"),
|
14
|
+
(NOT_AVAILABLE, "Not available"),
|
15
|
+
)
|
16
|
+
|
17
|
+
|
18
|
+
class MissingOgttNote(
|
19
|
+
fasting_model_mixin_factory(
|
20
|
+
None,
|
21
|
+
fasting=models.CharField(
|
22
|
+
verbose_name="Did the participant fast?",
|
23
|
+
max_length=15,
|
24
|
+
choices=YES_NO_NA,
|
25
|
+
default=NOT_APPLICABLE,
|
26
|
+
blank=False,
|
27
|
+
),
|
28
|
+
),
|
29
|
+
ogtt_model_mixin_factory("ogtt"),
|
30
|
+
UniqueSubjectIdentifierFieldMixin,
|
31
|
+
NoteModelMixin,
|
32
|
+
):
|
33
|
+
"""Model class to replace default `Note` model used with
|
34
|
+
QA Report 'Screening: Missing OGTT'.
|
35
|
+
"""
|
36
|
+
|
37
|
+
result_status = models.CharField(
|
38
|
+
verbose_name="Is the OGTT result available", max_length=25, default=YES, choices=YES_NO
|
39
|
+
)
|
40
|
+
|
41
|
+
status = models.CharField(max_length=25, default=DONE, choices=NOTE_STATUSES)
|
42
|
+
|
43
|
+
history = HistoricalRecords()
|
44
|
+
|
45
|
+
def __str__(self) -> str:
|
46
|
+
return f"{self._meta.verbose_name}: {self.subject_identifier}"
|
47
|
+
|
48
|
+
def save(self, *args, **kwargs):
|
49
|
+
if self.result_status == YES:
|
50
|
+
self.status = COMPLETE
|
51
|
+
else:
|
52
|
+
self.status = NOT_AVAILABLE
|
53
|
+
super().save(*args, **kwargs)
|
54
|
+
|
55
|
+
class Meta(UniqueSubjectIdentifierFieldMixin.Meta, BaseUuidModel.Meta):
|
56
|
+
verbose_name = "Screening: Missing OGTT Note"
|
57
|
+
verbose_name_plural = "Screening: Missing OGTT Notes"
|
@@ -7,8 +7,6 @@ from .view_definition import get_view_definition
|
|
7
7
|
|
8
8
|
class MissingScreeningOgtt(QaReportModelMixin, DBView):
|
9
9
|
|
10
|
-
screening_identifier = models.CharField(max_length=25)
|
11
|
-
|
12
10
|
screening_datetime = models.DateTimeField(null=True)
|
13
11
|
|
14
12
|
fbg_datetime = models.DateTimeField(null=True)
|
@@ -4,8 +4,8 @@ mysql_view: str = """ # noqa
|
|
4
4
|
from (
|
5
5
|
select screening_identifier, site_id, report_datetime as 'screening_datetime', fbg_datetime,
|
6
6
|
converted_fbg_value as fbg_value, converted_ogtt_value as ogtt_value, repeat_glucose_performed as repeated,
|
7
|
-
p3_ltfu, fbg2_value, ogtt2_value, fbg2_datetime, ogtt2_datetime, consented,
|
8
|
-
id as original_id
|
7
|
+
p3_ltfu, fbg2_value, ogtt2_value, fbg2_datetime, ogtt2_datetime, consented,
|
8
|
+
screening_identifier as subject_identifier, id as original_id
|
9
9
|
from meta_screening_subjectscreening
|
10
10
|
where converted_fbg_value is not null and converted_ogtt_value is null and unsuitable_agreed != "Yes"
|
11
11
|
) as A
|
@@ -18,8 +18,8 @@ pg_view: str = """ # noqa
|
|
18
18
|
from (
|
19
19
|
select screening_identifier, site_id, report_datetime as 'screening_datetime', fbg_datetime,
|
20
20
|
converted_fbg_value as fbg_value, converted_ogtt_value as ogtt_value, repeat_glucose_performed as repeated,
|
21
|
-
p3_ltfu, fbg2_value, ogtt2_value, fbg2_datetime, ogtt2_datetime, consented,
|
22
|
-
id as original_id
|
21
|
+
p3_ltfu, fbg2_value, ogtt2_value, fbg2_datetime, ogtt2_datetime, consented,
|
22
|
+
screening_identifier as subject_identifier, id as original_id
|
23
23
|
from meta_screening_subjectscreening
|
24
24
|
where converted_fbg_value is not null and converted_ogtt_value is null and unsuitable_agreed != "Yes"
|
25
25
|
) as A
|
@@ -38,8 +38,8 @@ SELECT *, lower(
|
|
38
38
|
from (
|
39
39
|
select screening_identifier, site_id, report_datetime as 'screening_datetime', fbg_datetime,
|
40
40
|
converted_fbg_value as fbg_value, converted_ogtt_value as ogtt_value, fbg2_value, ogtt2_value,
|
41
|
-
repeat_glucose_performed as repeated, p3_ltfu, fbg2_datetime, ogtt2_datetime, consented,
|
42
|
-
id as original_id
|
41
|
+
repeat_glucose_performed as repeated, p3_ltfu, fbg2_datetime, ogtt2_datetime, consented,
|
42
|
+
screening_identifier as subject_identifier, id as original_id
|
43
43
|
from meta_screening_subjectscreening
|
44
44
|
where converted_fbg_value is not null and converted_ogtt_value is null and unsuitable_agreed != "Yes"
|
45
45
|
) as A
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|