diff --git a/smash/web/migrations/0071_auto_20171130_1607.py b/smash/web/migrations/0071_auto_20171130_1607.py new file mode 100644 index 0000000000000000000000000000000000000000..c757fdc14f19e05e1dc95a1518757140e59179db --- /dev/null +++ b/smash/web/migrations/0071_auto_20171130_1607.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2017-11-30 16:07 +from __future__ import unicode_literals + +import django.db.models.deletion +from django.db import migrations, models + + +# noinspection PyUnusedLocal +# noinspection PyPep8Naming +def create_default_study(apps, schema_editor): + # We can't import the Study model directly as it may be a newer + # version than this migration expects. We use the historical version. + Study = apps.get_model("web", "Study") + study = Study.objects.create() + study.name = "New study" + study.save() + + +class Migration(migrations.Migration): + dependencies = [ + ('web', '0070_auto_20171128_1124'), + ] + + operations = [ + migrations.CreateModel( + name='Study', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255, verbose_name=b'Name')), + ], + ), + migrations.AlterField( + model_name='studysubject', + name='subject', + field=models.ForeignKey(editable=False, on_delete=django.db.models.deletion.CASCADE, to='web.Subject', + verbose_name=b'Subject'), + ), + migrations.AddField( + model_name='studysubject', + name='study', + field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, + to='web.Study', verbose_name=b'Study'), + ), + migrations.RunPython(create_default_study), + migrations.AlterField( + model_name='studysubject', + name='study', + field=models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.CASCADE, to='web.Study', verbose_name=b'Study'), + preserve_default=False, + ), + + ] diff --git a/smash/web/models/__init__.py b/smash/web/models/__init__.py index 2b7f7dba19788a6778d0430ed60436cc0c6c4e88..de19e31d99316eea3864bec1fa3fd598ca48d04f 100644 --- a/smash/web/models/__init__.py +++ b/smash/web/models/__init__.py @@ -8,6 +8,7 @@ from flying_team import FlyingTeam from location import Location from appointment_type_link import AppointmentTypeLink from country import Country +from study import Study from room import Room from visit import Visit from worker import Worker @@ -25,6 +26,6 @@ from missing_subject import MissingSubject from inconsistent_subject import InconsistentSubject, InconsistentField -__all__ = [FlyingTeam, Appointment, AppointmentType, Availability, Holiday, Item, Language, Location, Room, Subject, StudySubject, +__all__ = [Study, FlyingTeam, Appointment, AppointmentType, Availability, Holiday, Item, Language, Location, Room, Subject, StudySubject, Visit, Worker, ContactAttempt, ConfigurationItem, MailTemplate, AppointmentTypeLink, MissingSubject, InconsistentSubject, InconsistentField, Country] diff --git a/smash/web/models/constants.py b/smash/web/models/constants.py index d2defa4d3d1f8a52f4f40fe60fc0dcf71f0963be..fe6ade3b9b0c61fb9df46206f7c427d0735157f9 100644 --- a/smash/web/models/constants.py +++ b/smash/web/models/constants.py @@ -76,4 +76,8 @@ REDCAP_TOKEN_CONFIGURATION_TYPE = "REDCAP_TOKEN_CONFIGURATION_TYPE" REDCAP_BASE_URL_CONFIGURATION_TYPE = "REDCAP_BASE_URL_CONFIGURATION_TYPE" COUNTRY_OTHER_ID = 1 -COUNTRY_AFGHANISTAN_ID = 2 \ No newline at end of file +COUNTRY_AFGHANISTAN_ID = 2 + +# id of the singleton Study, +# TODO remove after allowing many studies per Smasch instance +GLOBAL_STUDY_ID = 1 diff --git a/smash/web/models/study.py b/smash/web/models/study.py new file mode 100644 index 0000000000000000000000000000000000000000..469c5f4ebaa1ff0485499a04ce4f9f6bd7ee9834 --- /dev/null +++ b/smash/web/models/study.py @@ -0,0 +1,15 @@ +# coding=utf-8 +from django.db import models + + +class Study(models.Model): + class Meta: + app_label = 'web' + + name = models.CharField(max_length=255, verbose_name='Name') + + def __str__(self): + return "%s" % self.name + + def __unicode__(self): + return "%s" % self.name diff --git a/smash/web/models/study_subject.py b/smash/web/models/study_subject.py index 7fdc2eaca43b9bfffe90bca16f298dc88056d1ec..29af95317831116ccb0bf01b162c31ad8d191db1 100644 --- a/smash/web/models/study_subject.py +++ b/smash/web/models/study_subject.py @@ -33,6 +33,12 @@ class StudySubject(models.Model): null=False, ) + study = models.ForeignKey("web.Study", + verbose_name='Study', + editable=False, + null=False, + ) + postponed = models.BooleanField(choices=BOOL_CHOICES, verbose_name='Postponed', default=False diff --git a/smash/web/tests/forms/test_StudySubjectAddForm.py b/smash/web/tests/forms/test_StudySubjectAddForm.py index a417a5bb3f11f562dbf2121b02c4074d3f5f45ff..21ff5486c2c5b01c2dc6a250e72d1d73b4c32576 100644 --- a/smash/web/tests/forms/test_StudySubjectAddForm.py +++ b/smash/web/tests/forms/test_StudySubjectAddForm.py @@ -3,7 +3,7 @@ import logging from web.forms import StudySubjectAddForm, get_new_screening_number from web.models.constants import SUBJECT_TYPE_CHOICES_CONTROL from web.tests import LoggedInWithWorkerTestCase -from web.tests.functions import create_study_subject, create_subject +from web.tests.functions import create_study_subject, create_subject, get_test_study logger = logging.getLogger(__name__) @@ -14,6 +14,7 @@ class StudySubjectAddFormTests(LoggedInWithWorkerTestCase): location = self.worker.locations.all()[0] self.subject = create_subject() + self.study = get_test_study() self.sample_data = { 'type': SUBJECT_TYPE_CHOICES_CONTROL, 'default_location': location.id, @@ -33,6 +34,7 @@ class StudySubjectAddFormTests(LoggedInWithWorkerTestCase): form = StudySubjectAddForm(data=form_data, user=self.user) form.is_valid() form.instance.subject_id = self.subject.id + form.instance.study_id = self.study.id self.assertTrue(form.is_valid()) self.assertIsNone(form.fields['year_of_diagnosis'].initial) form.save() @@ -50,6 +52,7 @@ class StudySubjectAddFormTests(LoggedInWithWorkerTestCase): form.is_valid() self.assertTrue(form.is_valid()) form.instance.subject_id = self.subject.id + form.instance.study_id = self.study.id form.save() form_data['screening_number'] = "2" @@ -66,6 +69,7 @@ class StudySubjectAddFormTests(LoggedInWithWorkerTestCase): form.is_valid() self.assertTrue(form.is_valid()) form.instance.subject_id = self.subject.id + form.instance.study_id = self.study.id form.save() form_data['screening_number'] = "2" diff --git a/smash/web/tests/functions.py b/smash/web/tests/functions.py index adb1eaf8511656ec1b92688405d4979d893ccb53..be71820bdffef0bfb153445509324462c1315be1 100644 --- a/smash/web/tests/functions.py +++ b/smash/web/tests/functions.py @@ -4,7 +4,7 @@ import os from django.contrib.auth.models import User from web.models import Location, AppointmentType, StudySubject, Worker, Visit, Appointment, ConfigurationItem, Language, \ - ContactAttempt, FlyingTeam, Availability, Subject + ContactAttempt, FlyingTeam, Availability, Subject, Study from web.models.constants import REDCAP_TOKEN_CONFIGURATION_TYPE, REDCAP_BASE_URL_CONFIGURATION_TYPE, \ SEX_CHOICES_MALE, SUBJECT_TYPE_CHOICES_CONTROL, CONTACT_TYPES_PHONE, \ MONDAY_AS_DAY_OF_WEEK, COUNTRY_AFGHANISTAN_ID @@ -23,6 +23,10 @@ def create_location(name="test"): return Location.objects.create(name=name) +def create_study(name="test"): + return Study.objects.create(name=name) + + def get_test_location(): locations = Location.objects.filter(name="test") if len(locations) > 0: @@ -31,6 +35,14 @@ def get_test_location(): return create_location() +def get_test_study(): + locations = Study.objects.filter(name="test-study") + if len(locations) > 0: + return locations[0] + else: + return create_study("test-study") + + def create_appointment_type(): return AppointmentType.objects.create( code="C", @@ -70,6 +82,7 @@ def create_study_subject(subject_id=1, subject=None): default_location=get_test_location(), type=SUBJECT_TYPE_CHOICES_CONTROL, screening_number="piotr's number" + str(subject_id), + study=get_test_study(), subject=subject ) diff --git a/smash/web/tests/models/test_study.py b/smash/web/tests/models/test_study.py new file mode 100644 index 0000000000000000000000000000000000000000..9c9e02f77c08015bd59a4ef19149945caa5a0e6b --- /dev/null +++ b/smash/web/tests/models/test_study.py @@ -0,0 +1,14 @@ +import logging + +from django.test import TestCase + +from web.tests.functions import create_study + +logger = logging.getLogger(__name__) + + +class StudyTests(TestCase): + def test_image_img(self): + study = create_study() + + self.assertTrue(study.name in str(study)) diff --git a/smash/web/views/subject.py b/smash/web/views/subject.py index 53ceafe61a78afb0d1e260df5cfb4e8248e547b5..d8d040461219930f21eaa04c6907c8055ba365a7 100644 --- a/smash/web/views/subject.py +++ b/smash/web/views/subject.py @@ -4,6 +4,7 @@ import logging from django.contrib import messages from django.shortcuts import redirect, get_object_or_404 +from ..models.constants import GLOBAL_STUDY_ID from . import wrap_response from ..forms import StudySubjectAddForm, StudySubjectEditForm, VisitDetailForm, SubjectEditForm, SubjectAddForm from ..models import StudySubject, MailTemplate, Worker @@ -31,6 +32,7 @@ def subject_add(request): if study_subject_form.is_valid() and subject_form.is_valid(): subject = subject_form.save() study_subject_form.instance.subject_id = subject.id + study_subject_form.instance.study_id = GLOBAL_STUDY_ID study_subject_form.save() messages.add_message(request, messages.SUCCESS, 'Subject created') return redirect('web.views.subject_edit', id=study_subject_form.instance.id)