From b4e9aff5fc7c00eecf32dba8d7f325c145c24bad Mon Sep 17 00:00:00 2001 From: Henry Cooksley Date: Fri, 10 Jan 2025 14:53:06 +0000 Subject: [PATCH 01/13] Add class FieldsetForm --- core/assets/styles/overrides/_all.scss | 1 + core/assets/styles/overrides/_fieldset.scss | 11 +++++++++ core/common/forms.py | 26 +++++++++++++++++++++ exporter/core/organisation/forms.py | 4 ++-- 4 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 core/assets/styles/overrides/_fieldset.scss diff --git a/core/assets/styles/overrides/_all.scss b/core/assets/styles/overrides/_all.scss index e8af924447..7c234ca02c 100644 --- a/core/assets/styles/overrides/_all.scss +++ b/core/assets/styles/overrides/_all.scss @@ -1,5 +1,6 @@ @import "button"; @import "checkboxes"; +@import "fieldset"; @import "file-upload"; @import "form-group"; @import "form-input"; diff --git a/core/assets/styles/overrides/_fieldset.scss b/core/assets/styles/overrides/_fieldset.scss new file mode 100644 index 0000000000..cd68a420a0 --- /dev/null +++ b/core/assets/styles/overrides/_fieldset.scss @@ -0,0 +1,11 @@ +fieldset { + .govuk-fieldset__legend--xl { + margin-bottom: 30px; + } + + @media (min-width: 40.0625em) { + .govuk-fieldset__legend--xl { + margin-bottom: 50px; + } + } +} diff --git a/core/common/forms.py b/core/common/forms.py index 09eed70245..3bcb35e768 100644 --- a/core/common/forms.py +++ b/core/common/forms.py @@ -2,8 +2,10 @@ from crispy_forms_gds.choices import Choice from crispy_forms_gds.layout import ( Div, + Fieldset, HTML, Layout, + Size, Submit, ) from django import forms @@ -62,6 +64,30 @@ def get_layout_actions(self): ] +class FieldsetForm(BaseForm): + """This is a suitable layout for a single question form. By using a +
and it ensures that related inputs are grouped together + with a common label to enable users to easily identify the group, as + covered by WCAG Technique H71. + """ + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.helper.layout = Layout( + Fieldset( + *self.get_layout_fields(), + legend=self.get_title(), + legend_size=Size.EXTRA_LARGE, + legend_tag="h1", + ), + Div( + *self.get_layout_actions(), + css_class="govuk-button-group", + ), + ) + + class MultipleFileInput(forms.ClearableFileInput): allow_multiple_selected = True diff --git a/exporter/core/organisation/forms.py b/exporter/core/organisation/forms.py index 82e50f1529..09ceb4640e 100644 --- a/exporter/core/organisation/forms.py +++ b/exporter/core/organisation/forms.py @@ -5,7 +5,7 @@ from crispy_forms_gds.layout import HTML -from core.common.forms import BaseForm, TextChoice +from core.common.forms import BaseForm, FieldsetForm, TextChoice from exporter.core.services import get_countries from .validators import validate_phone from exporter.core.organisation.services import validate_registration_number @@ -27,7 +27,7 @@ def get_layout_fields(self): return () -class RegistrationTypeForm(BaseForm): +class RegistrationTypeForm(FieldsetForm): class Layout: TITLE = "Select the type of organisation" From 6f8c7c0f4461dc5a3ef9525de5369c6d6788b831 Mon Sep 17 00:00:00 2001 From: Henry Cooksley Date: Mon, 13 Jan 2025 11:10:22 +0000 Subject: [PATCH 02/13] Change RegistrationUKBasedForm to use FieldsetForm --- exporter/core/organisation/forms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exporter/core/organisation/forms.py b/exporter/core/organisation/forms.py index 09ceb4640e..2565667eb2 100644 --- a/exporter/core/organisation/forms.py +++ b/exporter/core/organisation/forms.py @@ -58,7 +58,7 @@ def get_layout_fields(self): return ("type",) -class RegistrationUKBasedForm(BaseForm): +class RegistrationUKBasedForm(FieldsetForm): class Layout: TITLE = "Where is your organisation based?" From 182b2b73dab9fd0e90dc5caf87052993e589e99b Mon Sep 17 00:00:00 2001 From: Henry Cooksley Date: Mon, 13 Jan 2025 12:21:13 +0000 Subject: [PATCH 03/13] Update GroupTwoProductTypeForm to use FieldsetForm --- exporter/applications/views/goods/goods.py | 5 ++++- exporter/goods/forms/goods.py | 20 +++++++------------- exporter/goods/views.py | 7 +++++-- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/exporter/applications/views/goods/goods.py b/exporter/applications/views/goods/goods.py index 2fd21257e4..eef5329548 100644 --- a/exporter/applications/views/goods/goods.py +++ b/exporter/applications/views/goods/goods.py @@ -354,7 +354,10 @@ def get_product_type(self): def get_context_data(self, form, **kwargs): context = super().get_context_data(form, **kwargs) - context["title"] = form.title + try: + context["title"] = form.Layout.TITLE + except AttributeError: + context["title"] = form.title # The back_link_url is used for the first form in the sequence. For subsequent forms, # the wizard automatically generates the back link to the previous form. context["back_link_url"] = reverse("applications:goods", kwargs={"pk": self.kwargs["pk"]}) diff --git a/exporter/goods/forms/goods.py b/exporter/goods/forms/goods.py index e94f69cbbf..43362db1de 100644 --- a/exporter/goods/forms/goods.py +++ b/exporter/goods/forms/goods.py @@ -13,7 +13,7 @@ from core.forms.layouts import ConditionalRadiosQuestion, ConditionalRadios, summary_list from core.forms.utils import coerce_str_to_bool -from core.common.forms import TextChoice +from core.common.forms import FieldsetForm, TextChoice from exporter.core.constants import ( ProductSecurityFeatures, ProductDeclaredAtCustoms, @@ -332,8 +332,9 @@ def has_valid_section_five_certificate(application): return False -class GroupTwoProductTypeForm(forms.Form): - title = CreateGoodForm.FirearmGood.ProductType.TITLE +class GroupTwoProductTypeForm(FieldsetForm): + class Layout: + TITLE = CreateGoodForm.FirearmGood.ProductType.TITLE type = forms.TypedChoiceField( choices=( @@ -352,21 +353,14 @@ class GroupTwoProductTypeForm(forms.Form): label="", ) - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - self.helper = FormHelper() - self.helper.layout = Layout( - HTML.h1(self.title), - "type", - Submit("submit", CreateGoodForm.SUBMIT_BUTTON), - ) - def clean(self): cleaned_data = super().clean() cleaned_data["product_type_step"] = True return cleaned_data + def get_layout_fields(self): + return ("type",) + class FirearmsNumberOfItemsForm(forms.Form): title = "Number of items" diff --git a/exporter/goods/views.py b/exporter/goods/views.py index 9f10107aff..e19d10be74 100644 --- a/exporter/goods/views.py +++ b/exporter/goods/views.py @@ -102,7 +102,10 @@ class GoodCommonMixin: def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context["title"] = self.get_form().title + try: + context["title"] = self.get_form().Layout.TITLE + except AttributeError: + context["title"] = self.get_form().title return context @@ -543,7 +546,7 @@ def get_initial(self): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context["form_title"] = self.form_class.title + context["form_title"] = self.form_class.Layout.TITLE return context def form_valid(self, form): From 7ba62e157b2f9a4cb633965ac76c46461de7b185 Mon Sep 17 00:00:00 2001 From: Henry Cooksley Date: Mon, 13 Jan 2025 14:55:58 +0000 Subject: [PATCH 04/13] Update ProductControlListEntryForm to use FieldsetForm --- exporter/goods/forms/common.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exporter/goods/forms/common.py b/exporter/goods/forms/common.py index b99ff58152..8405894daa 100644 --- a/exporter/goods/forms/common.py +++ b/exporter/goods/forms/common.py @@ -16,7 +16,7 @@ ) from core.forms.utils import coerce_str_to_bool -from core.common.forms import BaseForm +from core.common.forms import BaseForm, FieldsetForm from exporter.core.forms import CustomErrorDateInputField from exporter.core.services import ( get_control_list_entries, @@ -52,7 +52,7 @@ def get_layout_fields(self): ) -class ProductControlListEntryForm(BaseForm): +class ProductControlListEntryForm(FieldsetForm): class Layout: TITLE = "Do you know the product's control list entry?" From 890c42dd7e945f5b9395c529de63ae0478bdb998 Mon Sep 17 00:00:00 2001 From: Henry Cooksley Date: Mon, 13 Jan 2025 15:06:48 +0000 Subject: [PATCH 05/13] Update ProductPVGradingForm to use FieldsetForm --- exporter/goods/forms/common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exporter/goods/forms/common.py b/exporter/goods/forms/common.py index 8405894daa..a850e8698c 100644 --- a/exporter/goods/forms/common.py +++ b/exporter/goods/forms/common.py @@ -120,7 +120,7 @@ def clean(self): return cleaned_data -class ProductPVGradingForm(BaseForm): +class ProductPVGradingForm(FieldsetForm): class Layout: TITLE = "Does the product have a government security grading or classification?" From 73215668b13e1a3b42860c3bdb490643a2200d0b Mon Sep 17 00:00:00 2001 From: Henry Cooksley Date: Mon, 13 Jan 2025 15:14:28 +0000 Subject: [PATCH 06/13] Update ProductPVGradingDetailsForm to use FieldsetForm --- exporter/goods/forms/common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exporter/goods/forms/common.py b/exporter/goods/forms/common.py index a850e8698c..eb8da958b9 100644 --- a/exporter/goods/forms/common.py +++ b/exporter/goods/forms/common.py @@ -148,7 +148,7 @@ def get_layout_fields(self): ) -class ProductPVGradingDetailsForm(BaseForm): +class ProductPVGradingDetailsForm(FieldsetForm): class Layout: TITLE = "What is the security grading or classification?" From c43795bb6780dc0d8d9c8a83b56c8225ea5b747e Mon Sep 17 00:00:00 2001 From: Henry Cooksley Date: Mon, 13 Jan 2025 15:17:17 +0000 Subject: [PATCH 07/13] Update FirearmReplicaForm to use FieldsetForm --- exporter/goods/forms/firearms.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exporter/goods/forms/firearms.py b/exporter/goods/forms/firearms.py index eaab0f5f97..cc5ad455c5 100644 --- a/exporter/goods/forms/firearms.py +++ b/exporter/goods/forms/firearms.py @@ -16,7 +16,7 @@ ) from core.forms.utils import coerce_str_to_bool -from core.common.forms import BaseForm, TextChoice +from core.common.forms import BaseForm, FieldsetForm, TextChoice from exporter.core.forms import ( CustomErrorDateInputField, PotentiallyUnsafeClearableFileInput, @@ -100,7 +100,7 @@ def get_layout_fields(self): return ("calibre",) -class FirearmReplicaForm(BaseForm): +class FirearmReplicaForm(FieldsetForm): class Layout: TITLE = "Is the product a replica firearm?" From ea5a5ee7d68d5b7daea50d321a98051942e2aa5e Mon Sep 17 00:00:00 2001 From: Henry Cooksley Date: Mon, 13 Jan 2025 15:18:52 +0000 Subject: [PATCH 08/13] Update FirearmRegisteredFirearmsDealerForm to use FieldsetForm --- exporter/goods/forms/firearms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exporter/goods/forms/firearms.py b/exporter/goods/forms/firearms.py index cc5ad455c5..c5c5bf3b4b 100644 --- a/exporter/goods/forms/firearms.py +++ b/exporter/goods/forms/firearms.py @@ -192,7 +192,7 @@ def get_layout_fields(self): ) -class FirearmRegisteredFirearmsDealerForm(BaseForm): +class FirearmRegisteredFirearmsDealerForm(FieldsetForm): class Layout: TITLE = "Are you a registered firearms dealer?" From 4b0719ebf7eb6f5ec1ae507a063584dbd5deb057 Mon Sep 17 00:00:00 2001 From: Henry Cooksley Date: Mon, 13 Jan 2025 15:20:41 +0000 Subject: [PATCH 09/13] Update FirearmFirearmAct1968Form to use FieldsetForm --- exporter/goods/forms/firearms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exporter/goods/forms/firearms.py b/exporter/goods/forms/firearms.py index c5c5bf3b4b..4d4061830f 100644 --- a/exporter/goods/forms/firearms.py +++ b/exporter/goods/forms/firearms.py @@ -267,7 +267,7 @@ def get_layout_fields(self): ) -class FirearmFirearmAct1968Form(BaseForm): +class FirearmFirearmAct1968Form(FieldsetForm): class Layout: TITLE = "Which section of the Firearms Act 1968 is the product covered by?" From c26705bf78cb817e5cee210f609cc83a4f0dd815 Mon Sep 17 00:00:00 2001 From: Henry Cooksley Date: Mon, 13 Jan 2025 17:00:00 +0000 Subject: [PATCH 10/13] Update goods forms to use FieldsetForm --- exporter/goods/forms/common.py | 12 ++++++------ exporter/goods/forms/firearms.py | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/exporter/goods/forms/common.py b/exporter/goods/forms/common.py index eb8da958b9..cf0314dbfc 100644 --- a/exporter/goods/forms/common.py +++ b/exporter/goods/forms/common.py @@ -275,7 +275,7 @@ def clean(self): return cleaned_data -class ProductDocumentAvailabilityForm(BaseForm): +class ProductDocumentAvailabilityForm(FieldsetForm): class Layout: TITLE = "Do you have a document that shows what your product is and what it's designed to do?" @@ -324,7 +324,7 @@ def clean(self): return cleaned_data -class ProductDocumentSensitivityForm(BaseForm): +class ProductDocumentSensitivityForm(FieldsetForm): class Layout: TITLE = "Is the document rated above Official-sensitive?" @@ -354,7 +354,7 @@ def get_layout_fields(self): ) -class ProductDocumentUploadForm(BaseForm): +class ProductDocumentUploadForm(FieldsetForm): class Layout: TITLE = "Upload a document that shows what your product is designed to do" @@ -404,7 +404,7 @@ def get_layout_fields(self): return layout_fields -class ProductOnwardExportedForm(BaseForm): +class ProductOnwardExportedForm(FieldsetForm): class Layout: TITLE = "Is the product going to any ultimate end-users?" @@ -431,7 +431,7 @@ def get_layout_fields(self): ) -class ProductOnwardAlteredProcessedForm(BaseForm): +class ProductOnwardAlteredProcessedForm(FieldsetForm): class Layout: TITLE = "Will the item be altered or processed before it is exported again?" @@ -482,7 +482,7 @@ def clean(self): return cleaned_data -class ProductOnwardIncorporatedForm(BaseForm): +class ProductOnwardIncorporatedForm(FieldsetForm): class Layout: TITLE = "Will the product be incorporated into another item before it is onward exported?" diff --git a/exporter/goods/forms/firearms.py b/exporter/goods/forms/firearms.py index 4d4061830f..589e90d13a 100644 --- a/exporter/goods/forms/firearms.py +++ b/exporter/goods/forms/firearms.py @@ -462,7 +462,7 @@ def get_layout_fields(self): return ("is_covered_by_section_5",) -class FirearmMadeBefore1938Form(BaseForm): +class FirearmMadeBefore1938Form(FieldsetForm): class Layout: TITLE = "Was the product made before 1938?" @@ -503,7 +503,7 @@ def get_layout_fields(self): return ("year_of_manufacture",) -class FirearmIsDeactivatedForm(BaseForm): +class FirearmIsDeactivatedForm(FieldsetForm): class Layout: TITLE = "Has the product been deactivated?" @@ -599,7 +599,7 @@ def clean(self): return cleaned_data -class FirearmSerialIdentificationMarkingsForm(BaseForm): +class FirearmSerialIdentificationMarkingsForm(FieldsetForm): class Layout: TITLE = "Will each product have a serial number or other identification marking?" From 412658f203e080c8dba1a7fbf2c4d72e7ba987c8 Mon Sep 17 00:00:00 2001 From: Henry Cooksley Date: Mon, 13 Jan 2025 17:00:11 +0000 Subject: [PATCH 11/13] Update parties forms to use Fieldset --- exporter/applications/forms/parties.py | 33 ++++++++++--------- .../views/parties/test_end_users.py | 8 ++--- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/exporter/applications/forms/parties.py b/exporter/applications/forms/parties.py index e7be51a22c..86c7c28748 100644 --- a/exporter/applications/forms/parties.py +++ b/exporter/applications/forms/parties.py @@ -1,13 +1,13 @@ from core.helpers import remove_non_printable_characters from crispy_forms_gds.choices import Choice from crispy_forms_gds.helper import FormHelper -from crispy_forms_gds.layout import Layout, Submit, HTML +from crispy_forms_gds.layout import Fieldset, Layout, Size, Submit, HTML from django import forms from django.core.exceptions import ValidationError from django.core.validators import MaxLengthValidator, URLValidator from django.urls import reverse_lazy -from core.common.forms import BaseForm +from core.common.forms import BaseForm, FieldsetForm from core.forms.layouts import ConditionalRadios, ConditionalRadiosQuestion from core.forms.widgets import Autocomplete from exporter.core.constants import CaseTypes, FileUploadFileTypes @@ -133,10 +133,9 @@ def new_party_form_group(request, application, strings, back_url, clearance_opti return FormGroup(forms) -class PartyReuseForm(BaseForm): +class PartyReuseForm(FieldsetForm): class Layout: TITLE = "Do you want to reuse an existing party?" - TITLE_AS_LABEL_FOR = "reuse_party" reuse_party = forms.ChoiceField( choices=( @@ -154,7 +153,7 @@ def get_layout_fields(self): return ("reuse_party",) -class PartySubTypeSelectForm(BaseForm): +class PartySubTypeSelectForm(FieldsetForm): """ This form needs to be instantiated with a Layout.TITLE for the type of party whose data is being set as per the BaseForm. @@ -200,13 +199,11 @@ def clean(self): class EndUserSubTypeSelectForm(PartySubTypeSelectForm): class Layout: TITLE = "Select the type of end user" - TITLE_AS_LABEL_FOR = "sub_type" class ConsigneeSubTypeSelectForm(PartySubTypeSelectForm): class Layout: TITLE = "Select the type of consignee" - TITLE_AS_LABEL_FOR = "sub_type" class PartyNameForm(BaseForm): @@ -395,15 +392,19 @@ def __init__(self, *args, **kwargs): self.helper = FormHelper() self.helper.layout = Layout( - HTML.h1(self.title), - HTML.p(self.text_p1), - HTML.p(self.text_p2), - HTML.p(self.text_p3), - HTML.p(self.text_p4), - ConditionalRadios( - "end_user_document_available", - "Yes", - ConditionalRadiosQuestion("No", "end_user_document_missing_reason"), + Fieldset( + HTML.p(self.text_p1), + HTML.p(self.text_p2), + HTML.p(self.text_p3), + HTML.p(self.text_p4), + ConditionalRadios( + "end_user_document_available", + "Yes", + ConditionalRadiosQuestion("No", "end_user_document_missing_reason"), + ), + legend=self.title, + legend_size=Size.EXTRA_LARGE, + legend_tag="h1", ), Submit("submit", "Continue"), ) diff --git a/unit_tests/exporter/applications/views/parties/test_end_users.py b/unit_tests/exporter/applications/views/parties/test_end_users.py index 700b88f2f9..5a0fca3a77 100644 --- a/unit_tests/exporter/applications/views/parties/test_end_users.py +++ b/unit_tests/exporter/applications/views/parties/test_end_users.py @@ -127,9 +127,9 @@ def set_end_user(url, authorized_client): assert not response.context["form"].errors content = BeautifulSoup(response.content, "html.parser") - heading_element = content.find("h1", class_="govuk-heading-xl") + heading_element = content.find("h1", class_="govuk-fieldset__heading") - assert heading_element.string == "Select the type of end user" + assert heading_element.string.strip() == "Select the type of end user" response = authorized_client.post( url, @@ -457,6 +457,6 @@ def test_add_end_user_view(authorized_client, data_standard_case): url = reverse("applications:add_end_user", kwargs={"pk": application_id}) response = authorized_client.get(url) soup = BeautifulSoup(response.content, "html.parser") - heading_element = soup.find("h1", class_="govuk-heading-xl") + heading_element = soup.find("h1", class_="govuk-fieldset__heading") - assert heading_element.string == "Do you want to reuse an existing party?" + assert heading_element.string.strip() == "Do you want to reuse an existing party?" From f045a6ea38a084ad8e6e9cfef3d5082fcd91de2a Mon Sep 17 00:00:00 2001 From: Henry Cooksley Date: Mon, 13 Jan 2025 17:10:21 +0000 Subject: [PATCH 12/13] Update HCSATminiform to use Fieldset --- exporter/applications/forms/hcsat.py | 15 +++++++++++++-- .../applications/application-submit-success.html | 1 - 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/exporter/applications/forms/hcsat.py b/exporter/applications/forms/hcsat.py index e9c1b02d26..a3747a9c2a 100644 --- a/exporter/applications/forms/hcsat.py +++ b/exporter/applications/forms/hcsat.py @@ -1,5 +1,5 @@ from crispy_forms_gds.helper import FormHelper -from crispy_forms_gds.layout import Field, Layout, Submit, HTML +from crispy_forms_gds.layout import Field, Fieldset, Layout, Size, Submit, HTML from django.urls import reverse_lazy from django import forms @@ -7,6 +7,9 @@ class HCSATminiform(forms.Form): + class Layout: + TITLE = "Overall, how would you rate your experience with the 'apply for a standard individual export licence (SIEL)' service today?" + RECOMMENDATION_CHOICES = [ ("VERY_DISSATISFIED", "Very dissatisfied"), ("DISSATISFIED", "Dissatisfied"), @@ -23,11 +26,19 @@ class HCSATminiform(forms.Form): error_messages={"required": "Star rating is required"}, ) + def get_title(self): + return self.Layout.TITLE + def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.helper = FormHelper() self.helper.layout = Layout( - StarRadioSelect("satisfaction_rating"), + Fieldset( + StarRadioSelect("satisfaction_rating"), + legend=self.get_title(), + legend_size=Size.MEDIUM, + legend_tag="h2", + ), Submit("submit", "Submit and continue"), ) diff --git a/exporter/templates/applications/application-submit-success.html b/exporter/templates/applications/application-submit-success.html index 5aeefd22c4..5157ecd134 100644 --- a/exporter/templates/applications/application-submit-success.html +++ b/exporter/templates/applications/application-submit-success.html @@ -51,7 +51,6 @@

What happens next

{% endfor %}
-

Overall, how would you rate your experience with the 'apply for a standard individual export licence (SIEL)' service today?

{% crispy form %} {% endblock %} From 6d54c598394dd34471854ae654fc3eb370fe7e51 Mon Sep 17 00:00:00 2001 From: Henry Cooksley Date: Thu, 16 Jan 2025 14:43:39 +0000 Subject: [PATCH 13/13] Remove try-except statement and use hasattr --- exporter/applications/views/goods/goods.py | 4 ++-- exporter/goods/views.py | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/exporter/applications/views/goods/goods.py b/exporter/applications/views/goods/goods.py index eef5329548..2bb9d86514 100644 --- a/exporter/applications/views/goods/goods.py +++ b/exporter/applications/views/goods/goods.py @@ -354,9 +354,9 @@ def get_product_type(self): def get_context_data(self, form, **kwargs): context = super().get_context_data(form, **kwargs) - try: + if hasattr(form, "Layout") and hasattr(form.Layout, "TITLE"): context["title"] = form.Layout.TITLE - except AttributeError: + else: context["title"] = form.title # The back_link_url is used for the first form in the sequence. For subsequent forms, # the wizard automatically generates the back link to the previous form. diff --git a/exporter/goods/views.py b/exporter/goods/views.py index e19d10be74..b885088054 100644 --- a/exporter/goods/views.py +++ b/exporter/goods/views.py @@ -102,10 +102,11 @@ class GoodCommonMixin: def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - try: - context["title"] = self.get_form().Layout.TITLE - except AttributeError: - context["title"] = self.get_form().title + form = self.get_form() + if hasattr(form, "Layout") and hasattr(form.Layout, "TITLE"): + context["title"] = form.Layout.TITLE + else: + context["title"] = form.title return context