diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 150f435192..5a2b35c9e8 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -5,6 +5,7 @@ Changelog ~~~~~~~~~~~~~~~~ * View live / draft links in the admin now consistently open in a new window (Marco Fucci) + * `ChoiceBlock` now omits the blank option if the block is required and has a default value (Andreas Nüßlein) 1.8 (15.12.2016) diff --git a/CONTRIBUTORS.rst b/CONTRIBUTORS.rst index ef396b3e6c..b409c4fb1c 100644 --- a/CONTRIBUTORS.rst +++ b/CONTRIBUTORS.rst @@ -197,6 +197,7 @@ Contributors * Mihail Russu * Robert Slotboom * Erick M'bwana +* Andreas Nüßlein Translators =========== diff --git a/wagtail/wagtailcore/blocks/field_block.py b/wagtail/wagtailcore/blocks/field_block.py index df1e040fed..5970103243 100644 --- a/wagtail/wagtailcore/blocks/field_block.py +++ b/wagtail/wagtailcore/blocks/field_block.py @@ -333,7 +333,7 @@ class ChoiceBlock(FieldBlock): choices = () - def __init__(self, choices=None, required=True, help_text=None, **kwargs): + def __init__(self, choices=None, default=None, required=True, help_text=None, **kwargs): if choices is None: # no choices specified, so pick up the choice defined at the class level choices = self.choices @@ -361,14 +361,18 @@ class ChoiceBlock(FieldBlock): # one already. We have to do this at render time in the case of callable choices - so rather # than having separate code paths for static vs dynamic lists, we'll _always_ pass a callable # to ChoiceField to perform this step at render time. - callable_choices = self.get_callable_choices(choices) - self.field = forms.ChoiceField(choices=callable_choices, required=required, help_text=help_text) - super(ChoiceBlock, self).__init__(**kwargs) - def get_callable_choices(self, choices): + # If we have a default choice and the field is required, we don't need to add a blank option. + callable_choices = self.get_callable_choices(choices, blank_choice=not(default and required)) + + self.field = forms.ChoiceField(choices=callable_choices, required=required, help_text=help_text) + super(ChoiceBlock, self).__init__(default=default, **kwargs) + + def get_callable_choices(self, choices, blank_choice=True): """ Return a callable that we can pass into `forms.ChoiceField`, which will provide the - choices list with the addition of a blank choice (if one does not already exist). + choices list with the addition of a blank choice (if blank_choice=True and one does not + already exist). """ def choices_callable(): # Variable choices could be an instance of CallableChoiceIterator, which may be wrapping @@ -377,7 +381,11 @@ class ChoiceBlock(FieldBlock): # once while rendering the final ChoiceField). local_choices = list(choices) - # If choices does not already contain a blank option, insert one + # If blank_choice=False has been specified, return the choices list as is + if not blank_choice: + return local_choices + + # Else: if choices does not already contain a blank option, insert one # (to match Django's own behaviour for modelfields: # https://github.com/django/django/blob/1.7.5/django/db/models/fields/__init__.py#L732-744) has_blank_choice = False diff --git a/wagtail/wagtailcore/tests/test_blocks.py b/wagtail/wagtailcore/tests/test_blocks.py index 151e6e069b..706c94ba1a 100644 --- a/wagtail/wagtailcore/tests/test_blocks.py +++ b/wagtail/wagtailcore/tests/test_blocks.py @@ -426,6 +426,15 @@ class TestChoiceBlock(unittest.TestCase): self.assertIn('', html) self.assertIn('', html) + def test_render_required_choice_block_with_default(self): + block = blocks.ChoiceBlock(choices=[('tea', 'Tea'), ('coffee', 'Coffee')], default='tea') + html = block.render_form('coffee', prefix='beverage') + self.assertIn('