From f75d497b81c5ca3194068a670bd1724af3a10b24 Mon Sep 17 00:00:00 2001 From: Tobias Bengfort Date: Wed, 29 Apr 2020 16:02:47 +0200 Subject: [PATCH 1/4] demo content: do not assign study_types --- .../recruitment/management/commands/create_demo_content.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/castellum/recruitment/management/commands/create_demo_content.py b/castellum/recruitment/management/commands/create_demo_content.py index 18aade902..67e522332 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 -- GitLab From 2984533c2398596265f0d979588c4e75fb6a244c Mon Sep 17 00:00:00 2001 From: Tobias Bengfort Date: Wed, 29 Apr 2020 16:28:40 +0200 Subject: [PATCH 2/4] mv study_type to session --- .../templates/recruitment/contact.html | 2 +- castellum/studies/forms.py | 9 ++++++-- .../migrations/0009_studysession_type.py | 22 +++++++++++++++++++ castellum/studies/models.py | 6 ++++- .../templates/studies/study_detail.html | 2 +- .../studies/templates/studies/study_form.html | 1 - .../templates/studies/study_sessions.html | 2 ++ castellum/studies/views/recruitment.py | 11 +++------- castellum/studies/views/studies.py | 2 +- .../recruitment/models/test_subjectfilters.py | 4 +++- 10 files changed, 45 insertions(+), 16 deletions(-) create mode 100644 castellum/studies/migrations/0009_studysession_type.py diff --git a/castellum/recruitment/templates/recruitment/contact.html b/castellum/recruitment/templates/recruitment/contact.html index 9bb41aa35..49df62404 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 fac504437..85046cfb7 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 000000000..83baf458e --- /dev/null +++ b/castellum/studies/migrations/0009_studysession_type.py @@ -0,0 +1,22 @@ +# Generated by Django 3.0.5 on 2020-04-29 14:01 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('studies', '0008_study_type_rm_3rd_party') + ] + + operations = [ + migrations.RemoveField( + model_name='study', + name='study_type', + ), + migrations.AddField( + model_name='studysession', + name='type', + field=models.ManyToManyField(blank=True, to='studies.StudyType', verbose_name='Type'), + ), + ] diff --git a/castellum/studies/models.py b/castellum/studies/models.py index af26f3184..398b0c1b3 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 d45b1ff8d..dabfc1617 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 d9173f0c9..9549ccb53 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 eca14313e..464f02377 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 6bdb84ab5..035c9e6b3 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 e52399ed5..996a13a52 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) diff --git a/tests/recruitment/models/test_subjectfilters.py b/tests/recruitment/models/test_subjectfilters.py index a99ae21d8..8f4bce00c 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() -- GitLab From b7c4c0f68a925590d5df2efcbad23bc8ad13673b Mon Sep 17 00:00:00 2001 From: Tobias Bengfort Date: Wed, 29 Apr 2020 16:59:37 +0200 Subject: [PATCH 3/4] migrate data --- .../migrations/0009_studysession_type.py | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/castellum/studies/migrations/0009_studysession_type.py b/castellum/studies/migrations/0009_studysession_type.py index 83baf458e..90890ba08 100644 --- a/castellum/studies/migrations/0009_studysession_type.py +++ b/castellum/studies/migrations/0009_studysession_type.py @@ -1,8 +1,20 @@ -# Generated by Django 3.0.5 on 2020-04-29 14:01 - 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 = [ @@ -10,13 +22,14 @@ class Migration(migrations.Migration): ] operations = [ - migrations.RemoveField( - model_name='study', - name='study_type', - ), 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', + ), ] -- GitLab From 54575bb8d039a12815ea0fede1ef176e5eb62c91 Mon Sep 17 00:00:00 2001 From: Tobias Bengfort Date: Tue, 5 May 2020 10:46:41 +0200 Subject: [PATCH 4/4] duplicate session types --- castellum/studies/views/studies.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/castellum/studies/views/studies.py b/castellum/studies/views/studies.py index 996a13a52..3c7286342 100644 --- a/castellum/studies/views/studies.py +++ b/castellum/studies/views/studies.py @@ -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 -- GitLab