From a350bfa6f44befff8779dbbdd72c9760bf5df959 Mon Sep 17 00:00:00 2001 From: David Smith Date: Wed, 1 Apr 2020 17:48:23 +0100 Subject: [PATCH] Fixed #13009 -- Added BoundField.widget_type property. --- django/forms/boundfield.py | 5 +++++ docs/ref/forms/api.txt | 17 +++++++++++++++++ docs/releases/3.1.txt | 3 +++ tests/forms_tests/tests/test_forms.py | 9 +++++++++ 4 files changed, 34 insertions(+) diff --git a/django/forms/boundfield.py b/django/forms/boundfield.py index 8832169021..66d065c9c8 100644 --- a/django/forms/boundfield.py +++ b/django/forms/boundfield.py @@ -1,4 +1,5 @@ import datetime +import re from django.forms.utils import flatatt, pretty_name from django.forms.widgets import Textarea, TextInput @@ -227,6 +228,10 @@ class BoundField: attrs['disabled'] = True return attrs + @property + def widget_type(self): + return re.sub(r'widget$|input$', '', self.field.widget.__class__.__name__.lower()) + @html_safe class BoundWidget: diff --git a/docs/ref/forms/api.txt b/docs/ref/forms/api.txt index 23fbab9aff..a084867011 100644 --- a/docs/ref/forms/api.txt +++ b/docs/ref/forms/api.txt @@ -972,6 +972,23 @@ Attributes of ``BoundField`` >>> print(f['message'].name) message +.. attribute:: BoundField.widget_type + + .. versionadded:: 3.1 + + Returns the lowercased class name of the wrapped field's widget, with any + trailing ``input`` or ``widget`` removed. This may be used when building + forms where the layout is dependent upon the widget type. For example:: + + {% for field in form %} + {% if field.widget_type == 'checkbox' %} + # render one way + {% else %} + # render another way + {% endif %} + {% endfor %} + + Methods of ``BoundField`` ------------------------- diff --git a/docs/releases/3.1.txt b/docs/releases/3.1.txt index 7df81329b4..85f4ca2d99 100644 --- a/docs/releases/3.1.txt +++ b/docs/releases/3.1.txt @@ -278,6 +278,9 @@ Forms * :attr:`.MultiWidget.widgets` now accepts a dictionary which allows customizing subwidget ``name`` attributes. +* The new :attr:`.BoundField.widget_type` property can be used to dynamically + adjust form rendering based upon the widget type. + Generic Views ~~~~~~~~~~~~~ diff --git a/tests/forms_tests/tests/test_forms.py b/tests/forms_tests/tests/test_forms.py index b62b32de4b..f56eaee4b0 100644 --- a/tests/forms_tests/tests/test_forms.py +++ b/tests/forms_tests/tests/test_forms.py @@ -3142,6 +3142,15 @@ Good luck picking a username that doesn't already exist.

self.assertEqual(form['field'].id_for_label, 'myCustomID') self.assertEqual(form['field_none'].id_for_label, 'id_field_none') + def test_boundfield_widget_type(self): + class SomeForm(Form): + first_name = CharField() + birthday = SplitDateTimeField(widget=SplitHiddenDateTimeWidget) + + f = SomeForm() + self.assertEqual(f['first_name'].widget_type, 'text') + self.assertEqual(f['birthday'].widget_type, 'splithiddendatetime') + def test_label_tag_override(self): """ BoundField label_suffix (if provided) overrides Form label_suffix