mirror of
https://github.com/django/django.git
synced 2024-12-23 01:25:58 +00:00
Fixed #32340 -- Improved usability for form fields with specific input patterns.
This commit is contained in:
parent
f05edb2b43
commit
25a2631d64
@ -19,6 +19,7 @@ from django.conf import settings
|
|||||||
from django.core import validators
|
from django.core import validators
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.forms.boundfield import BoundField
|
from django.forms.boundfield import BoundField
|
||||||
|
from django.forms.fields import Field as DjangoField
|
||||||
from django.forms.utils import from_current_timezone, to_current_timezone
|
from django.forms.utils import from_current_timezone, to_current_timezone
|
||||||
from django.forms.widgets import (
|
from django.forms.widgets import (
|
||||||
FILE_INPUT_CONTRADICTION,
|
FILE_INPUT_CONTRADICTION,
|
||||||
@ -29,6 +30,7 @@ from django.forms.widgets import (
|
|||||||
EmailInput,
|
EmailInput,
|
||||||
FileInput,
|
FileInput,
|
||||||
HiddenInput,
|
HiddenInput,
|
||||||
|
Input,
|
||||||
MultipleHiddenInput,
|
MultipleHiddenInput,
|
||||||
NullBooleanSelect,
|
NullBooleanSelect,
|
||||||
NumberInput,
|
NumberInput,
|
||||||
@ -1408,3 +1410,14 @@ class JSONField(CharField):
|
|||||||
return json.dumps(initial, sort_keys=True, cls=self.encoder) != json.dumps(
|
return json.dumps(initial, sort_keys=True, cls=self.encoder) != json.dumps(
|
||||||
self.to_python(data), sort_keys=True, cls=self.encoder
|
self.to_python(data), sort_keys=True, cls=self.encoder
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class CustomField(DjangoField):
|
||||||
|
def __init__(self, *, widget=None, placeholder=None, **kwargs):
|
||||||
|
self.placeholder = placeholder
|
||||||
|
widget = widget or Input()
|
||||||
|
|
||||||
|
if self.placeholder:
|
||||||
|
widget.attrs.setdefault("placeholder", self.placeholder)
|
||||||
|
|
||||||
|
super().__init__(widget=widget, **kwargs)
|
||||||
|
@ -1 +1,3 @@
|
|||||||
<input type="{{ widget.type }}" name="{{ widget.name }}"{% if widget.value != None %} value="{{ widget.value|stringformat:'s' }}"{% endif %}{% include "django/forms/widgets/attrs.html" %}>
|
<input type="{{ widget.type }}" name="{{ widget.name }}"{% if widget.value != None %} value="{{ widget.value|stringformat:'s' }}"{% endif %}{% include "django/forms/widgets/attrs.html" %}>
|
||||||
|
|
||||||
|
{% if widget.attrs.placeholder %}placeholder="{{ widget.attrs.placeholder }}" {% endif %}>
|
||||||
|
@ -1226,3 +1226,25 @@ class SelectDateWidget(Widget):
|
|||||||
("{}_{}".format(name, interval) in data)
|
("{}_{}".format(name, interval) in data)
|
||||||
for interval in ("year", "month", "day")
|
for interval in ("year", "month", "day")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Input(Widget):
|
||||||
|
input_type = None # Subclass must define this
|
||||||
|
|
||||||
|
def __init__(self, attrs=None, placeholder=None):
|
||||||
|
self.placeholder = placeholder # Add placeholder attribute
|
||||||
|
super().__init__(attrs)
|
||||||
|
|
||||||
|
def get_context(self, name, value, attrs):
|
||||||
|
context = super().get_context(name, value, attrs)
|
||||||
|
if self.placeholder:
|
||||||
|
attrs = attrs or {}
|
||||||
|
attrs.setdefault("placeholder", self.placeholder)
|
||||||
|
context["widget"]["attrs"] = attrs
|
||||||
|
return context
|
||||||
|
|
||||||
|
def render(self, name, value, attrs=None, renderer=None):
|
||||||
|
attrs = attrs or {}
|
||||||
|
if self.placeholder:
|
||||||
|
attrs["placeholder"] = self.placeholder
|
||||||
|
return super().render(name, value, attrs, renderer)
|
||||||
|
@ -1627,3 +1627,13 @@ only requirements are that it implement a ``clean()`` method and that its
|
|||||||
|
|
||||||
You can also customize how a field will be accessed by overriding
|
You can also customize how a field will be accessed by overriding
|
||||||
:meth:`~django.forms.Field.get_bound_field()`.
|
:meth:`~django.forms.Field.get_bound_field()`.
|
||||||
|
|
||||||
|
DateField
|
||||||
|
---------
|
||||||
|
Use this field to input dates. The default expected format is ``YYYY-MM-DD``.
|
||||||
|
For example: ``2024-12-31``.
|
||||||
|
|
||||||
|
TimeField
|
||||||
|
---------
|
||||||
|
Use this field to input time. The default expected format is ``HH:MM``.
|
||||||
|
For example: ``14:30``.
|
@ -1,5 +1,6 @@
|
|||||||
from django.contrib.admin.tests import AdminSeleniumTestCase
|
from django.contrib.admin.tests import AdminSeleniumTestCase
|
||||||
from django.test import override_settings
|
from django.forms import CharField, Form, TextInput
|
||||||
|
from django.test import SimpleTestCase, override_settings
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
|
||||||
from ..models import Article
|
from ..models import Article
|
||||||
@ -22,3 +23,17 @@ class LiveWidgetTests(AdminSeleniumTestCase):
|
|||||||
self.selenium.find_element(By.ID, "submit").click()
|
self.selenium.find_element(By.ID, "submit").click()
|
||||||
article = Article.objects.get(pk=article.pk)
|
article = Article.objects.get(pk=article.pk)
|
||||||
self.assertEqual(article.content, "\r\nTst\r\n")
|
self.assertEqual(article.content, "\r\nTst\r\n")
|
||||||
|
|
||||||
|
|
||||||
|
class WidgetPlaceholderTests(SimpleTestCase):
|
||||||
|
def test_placeholder_in_input_widget(self):
|
||||||
|
widget = TextInput(attrs={"placeholder": "Enter text"})
|
||||||
|
output = widget.render("name", "")
|
||||||
|
self.assertIn('placeholder="Enter text"', output)
|
||||||
|
|
||||||
|
def test_placeholder_in_field(self):
|
||||||
|
class ExampleForm(Form):
|
||||||
|
name = CharField(widget=TextInput(attrs={"placeholder": "Your name"}))
|
||||||
|
|
||||||
|
form = ExampleForm()
|
||||||
|
self.assertIn('placeholder="Your name"', str(form["name"]))
|
||||||
|
Loading…
Reference in New Issue
Block a user