diff --git a/people/forms.py b/people/forms.py index 0d49422..e6c4fe8 100644 --- a/people/forms.py +++ b/people/forms.py @@ -1,7 +1,6 @@ """ Forms for creating / updating models belonging to the 'people' app. """ - from django import forms from . import models @@ -17,3 +16,42 @@ class PersonForm(forms.ModelForm): 'name', 'core_member', ] + + +class RelationshipForm(forms.ModelForm): + """ + Form to allow users to describe a relationship - includes :class:`RelationshipQuestion`s. + + Dynamic fields inspired by https://jacobian.org/2010/feb/28/dynamic-form-generation/ + """ + class Meta: + model = models.Relationship + fields = [ + 'source', + 'target', + ] + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + for question in models.RelationshipQuestion.objects.all(): + # Get choices from model and add default 'not selected' option + choices = question.choices + [['', '---------']] + + field = forms.ChoiceField(label=question, + choices=choices) + self.fields['question_{}'.format(question.pk)] = field + + def save(self, commit=True) -> models.Relationship: + # Save Relationship model + self.instance = super().save(commit=commit) + + if commit: + # Save answers to relationship questions + for key, value in self.cleaned_data.items(): + if key.startswith('question_'): + question_pk = key.split('_')[-1] + answer = models.RelationshipQuestionChoice.objects.get(pk=value) + self.instance.question_answers.add(answer) + + return self.instance diff --git a/people/migrations/0007_relationship_question_answers.py b/people/migrations/0007_relationship_question_answers.py new file mode 100644 index 0000000..bf8e972 --- /dev/null +++ b/people/migrations/0007_relationship_question_answers.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.10 on 2020-02-20 13:47 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('people', '0006_relationship_questions_order'), + ] + + operations = [ + migrations.AddField( + model_name='relationship', + name='question_answers', + field=models.ManyToManyField(to='people.RelationshipQuestionChoice'), + ), + ] diff --git a/people/models.py b/people/models.py index 180c8b0..ba3cf0f 100644 --- a/people/models.py +++ b/people/models.py @@ -139,5 +139,11 @@ class Relationship(models.Model): on_delete=models.CASCADE, blank=False, null=False) + #: Answers to :class:`RelationshipQuestion`s + question_answers = models.ManyToManyField(RelationshipQuestionChoice) + + def get_absolute_url(self): + return reverse('people:relationship.detail', kwargs={'pk': self.pk}) + def __str__(self) -> str: return f'{self.source} -> {self.target}' diff --git a/people/templates/people/person/detail.html b/people/templates/people/person/detail.html index ad469a6..f12ccdf 100644 --- a/people/templates/people/person/detail.html +++ b/people/templates/people/person/detail.html @@ -14,6 +14,10 @@

Relationships As Source

+ New Relationship + + diff --git a/people/templates/people/relationship/create.html b/people/templates/people/relationship/create.html new file mode 100644 index 0000000..d68a8fd --- /dev/null +++ b/people/templates/people/relationship/create.html @@ -0,0 +1,30 @@ +{% extends 'base.html' %} + +{% block content %} + + +
+ + + {% csrf_token %} + + {% load bootstrap4 %} + {% bootstrap_form form %} + + {% buttons %} + + {% endbuttons %} + + +{% endblock %} diff --git a/people/urls.py b/people/urls.py index f4ab036..cec6bed 100644 --- a/people/urls.py +++ b/people/urls.py @@ -22,6 +22,10 @@ urlpatterns = [ views.ProfileView.as_view(), name='person.detail'), + path('people//relationships/create', + views.RelationshipCreateView.as_view(), + name='person.relationship.create'), + path('relationships/', views.RelationshipDetailView.as_view(), name='relationship.detail'), diff --git a/people/views.py b/people/views.py index 9644b78..d9883f1 100644 --- a/people/views.py +++ b/people/views.py @@ -2,6 +2,7 @@ Views for displaying or manipulating models in the 'people' app. """ +from django.http import HttpResponseRedirect from django.views.generic import CreateView, DetailView, ListView from . import forms, models @@ -58,3 +59,48 @@ class RelationshipDetailView(DetailView): """ model = models.Relationship template_name = 'people/relationship/detail.html' + + +class RelationshipCreateView(CreateView): + """ + View for creating a :class:`Relationship`. + + Displays / processes a form containing the :class:`RelationshipQuestion`s. + """ + model = models.Relationship + template_name = 'people/relationship/create.html' + form_class = forms.RelationshipForm + + def get(self, request, *args, **kwargs): + self.person = models.Person.objects.get(pk=self.kwargs.get('person_pk')) + + return super().get(request, *args, **kwargs) + + def post(self, request, *args, **kwargs): + self.person = models.Person.objects.get(pk=self.kwargs.get('person_pk')) + + 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 + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + + context['person'] = self.person + + return context + + def form_valid(self, form): + """ + Form is valid - create :class:`Relationship` and save answers to questions. + """ + self.object = form.save() + + return HttpResponseRedirect(self.object.get_absolute_url()) +