diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index 150f43519..5a2b35c9e 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 ef396b3e6..b409c4fb1 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 df1e040fe..597010324 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 151e6e069..706c94ba1 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('