Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions tests/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class MyForm(Form):
"""

simple = CharField()
flag = forms.BooleanField(required=False)
with_attrs = CharField(widget=TextInput(attrs={"foo": "baz", "egg": "spam"}))
with_cls = CharField(widget=TextInput(attrs={"class": "class0"}))
date = forms.DateField(widget=SelectDateWidget(attrs={"egg": "spam"}))
Expand Down
15 changes: 15 additions & 0 deletions tests/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,21 @@ def test_use_template_variable_in_parameters(self):
assertIn('placeholder="With attrs"', res)


class RenderFieldTagBooleanAttributeTest(TestCase):
def test_checked_true_renders_bare_attribute(self):
res = render_form(
"{% render_field form.flag checked=is_checked %}", is_checked=True
)
assertIn("checked", res)
assertNotIn('checked="True"', res)

def test_checked_false_omits_attribute(self):
res = render_form(
"{% render_field form.flag checked=is_checked %}", is_checked=False
)
assertNotIn("checked", res)


class RenderFieldFilter_field_type_widget_type_Test(TestCase):
def test_field_type_widget_type_rendering_simple(self):
res = render_form(
Expand Down
52 changes: 37 additions & 15 deletions widget_tweaks/templatetags/widget_tweaks.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ def _process_field_attributes(field, attr, process):
# attribute = params[0]
attribute = params[0].replace("::", ":")
value = params[1] if len(params) == 2 else True
return _process_field_attribute_value(field, attribute, value, process)


def _process_field_attribute_value(field, attribute, value, process):
# mirrors silence_without_field's guard, needed here since render_field calls this directly
if not field:
return ""
field = copy(field)

if not hasattr(field, "as_widget"):
Expand Down Expand Up @@ -55,13 +62,25 @@ def as_widget(self, widget=None, attrs=None, only_initial=False):
return field


def _set_attr_process(
widget, attrs, attribute, value
): # pylint: disable=unused-argument
attrs[attribute] = value


def _append_attr_process(widget, attrs, attribute, value):
if attrs.get(attribute):
attrs[attribute] += " " + value
elif widget.attrs.get(attribute):
attrs[attribute] = widget.attrs[attribute] + " " + value
else:
attrs[attribute] = value


@register.filter("attr")
@silence_without_field
def set_attr(field, attr):
def process(widget, attrs, attribute, value): # pylint: disable=unused-argument
attrs[attribute] = value

return _process_field_attributes(field, attr, process)
return _process_field_attributes(field, attr, _set_attr_process)


@register.filter("add_error_attr")
Expand All @@ -75,15 +94,7 @@ def add_error_attr(field, attr):
@register.filter("append_attr")
@silence_without_field
def append_attr(field, attr):
def process(widget, attrs, attribute, value):
if attrs.get(attribute):
attrs[attribute] += " " + value
elif widget.attrs.get(attribute):
attrs[attribute] = widget.attrs[attribute] + " " + value
else:
attrs[attribute] = value

return _process_field_attributes(field, attr, process)
return _process_field_attributes(field, attr, _append_attr_process)


@register.filter("add_class")
Expand Down Expand Up @@ -233,9 +244,20 @@ def render(self, context):
if k == "type":
bounded_field.field.widget.input_type = v.resolve(context)
else:
bounded_field = set_attr(bounded_field, f"{k}:{v.resolve(context)}")
# pass the resolved value through as-is, not stringified, so e.g. checked=False stays a bool
bounded_field = _process_field_attribute_value(
bounded_field,
k.replace("::", ":"),
v.resolve(context),
_set_attr_process,
)
for k, v in self.append_attrs:
bounded_field = append_attr(bounded_field, f"{k}:{v.resolve(context)}")
bounded_field = _process_field_attribute_value(
bounded_field,
k.replace("::", ":"),
v.resolve(context),
_append_attr_process,
)
return str(bounded_field)


Expand Down