Skip to content

Commit a40f609

Browse files
committed
Move HaveYouEverSmokedResponse to its own model
1 parent 06d6ffb commit a40f609

File tree

10 files changed

+177
-62
lines changed

10 files changed

+177
-62
lines changed

lung_cancer_screening/questions/forms/have_you_ever_smoked_form.py

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

33
from ...nhsuk_forms.typed_choice_field import TypedChoiceField
4-
from ..models.response_set import ResponseSet, HaveYouEverSmokedValues
4+
from ..models.have_you_ever_smoked_response import HaveYouEverSmokedResponse, HaveYouEverSmokedValues
55

66
class HaveYouEverSmokedForm(forms.ModelForm):
77

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

11-
self.fields["have_you_ever_smoked"] = TypedChoiceField(
11+
self.fields["value"] = TypedChoiceField(
1212
choices=HaveYouEverSmokedValues.choices,
1313
widget=forms.RadioSelect,
1414
label="Have you ever smoked?",
@@ -21,5 +21,5 @@ def __init__(self, *args, **kwargs):
2121
)
2222

2323
class Meta:
24-
model = ResponseSet
25-
fields = ['have_you_ever_smoked']
24+
model = HaveYouEverSmokedResponse
25+
fields = ['value']

lung_cancer_screening/questions/jinja2/responses.jinja

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,24 @@
1818
<div class="nhsuk-grid-column-two-thirds">
1919
<h1 class="nhsuk-heading-l">Responses</h1>
2020
<ul class="responses">
21-
<li>Have you ever smoked? {{ response_set.get_have_you_ever_smoked_display() }}</li>
22-
<li>What is your date of birth? {{ response_set.date_of_birth }}</li>
23-
<li>What is your height? {{ response_set.formatted_height }}</li>
24-
<li>What is your weight? {{ response_set.formatted_weight }}</li>
25-
<li>What was your sex at birth? {{ response_set.get_sex_at_birth_display() }}</li>
26-
<li>Which of these best describes you? {{ response_set.get_gender_display() }}</li>
27-
<li>What is your ethnic background? {{ response_set.get_ethnicity_display() }}</li>
28-
<li>Have you ever worked in a job where you might have been exposed to asbestos? {{ "Yes" if response_set.asbestos_exposure else "No" }}</li>
29-
<li>Have you ever been diagnosed with any of the following respiratory conditions? {{ response_set.formatted_respiratory_conditions }}</li>
21+
{% set have_you_ever_smoked = response_set.have_you_ever_smoked_response %}
22+
{% set date_of_birth = response_set.date_of_birth_response %}
23+
{% set height = response_set.height_response %}
24+
{% set weight = response_set.weight_response %}
25+
{% set sex_at_birth = response_set.sex_at_birth_response %}
26+
{% set gender = response_set.gender_response %}
27+
{% set ethnicity = response_set.ethnicity_response %}
28+
{% set asbestos_exposure = response_set.asbestos_exposure_response %}
29+
{% set respiratory_conditions = response_set.respiratory_conditions_response %}
30+
<li>Have you ever smoked? {% if have_you_ever_smoked %}{{ have_you_ever_smoked.get_value_display() }}{% endif %}</li>
31+
<li>What is your date of birth? {% if date_of_birth %}{{ date_of_birth.value }}{% endif %}</li>
32+
<li>What is your height? {% if height %}{{ height.formatted }}{% endif %}</li>
33+
<li>What is your weight? {% if weight %}{{ weight.formatted }}{% endif %}</li>
34+
<li>What was your sex at birth? {% if sex_at_birth %}{{ sex_at_birth.get_value_display() }}{% endif %}</li>
35+
<li>Which of these best describes you? {% if gender %}{{ gender.get_value_display() }}{% endif %}</li>
36+
<li>What is your ethnic background? {% if ethnicity %}{{ ethnicity.get_value_display() }}{% endif %}</li>
37+
<li>Have you ever worked in a job where you might have been exposed to asbestos? {% if asbestos_exposure %}{{ "Yes" if asbestos_exposure.value else "No" }}{% else %}No{% endif %}</li>
38+
<li>Have you ever been diagnosed with any of the following respiratory conditions? {% if respiratory_conditions %}{{ respiratory_conditions.formatted }}{% endif %}</li>
3039
</ul>
3140
<form action="{{ request.path }}" method="post">
3241
{{ csrf_input }}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# Generated by Django 5.2.9 on 2025-12-18 17:15
2+
3+
import django.db.models.deletion
4+
from django.db import migrations, models
5+
6+
7+
def copy_have_you_ever_smoked_data(apps, schema_editor):
8+
with schema_editor.connection.cursor() as cursor:
9+
cursor.execute("""
10+
INSERT INTO questions_haveyoueversmokedresponse (created_at, updated_at, value, response_set_id)
11+
SELECT NOW(), NOW(), have_you_ever_smoked, id
12+
FROM questions_responseset
13+
WHERE have_you_ever_smoked IS NOT NULL
14+
ON CONFLICT (response_set_id) DO NOTHING
15+
""")
16+
17+
18+
def reverse_copy_have_you_ever_smoked_data(apps, schema_editor):
19+
with schema_editor.connection.cursor() as cursor:
20+
cursor.execute("""
21+
UPDATE questions_responseset rs
22+
SET have_you_ever_smoked = h.value
23+
FROM questions_haveyoueversmokedresponse h
24+
WHERE rs.id = h.response_set_id
25+
""")
26+
27+
28+
class Migration(migrations.Migration):
29+
30+
dependencies = [
31+
('questions', '0024_add_email_to_user'),
32+
]
33+
34+
operations = [
35+
migrations.CreateModel(
36+
name='HaveYouEverSmokedResponse',
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.IntegerField(choices=[(0, 'Yes, I currently smoke'), (1, 'Yes, I used to smoke'), (2, 'Yes, but I have smoked fewer than 100 cigarettes in my lifetime'), (3, 'No, I have never smoked')])),
42+
('response_set', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='questions.responseset')),
43+
],
44+
options={
45+
'abstract': False,
46+
},
47+
),
48+
migrations.RunPython(copy_have_you_ever_smoked_data, reverse_copy_have_you_ever_smoked_data),
49+
migrations.RemoveField(
50+
model_name='responseset',
51+
name='have_you_ever_smoked',
52+
),
53+
]
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
from .response_set import ResponseSet # noqa: F401
22
from .user import User # noqa: F401
3+
from .have_you_ever_smoked_response import HaveYouEverSmokedResponse # noqa: F401
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
from django.db import models
2+
3+
from .base import BaseModel
4+
from .response_set import ResponseSet
5+
6+
7+
class HaveYouEverSmokedValues(models.IntegerChoices):
8+
YES_I_CURRENTLY_SMOKE = 0, 'Yes, I currently smoke'
9+
YES_I_USED_TO_SMOKE_REGULARLY = 1, 'Yes, I used to smoke'
10+
YES_BUT_ONLY_A_FEW_TIMES = 2, 'Yes, but I have smoked fewer than 100 cigarettes in my lifetime'
11+
NO_I_HAVE_NEVER_SMOKED = 3, 'No, I have never smoked'
12+
13+
14+
class HaveYouEverSmokedResponse(BaseModel):
15+
response_set = models.OneToOneField(ResponseSet, on_delete=models.CASCADE, related_name='have_you_ever_smoked_response')
16+
value = models.IntegerField(choices=HaveYouEverSmokedValues.choices)
Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,23 @@
11
from django.test import TestCase
22

3-
from ...factories.user_factory import UserFactory
4-
from ....models.response_set import ResponseSet, HaveYouEverSmokedValues
3+
from ...factories.response_set_factory import ResponseSetFactory
4+
from ....models.have_you_ever_smoked_response import HaveYouEverSmokedResponse, HaveYouEverSmokedValues
55
from ....forms.have_you_ever_smoked_form import HaveYouEverSmokedForm
66

77

88
class TestHaveYouEverSmokedForm(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 = HaveYouEverSmokedResponse.objects.create(
12+
response_set=self.response_set,
13+
value=HaveYouEverSmokedValues.YES_I_USED_TO_SMOKE_REGULARLY
14+
)
1215

1316
def test_is_valid(self):
1417
form = HaveYouEverSmokedForm(
15-
instance=self.response_set,
18+
instance=self.response,
1619
data={
17-
"have_you_ever_smoked": (
20+
"value": (
1821
HaveYouEverSmokedValues.YES_I_USED_TO_SMOKE_REGULARLY
1922
)
2023
}
@@ -23,41 +26,41 @@ def test_is_valid(self):
2326

2427
def test_is_invalid(self):
2528
form = HaveYouEverSmokedForm(
26-
instance=self.response_set,
29+
instance=self.response,
2730
data={
28-
"have_you_ever_smoked": "invalid"
31+
"value": "invalid"
2932
}
3033
)
3134
self.assertFalse(form.is_valid())
3235
self.assertEqual(
33-
form.errors["have_you_ever_smoked"],
36+
form.errors["value"],
3437
["Select a valid choice. invalid is not one of the available choices."]
3538
)
3639

3740
def test_is_invalid_when_no_option_is_selected(self):
3841
form = HaveYouEverSmokedForm(
39-
instance=self.response_set,
42+
instance=self.response,
4043
data={
41-
"have_you_ever_smoked": None
44+
"value": None
4245
}
4346
)
4447
self.assertFalse(form.is_valid())
4548
self.assertEqual(
46-
form.errors["have_you_ever_smoked"],
49+
form.errors["value"],
4750
["Select if you have ever smoked"]
4851
)
4952

5053
def test_returns_a_boolean_type(self):
5154
form = HaveYouEverSmokedForm(
52-
instance=self.response_set,
55+
instance=self.response,
5356
data={
54-
"have_you_ever_smoked": (
57+
"value": (
5558
HaveYouEverSmokedValues.YES_I_USED_TO_SMOKE_REGULARLY
5659
)
5760
}
5861
)
5962
form.is_valid()
6063
self.assertEqual(
61-
form.cleaned_data["have_you_ever_smoked"],
64+
form.cleaned_data["value"],
6265
HaveYouEverSmokedValues.YES_I_USED_TO_SMOKE_REGULARLY.value
6366
)
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from django.test import TestCase
2+
3+
from ...factories.response_set_factory import ResponseSetFactory
4+
from ....models.have_you_ever_smoked_response import HaveYouEverSmokedResponse, HaveYouEverSmokedValues
5+
6+
7+
class TestHaveYouEverSmokedResponse(TestCase):
8+
def test_has_response_set_as_foreign_key(self):
9+
response_set = ResponseSetFactory()
10+
response = HaveYouEverSmokedResponse.objects.create(
11+
response_set=response_set,
12+
value=HaveYouEverSmokedValues.YES_I_CURRENTLY_SMOKE
13+
)
14+
15+
self.assertEqual(response.response_set, response_set)
16+
17+
def test_has_value_as_enum(self):
18+
response_set = ResponseSetFactory()
19+
response = HaveYouEverSmokedResponse.objects.create(
20+
response_set=response_set,
21+
value=HaveYouEverSmokedValues.YES_I_USED_TO_SMOKE_REGULARLY
22+
)
23+
24+
self.assertEqual(
25+
response.get_value_display(),
26+
HaveYouEverSmokedValues.YES_I_USED_TO_SMOKE_REGULARLY.label
27+
)

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

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +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 HaveYouEverSmokedValues
7+
from lung_cancer_screening.questions.models.have_you_ever_smoked_response import HaveYouEverSmokedResponse, HaveYouEverSmokedValues
88

99
class TestGetHaveYouEverSmoked(TestCase):
1010
def setUp(self):
@@ -43,7 +43,7 @@ class TestPostHaveYouEverSmoked(TestCase):
4343
def setUp(self):
4444
self.user = login_user(self.client)
4545

46-
self.valid_params = { "have_you_ever_smoked": HaveYouEverSmokedValues.YES_I_USED_TO_SMOKE_REGULARLY }
46+
self.valid_params = { "value": HaveYouEverSmokedValues.YES_I_USED_TO_SMOKE_REGULARLY }
4747

4848

4949
def test_post_redirects_if_the_user_is_not_logged_in(self):
@@ -66,7 +66,7 @@ def test_post_creates_an_unsubmitted_response_set_for_the_user_when_no_response_
6666
response_set = self.user.responseset_set.first()
6767
self.assertEqual(self.user.responseset_set.count(), 1)
6868
self.assertEqual(response_set.submitted_at, None)
69-
self.assertEqual(response_set.have_you_ever_smoked, self.valid_params["have_you_ever_smoked"])
69+
self.assertEqual(HaveYouEverSmokedResponse.objects.get(response_set=response_set).value, self.valid_params["value"])
7070
self.assertEqual(response_set.user, self.user)
7171

7272

@@ -81,7 +81,7 @@ def test_post_updates_an_unsubmitted_response_set_for_the_user_when_an_unsubmitt
8181
response_set.refresh_from_db()
8282
self.assertEqual(self.user.responseset_set.count(), 1)
8383
self.assertEqual(response_set.submitted_at, None)
84-
self.assertEqual(response_set.have_you_ever_smoked, self.valid_params["have_you_ever_smoked"])
84+
self.assertEqual(HaveYouEverSmokedResponse.objects.get(response_set=response_set).value, self.valid_params["value"])
8585
self.assertEqual(response_set.user, self.user)
8686

8787

@@ -100,7 +100,7 @@ def test_post_creates_an_new_unsubmitted_response_set_for_the_user_when_an_submi
100100

101101
response_set = self.user.responseset_set.last()
102102
self.assertEqual(response_set.submitted_at, None)
103-
self.assertEqual(response_set.have_you_ever_smoked, self.valid_params["have_you_ever_smoked"])
103+
self.assertEqual(HaveYouEverSmokedResponse.objects.get(response_set=response_set).value, self.valid_params["value"])
104104
self.assertEqual(response_set.user, self.user)
105105

106106

@@ -128,23 +128,25 @@ def test_post_redirects_to_the_date_of_birth_path(self):
128128
def test_post_responds_with_422_if_the_date_response_fails_to_create(self):
129129
response = self.client.post(
130130
reverse("questions:have_you_ever_smoked"),
131-
{"have_you_ever_smoked": "something not in list"}
131+
{"value": "something not in list"}
132132
)
133133

134134
self.assertEqual(response.status_code, 422)
135135

136136
def test_post_does_not_update_the_response_set_if_the_user_is_not_a_smoker(self):
137137
self.client.post(
138138
reverse("questions:have_you_ever_smoked"),
139-
{ "have_you_ever_smoked": HaveYouEverSmokedValues.NO_I_HAVE_NEVER_SMOKED.value }
139+
{ "value": HaveYouEverSmokedValues.NO_I_HAVE_NEVER_SMOKED.value }
140140
)
141141

142-
self.assertEqual(self.user.responseset_set.first().have_you_ever_smoked, None)
142+
response_set = self.user.responseset_set.first()
143+
if response_set:
144+
self.assertFalse(HaveYouEverSmokedResponse.objects.filter(response_set=response_set).exists())
143145

144146
def test_post_redirects_if_the_user_not_a_smoker(self):
145147
response = self.client.post(
146148
reverse("questions:have_you_ever_smoked"),
147-
{"have_you_ever_smoked": HaveYouEverSmokedValues.NO_I_HAVE_NEVER_SMOKED.value }
149+
{"value": HaveYouEverSmokedValues.NO_I_HAVE_NEVER_SMOKED.value }
148150
)
149151

150152
self.assertRedirects(response, reverse("questions:non_smoker_exit"))

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

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,17 @@
66

77
from ...factories.user_factory import UserFactory
88
from .helpers.authentication import login_user
9+
from ....models.have_you_ever_smoked_response import HaveYouEverSmokedResponse, HaveYouEverSmokedValues
10+
from ....models.date_of_birth_response import DateOfBirthResponse
911

1012

1113
class TestGetResponses(TestCase):
1214
def setUp(self):
1315
self.user = login_user(self.client)
1416

15-
self.response_set = self.user.responseset_set.create(
16-
have_you_ever_smoked=True,
17-
date_of_birth=date(2000, 9, 8)
18-
)
17+
self.response_set = self.user.responseset_set.create()
18+
HaveYouEverSmokedResponse.objects.create(response_set=self.response_set, value=HaveYouEverSmokedValues.YES_I_CURRENTLY_SMOKE)
19+
DateOfBirthResponse.objects.create(response_set=self.response_set, value=date(2000, 9, 8))
1920

2021
def test_get_redirects_if_the_user_is_not_logged_in(self):
2122
self.client.logout()
@@ -55,39 +56,37 @@ def test_get_contains_the_users_responses(self):
5556
reverse("questions:responses")
5657
)
5758

59+
have_you_ever_smoked = HaveYouEverSmokedResponse.objects.get(response_set=self.response_set)
60+
date_of_birth = DateOfBirthResponse.objects.get(response_set=self.response_set)
5861
self.assertContains(
5962
response,
60-
self.response_set.get_have_you_ever_smoked_display()
63+
have_you_ever_smoked.get_value_display()
6164
)
6265
self.assertContains(
63-
response, self.response_set.date_of_birth
66+
response, date_of_birth.value
6467
)
6568

6669
def test_get_does_not_contain_responses_for_other_users(self):
6770
other_user = UserFactory()
68-
other_date_response = other_user.responseset_set.create(
69-
have_you_ever_smoked=0, date_of_birth=date(1990, 1, 1)
70-
)
71+
other_response_set = other_user.responseset_set.create()
72+
DateOfBirthResponse.objects.create(response_set=other_response_set, value=date(1990, 1, 1))
7173

7274
response = self.client.get(reverse("questions:responses"))
7375

76+
other_date_of_birth = DateOfBirthResponse.objects.get(response_set=other_response_set)
77+
7478
self.assertNotContains(
75-
response,
76-
other_date_response.get_have_you_ever_smoked_display()
77-
)
78-
self.assertNotContains(
79-
response, other_date_response.date_of_birth
79+
response, other_date_of_birth.value
8080
)
8181

8282

8383
class TestPostResponses(TestCase):
8484
def setUp(self):
8585
self.user = login_user(self.client)
8686

87-
self.response_set = self.user.responseset_set.create(
88-
have_you_ever_smoked=True,
89-
date_of_birth=date(2000, 9, 8)
90-
)
87+
self.response_set = self.user.responseset_set.create()
88+
HaveYouEverSmokedResponse.objects.create(response_set=self.response_set, value=HaveYouEverSmokedValues.YES_I_CURRENTLY_SMOKE)
89+
DateOfBirthResponse.objects.create(response_set=self.response_set, value=date(2000, 9, 8))
9190

9291
def test_post_redirects_if_the_user_is_not_logged_in(self):
9392
self.client.logout()

0 commit comments

Comments
 (0)