Skip to content

Commit 5ffffec

Browse files
committed
Move GenderResponse to its own model
1 parent ec19130 commit 5ffffec

File tree

8 files changed

+134
-30
lines changed

8 files changed

+134
-30
lines changed

lung_cancer_screening/questions/forms/gender_form.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
from django import forms
22

33
from ...nhsuk_forms.choice_field import ChoiceField
4-
from ..models.response_set import ResponseSet, GenderValues
4+
from ..models.gender_response import GenderResponse, GenderValues
55

66

77
class GenderForm(forms.ModelForm):
88

99
def __init__(self, *args, **kwargs):
1010
super().__init__(*args, **kwargs)
1111

12-
self.fields["gender"] = ChoiceField(
12+
self.fields["value"] = ChoiceField(
1313
choices=GenderValues.choices,
1414
widget=forms.RadioSelect,
1515
label="Which of these best describes you?",
@@ -25,5 +25,5 @@ def __init__(self, *args, **kwargs):
2525
)
2626

2727
class Meta:
28-
model = ResponseSet
29-
fields = ['gender']
28+
model = GenderResponse
29+
fields = ['value']
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# Generated manually to create GenderResponse and copy data
2+
3+
import django.db.models.deletion
4+
from django.db import migrations, models
5+
6+
7+
def copy_gender_data(apps, schema_editor):
8+
with schema_editor.connection.cursor() as cursor:
9+
cursor.execute("""
10+
INSERT INTO questions_genderresponse (created_at, updated_at, value, response_set_id)
11+
SELECT NOW(), NOW(), gender, id
12+
FROM questions_responseset
13+
WHERE gender IS NOT NULL
14+
ON CONFLICT (response_set_id) DO NOTHING
15+
""")
16+
17+
18+
def reverse_copy_gender_data(apps, schema_editor):
19+
with schema_editor.connection.cursor() as cursor:
20+
cursor.execute("""
21+
UPDATE questions_responseset rs
22+
SET gender = g.value
23+
FROM questions_genderresponse g
24+
WHERE rs.id = g.response_set_id
25+
""")
26+
27+
28+
class Migration(migrations.Migration):
29+
30+
dependencies = [
31+
('questions', '0028_ethnicityresponse'),
32+
]
33+
34+
operations = [
35+
migrations.CreateModel(
36+
name='GenderResponse',
37+
fields=[
38+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
39+
('created_at', models.DateTimeField(auto_now_add=True)),
40+
('updated_at', models.DateTimeField(auto_now=True)),
41+
('value', models.CharField(choices=[('F', 'Female'), ('M', 'Male'), ('N', 'Non-binary'), ('P', 'Prefer not to say'), ('G', 'How I describe myself may not match my GP record')], max_length=1)),
42+
('response_set', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='gender_response', to='questions.responseset')),
43+
],
44+
options={
45+
'abstract': False,
46+
},
47+
),
48+
migrations.RunPython(copy_gender_data, reverse_copy_gender_data),
49+
migrations.RemoveField(
50+
model_name='responseset',
51+
name='gender',
52+
),
53+
]

lung_cancer_screening/questions/models/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@
44
from .asbestos_exposure_response import AsbestosExposureResponse # noqa: F401
55
from .date_of_birth_response import DateOfBirthResponse # noqa: F401
66
from .ethnicity_response import EthnicityResponse # noqa: F401
7+
from .gender_response import GenderResponse # noqa: F401
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from django.db import models
2+
3+
from .base import BaseModel
4+
from .response_set import ResponseSet
5+
6+
7+
class GenderValues(models.TextChoices):
8+
FEMALE = "F", 'Female'
9+
MALE = "M", 'Male'
10+
NON_BINARY = "N", 'Non-binary'
11+
PREFER_NOT_TO_SAY = "P", 'Prefer not to say'
12+
GP = "G", 'How I describe myself may not match my GP record'
13+
14+
15+
class GenderResponse(BaseModel):
16+
response_set = models.OneToOneField(ResponseSet, on_delete=models.CASCADE, related_name='gender_response')
17+
value = models.CharField(max_length=1, choices=GenderValues.choices)
Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,53 @@
11
from django.test import TestCase
22

3-
from ...factories.user_factory import UserFactory
4-
from ....models.response_set import ResponseSet, GenderValues
3+
from ...factories.response_set_factory import ResponseSetFactory
4+
from ....models.gender_response import GenderResponse, GenderValues
55
from ....forms.gender_form import GenderForm
66

77

88
class TestGenderForm(TestCase):
99
def setUp(self):
10-
self.user = UserFactory()
11-
self.response_set = ResponseSet(user=self.user)
10+
self.response_set = ResponseSetFactory()
11+
self.response = GenderResponse.objects.create(
12+
response_set=self.response_set,
13+
value=GenderValues.MALE
14+
)
1215

1316
def test_is_valid_with_a_valid_value(self):
1417
form = GenderForm(
15-
instance=self.response_set,
18+
instance=self.response,
1619
data={
17-
"gender": GenderValues.MALE
20+
"value": GenderValues.MALE
1821
}
1922
)
2023
self.assertTrue(form.is_valid())
2124
self.assertEqual(
22-
form.cleaned_data["gender"],
25+
form.cleaned_data["value"],
2326
GenderValues.MALE.value
2427
)
2528

2629
def test_is_invalid_with_an_invalid_value(self):
2730
form = GenderForm(
28-
instance=self.response_set,
31+
instance=self.response,
2932
data={
30-
"gender": "invalid"
33+
"value": "invalid"
3134
}
3235
)
3336
self.assertFalse(form.is_valid())
3437
self.assertEqual(
35-
form.errors["gender"],
38+
form.errors["value"],
3639
["Select a valid choice. invalid is not one of the available choices."]
3740
)
3841

3942
def test_is_invalid_when_no_option_is_selected(self):
4043
form = GenderForm(
41-
instance=self.response_set,
44+
instance=self.response,
4245
data={
43-
"gender": None
46+
"value": None
4447
}
4548
)
4649
self.assertFalse(form.is_valid())
4750
self.assertEqual(
48-
form.errors["gender"],
51+
form.errors["value"],
4952
["Select the option that best describes your gender"]
5053
)
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
from django.test import TestCase
2+
3+
from ...factories.response_set_factory import ResponseSetFactory
4+
from ....models.gender_response import GenderResponse, GenderValues
5+
6+
7+
class TestGenderResponse(TestCase):
8+
def test_has_response_set_as_foreign_key(self):
9+
response_set = ResponseSetFactory()
10+
response = GenderResponse.objects.create(
11+
response_set=response_set,
12+
value=GenderValues.MALE
13+
)
14+
15+
self.assertEqual(response.response_set, response_set)
16+
17+
def test_has_value_as_string(self):
18+
response_set = ResponseSetFactory()
19+
response = GenderResponse.objects.create(
20+
response_set=response_set,
21+
value=GenderValues.MALE
22+
)
23+
24+
self.assertIsInstance(response.value, str)

lung_cancer_screening/questions/tests/unit/views/test_gender.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from dateutil.relativedelta import relativedelta
44
from django.utils import timezone
55

6-
from lung_cancer_screening.questions.models.response_set import GenderValues
6+
from lung_cancer_screening.questions.models.gender_response import GenderResponse, GenderValues
77
from .helpers.authentication import login_user
88

99

@@ -52,7 +52,7 @@ class TestPostGender(TestCase):
5252
def setUp(self):
5353
self.user = login_user(self.client)
5454

55-
self.valid_params = {"gender": GenderValues.MALE}
55+
self.valid_params = {"value": GenderValues.MALE}
5656

5757
def test_post_redirects_if_the_user_is_not_logged_in(self):
5858
self.client.logout()
@@ -79,7 +79,7 @@ def test_post_creates_unsubmitted_response_set_when_no_response_set_exists(
7979
response_set = self.user.responseset_set.first()
8080
self.assertEqual(self.user.responseset_set.count(), 1)
8181
self.assertEqual(response_set.submitted_at, None)
82-
self.assertEqual(response_set.gender, self.valid_params["gender"])
82+
self.assertEqual(GenderResponse.objects.get(response_set=response_set).value, self.valid_params["value"])
8383
self.assertEqual(response_set.user, self.user)
8484

8585
def test_post_updates_unsubmitted_response_set_when_one_exists(self):
@@ -93,7 +93,7 @@ def test_post_updates_unsubmitted_response_set_when_one_exists(self):
9393
response_set.refresh_from_db()
9494
self.assertEqual(self.user.responseset_set.count(), 1)
9595
self.assertEqual(response_set.submitted_at, None)
96-
self.assertEqual(response_set.gender, self.valid_params["gender"])
96+
self.assertEqual(GenderResponse.objects.get(response_set=response_set).value, self.valid_params["value"])
9797
self.assertEqual(response_set.user, self.user)
9898

9999
def test_post_creates_new_unsubmitted_response_set_when_submitted_exists_over_year_ago( # noqa: E501
@@ -113,7 +113,7 @@ def test_post_creates_new_unsubmitted_response_set_when_submitted_exists_over_ye
113113

114114
response_set = self.user.responseset_set.last()
115115
self.assertEqual(response_set.submitted_at, None)
116-
self.assertEqual(response_set.gender, self.valid_params["gender"])
116+
self.assertEqual(GenderResponse.objects.get(response_set=response_set).value, self.valid_params["value"])
117117
self.assertEqual(response_set.user, self.user)
118118

119119
def test_post_redirects_when_submitted_response_set_exists_within_last_year( # noqa: E501
@@ -137,7 +137,7 @@ def test_post_stores_a_valid_response_for_the_user(self):
137137
)
138138

139139
response_set = self.user.responseset_set.first()
140-
self.assertEqual(response_set.gender, self.valid_params["gender"])
140+
self.assertEqual(GenderResponse.objects.get(response_set=response_set).value, self.valid_params["value"])
141141
self.assertEqual(response_set.user, self.user)
142142

143143
def test_post_redirects_to_the_ethnicity_path(self):
@@ -151,7 +151,7 @@ def test_post_redirects_to_the_ethnicity_path(self):
151151
def test_post_responds_with_422_if_the_response_fails_to_create(self):
152152
response = self.client.post(
153153
reverse("questions:gender"),
154-
{"gender": "something not in list"}
154+
{"value": "something not in list"}
155155
)
156156

157157
self.assertEqual(response.status_code, 422)
@@ -161,7 +161,7 @@ def test_post_renders_the_gender_page_with_an_error_if_form_invalid(
161161
):
162162
response = self.client.post(
163163
reverse("questions:gender"),
164-
{"gender": "something not in list"}
164+
{"value": "something not in list"}
165165
)
166166

167167
self.assertContains(

lung_cancer_screening/questions/views/gender.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,31 @@
55

66
from .mixins.ensure_response_set import EnsureResponseSet
77
from ..forms.gender_form import GenderForm
8+
from ..models.gender_response import GenderResponse
89

910

1011
class GenderView(LoginRequiredMixin, EnsureResponseSet, View):
1112
def get(self, request):
13+
response, _ = GenderResponse.objects.get_or_build(
14+
response_set=request.response_set
15+
)
1216
return render_template(
1317
request,
14-
GenderForm(instance=request.response_set),
18+
GenderForm(instance=response),
1519
)
1620

1721
def post(self, request):
22+
response, _ = GenderResponse.objects.get_or_build(
23+
response_set=request.response_set
24+
)
1825
form = GenderForm(
19-
instance=request.response_set,
26+
instance=response,
2027
data=request.POST
2128
)
2229

2330
if form.is_valid():
24-
response_set = request.response_set
25-
response_set.gender = form.cleaned_data["gender"]
26-
response_set.save()
31+
response.value = form.cleaned_data["value"]
32+
response.save()
2733
return redirect(reverse("questions:ethnicity"))
2834
else:
2935
return render_template(

0 commit comments

Comments
 (0)