diff --git a/castellum/recruitment/management/commands/create_demo_content.py b/castellum/recruitment/management/commands/create_demo_content.py index 18aade902383f8576c29803071b6374b733c8408..67e5223321c5efe11f45318bdc122dc40a2bdc18 100644 --- a/castellum/recruitment/management/commands/create_demo_content.py +++ b/castellum/recruitment/management/commands/create_demo_content.py @@ -35,7 +35,6 @@ from castellum.recruitment.models import AttributeChoice from castellum.recruitment.models import AttributeSet from castellum.studies.models import Study from castellum.studies.models import StudySession -from castellum.studies.models import StudyType from castellum.subjects.models import Consent from castellum.subjects.models import ConsentDocument from castellum.subjects.models import Subject @@ -195,10 +194,6 @@ def generate_studies(count): study.save() StudySession.objects.bulk_create(fake_studysession(study) for study in studies) - study_types = list(StudyType.objects.all()) - for study in studies: - study.study_type.add(fake.random.choice(study_types)) - def generate_subjects(count): # NOTE: We have ForeignKeys to Address and Subject. Unfortunately, bulk_create does not set diff --git a/castellum/recruitment/templates/recruitment/contact.html b/castellum/recruitment/templates/recruitment/contact.html index 9bb41aa35c9d96071b48187ab0610ad7da668057..49df6240495bd7856426033ebb6fab9686f66dc6 100644 --- a/castellum/recruitment/templates/recruitment/contact.html +++ b/castellum/recruitment/templates/recruitment/contact.html @@ -102,7 +102,7 @@
{{ study|verbose_name:'recruitment_text' }}
{{ study|display:'recruitment_text' }}
-
{{ study|verbose_name:'study_type' }}
+
{% trans 'Type of study' %}
{{ study|display:'study_type' }}
{{ study|verbose_name:'expense_allowance' }}
diff --git a/castellum/studies/forms.py b/castellum/studies/forms.py index fac504437bfd2f7afe8678df53de855fb5f856e8..85046cfb778fcf0b38346f3cc7aea7935928ebc2 100644 --- a/castellum/studies/forms.py +++ b/castellum/studies/forms.py @@ -45,14 +45,19 @@ class StudyForm(ReadonlyModelForm): 'affiliated_research_assistants', 'description', 'keywords', - 'study_type', 'data_sensitivity', 'consent', 'min_subject_count', 'expense_allowance', ] + + +class SessionForm(ReadonlyModelForm): + class Meta: + model = models.StudySession + fields = ('name', 'duration', 'resource', 'type') widgets = { - 'study_type': forms.CheckboxSelectMultiple(), + 'type': forms.CheckboxSelectMultiple(), } diff --git a/castellum/studies/migrations/0009_studysession_type.py b/castellum/studies/migrations/0009_studysession_type.py new file mode 100644 index 0000000000000000000000000000000000000000..90890ba08118e151b27f56b73adeefafe9d3c15b --- /dev/null +++ b/castellum/studies/migrations/0009_studysession_type.py @@ -0,0 +1,35 @@ +from django.db import migrations, models + + +def migrate_data(apps, schema_editor): + Study = apps.get_model('studies', 'Study') + StudySession = apps.get_model('studies', 'StudySession') + + for study in Study.objects.all(): + if not study.study_type.exists(): + continue + try: + session = study.studysession_set.first() + except StudySession.DoesNotExist: + session = study.studysession_set.create(name='session', duration=0) + session.type.set(study.study_type.all()) + + +class Migration(migrations.Migration): + + dependencies = [ + ('studies', '0008_study_type_rm_3rd_party') + ] + + operations = [ + migrations.AddField( + model_name='studysession', + name='type', + field=models.ManyToManyField(blank=True, to='studies.StudyType', verbose_name='Type'), + ), + migrations.RunPython(migrate_data), + migrations.RemoveField( + model_name='study', + name='study_type', + ), + ] diff --git a/castellum/studies/models.py b/castellum/studies/models.py index af26f318492013618a293e58561c9e173372d674..398b0c1b399bce90ab1668a35c5370d0f6bd04fa 100644 --- a/castellum/studies/models.py +++ b/castellum/studies/models.py @@ -78,7 +78,6 @@ class Study(models.Model): ) description = models.TextField(_('Description'), blank=True) keywords = models.CharField(_('Keywords'), max_length=254, blank=True) - study_type = models.ManyToManyField(StudyType, verbose_name=_('Type of study'), blank=True) previous_status = models.SmallIntegerField( _('Previous status'), choices=STATUS, default=EDIT ) @@ -203,6 +202,10 @@ class Study(models.Model): result = self.subjectfiltergroup_set.aggregate(models.Max(key)) return result[key + '__max'] or 0 + @property + def study_type(self): + return StudyType.objects.filter(studysession__study=self).distinct() + @property def followup_urgent(self): today = datetime.date.today() @@ -266,6 +269,7 @@ class StudySession(models.Model): study = models.ForeignKey(Study, on_delete=models.CASCADE) name = models.CharField(_('Name'), max_length=128) duration = models.PositiveIntegerField(_('Duration of a session in minutes')) + type = models.ManyToManyField(StudyType, verbose_name=_('Type'), blank=True) resource = models.ForeignKey( Resource, on_delete=models.SET_NULL, verbose_name=_('Resource'), blank=True, null=True ) diff --git a/castellum/studies/templates/studies/study_detail.html b/castellum/studies/templates/studies/study_detail.html index d45b1ff8d4b8f0fbe5014b5e1c687c8f693a843a..dabfc1617d4f58110be98809accc88a166ca3f1c 100644 --- a/castellum/studies/templates/studies/study_detail.html +++ b/castellum/studies/templates/studies/study_detail.html @@ -11,7 +11,7 @@
{{ object|verbose_name:'affiliated_scientists' }}
{{ object|display:'affiliated_scientists' }}
-
{{ object|verbose_name:'study_type' }}
+
{% trans 'Type of study' %}
{{ object|display:'study_type' }}
{% trans 'Scheduled runtime' %}
diff --git a/castellum/studies/templates/studies/study_form.html b/castellum/studies/templates/studies/study_form.html index d9173f0c9908a30702d34a3628887e405f76a444..9549ccb53e74e14a8396e1dce8af5b15d797a848 100644 --- a/castellum/studies/templates/studies/study_form.html +++ b/castellum/studies/templates/studies/study_form.html @@ -25,7 +25,6 @@ {% bootstrap_field form.affiliated_research_assistants %} {% bootstrap_field form.description %} {% bootstrap_field form.keywords %} - {% bootstrap_field form.study_type %} {% bootstrap_field form.data_sensitivity %} {% include "file_field.html" with field=form.consent %} {% bootstrap_field form.min_subject_count %} diff --git a/castellum/studies/templates/studies/study_sessions.html b/castellum/studies/templates/studies/study_sessions.html index eca14313e3d5bdfb38e05b190d613cb4963905ca..464f02377134c2568f4672c981754105a3ba438e 100644 --- a/castellum/studies/templates/studies/study_sessions.html +++ b/castellum/studies/templates/studies/study_sessions.html @@ -16,6 +16,7 @@ {% else %} {% endif %} + {% bootstrap_field template_form.type %} @@ -44,6 +45,7 @@ {% else %} {% endif %} + {% bootstrap_field subform.type %} {% endfor %} diff --git a/castellum/studies/views/recruitment.py b/castellum/studies/views/recruitment.py index 6bdb84ab51c121e6badb635d811c40f00a012a1a..035c9e6b3a47059995fa16ee21474de5b7789ace 100644 --- a/castellum/studies/views/recruitment.py +++ b/castellum/studies/views/recruitment.py @@ -34,10 +34,10 @@ from castellum.recruitment import filter_queries from castellum.recruitment.models import ParticipationRequest from castellum.recruitment.models import SubjectFilter from castellum.subjects.models import Subject -from castellum.utils.forms import ReadonlyModelForm from castellum.utils.views import ReadonlyMixin from ..forms import ExcludedStudiesForm +from ..forms import SessionForm from ..mixins import StudyMixin from ..models import Resource from ..models import Study @@ -151,16 +151,11 @@ class StudySessionsView( subtab = 'sessions' def get_session_form(self): - form_class = forms.modelform_factory(StudySession, fields=('name', 'duration', 'resource')) - return form_class(prefix='{prefix}') + return SessionForm(prefix='{prefix}') def get_session_formset(self): formset_class = forms.modelformset_factory( - StudySession, - fields=('name', 'duration', 'resource'), - form=ReadonlyModelForm, - extra=0, - can_delete=True, + StudySession, form=SessionForm, extra=0, can_delete=True ) kwargs = self.get_form_kwargs() study = kwargs.pop('instance', None) diff --git a/castellum/studies/views/studies.py b/castellum/studies/views/studies.py index e52399ed547d5f5913c24708860cafb5a967e65e..3c7286342de9f1bc4bf745795f1ed9d4a55c50df 100644 --- a/castellum/studies/views/studies.py +++ b/castellum/studies/views/studies.py @@ -74,7 +74,7 @@ class StudyIndexView(LoginRequiredMixin, ListView): models.Q(contact_person__icontains=part) | models.Q(description__icontains=part) | models.Q(keywords__icontains=part) | - models.Q(study_type__translations__label__iexact=part) + models.Q(studysession__study_type__translations__label__iexact=part) ) if 'all' not in self.request.GET: qs = qs.filter(studymembership__user=self.request.user) @@ -134,11 +134,12 @@ class StudyCreateView(PermissionRequiredMixin, CreateView): self.object.save() for session in self.duplicate.studysession_set.all(): - self.object.studysession_set.create( + s = self.object.studysession_set.create( name=session.name, duration=session.duration, resource_id=session.resource_id, ) + s.type.set(session.type.all()) return response diff --git a/tests/recruitment/models/test_subjectfilters.py b/tests/recruitment/models/test_subjectfilters.py index a99ae21d8cb08c39ddf41027de8af1a32c3d62b3..8f4bce00cd4e0c314131f178bfc7953f06e4c4a0 100644 --- a/tests/recruitment/models/test_subjectfilters.py +++ b/tests/recruitment/models/test_subjectfilters.py @@ -7,6 +7,7 @@ from castellum.recruitment.models import ParticipationRequest from castellum.recruitment.models import SubjectFilter from castellum.recruitment.models import SubjectFilterGroup from castellum.studies.models import Study +from castellum.studies.models import StudySession from castellum.studies.models import StudyType from castellum.subjects.models import Subject @@ -102,7 +103,8 @@ def test_to_q_first_study_exclusive_second_study_unfinished(attributeset): def test_disinterest_in_study_type(db): study_type = StudyType.objects.first() study = baker.make(Study) - study.study_type.add(study_type) + session = baker.make(StudySession, study=study) + session.type.add(study_type) baker.make(AttributeSet, study_type_disinterest=[study_type]) assert not Subject.objects.filter(filter_queries.study(study)).exists()