added default argument to ChoiceBlock.

If default is not None and required is True,
don't render a blank option.
pull/2254/merge
Andreas Nüßlein 2016-12-30 14:12:53 +01:00 zatwierdzone przez Matt Westcott
rodzic eb16a476ba
commit 2734dfca8b
4 zmienionych plików z 26 dodań i 7 usunięć

Wyświetl plik

@ -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)

Wyświetl plik

@ -197,6 +197,7 @@ Contributors
* Mihail Russu
* Robert Slotboom
* Erick M'bwana
* Andreas Nüßlein
Translators
===========

Wyświetl plik

@ -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

Wyświetl plik

@ -426,6 +426,15 @@ class TestChoiceBlock(unittest.TestCase):
self.assertIn('<option value="tea">Tea</option>', html)
self.assertIn('<option value="coffee" selected="selected">Coffee</option>', 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('<select id="beverage" name="beverage" placeholder="">', html)
# blank option should NOT be rendered if default and required are set.
self.assertNotIn('<option value="">%s</option>' % self.blank_choice_dash_label, html)
self.assertIn('<option value="tea">Tea</option>', html)
self.assertIn('<option value="coffee" selected="selected">Coffee</option>', html)
def test_render_required_choice_block_with_callable_choices(self):
def callable_choices():
return [('tea', 'Tea'), ('coffee', 'Coffee')]