diff --git a/breccia_mapper/urls.py b/breccia_mapper/urls.py index 2806827..0aade11 100644 --- a/breccia_mapper/urls.py +++ b/breccia_mapper/urls.py @@ -19,7 +19,11 @@ from django.urls import include, path from . import views urlpatterns = [ - path('admin/', admin.site.urls), + path('admin/', + admin.site.urls), + + path('select2/', + include('django_select2.urls')), path('', include('django.contrib.auth.urls')), @@ -36,4 +40,4 @@ urlpatterns = [ path('', include('activities.urls')), -] +] # yapf: disable diff --git a/people/forms.py b/people/forms.py index 5f7c5a3..7ddf909 100644 --- a/people/forms.py +++ b/people/forms.py @@ -8,7 +8,7 @@ from django import forms from django.forms.widgets import SelectDateWidget from django.utils import timezone -from django_select2.forms import Select2Widget, Select2MultipleWidget +from django_select2.forms import ModelSelect2Widget, Select2Widget, Select2MultipleWidget from . import models @@ -60,6 +60,12 @@ class PersonForm(forms.ModelForm): years=get_date_year_range()) +class RelationshipForm(forms.Form): + target = forms.ModelChoiceField( + models.Person.objects.all(), + widget=ModelSelect2Widget(search_fields=['name__icontains'])) + + class DynamicAnswerSetBase(forms.Form): field_class = forms.ModelChoiceField field_widget = None diff --git a/people/permissions.py b/people/permissions.py index 2e6c585..5e17f19 100644 --- a/people/permissions.py +++ b/people/permissions.py @@ -23,7 +23,9 @@ class UserIsLinkedPersonMixin(UserPassesTestMixin): test_person = self.get_object() if not isinstance(test_person, models.Person): - raise AttributeError('View incorrectly configured: \'related_person_field\' must be defined.') + raise AttributeError( + 'View incorrectly configured: \'related_person_field\' must be defined.' + ) return test_person @@ -34,4 +36,5 @@ class UserIsLinkedPersonMixin(UserPassesTestMixin): Require that user is either staff or is the linked person. """ user = self.request.user - return user.is_authenticated and (user.is_staff or self.get_test_person() == user.person) + return user.is_authenticated and ( + user.is_staff or self.get_test_person() == user.person) diff --git a/people/views/relationship.py b/people/views/relationship.py index 8709b99..3ea46d9 100644 --- a/people/views/relationship.py +++ b/people/views/relationship.py @@ -2,9 +2,11 @@ Views for displaying or manipulating instances of :class:`Relationship`. """ +from django.db import IntegrityError +from django.forms import ValidationError from django.urls import reverse from django.utils import timezone -from django.views.generic import CreateView, DetailView +from django.views.generic import CreateView, DetailView, FormView from people import forms, models, permissions @@ -18,7 +20,7 @@ class RelationshipDetailView(permissions.UserIsLinkedPersonMixin, DetailView): related_person_field = 'source' -class RelationshipCreateView(permissions.UserIsLinkedPersonMixin, CreateView): +class RelationshipCreateView(permissions.UserIsLinkedPersonMixin, FormView): """ View for creating a :class:`Relationship`. @@ -26,53 +28,45 @@ class RelationshipCreateView(permissions.UserIsLinkedPersonMixin, CreateView): """ model = models.Relationship template_name = 'people/relationship/create.html' - fields = [ - 'source', - 'target', - ] - - def get_test_person(self) -> models.Person: - """ - Get the person instance which should be used for access control checks. - """ - if self.request.method == 'POST': - return models.Person.objects.get(pk=self.request.POST.get('source')) + form_class = forms.RelationshipForm + def get_person(self) -> models.Person: return models.Person.objects.get(pk=self.kwargs.get('person_pk')) - def get(self, request, *args, **kwargs): - self.person = models.Person.objects.get(pk=self.kwargs.get('person_pk')) + def get_test_person(self) -> models.Person: + return self.get_person() - return super().get(request, *args, **kwargs) + def form_valid(self, form): + try: + self.object = models.Relationship.objects.create( + source=self.get_person(), target=form.cleaned_data['target']) - def post(self, request, *args, **kwargs): - self.person = models.Person.objects.get(pk=self.kwargs.get('person_pk')) + except IntegrityError: + form.add_error( + None, + ValidationError('This relationship already exists', + code='already-exists')) + return self.form_invalid(form) - return super().post(request, *args, **kwargs) - - def get_initial(self): - initial = super().get_initial() - - initial['source'] = self.request.user.person - initial['target'] = self.person - - return initial + return super().form_valid(form) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context['person'] = self.person + context['person'] = self.get_person() return context def get_success_url(self): - return reverse('people:relationship.update', kwargs={'relationship_pk': self.object.pk}) + return reverse('people:relationship.update', + kwargs={'relationship_pk': self.object.pk}) class RelationshipUpdateView(permissions.UserIsLinkedPersonMixin, CreateView): """ - View for creating a :class:`Relationship`. + View for updating the details of a relationship. + Creates a new :class:`RelationshipAnswerSet` for the :class:`Relationship`. Displays / processes a form containing the :class:`RelationshipQuestion`s. """ model = models.RelationshipAnswerSet @@ -83,18 +77,21 @@ class RelationshipUpdateView(permissions.UserIsLinkedPersonMixin, CreateView): """ Get the person instance which should be used for access control checks. """ - relationship = models.Relationship.objects.get(pk=self.kwargs.get('relationship_pk')) + relationship = models.Relationship.objects.get( + pk=self.kwargs.get('relationship_pk')) return relationship.source def get(self, request, *args, **kwargs): - self.relationship = models.Relationship.objects.get(pk=self.kwargs.get('relationship_pk')) + self.relationship = models.Relationship.objects.get( + pk=self.kwargs.get('relationship_pk')) self.person = self.relationship.source return super().get(request, *args, **kwargs) def post(self, request, *args, **kwargs): - self.relationship = models.Relationship.objects.get(pk=self.kwargs.get('relationship_pk')) + self.relationship = models.Relationship.objects.get( + pk=self.kwargs.get('relationship_pk')) self.person = self.relationship.source return super().post(request, *args, **kwargs) @@ -122,7 +119,8 @@ class RelationshipUpdateView(permissions.UserIsLinkedPersonMixin, CreateView): now_date = timezone.now().date() # Shouldn't be more than one after initial updates after migration - for answer_set in self.relationship.answer_sets.exclude(pk=self.object.pk): + for answer_set in self.relationship.answer_sets.exclude( + pk=self.object.pk): answer_set.replaced_timestamp = now_date answer_set.save()