Opened 7 years ago
Last modified 43 hours ago
#30306 assigned New feature
Textarea widget missing input_type
| Reported by: | minusf | Owned by: | Hossein Shams |
|---|---|---|---|
| Component: | Forms | Version: | 6.1 |
| Severity: | Normal | Keywords: | |
| Cc: | Triage Stage: | Accepted | |
| Has patch: | yes | Needs documentation: | yes |
| Needs tests: | no | Patch needs improvement: | yes |
| Easy pickings: | yes | UI/UX: | no |
Description
(I tried to search for this both in here and the pull requests on github but there is an eerie quiet about it.)
Textarea seems to be one of the few (if not the only) widget not defining input_type.
I can't think of a good reason why it couldn't have one and some people find out about this strange omission when they try to do something like:
for field in self.fields:
widget = self.fields[field].widget
if widget.input_type == "select":
...
elif widget.input_type == "checkbox":
...
but end up with:
... AttributeError: 'Textarea' object has no attribute 'input_type'
Change History (11)
comment:1 by , 7 years ago
| Resolution: | → invalid |
|---|---|
| Status: | new → closed |
| Type: | Uncategorized → Cleanup/optimization |
comment:2 by , 7 years ago
Closed already? I think this is a fair bit of inconsistency and I would welcome at least some discussion.
This is not just about not triggering an exception. This is about having a useful way to identify widget types.
So textareas are the widgets that have no input_type? This makes programmatic widget customisation painful.
As for the value, what's wrong with 'textarea' ? Select has select, checkbox has checkbox, etc. Even hidden has one.
Why should textarea be different?
class Input(Widget):
"""
Base class for all <input> widgets.
"""
input_type = None # Subclasses must define this. <================= my emphasis
template_name = 'django/forms/widgets/input.html'
While this comment is in Input and not Widget (and Textarea inherits from Widget) the intention and philosophy seems clear to me.
follow-up: 9 comment:3 by , 7 years ago
For Input subclasses, input_type corresponds to <input type="...">. ChoiceWidget uses input_type for a different purpose.
comment:4 by , 7 years ago
I understand that the "abstraction" is leaking. But Select and RadioSelect both have input_type, even if for a "different purpose", those can be used in the same way as input_type for "true" Input widgets... It's not ideal, but it's already there and only Textarea is left out in the cold. The other alternative could be to add widget_type or such to every Widget subclass but at this point it would just duplicate input_type.
comment:5 by , 4 months ago
I just ran into this working in a template where I was checking input_type in order to fully customize the markup for the field. Here's a simplified example:
{% with field_type=field.field.widget.input_type %}
{% if field_type == "text" or field_type == "email" %}
<input type="{{ field_type }}">
{% elif field_type == "select" %}
<select>...</select>
{% endif %}
{% endwith %}
I was quite surprised when I went to add {% elif field_type == "textarea" %} and it had no effect.
There may be a better way to handle it, but for now I'm checking field.field.widget.template_name == "django/forms/widgets/textarea.html".
It would be nice if this could be reconsidered. It's a one-line addition that would seem to me to make things more consistent and predictable. I would be happy to submit a PR if this is reopened.
comment:6 by , 7 days ago
| Resolution: | invalid |
|---|---|
| Status: | closed → new |
| Version: | 2.2 → 6.1 |
I am reopening this issue following discussions with a few people during DjangoCon US sprints who agreed it was worth reconsidering. I also raised a discussion on the forum a few weeks after my last comment here, which received a couple hearts.
Original intent(s) for input_type not withstanding (see comment 3), I feel that Textarea now being the only widget class with no input_type attribute results in a situation where it behaves in a way inconsistent with all other widgets, and the workaround for the template use case I raised feels pretty icky and against Django template best practices.
I found a healthy number of other people having to leverage the workaround, so I'm not the first to encounter this. 1 2 3 4 5 6
comment:7 by , 5 days ago
| Has patch: | set |
|---|---|
| Owner: | changed from to |
| Status: | new → assigned |
comment:8 by , 5 days ago
I've submitted a pull request implementing the requested change:
https://github.com/django/django/pull/21857
Could someone please triage this and set the stage to "Accepted" if it
looks good? Happy to make any adjustments needed.
comment:9 by , 44 hours ago
| Triage Stage: | Unreviewed → Accepted |
|---|
Thanks for reopening and for being so patient!
Replying to Tim Graham:
For
Inputsubclasses,input_typecorresponds to<input type="...">.ChoiceWidgetusesinput_typefor a different purpose.
When I look at RadioSelectTest.test_render() I see that the RadioSelect.input_type does flow through to an eventual <input type="radio">. I only see a couple tests for ChoiceWidget itself, in a unit test style. RadioSelect is documented; ChoiceWidget isn't. Just sounding out why I think the request makes sense -- Textarea is a documented widget, and the request to make it quack like the others seems like it comes up in actual usage.
comment:10 by , 44 hours ago
To make this feature appear more meaningful/purposeful, we could perhaps implement input_type = "hidden" on Textarea like this (untested sketch):
-
django/forms/jinja2/django/forms/widgets/textarea.html
diff --git a/django/forms/jinja2/django/forms/widgets/textarea.html b/django/forms/jinja2/django/forms/widgets/textarea.html index b86766c894..23812661b1 100644
a b 1 1 <textarea name="{{ widget.name }}"{% include "django/forms/widgets/attrs.html" %}> 2 {% if widget.value %}{{ widget.value }}{% endif %} </textarea>2 {% if widget.value %}{{ widget.value }}{% endif %}{% if widget.is_hidden %} hidden{% endif %}</textarea> -
django/forms/templates/django/forms/widgets/textarea.html
diff --git a/django/forms/templates/django/forms/widgets/textarea.html b/django/forms/templates/django/forms/widgets/textarea.html index b86766c894..23812661b1 100644
a b 1 1 <textarea name="{{ widget.name }}"{% include "django/forms/widgets/attrs.html" %}> 2 {% if widget.value %}{{ widget.value }}{% endif %} </textarea>2 {% if widget.value %}{{ widget.value }}{% endif %}{% if widget.is_hidden %} hidden{% endif %}</textarea> -
django/forms/widgets.py
diff --git a/django/forms/widgets.py b/django/forms/widgets.py index a52ad18b09..3a9a6bdcc7 100644
a b class ClearableFileInput(FileInput): 645 645 646 646 647 647 class Textarea(Widget): 648 input_type = "textarea" 648 649 template_name = "django/forms/widgets/textarea.html" 649 650 650 651 def __init__(self, attrs=None):
The OpenLayersWidget in the GIS module does fathom a hidden attribute on a Textarea, but it has to define it via a display_raw attribute.
comment:11 by , 43 hours ago
| Needs documentation: | set |
|---|---|
| Patch needs improvement: | set |
| Type: | Cleanup/optimization → New feature |
If we implement hidden in the template, it's worth a tiny release note.
What would a sensible value be? It doesn't seem applicable to me. The code in question should use
if hasattr(widget, 'input_type')as Django does.