From a66f1083e84041eb7a9f5335c2e82ff30a9fe267 Mon Sep 17 00:00:00 2001 From: Ross Jones Date: Mon, 18 Jun 2018 16:59:02 +0100 Subject: [PATCH 1/3] WIP - Allow inference of booleans in enums Where a field is a BooleanField or a NullBooleanField inference should generate a lookup list with `[Yes, No]` and `[Yes, No, Unknown]` as options (for radio buttons). This will require changes to templates/radio.html so that Unkown does not use Unknown as a value, instead leaving the value empty so that we know the intended value is None. This would be easier if lookuplists were tuples (like choices in Django) so I'm considering implementing support for lists of tuples (as well as the current list of strings) for lookuplists - the alternative is too much logic in the template and special-casing the string 'Unknown' Will fix #1540 --- opal/models.py | 9 ++++++++- opal/tests/models.py | 1 + opal/tests/test_templatetags_forms.py | 14 ++++++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/opal/models.py b/opal/models.py index 883e06a20..a74bad58a 100644 --- a/opal/models.py +++ b/opal/models.py @@ -200,11 +200,18 @@ def get_field_description(cls, name): @classmethod def get_field_enum(cls, name): field = cls._get_field(name) - choices = getattr(field, "choices", []) + choices = getattr(field, "choices", []) if choices: return [i[1] for i in choices] + yes_no = ["Yes", "No"] + if cls._get_field_type(name) == models.fields.BooleanField: + return yes_no + elif cls._get_field_type(name) == models.fields.NullBooleanField: + return yes_no + ["Unknown"] + + @classmethod def get_lookup_list_api_name(cls, field_name): lookup_list = None diff --git a/opal/tests/models.py b/opal/tests/models.py index 2358fbb69..459cb077f 100644 --- a/opal/tests/models.py +++ b/opal/tests/models.py @@ -37,6 +37,7 @@ class HatWearer(models.EpisodeSubrecord): name = dmodels.CharField(max_length=200) hats = dmodels.ManyToManyField(Hat, related_name="hat_wearers") wearing_a_hat = dmodels.BooleanField(default=True) + suits_a_hat = dmodels.NullBooleanField() class Meta: verbose_name = 'Wearer of Hats' diff --git a/opal/tests/test_templatetags_forms.py b/opal/tests/test_templatetags_forms.py index cd3e90ece..6d2d88f0e 100644 --- a/opal/tests/test_templatetags_forms.py +++ b/opal/tests/test_templatetags_forms.py @@ -449,6 +449,20 @@ def test_radio_infer_lookuplists(self): rendered = template.render(Context({})) self.assertIn('purple', rendered) + def test_radio_infer_lookuplists_with_boolean(self): + template = Template('{% load forms %}{% radio field="HatWearer.wearing_a_hat" %}') + rendered = template.render(Context({})) + self.assertIn('Yes', rendered) + self.assertIn('No', rendered) + self.assertNotIn('Unknown', rendered) + + def test_radio_infer_lookuplists_with_quantum_boolean(self): + template = Template('{% load forms %}{% radio field="HatWearer.suits_a_hat" %}') + rendered = template.render(Context({})) + self.assertIn('Yes', rendered) + self.assertIn('No', rendered) + self.assertIn('Unknown', rendered) + def test_element_name(self): tpl = Template('{% load forms %}{% radio label="hai" model="bai" element_name="onions"%}') rendered = tpl.render(Context({})) From a6acac4673e20df9fa58a44d2c51ad5edc0385a0 Mon Sep 17 00:00:00 2001 From: Ross Jones Date: Mon, 18 Jun 2018 17:12:02 +0100 Subject: [PATCH 2/3] Appease the linter --- opal/models.py | 1 - 1 file changed, 1 deletion(-) diff --git a/opal/models.py b/opal/models.py index a74bad58a..866097bc2 100644 --- a/opal/models.py +++ b/opal/models.py @@ -211,7 +211,6 @@ def get_field_enum(cls, name): elif cls._get_field_type(name) == models.fields.NullBooleanField: return yes_no + ["Unknown"] - @classmethod def get_lookup_list_api_name(cls, field_name): lookup_list = None From 0ce132e647661b940a71d3bcc438ee71611fdfe2 Mon Sep 17 00:00:00 2001 From: David Miller Date: Fri, 26 Oct 2018 14:39:21 +0100 Subject: [PATCH 3/3] Add explicit unittests for get_field_enum inference on boolean fields refs #1540 --- opal/tests/test_models.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/opal/tests/test_models.py b/opal/tests/test_models.py index 24a7b29b7..76a3465d6 100644 --- a/opal/tests/test_models.py +++ b/opal/tests/test_models.py @@ -434,6 +434,14 @@ def test_enum(self): enum = FavouriteColour.get_field_enum('name') self.assertEqual(enum, ["purple", "yellow", "blue"]) + def test_get_field_enum_for_boolean_field(self): + enum = HatWearer.get_field_enum('wearing_a_hat') + self.assertEqual(enum, ['Yes', 'No']) + + def test_get_field_enum_for_null_boolean_field(self): + enum = HatWearer.get_field_enum('suits_a_hat') + self.assertEqual(enum, ['Yes', 'No', 'Unknown']) + def test_description(self): description = FavouriteColour.get_field_description('name') self.assertEqual(description, "orange is the new black")