Skip to content

Commit 4e812b7

Browse files
committed
Move EthnicityResponse to its own model
1 parent e9ddc43 commit 4e812b7

File tree

8 files changed

+136
-33
lines changed

8 files changed

+136
-33
lines changed

lung_cancer_screening/questions/forms/ethnicity_form.py

Lines changed: 5 additions & 5 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, EthnicityValues
4+
from ..models.ethnicity_response import EthnicityResponse, EthnicityValues
55

66

77
class EthnicityForm(forms.ModelForm):
88

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

12-
self.fields["ethnicity"] = ChoiceField(
12+
self.fields["value"] = ChoiceField(
1313
choices=EthnicityValues.choices,
1414
label="What is your ethnic background?",
1515
widget=forms.RadioSelect,
@@ -24,10 +24,10 @@ def __init__(self, *args, **kwargs):
2424
}
2525
)
2626

27-
self["ethnicity"].add_divider_after(
27+
self["value"].add_divider_after(
2828
EthnicityValues.OTHER.value, "or"
2929
)
3030

3131
class Meta:
32-
model = ResponseSet
33-
fields = ['ethnicity']
32+
model = EthnicityResponse
33+
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 EthnicityResponse and copy data
2+
3+
import django.db.models.deletion
4+
from django.db import migrations, models
5+
6+
7+
def copy_ethnicity_data(apps, schema_editor):
8+
with schema_editor.connection.cursor() as cursor:
9+
cursor.execute("""
10+
INSERT INTO questions_ethnicityresponse (created_at, updated_at, value, response_set_id)
11+
SELECT NOW(), NOW(), ethnicity, id
12+
FROM questions_responseset
13+
WHERE ethnicity IS NOT NULL
14+
ON CONFLICT (response_set_id) DO NOTHING
15+
""")
16+
17+
18+
def reverse_copy_ethnicity_data(apps, schema_editor):
19+
with schema_editor.connection.cursor() as cursor:
20+
cursor.execute("""
21+
UPDATE questions_responseset rs
22+
SET ethnicity = e.value
23+
FROM questions_ethnicityresponse e
24+
WHERE rs.id = e.response_set_id
25+
""")
26+
27+
28+
class Migration(migrations.Migration):
29+
30+
dependencies = [
31+
('questions', '0027_dateofbirthresponse'),
32+
]
33+
34+
operations = [
35+
migrations.CreateModel(
36+
name='EthnicityResponse',
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=[('A', 'Asian or Asian British'), ('B', 'Black, African, Caribbean or Black British'), ('M', 'Mixed or multiple ethnic groups'), ('W', 'White'), ('O', 'Other ethnic group'), ('N', "I'd prefer not to say")], max_length=1)),
42+
('response_set', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='ethnicity_response', to='questions.responseset')),
43+
],
44+
options={
45+
'abstract': False,
46+
},
47+
),
48+
migrations.RunPython(copy_ethnicity_data, reverse_copy_ethnicity_data),
49+
migrations.RemoveField(
50+
model_name='responseset',
51+
name='ethnicity',
52+
),
53+
]

lung_cancer_screening/questions/models/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33
from .have_you_ever_smoked_response import HaveYouEverSmokedResponse # noqa: F401
44
from .asbestos_exposure_response import AsbestosExposureResponse # noqa: F401
55
from .date_of_birth_response import DateOfBirthResponse # noqa: F401
6+
from .ethnicity_response import EthnicityResponse # noqa: F401
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from django.db import models
2+
3+
from .base import BaseModel
4+
from .response_set import ResponseSet
5+
6+
7+
class EthnicityValues(models.TextChoices):
8+
ASIAN = "A", "Asian or Asian British"
9+
BLACK = "B", "Black, African, Caribbean or Black British"
10+
MIXED = "M", "Mixed or multiple ethnic groups"
11+
WHITE = "W", "White"
12+
OTHER = "O", "Other ethnic group"
13+
PREFER_NOT_TO_SAY = "N", "I'd prefer not to say"
14+
15+
16+
class EthnicityResponse(BaseModel):
17+
response_set = models.OneToOneField(ResponseSet, on_delete=models.CASCADE, related_name='ethnicity_response')
18+
value = models.CharField(max_length=1, choices=EthnicityValues.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, EthnicityValues
3+
from ...factories.response_set_factory import ResponseSetFactory
4+
from ....models.ethnicity_response import EthnicityResponse, EthnicityValues
55
from ....forms.ethnicity_form import EthnicityForm
66

77

88
class TestEthnicityForm(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 = EthnicityResponse.objects.create(
12+
response_set=self.response_set,
13+
value=EthnicityValues.WHITE
14+
)
1215

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

2629
def test_is_invalid_with_an_invalid_value(self):
2730
form = EthnicityForm(
28-
instance=self.response_set,
31+
instance=self.response,
2932
data={
30-
"ethnicity": "invalid"
33+
"value": "invalid"
3134
}
3235
)
3336
self.assertFalse(form.is_valid())
3437
self.assertEqual(
35-
form.errors["ethnicity"],
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 = EthnicityForm(
41-
instance=self.response_set,
44+
instance=self.response,
4245
data={
43-
"ethnicity": None
46+
"value": None
4447
}
4548
)
4649
self.assertFalse(form.is_valid())
4750
self.assertEqual(
48-
form.errors["ethnicity"],
51+
form.errors["value"],
4952
["Select your ethnic background"]
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.ethnicity_response import EthnicityResponse, EthnicityValues
5+
6+
7+
class TestEthnicityResponse(TestCase):
8+
def test_has_response_set_as_foreign_key(self):
9+
response_set = ResponseSetFactory()
10+
response = EthnicityResponse.objects.create(
11+
response_set=response_set,
12+
value=EthnicityValues.WHITE
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 = EthnicityResponse.objects.create(
20+
response_set=response_set,
21+
value=EthnicityValues.WHITE
22+
)
23+
24+
self.assertIsInstance(response.value, str)

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

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@
44
from django.utils import timezone
55

66
from .helpers.authentication import login_user
7-
from lung_cancer_screening.questions.models.response_set import (
8-
EthnicityValues
9-
)
7+
from lung_cancer_screening.questions.models.ethnicity_response import EthnicityResponse, EthnicityValues
108

119

1210
class TestGetEthnicity(TestCase):
@@ -54,7 +52,7 @@ class TestPostEthnicity(TestCase):
5452
def setUp(self):
5553
self.user = login_user(self.client)
5654

57-
self.valid_params = {"ethnicity": EthnicityValues.WHITE}
55+
self.valid_params = {"value": EthnicityValues.WHITE}
5856

5957
def test_post_redirects_if_the_user_is_not_logged_in(self):
6058
self.client.logout()
@@ -82,7 +80,7 @@ def test_post_creates_unsubmitted_response_set_when_no_response_set_exists(
8280
self.assertEqual(self.user.responseset_set.count(), 1)
8381
self.assertEqual(response_set.submitted_at, None)
8482
self.assertEqual(
85-
response_set.ethnicity, self.valid_params["ethnicity"]
83+
EthnicityResponse.objects.get(response_set=response_set).value, self.valid_params["value"]
8684
)
8785
self.assertEqual(response_set.user, self.user)
8886

@@ -98,7 +96,7 @@ def test_post_updates_unsubmitted_response_set_when_one_exists(self):
9896
self.assertEqual(self.user.responseset_set.count(), 1)
9997
self.assertEqual(response_set.submitted_at, None)
10098
self.assertEqual(
101-
response_set.ethnicity, self.valid_params["ethnicity"]
99+
EthnicityResponse.objects.get(response_set=response_set).value, self.valid_params["value"]
102100
)
103101
self.assertEqual(response_set.user, self.user)
104102

@@ -120,7 +118,7 @@ def test_post_creates_new_unsubmitted_response_set_when_submitted_exists_over_ye
120118
response_set = self.user.responseset_set.last()
121119
self.assertEqual(response_set.submitted_at, None)
122120
self.assertEqual(
123-
response_set.ethnicity, self.valid_params["ethnicity"]
121+
EthnicityResponse.objects.get(response_set=response_set).value, self.valid_params["value"]
124122
)
125123
self.assertEqual(response_set.user, self.user)
126124

@@ -146,7 +144,7 @@ def test_post_stores_a_valid_response_for_the_user(self):
146144

147145
response_set = self.user.responseset_set.first()
148146
self.assertEqual(
149-
response_set.ethnicity, self.valid_params["ethnicity"]
147+
EthnicityResponse.objects.get(response_set=response_set).value, self.valid_params["value"]
150148
)
151149
self.assertEqual(response_set.user, self.user)
152150

@@ -161,7 +159,7 @@ def test_post_redirects_to_the_education_path(self):
161159
def test_post_responds_with_422_if_the_response_fails_to_create(self):
162160
response = self.client.post(
163161
reverse("questions:ethnicity"),
164-
{"ethnicity": "something not in list"}
162+
{"value": "something not in list"}
165163
)
166164

167165
self.assertEqual(response.status_code, 422)
@@ -171,7 +169,7 @@ def test_post_renders_the_ethnicity_page_with_an_error_if_form_invalid(
171169
):
172170
response = self.client.post(
173171
reverse("questions:ethnicity"),
174-
{"ethnicity": "something not in list"}
172+
{"value": "something not in list"}
175173
)
176174

177175
self.assertContains(

lung_cancer_screening/questions/views/ethnicity.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.ethnicity_form import EthnicityForm
8+
from ..models.ethnicity_response import EthnicityResponse
89

910

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

1721
def post(self, request):
22+
response, _ = EthnicityResponse.objects.get_or_build(
23+
response_set=request.response_set
24+
)
1825
form = EthnicityForm(
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.ethnicity = form.cleaned_data["ethnicity"]
26-
response_set.save()
31+
response.value = form.cleaned_data["value"]
32+
response.save()
2733
return redirect(reverse("questions:education"))
2834
else:
2935
return render_template(

0 commit comments

Comments
 (0)