mirror of
https://github.com/django/django.git
synced 2024-11-28 21:43:13 +01:00
Refs #32339 -- Deprecated default.html form template.
Co-authored-by: Carlton Gibson <carlton.gibson@noumenal.es>
This commit is contained in:
parent
6af8673255
commit
d126eba363
@ -15,6 +15,9 @@ def get_default_renderer():
|
|||||||
|
|
||||||
|
|
||||||
class BaseRenderer:
|
class BaseRenderer:
|
||||||
|
# RemovedInDjango50Warning: When the deprecation ends, replace with
|
||||||
|
# form_template_name = "django/forms/div.html"
|
||||||
|
# formset_template_name = "django/forms/formsets/div.html"
|
||||||
form_template_name = "django/forms/default.html"
|
form_template_name = "django/forms/default.html"
|
||||||
formset_template_name = "django/forms/formsets/default.html"
|
formset_template_name = "django/forms/formsets/default.html"
|
||||||
|
|
||||||
@ -64,6 +67,31 @@ class Jinja2(EngineMixin, BaseRenderer):
|
|||||||
return Jinja2
|
return Jinja2
|
||||||
|
|
||||||
|
|
||||||
|
class DjangoDivFormRenderer(DjangoTemplates):
|
||||||
|
"""
|
||||||
|
Load Django templates from django/forms/templates and from apps'
|
||||||
|
'templates' directory and use the 'div.html' template to render forms and
|
||||||
|
formsets.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# RemovedInDjango50Warning Deprecate this class in 5.0 and remove in 6.0.
|
||||||
|
|
||||||
|
form_template_name = "django/forms/div.html"
|
||||||
|
formset_template_name = "django/forms/formsets/div.html"
|
||||||
|
|
||||||
|
|
||||||
|
class Jinja2DivFormRenderer(Jinja2):
|
||||||
|
"""
|
||||||
|
Load Jinja2 templates from the built-in widget templates in
|
||||||
|
django/forms/jinja2 and from apps' 'jinja2' directory.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# RemovedInDjango50Warning Deprecate this class in 5.0 and remove in 6.0.
|
||||||
|
|
||||||
|
form_template_name = "django/forms/div.html"
|
||||||
|
formset_template_name = "django/forms/formsets/div.html"
|
||||||
|
|
||||||
|
|
||||||
class TemplatesSetting(BaseRenderer):
|
class TemplatesSetting(BaseRenderer):
|
||||||
"""
|
"""
|
||||||
Load templates using template.loader.get_template() which is configured
|
Load templates using template.loader.get_template() which is configured
|
||||||
|
@ -1,13 +1,16 @@
|
|||||||
import json
|
import json
|
||||||
|
import warnings
|
||||||
from collections import UserList
|
from collections import UserList
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.forms.renderers import get_default_renderer
|
from django.forms.renderers import get_default_renderer
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
from django.utils.deprecation import RemovedInDjango50Warning
|
||||||
from django.utils.html import escape, format_html_join
|
from django.utils.html import escape, format_html_join
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from django.utils.version import get_docs_version
|
||||||
|
|
||||||
|
|
||||||
def pretty_name(name):
|
def pretty_name(name):
|
||||||
@ -42,6 +45,16 @@ def flatatt(attrs):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
DEFAULT_TEMPLATE_DEPRECATION_MSG = (
|
||||||
|
'The "default.html" templates for forms and formsets will be removed. These were '
|
||||||
|
'proxies to the equivalent "table.html" templates, but the new "div.html" '
|
||||||
|
"templates will be the default from Django 5.0. Transitional renderers are "
|
||||||
|
"provided to allow you to opt-in to the new output style now. See "
|
||||||
|
"https://docs.djangoproject.com/en/%s/releases/4.1/ for more details"
|
||||||
|
% get_docs_version()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class RenderableMixin:
|
class RenderableMixin:
|
||||||
def get_context(self):
|
def get_context(self):
|
||||||
raise NotImplementedError(
|
raise NotImplementedError(
|
||||||
@ -49,12 +62,17 @@ class RenderableMixin:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def render(self, template_name=None, context=None, renderer=None):
|
def render(self, template_name=None, context=None, renderer=None):
|
||||||
return mark_safe(
|
renderer = renderer or self.renderer
|
||||||
(renderer or self.renderer).render(
|
template = template_name or self.template_name
|
||||||
template_name or self.template_name,
|
context = context or self.get_context()
|
||||||
context or self.get_context(),
|
if (
|
||||||
|
template == "django/forms/default.html"
|
||||||
|
or template == "django/forms/formsets/default.html"
|
||||||
|
):
|
||||||
|
warnings.warn(
|
||||||
|
DEFAULT_TEMPLATE_DEPRECATION_MSG, RemovedInDjango50Warning, stacklevel=2
|
||||||
)
|
)
|
||||||
)
|
return mark_safe(renderer.render(template, context))
|
||||||
|
|
||||||
__str__ = render
|
__str__ = render
|
||||||
__html__ = render
|
__html__ = render
|
||||||
|
@ -105,6 +105,9 @@ details on these changes.
|
|||||||
|
|
||||||
* The ``django.contrib.auth.hashers.CryptPasswordHasher`` will be removed.
|
* The ``django.contrib.auth.hashers.CryptPasswordHasher`` will be removed.
|
||||||
|
|
||||||
|
* The ``"django/forms/default.html"`` and
|
||||||
|
``"django/forms/formsets/default.html"`` templates will be removed.
|
||||||
|
|
||||||
* The ability to pass ``nulls_first=False`` or ``nulls_last=False`` to
|
* The ability to pass ``nulls_first=False`` or ``nulls_last=False`` to
|
||||||
``Expression.asc()`` and ``Expression.desc()`` methods, and the ``OrderBy``
|
``Expression.asc()`` and ``Expression.desc()`` methods, and the ``OrderBy``
|
||||||
expression will be removed.
|
expression will be removed.
|
||||||
|
@ -56,6 +56,12 @@ should return a rendered templates (as a string) or raise
|
|||||||
Defaults to ``"django/forms/default.html"``, which is a proxy for
|
Defaults to ``"django/forms/default.html"``, which is a proxy for
|
||||||
``"django/forms/table.html"``.
|
``"django/forms/table.html"``.
|
||||||
|
|
||||||
|
.. deprecated:: 4.1
|
||||||
|
|
||||||
|
The ``"django/forms/default.html"`` template is deprecated and will be
|
||||||
|
removed in Django 5.0. The default will become
|
||||||
|
``"django/forms/default.html"`` at that time.
|
||||||
|
|
||||||
.. attribute:: formset_template_name
|
.. attribute:: formset_template_name
|
||||||
|
|
||||||
.. versionadded:: 4.1
|
.. versionadded:: 4.1
|
||||||
@ -65,6 +71,12 @@ should return a rendered templates (as a string) or raise
|
|||||||
Defaults to ``"django/forms/formsets/default.html"``, which is a proxy
|
Defaults to ``"django/forms/formsets/default.html"``, which is a proxy
|
||||||
for ``"django/forms/formsets/table.html"``.
|
for ``"django/forms/formsets/table.html"``.
|
||||||
|
|
||||||
|
.. deprecated:: 4.1
|
||||||
|
|
||||||
|
The ``"django/forms/formset/default.html"`` template is deprecated and
|
||||||
|
will be removed in Django 5.0. The default will become
|
||||||
|
``"django/forms/formset/div.html"`` template.
|
||||||
|
|
||||||
.. method:: get_template(template_name)
|
.. method:: get_template(template_name)
|
||||||
|
|
||||||
Subclasses must implement this method with the appropriate template
|
Subclasses must implement this method with the appropriate template
|
||||||
@ -97,6 +109,26 @@ If you want to render templates with customizations from your
|
|||||||
:setting:`TEMPLATES` setting, such as context processors for example, use the
|
:setting:`TEMPLATES` setting, such as context processors for example, use the
|
||||||
:class:`TemplatesSetting` renderer.
|
:class:`TemplatesSetting` renderer.
|
||||||
|
|
||||||
|
.. class:: DjangoDivFormRenderer
|
||||||
|
|
||||||
|
.. versionadded:: 4.1
|
||||||
|
|
||||||
|
Subclass of :class:`DjangoTemplates` that specifies
|
||||||
|
:attr:`~BaseRenderer.form_template_name` and
|
||||||
|
:attr:`~BaseRenderer.formset_template_name` as ``"django/forms/div.html"`` and
|
||||||
|
``"django/forms/formset/div.html"`` respectively.
|
||||||
|
|
||||||
|
This is a transitional renderer for opt-in to the new ``<div>`` based
|
||||||
|
templates, which are the default from Django 5.0.
|
||||||
|
|
||||||
|
Apply this via the :setting:`FORM_RENDERER` setting::
|
||||||
|
|
||||||
|
FORM_RENDERER = "django.forms.renderers.DjangoDivFormRenderer"
|
||||||
|
|
||||||
|
Once the ``<div>`` templates are the default, this transitional renderer will
|
||||||
|
be deprecated, for removal in Django 6.0. The ``FORM_RENDERER`` declaration can
|
||||||
|
be removed at that time.
|
||||||
|
|
||||||
``Jinja2``
|
``Jinja2``
|
||||||
----------
|
----------
|
||||||
|
|
||||||
@ -113,6 +145,17 @@ templates for widgets that don't have any, you can't use this renderer. For
|
|||||||
example, :mod:`django.contrib.admin` doesn't include Jinja2 templates for its
|
example, :mod:`django.contrib.admin` doesn't include Jinja2 templates for its
|
||||||
widgets due to their usage of Django template tags.
|
widgets due to their usage of Django template tags.
|
||||||
|
|
||||||
|
.. class:: Jinja2DivFormRenderer
|
||||||
|
|
||||||
|
.. versionadded:: 4.1
|
||||||
|
|
||||||
|
A transitional renderer as per :class:`DjangoDivFormRenderer` above, but
|
||||||
|
subclassing :class:`Jinja2` for use with the Jinja2 backend.
|
||||||
|
|
||||||
|
Apply this via the :setting:`FORM_RENDERER` setting::
|
||||||
|
|
||||||
|
FORM_RENDERER = "django.forms.renderers.Jinja2DivFormRenderer"
|
||||||
|
|
||||||
``TemplatesSetting``
|
``TemplatesSetting``
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
|
@ -74,6 +74,24 @@ Validation of Constraints
|
|||||||
in the :attr:`Meta.constraints <django.db.models.Options.constraints>` option
|
in the :attr:`Meta.constraints <django.db.models.Options.constraints>` option
|
||||||
are now checked during :ref:`model validation <validating-objects>`.
|
are now checked during :ref:`model validation <validating-objects>`.
|
||||||
|
|
||||||
|
Form rendering accessibility
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
In order to aid users with screen readers, and other assistive technology, new
|
||||||
|
``<div>`` based form templates are available from this release. These provide
|
||||||
|
more accessible navigation than the older templates, and are able to correctly
|
||||||
|
group related controls, such as radio-lists, into fieldsets.
|
||||||
|
|
||||||
|
The new templates are recommended, and will become the default form rendering
|
||||||
|
style when outputting a form, like ``{{ form }}`` in a template, from Django
|
||||||
|
5.0.
|
||||||
|
|
||||||
|
In order to ease adopting the new output style, the default form and formset
|
||||||
|
templates are now configurable at the project level via the
|
||||||
|
:setting:`FORM_RENDERER` setting.
|
||||||
|
|
||||||
|
See :ref:`the Forms section (below)<forms-4.1>` for full details.
|
||||||
|
|
||||||
.. _csrf-cookie-masked-usage:
|
.. _csrf-cookie-masked-usage:
|
||||||
|
|
||||||
``CSRF_COOKIE_MASKED`` setting
|
``CSRF_COOKIE_MASKED`` setting
|
||||||
@ -253,6 +271,8 @@ File Uploads
|
|||||||
|
|
||||||
* ...
|
* ...
|
||||||
|
|
||||||
|
.. _forms-4.1:
|
||||||
|
|
||||||
Forms
|
Forms
|
||||||
~~~~~
|
~~~~~
|
||||||
|
|
||||||
@ -279,6 +299,34 @@ Forms
|
|||||||
as the template implements ``<fieldset>`` and ``<legend>`` to group related
|
as the template implements ``<fieldset>`` and ``<legend>`` to group related
|
||||||
inputs and is easier for screen reader users to navigate.
|
inputs and is easier for screen reader users to navigate.
|
||||||
|
|
||||||
|
The div-based output will become the default rendering style from Django 5.0.
|
||||||
|
|
||||||
|
* In order to smooth adoption of the new ``<div>`` output style, two
|
||||||
|
transitional form renderer classes are available:
|
||||||
|
:class:`django.forms.renderers.DjangoDivFormRenderer` and
|
||||||
|
:class:`django.forms.renderers.Jinja2DivFormRenderer`, for the Django and
|
||||||
|
Jinja2 template backends respectively.
|
||||||
|
|
||||||
|
You can apply one of these via the :setting:`FORM_RENDERER` setting. For
|
||||||
|
example::
|
||||||
|
|
||||||
|
FORM_RENDERER = "django.forms.renderers.DjangoDivFormRenderer"
|
||||||
|
|
||||||
|
Once the ``<div>`` output style is the default, from Django 5.0, these
|
||||||
|
transitional renderers will be deprecated, for removal in Django 6.0. The
|
||||||
|
``FORM_RENDERER`` declaration can be removed at that time.
|
||||||
|
|
||||||
|
* If the new ``<div>`` output style is not appropriate for your project, you should
|
||||||
|
define a renderer subclass specifying
|
||||||
|
:attr:`~django.forms.renderers.BaseRenderer.form_template_name` and
|
||||||
|
:attr:`~django.forms.renderers.BaseRenderer.formset_template_name` for your
|
||||||
|
required style, and set :setting:`FORM_RENDERER` accordingly.
|
||||||
|
|
||||||
|
For example, for the ``<p>`` output style used by :meth:`~.Form.as_p`, you
|
||||||
|
would define a form renderer setting ``form_template_name`` to
|
||||||
|
``"django/forms/p.html"`` and ``formset_template_name`` to
|
||||||
|
``"django/forms/formsets/p.html"``.
|
||||||
|
|
||||||
* The new :meth:`~django.forms.BoundField.legend_tag` allows rendering field
|
* The new :meth:`~django.forms.BoundField.legend_tag` allows rendering field
|
||||||
labels in ``<legend>`` tags via the new ``tag`` argument of
|
labels in ``<legend>`` tags via the new ``tag`` argument of
|
||||||
:meth:`~django.forms.BoundField.label_tag`.
|
:meth:`~django.forms.BoundField.label_tag`.
|
||||||
@ -718,6 +766,10 @@ Miscellaneous
|
|||||||
``Expression.asc()`` and ``Expression.desc()`` methods, and the ``OrderBy``
|
``Expression.asc()`` and ``Expression.desc()`` methods, and the ``OrderBy``
|
||||||
expression is deprecated. Use ``None`` instead.
|
expression is deprecated. Use ``None`` instead.
|
||||||
|
|
||||||
|
* The ``"django/forms/default.html"`` and
|
||||||
|
``"django/forms/formsets/default.html"`` templates which are a proxy to the
|
||||||
|
table-based templates are deprecated. Use the specific template instead.
|
||||||
|
|
||||||
Features removed in 4.1
|
Features removed in 4.1
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
|
@ -11,6 +11,8 @@ except ImportError:
|
|||||||
def jinja2_tests(test_func):
|
def jinja2_tests(test_func):
|
||||||
test_func = skipIf(jinja2 is None, "this test requires jinja2")(test_func)
|
test_func = skipIf(jinja2 is None, "this test requires jinja2")(test_func)
|
||||||
return override_settings(
|
return override_settings(
|
||||||
FORM_RENDERER="django.forms.renderers.Jinja2",
|
# RemovedInDjango50Warning: When the deprecation ends, revert to
|
||||||
|
# FORM_RENDERER="django.forms.renderers.Jinja2",
|
||||||
|
FORM_RENDERER="django.forms.renderers.Jinja2DivFormRenderer",
|
||||||
TEMPLATES={"BACKEND": "django.template.backends.jinja2.Jinja2"},
|
TEMPLATES={"BACKEND": "django.template.backends.jinja2.Jinja2"},
|
||||||
)(test_func)
|
)(test_func)
|
||||||
|
@ -42,8 +42,9 @@ from django.forms.utils import ErrorList
|
|||||||
from django.http import QueryDict
|
from django.http import QueryDict
|
||||||
from django.template import Context, Template
|
from django.template import Context, Template
|
||||||
from django.test import SimpleTestCase
|
from django.test import SimpleTestCase
|
||||||
from django.test.utils import override_settings
|
from django.test.utils import isolate_lru_cache, override_settings
|
||||||
from django.utils.datastructures import MultiValueDict
|
from django.utils.datastructures import MultiValueDict
|
||||||
|
from django.utils.deprecation import RemovedInDjango50Warning
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
|
|
||||||
from . import jinja2_tests
|
from . import jinja2_tests
|
||||||
@ -149,17 +150,12 @@ class FormsTestCase(SimpleTestCase):
|
|||||||
)
|
)
|
||||||
self.assertHTMLEqual(
|
self.assertHTMLEqual(
|
||||||
str(p),
|
str(p),
|
||||||
"""
|
'<div><label for="id_first_name">First name:</label><input type="text" '
|
||||||
<tr><th><label for="id_first_name">First name:</label></th><td>
|
'name="first_name" value="John" required id="id_first_name"></div><div>'
|
||||||
<input type="text" name="first_name" value="John" id="id_first_name"
|
'<label for="id_last_name">Last name:</label><input type="text" '
|
||||||
required></td></tr>
|
'name="last_name" value="Lennon" required id="id_last_name"></div><div>'
|
||||||
<tr><th><label for="id_last_name">Last name:</label></th><td>
|
'<label for="id_birthday">Birthday:</label><input type="text" '
|
||||||
<input type="text" name="last_name" value="Lennon" id="id_last_name"
|
'name="birthday" value="1940-10-9" required id="id_birthday"></div>',
|
||||||
required></td></tr>
|
|
||||||
<tr><th><label for="id_birthday">Birthday:</label></th><td>
|
|
||||||
<input type="text" name="birthday" value="1940-10-9" id="id_birthday"
|
|
||||||
required></td></tr>
|
|
||||||
""",
|
|
||||||
)
|
)
|
||||||
self.assertHTMLEqual(
|
self.assertHTMLEqual(
|
||||||
p.as_div(),
|
p.as_div(),
|
||||||
@ -182,15 +178,15 @@ class FormsTestCase(SimpleTestCase):
|
|||||||
self.assertEqual(p.cleaned_data, {})
|
self.assertEqual(p.cleaned_data, {})
|
||||||
self.assertHTMLEqual(
|
self.assertHTMLEqual(
|
||||||
str(p),
|
str(p),
|
||||||
"""<tr><th><label for="id_first_name">First name:</label></th><td>
|
'<div><label for="id_first_name">First name:</label>'
|
||||||
<ul class="errorlist"><li>This field is required.</li></ul>
|
'<ul class="errorlist"><li>This field is required.</li></ul>'
|
||||||
<input type="text" name="first_name" id="id_first_name" required></td></tr>
|
'<input type="text" name="first_name" required id="id_first_name"></div>'
|
||||||
<tr><th><label for="id_last_name">Last name:</label></th>
|
'<div><label for="id_last_name">Last name:</label>'
|
||||||
<td><ul class="errorlist"><li>This field is required.</li></ul>
|
'<ul class="errorlist"><li>This field is required.</li></ul>'
|
||||||
<input type="text" name="last_name" id="id_last_name" required></td></tr>
|
'<input type="text" name="last_name" required id="id_last_name"></div><div>'
|
||||||
<tr><th><label for="id_birthday">Birthday:</label></th><td>
|
'<label for="id_birthday">Birthday:</label>'
|
||||||
<ul class="errorlist"><li>This field is required.</li></ul>
|
'<ul class="errorlist"><li>This field is required.</li></ul>'
|
||||||
<input type="text" name="birthday" id="id_birthday" required></td></tr>""",
|
'<input type="text" name="birthday" required id="id_birthday"></div>',
|
||||||
)
|
)
|
||||||
self.assertHTMLEqual(
|
self.assertHTMLEqual(
|
||||||
p.as_table(),
|
p.as_table(),
|
||||||
@ -261,12 +257,12 @@ class FormsTestCase(SimpleTestCase):
|
|||||||
|
|
||||||
self.assertHTMLEqual(
|
self.assertHTMLEqual(
|
||||||
str(p),
|
str(p),
|
||||||
"""<tr><th><label for="id_first_name">First name:</label></th><td>
|
'<div><label for="id_first_name">First name:</label><input type="text" '
|
||||||
<input type="text" name="first_name" id="id_first_name" required></td></tr>
|
'name="first_name" id="id_first_name" required></div><div><label '
|
||||||
<tr><th><label for="id_last_name">Last name:</label></th><td>
|
'for="id_last_name">Last name:</label><input type="text" name="last_name" '
|
||||||
<input type="text" name="last_name" id="id_last_name" required></td></tr>
|
'id="id_last_name" required></div><div><label for="id_birthday">'
|
||||||
<tr><th><label for="id_birthday">Birthday:</label></th><td>
|
'Birthday:</label><input type="text" name="birthday" id="id_birthday" '
|
||||||
<input type="text" name="birthday" id="id_birthday" required></td></tr>""",
|
"required></div>",
|
||||||
)
|
)
|
||||||
self.assertHTMLEqual(
|
self.assertHTMLEqual(
|
||||||
p.as_table(),
|
p.as_table(),
|
||||||
@ -4932,9 +4928,7 @@ class TemplateTests(SimpleTestCase):
|
|||||||
|
|
||||||
t = Template(
|
t = Template(
|
||||||
'<form method="post">'
|
'<form method="post">'
|
||||||
"<table>"
|
|
||||||
"{{ form }}"
|
"{{ form }}"
|
||||||
"</table>"
|
|
||||||
'<input type="submit" required>'
|
'<input type="submit" required>'
|
||||||
"</form>"
|
"</form>"
|
||||||
)
|
)
|
||||||
@ -4944,14 +4938,12 @@ class TemplateTests(SimpleTestCase):
|
|||||||
self.assertHTMLEqual(
|
self.assertHTMLEqual(
|
||||||
my_function("GET", {}),
|
my_function("GET", {}),
|
||||||
'<form method="post">'
|
'<form method="post">'
|
||||||
"<table>"
|
"<div>Username:"
|
||||||
"<tr><th>Username:</th><td>"
|
'<input type="text" name="username" maxlength="10" required></div>'
|
||||||
'<input type="text" name="username" maxlength="10" required></td></tr>'
|
"<div>Password1:"
|
||||||
"<tr><th>Password1:</th><td>"
|
'<input type="password" name="password1" required></div>'
|
||||||
'<input type="password" name="password1" required></td></tr>'
|
"<div>Password2:"
|
||||||
"<tr><th>Password2:</th><td>"
|
'<input type="password" name="password2" required></div>'
|
||||||
'<input type="password" name="password2" required></td></tr>'
|
|
||||||
"</table>"
|
|
||||||
'<input type="submit" required>'
|
'<input type="submit" required>'
|
||||||
"</form>",
|
"</form>",
|
||||||
)
|
)
|
||||||
@ -4966,18 +4958,16 @@ class TemplateTests(SimpleTestCase):
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
'<form method="post">'
|
'<form method="post">'
|
||||||
"<table>"
|
'<ul class="errorlist nonfield">'
|
||||||
'<tr><td colspan="2"><ul class="errorlist nonfield">'
|
"<li>Please make sure your passwords match.</li></ul>"
|
||||||
"<li>Please make sure your passwords match.</li></ul></td></tr>"
|
'<div>Username:<ul class="errorlist">'
|
||||||
'<tr><th>Username:</th><td><ul class="errorlist">'
|
|
||||||
"<li>Ensure this value has at most 10 characters (it has 23).</li></ul>"
|
"<li>Ensure this value has at most 10 characters (it has 23).</li></ul>"
|
||||||
'<input type="text" name="username" '
|
'<input type="text" name="username" '
|
||||||
'value="this-is-a-long-username" maxlength="10" required></td></tr>'
|
'value="this-is-a-long-username" maxlength="10" required></div>'
|
||||||
"<tr><th>Password1:</th><td>"
|
"<div>Password1:"
|
||||||
'<input type="password" name="password1" required></td></tr>'
|
'<input type="password" name="password1" required></div>'
|
||||||
"<tr><th>Password2:</th><td>"
|
"<div>Password2:"
|
||||||
'<input type="password" name="password2" required></td></tr>'
|
'<input type="password" name="password2" required></div>'
|
||||||
"</table>"
|
|
||||||
'<input type="submit" required>'
|
'<input type="submit" required>'
|
||||||
"</form>",
|
"</form>",
|
||||||
)
|
)
|
||||||
@ -5054,7 +5044,7 @@ class OverrideTests(SimpleTestCase):
|
|||||||
|
|
||||||
f = FirstNameForm()
|
f = FirstNameForm()
|
||||||
try:
|
try:
|
||||||
self.assertInHTML("<th>1</th>", f.render())
|
f.render()
|
||||||
except RecursionError:
|
except RecursionError:
|
||||||
self.fail("Cyclic reference in BoundField.render().")
|
self.fail("Cyclic reference in BoundField.render().")
|
||||||
|
|
||||||
@ -5069,3 +5059,16 @@ class OverrideTests(SimpleTestCase):
|
|||||||
'<label for="id_name" class="required">Name:</label>'
|
'<label for="id_name" class="required">Name:</label>'
|
||||||
'<legend class="required">Language:</legend>',
|
'<legend class="required">Language:</legend>',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class DeprecationTests(SimpleTestCase):
|
||||||
|
def test_warning(self):
|
||||||
|
from django.forms.utils import DEFAULT_TEMPLATE_DEPRECATION_MSG
|
||||||
|
|
||||||
|
with isolate_lru_cache(get_default_renderer), self.settings(
|
||||||
|
FORM_RENDERER="django.forms.renderers.DjangoTemplates"
|
||||||
|
), self.assertRaisesMessage(
|
||||||
|
RemovedInDjango50Warning, DEFAULT_TEMPLATE_DEPRECATION_MSG
|
||||||
|
):
|
||||||
|
form = Person()
|
||||||
|
str(form)
|
||||||
|
@ -23,10 +23,12 @@ from django.forms.formsets import (
|
|||||||
all_valid,
|
all_valid,
|
||||||
formset_factory,
|
formset_factory,
|
||||||
)
|
)
|
||||||
from django.forms.renderers import TemplatesSetting
|
from django.forms.renderers import TemplatesSetting, get_default_renderer
|
||||||
from django.forms.utils import ErrorList
|
from django.forms.utils import ErrorList
|
||||||
from django.forms.widgets import HiddenInput
|
from django.forms.widgets import HiddenInput
|
||||||
from django.test import SimpleTestCase
|
from django.test import SimpleTestCase
|
||||||
|
from django.test.utils import isolate_lru_cache
|
||||||
|
from django.utils.deprecation import RemovedInDjango50Warning
|
||||||
|
|
||||||
from . import jinja2_tests
|
from . import jinja2_tests
|
||||||
|
|
||||||
@ -125,8 +127,8 @@ class FormsFormsetTestCase(SimpleTestCase):
|
|||||||
<input type="hidden" name="choices-INITIAL_FORMS" value="0">
|
<input type="hidden" name="choices-INITIAL_FORMS" value="0">
|
||||||
<input type="hidden" name="choices-MIN_NUM_FORMS" value="0">
|
<input type="hidden" name="choices-MIN_NUM_FORMS" value="0">
|
||||||
<input type="hidden" name="choices-MAX_NUM_FORMS" value="1000">
|
<input type="hidden" name="choices-MAX_NUM_FORMS" value="1000">
|
||||||
<tr><th>Choice:</th><td><input type="text" name="choices-0-choice"></td></tr>
|
<div>Choice:<input type="text" name="choices-0-choice"></div>
|
||||||
<tr><th>Votes:</th><td><input type="number" name="choices-0-votes"></td></tr>""",
|
<div>Votes:<input type="number" name="choices-0-votes"></div>""",
|
||||||
)
|
)
|
||||||
# FormSet are treated similarly to Forms. FormSet has an is_valid()
|
# FormSet are treated similarly to Forms. FormSet has an is_valid()
|
||||||
# method, and a cleaned_data or errors attribute depending on whether
|
# method, and a cleaned_data or errors attribute depending on whether
|
||||||
@ -976,12 +978,12 @@ class FormsFormsetTestCase(SimpleTestCase):
|
|||||||
formset = LimitedFavoriteDrinkFormSet()
|
formset = LimitedFavoriteDrinkFormSet()
|
||||||
self.assertHTMLEqual(
|
self.assertHTMLEqual(
|
||||||
"\n".join(str(form) for form in formset.forms),
|
"\n".join(str(form) for form in formset.forms),
|
||||||
"""<tr><th><label for="id_form-0-name">Name:</label></th>
|
"""<div><label for="id_form-0-name">Name:</label>
|
||||||
<td><input type="text" name="form-0-name" id="id_form-0-name"></td></tr>
|
<input type="text" name="form-0-name" id="id_form-0-name"></div>
|
||||||
<tr><th><label for="id_form-1-name">Name:</label></th>
|
<div><label for="id_form-1-name">Name:</label>
|
||||||
<td><input type="text" name="form-1-name" id="id_form-1-name"></td></tr>
|
<input type="text" name="form-1-name" id="id_form-1-name"></div>
|
||||||
<tr><th><label for="id_form-2-name">Name:</label></th>
|
<div><label for="id_form-2-name">Name:</label>
|
||||||
<td><input type="text" name="form-2-name" id="id_form-2-name"></td></tr>""",
|
<input type="text" name="form-2-name" id="id_form-2-name"></div>""",
|
||||||
)
|
)
|
||||||
# If max_num is 0 then no form is rendered at all.
|
# If max_num is 0 then no form is rendered at all.
|
||||||
LimitedFavoriteDrinkFormSet = formset_factory(
|
LimitedFavoriteDrinkFormSet = formset_factory(
|
||||||
@ -997,10 +999,10 @@ class FormsFormsetTestCase(SimpleTestCase):
|
|||||||
formset = LimitedFavoriteDrinkFormSet()
|
formset = LimitedFavoriteDrinkFormSet()
|
||||||
self.assertHTMLEqual(
|
self.assertHTMLEqual(
|
||||||
"\n".join(str(form) for form in formset.forms),
|
"\n".join(str(form) for form in formset.forms),
|
||||||
"""<tr><th><label for="id_form-0-name">Name:</label></th><td>
|
"""<div><label for="id_form-0-name">Name:</label>
|
||||||
<input type="text" name="form-0-name" id="id_form-0-name"></td></tr>
|
<input type="text" name="form-0-name" id="id_form-0-name"></div>
|
||||||
<tr><th><label for="id_form-1-name">Name:</label></th>
|
<div><label for="id_form-1-name">Name:</label>
|
||||||
<td><input type="text" name="form-1-name" id="id_form-1-name"></td></tr>""",
|
<input type="text" name="form-1-name" id="id_form-1-name"></div>""",
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_limiting_extra_lest_than_max_num(self):
|
def test_limiting_extra_lest_than_max_num(self):
|
||||||
@ -1011,8 +1013,8 @@ class FormsFormsetTestCase(SimpleTestCase):
|
|||||||
formset = LimitedFavoriteDrinkFormSet()
|
formset = LimitedFavoriteDrinkFormSet()
|
||||||
self.assertHTMLEqual(
|
self.assertHTMLEqual(
|
||||||
"\n".join(str(form) for form in formset.forms),
|
"\n".join(str(form) for form in formset.forms),
|
||||||
"""<tr><th><label for="id_form-0-name">Name:</label></th>
|
"""<div><label for="id_form-0-name">Name:</label>
|
||||||
<td><input type="text" name="form-0-name" id="id_form-0-name"></td></tr>""",
|
<input type="text" name="form-0-name" id="id_form-0-name"></div>""",
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_max_num_with_initial_data(self):
|
def test_max_num_with_initial_data(self):
|
||||||
@ -1024,11 +1026,11 @@ class FormsFormsetTestCase(SimpleTestCase):
|
|||||||
self.assertHTMLEqual(
|
self.assertHTMLEqual(
|
||||||
"\n".join(str(form) for form in formset.forms),
|
"\n".join(str(form) for form in formset.forms),
|
||||||
"""
|
"""
|
||||||
<tr><th><label for="id_form-0-name">Name:</label></th>
|
<div><label for="id_form-0-name">Name:</label>
|
||||||
<td><input type="text" name="form-0-name" value="Fernet and Coke"
|
<input type="text" name="form-0-name" value="Fernet and Coke"
|
||||||
id="id_form-0-name"></td></tr>
|
id="id_form-0-name"></div>
|
||||||
<tr><th><label for="id_form-1-name">Name:</label></th>
|
<div><label for="id_form-1-name">Name:</label>
|
||||||
<td><input type="text" name="form-1-name" id="id_form-1-name"></td></tr>
|
<input type="text" name="form-1-name" id="id_form-1-name"></div>
|
||||||
""",
|
""",
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1056,12 +1058,12 @@ class FormsFormsetTestCase(SimpleTestCase):
|
|||||||
self.assertHTMLEqual(
|
self.assertHTMLEqual(
|
||||||
"\n".join(str(form) for form in formset.forms),
|
"\n".join(str(form) for form in formset.forms),
|
||||||
"""
|
"""
|
||||||
<tr><th><label for="id_form-0-name">Name:</label></th>
|
<div><label for="id_form-0-name">Name:</label>
|
||||||
<td><input id="id_form-0-name" name="form-0-name" type="text"
|
<input id="id_form-0-name" name="form-0-name" type="text"
|
||||||
value="Fernet and Coke"></td></tr>
|
value="Fernet and Coke"></div>
|
||||||
<tr><th><label for="id_form-1-name">Name:</label></th>
|
<div><label for="id_form-1-name">Name:</label>
|
||||||
<td><input id="id_form-1-name" name="form-1-name" type="text"
|
<input id="id_form-1-name" name="form-1-name" type="text"
|
||||||
value="Bloody Mary"></td></tr>
|
value="Bloody Mary"></div>
|
||||||
""",
|
""",
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1082,18 +1084,15 @@ class FormsFormsetTestCase(SimpleTestCase):
|
|||||||
self.assertHTMLEqual(
|
self.assertHTMLEqual(
|
||||||
"\n".join(str(form) for form in formset.forms),
|
"\n".join(str(form) for form in formset.forms),
|
||||||
"""
|
"""
|
||||||
<tr><th><label for="id_form-0-name">Name:</label></th>
|
<div><label for="id_form-0-name">Name:</label>
|
||||||
<td>
|
|
||||||
<input id="id_form-0-name" name="form-0-name" type="text" value="Gin Tonic">
|
<input id="id_form-0-name" name="form-0-name" type="text" value="Gin Tonic">
|
||||||
</td></tr>
|
</div>
|
||||||
<tr><th><label for="id_form-1-name">Name:</label></th>
|
<div><label for="id_form-1-name">Name:</label>
|
||||||
<td>
|
|
||||||
<input id="id_form-1-name" name="form-1-name" type="text"
|
<input id="id_form-1-name" name="form-1-name" type="text"
|
||||||
value="Bloody Mary"></td></tr>
|
value="Bloody Mary"></div>
|
||||||
<tr><th><label for="id_form-2-name">Name:</label></th>
|
<div><label for="id_form-2-name">Name:</label>
|
||||||
<td>
|
|
||||||
<input id="id_form-2-name" name="form-2-name" type="text"
|
<input id="id_form-2-name" name="form-2-name" type="text"
|
||||||
value="Jack and Coke"></td></tr>
|
value="Jack and Coke"></div>
|
||||||
""",
|
""",
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1173,12 +1172,11 @@ class FormsFormsetTestCase(SimpleTestCase):
|
|||||||
self.assertHTMLEqual(
|
self.assertHTMLEqual(
|
||||||
"\n".join(str(form) for form in formset.forms),
|
"\n".join(str(form) for form in formset.forms),
|
||||||
"""
|
"""
|
||||||
<tr><th><label for="id_form-0-name">Name:</label></th>
|
<div><label for="id_form-0-name">Name:</label>
|
||||||
<td>
|
|
||||||
<input type="text" name="form-0-name" value="Gin Tonic" id="id_form-0-name">
|
<input type="text" name="form-0-name" value="Gin Tonic" id="id_form-0-name">
|
||||||
</td></tr>
|
</div>
|
||||||
<tr><th><label for="id_form-1-name">Name:</label></th>
|
<div><label for="id_form-1-name">Name:</label>
|
||||||
<td><input type="text" name="form-1-name" id="id_form-1-name"></td></tr>""",
|
<input type="text" name="form-1-name" id="id_form-1-name"></div>""",
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_management_form_field_names(self):
|
def test_management_form_field_names(self):
|
||||||
@ -1701,16 +1699,16 @@ class TestIsBoundBehavior(SimpleTestCase):
|
|||||||
# Can still render the formset.
|
# Can still render the formset.
|
||||||
self.assertHTMLEqual(
|
self.assertHTMLEqual(
|
||||||
str(formset),
|
str(formset),
|
||||||
'<tr><td colspan="2">'
|
|
||||||
'<ul class="errorlist nonfield">'
|
'<ul class="errorlist nonfield">'
|
||||||
"<li>(Hidden field TOTAL_FORMS) This field is required.</li>"
|
"<li>(Hidden field TOTAL_FORMS) This field is required.</li>"
|
||||||
"<li>(Hidden field INITIAL_FORMS) This field is required.</li>"
|
"<li>(Hidden field INITIAL_FORMS) This field is required.</li>"
|
||||||
"</ul>"
|
"</ul>"
|
||||||
|
"<div>"
|
||||||
'<input type="hidden" name="form-TOTAL_FORMS" id="id_form-TOTAL_FORMS">'
|
'<input type="hidden" name="form-TOTAL_FORMS" id="id_form-TOTAL_FORMS">'
|
||||||
'<input type="hidden" name="form-INITIAL_FORMS" id="id_form-INITIAL_FORMS">'
|
'<input type="hidden" name="form-INITIAL_FORMS" id="id_form-INITIAL_FORMS">'
|
||||||
'<input type="hidden" name="form-MIN_NUM_FORMS" id="id_form-MIN_NUM_FORMS">'
|
'<input type="hidden" name="form-MIN_NUM_FORMS" id="id_form-MIN_NUM_FORMS">'
|
||||||
'<input type="hidden" name="form-MAX_NUM_FORMS" id="id_form-MAX_NUM_FORMS">'
|
'<input type="hidden" name="form-MAX_NUM_FORMS" id="id_form-MAX_NUM_FORMS">'
|
||||||
"</td></tr>\n",
|
"</div>\n",
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_management_form_invalid_data(self):
|
def test_management_form_invalid_data(self):
|
||||||
@ -1732,18 +1730,18 @@ class TestIsBoundBehavior(SimpleTestCase):
|
|||||||
# Can still render the formset.
|
# Can still render the formset.
|
||||||
self.assertHTMLEqual(
|
self.assertHTMLEqual(
|
||||||
str(formset),
|
str(formset),
|
||||||
'<tr><td colspan="2">'
|
|
||||||
'<ul class="errorlist nonfield">'
|
'<ul class="errorlist nonfield">'
|
||||||
"<li>(Hidden field TOTAL_FORMS) Enter a whole number.</li>"
|
"<li>(Hidden field TOTAL_FORMS) Enter a whole number.</li>"
|
||||||
"<li>(Hidden field INITIAL_FORMS) Enter a whole number.</li>"
|
"<li>(Hidden field INITIAL_FORMS) Enter a whole number.</li>"
|
||||||
"</ul>"
|
"</ul>"
|
||||||
|
"<div>"
|
||||||
'<input type="hidden" name="form-TOTAL_FORMS" value="two" '
|
'<input type="hidden" name="form-TOTAL_FORMS" value="two" '
|
||||||
'id="id_form-TOTAL_FORMS">'
|
'id="id_form-TOTAL_FORMS">'
|
||||||
'<input type="hidden" name="form-INITIAL_FORMS" value="one" '
|
'<input type="hidden" name="form-INITIAL_FORMS" value="one" '
|
||||||
'id="id_form-INITIAL_FORMS">'
|
'id="id_form-INITIAL_FORMS">'
|
||||||
'<input type="hidden" name="form-MIN_NUM_FORMS" id="id_form-MIN_NUM_FORMS">'
|
'<input type="hidden" name="form-MIN_NUM_FORMS" id="id_form-MIN_NUM_FORMS">'
|
||||||
'<input type="hidden" name="form-MAX_NUM_FORMS" id="id_form-MAX_NUM_FORMS">'
|
'<input type="hidden" name="form-MAX_NUM_FORMS" id="id_form-MAX_NUM_FORMS">'
|
||||||
"</td></tr>\n",
|
"</div>\n",
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_customize_management_form_error(self):
|
def test_customize_management_form_error(self):
|
||||||
@ -1889,3 +1887,17 @@ class AllValidTests(SimpleTestCase):
|
|||||||
]
|
]
|
||||||
self.assertEqual(formset1._errors, expected_errors)
|
self.assertEqual(formset1._errors, expected_errors)
|
||||||
self.assertEqual(formset2._errors, expected_errors)
|
self.assertEqual(formset2._errors, expected_errors)
|
||||||
|
|
||||||
|
|
||||||
|
class DeprecationTests(SimpleTestCase):
|
||||||
|
def test_warning(self):
|
||||||
|
from django.forms.utils import DEFAULT_TEMPLATE_DEPRECATION_MSG
|
||||||
|
|
||||||
|
with isolate_lru_cache(get_default_renderer), self.settings(
|
||||||
|
FORM_RENDERER="django.forms.renderers.DjangoTemplates"
|
||||||
|
), self.assertRaisesMessage(
|
||||||
|
RemovedInDjango50Warning, DEFAULT_TEMPLATE_DEPRECATION_MSG
|
||||||
|
):
|
||||||
|
ChoiceFormSet = formset_factory(Choice)
|
||||||
|
formset = ChoiceFormSet()
|
||||||
|
str(formset)
|
||||||
|
@ -687,12 +687,12 @@ class ModelFormBaseTest(TestCase):
|
|||||||
|
|
||||||
self.assertHTMLEqual(
|
self.assertHTMLEqual(
|
||||||
str(SubclassMeta()),
|
str(SubclassMeta()),
|
||||||
"""<tr><th><label for="id_name">Name:</label></th>
|
'<div><label for="id_name">Name:</label>'
|
||||||
<td><input id="id_name" type="text" name="name" maxlength="20" required></td></tr>
|
'<input type="text" name="name" maxlength="20" required id="id_name">'
|
||||||
<tr><th><label for="id_slug">Slug:</label></th>
|
'</div><div><label for="id_slug">Slug:</label><input type="text" '
|
||||||
<td><input id="id_slug" type="text" name="slug" maxlength="20" required></td></tr>
|
'name="slug" maxlength="20" required id="id_slug"></div><div>'
|
||||||
<tr><th><label for="id_checkbox">Checkbox:</label></th>
|
'<label for="id_checkbox">Checkbox:</label>'
|
||||||
<td><input type="checkbox" name="checkbox" id="id_checkbox" required></td></tr>""",
|
'<input type="checkbox" name="checkbox" required id="id_checkbox"></div>',
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_orderfields_form(self):
|
def test_orderfields_form(self):
|
||||||
@ -704,10 +704,10 @@ class ModelFormBaseTest(TestCase):
|
|||||||
self.assertEqual(list(OrderFields.base_fields), ["url", "name"])
|
self.assertEqual(list(OrderFields.base_fields), ["url", "name"])
|
||||||
self.assertHTMLEqual(
|
self.assertHTMLEqual(
|
||||||
str(OrderFields()),
|
str(OrderFields()),
|
||||||
"""<tr><th><label for="id_url">The URL:</label></th>
|
'<div><label for="id_url">The URL:</label>'
|
||||||
<td><input id="id_url" type="text" name="url" maxlength="40" required></td></tr>
|
'<input type="text" name="url" maxlength="40" required id="id_url">'
|
||||||
<tr><th><label for="id_name">Name:</label></th>
|
'</div><div><label for="id_name">Name:</label><input type="text" '
|
||||||
<td><input id="id_name" type="text" name="name" maxlength="20" required></td></tr>""",
|
'name="name" maxlength="20" required id="id_name"></div>',
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_orderfields2_form(self):
|
def test_orderfields2_form(self):
|
||||||
@ -1460,12 +1460,11 @@ class ModelFormBasicTests(TestCase):
|
|||||||
f = BaseCategoryForm()
|
f = BaseCategoryForm()
|
||||||
self.assertHTMLEqual(
|
self.assertHTMLEqual(
|
||||||
str(f),
|
str(f),
|
||||||
"""<tr><th><label for="id_name">Name:</label></th>
|
'<div><label for="id_name">Name:</label><input type="text" name="name" '
|
||||||
<td><input id="id_name" type="text" name="name" maxlength="20" required></td></tr>
|
'maxlength="20" required id="id_name"></div><div><label for="id_slug">Slug:'
|
||||||
<tr><th><label for="id_slug">Slug:</label></th>
|
'</label><input type="text" name="slug" maxlength="20" required '
|
||||||
<td><input id="id_slug" type="text" name="slug" maxlength="20" required></td></tr>
|
'id="id_slug"></div><div><label for="id_url">The URL:</label>'
|
||||||
<tr><th><label for="id_url">The URL:</label></th>
|
'<input type="text" name="url" maxlength="40" required id="id_url"></div>',
|
||||||
<td><input id="id_url" type="text" name="url" maxlength="40" required></td></tr>""",
|
|
||||||
)
|
)
|
||||||
self.assertHTMLEqual(
|
self.assertHTMLEqual(
|
||||||
str(f.as_ul()),
|
str(f.as_ul()),
|
||||||
@ -1538,12 +1537,9 @@ class ModelFormBasicTests(TestCase):
|
|||||||
f = RoykoForm(auto_id=False, instance=self.w_royko)
|
f = RoykoForm(auto_id=False, instance=self.w_royko)
|
||||||
self.assertHTMLEqual(
|
self.assertHTMLEqual(
|
||||||
str(f),
|
str(f),
|
||||||
"""
|
'<div>Name:<div class="helptext">Use both first and last names.</div>'
|
||||||
<tr><th>Name:</th><td>
|
'<input type="text" name="name" value="Mike Royko" maxlength="50" '
|
||||||
<input type="text" name="name" value="Mike Royko" maxlength="50" required>
|
"required></div>",
|
||||||
<br>
|
|
||||||
<span class="helptext">Use both first and last names.</span></td></tr>
|
|
||||||
""",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
art = Article.objects.create(
|
art = Article.objects.create(
|
||||||
@ -1703,30 +1699,39 @@ class ModelFormBasicTests(TestCase):
|
|||||||
self.assertHTMLEqual(
|
self.assertHTMLEqual(
|
||||||
str(f),
|
str(f),
|
||||||
"""
|
"""
|
||||||
<tr><th>Headline:</th><td>
|
<div>Headline:
|
||||||
<input type="text" name="headline" maxlength="50" required></td></tr>
|
<input type="text" name="headline" maxlength="50" required>
|
||||||
<tr><th>Slug:</th><td>
|
</div>
|
||||||
<input type="text" name="slug" maxlength="50" required></td></tr>
|
<div>Slug:
|
||||||
<tr><th>Pub date:</th><td>
|
<input type="text" name="slug" maxlength="50" required>
|
||||||
<input type="text" name="pub_date" required></td></tr>
|
</div>
|
||||||
<tr><th>Writer:</th><td><select name="writer" required>
|
<div>Pub date:
|
||||||
<option value="" selected>---------</option>
|
<input type="text" name="pub_date" required>
|
||||||
<option value="%s">Bob Woodward</option>
|
</div>
|
||||||
<option value="%s">Mike Royko</option>
|
<div>Writer:
|
||||||
</select></td></tr>
|
<select name="writer" required>
|
||||||
<tr><th>Article:</th><td>
|
<option value="" selected>---------</option>
|
||||||
<textarea rows="10" cols="40" name="article" required></textarea></td></tr>
|
<option value="%s">Bob Woodward</option>
|
||||||
<tr><th>Categories:</th><td><select multiple name="categories">
|
<option value="%s">Mike Royko</option>
|
||||||
<option value="%s">Entertainment</option>
|
</select>
|
||||||
<option value="%s">It's a test</option>
|
</div>
|
||||||
<option value="%s">Third test</option>
|
<div>Article:
|
||||||
</select></td></tr>
|
<textarea name="article" cols="40" rows="10" required></textarea>
|
||||||
<tr><th>Status:</th><td><select name="status">
|
</div>
|
||||||
<option value="" selected>---------</option>
|
<div>Categories:
|
||||||
<option value="1">Draft</option>
|
<select name="categories" multiple>
|
||||||
<option value="2">Pending</option>
|
<option value="%s">Entertainment</option>
|
||||||
<option value="3">Live</option>
|
<option value="%s">It's a test</option>
|
||||||
</select></td></tr>
|
<option value="%s">Third test</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>Status:
|
||||||
|
<select name="status">
|
||||||
|
<option value="" selected>---------</option>
|
||||||
|
<option value="1">Draft</option><option value="2">Pending</option>
|
||||||
|
<option value="3">Live</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
"""
|
"""
|
||||||
% (self.w_woodward.pk, self.w_royko.pk, self.c1.pk, self.c2.pk, self.c3.pk),
|
% (self.w_woodward.pk, self.w_royko.pk, self.c1.pk, self.c2.pk, self.c3.pk),
|
||||||
)
|
)
|
||||||
@ -1791,12 +1796,8 @@ class ModelFormBasicTests(TestCase):
|
|||||||
f = PartialArticleForm(auto_id=False)
|
f = PartialArticleForm(auto_id=False)
|
||||||
self.assertHTMLEqual(
|
self.assertHTMLEqual(
|
||||||
str(f),
|
str(f),
|
||||||
"""
|
'<div>Headline:<input type="text" name="headline" maxlength="50" required>'
|
||||||
<tr><th>Headline:</th><td>
|
'</div><div>Pub date:<input type="text" name="pub_date" required></div>',
|
||||||
<input type="text" name="headline" maxlength="50" required></td></tr>
|
|
||||||
<tr><th>Pub date:</th><td>
|
|
||||||
<input type="text" name="pub_date" required></td></tr>
|
|
||||||
""",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
class PartialArticleFormWithSlug(forms.ModelForm):
|
class PartialArticleFormWithSlug(forms.ModelForm):
|
||||||
@ -2990,10 +2991,10 @@ class OtherModelFormTests(TestCase):
|
|||||||
|
|
||||||
self.assertHTMLEqual(
|
self.assertHTMLEqual(
|
||||||
str(CategoryForm()),
|
str(CategoryForm()),
|
||||||
"""<tr><th><label for="id_description">Description:</label></th>
|
'<div><label for="id_description">Description:</label><input type="text" '
|
||||||
<td><input type="text" name="description" id="id_description" required></td></tr>
|
'name="description" required id="id_description"></div><div>'
|
||||||
<tr><th><label for="id_url">The URL:</label></th>
|
'<label for="id_url">The URL:</label><input type="text" name="url" '
|
||||||
<td><input id="id_url" type="text" name="url" maxlength="40" required></td></tr>""",
|
'maxlength="40" required id="id_url"></div>',
|
||||||
)
|
)
|
||||||
# to_field_name should also work on ModelMultipleChoiceField ##################
|
# to_field_name should also work on ModelMultipleChoiceField ##################
|
||||||
|
|
||||||
@ -3014,8 +3015,8 @@ class OtherModelFormTests(TestCase):
|
|||||||
self.assertEqual(list(CustomFieldForExclusionForm.base_fields), ["name"])
|
self.assertEqual(list(CustomFieldForExclusionForm.base_fields), ["name"])
|
||||||
self.assertHTMLEqual(
|
self.assertHTMLEqual(
|
||||||
str(CustomFieldForExclusionForm()),
|
str(CustomFieldForExclusionForm()),
|
||||||
"""<tr><th><label for="id_name">Name:</label></th>
|
'<div><label for="id_name">Name:</label><input type="text" '
|
||||||
<td><input id="id_name" type="text" name="name" maxlength="10" required></td></tr>""",
|
'name="name" maxlength="10" required id="id_name"></div>',
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_iterable_model_m2m(self):
|
def test_iterable_model_m2m(self):
|
||||||
|
@ -1196,14 +1196,12 @@ class TestSplitFormField(PostgreSQLSimpleTestCase):
|
|||||||
self.assertHTMLEqual(
|
self.assertHTMLEqual(
|
||||||
str(SplitForm()),
|
str(SplitForm()),
|
||||||
"""
|
"""
|
||||||
<tr>
|
<div>
|
||||||
<th><label for="id_array_0">Array:</label></th>
|
<label for="id_array_0">Array:</label>
|
||||||
<td>
|
<input id="id_array_0" name="array_0" type="text" required>
|
||||||
<input id="id_array_0" name="array_0" type="text" required>
|
<input id="id_array_1" name="array_1" type="text" required>
|
||||||
<input id="id_array_1" name="array_1" type="text" required>
|
<input id="id_array_2" name="array_2" type="text" required>
|
||||||
<input id="id_array_2" name="array_2" type="text" required>
|
</div>
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
""",
|
""",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -687,17 +687,15 @@ class TestFormField(PostgreSQLSimpleTestCase):
|
|||||||
self.assertHTMLEqual(
|
self.assertHTMLEqual(
|
||||||
str(form),
|
str(form),
|
||||||
"""
|
"""
|
||||||
<tr>
|
<div>
|
||||||
<th>
|
<fieldset>
|
||||||
<label>Field:</label>
|
<legend>Field:</legend>
|
||||||
</th>
|
|
||||||
<td>
|
|
||||||
<input id="id_field_0_0" name="field_0_0" type="text">
|
<input id="id_field_0_0" name="field_0_0" type="text">
|
||||||
<input id="id_field_0_1" name="field_0_1" type="text">
|
<input id="id_field_0_1" name="field_0_1" type="text">
|
||||||
<input id="id_field_1_0" name="field_1_0" type="text">
|
<input id="id_field_1_0" name="field_1_0" type="text">
|
||||||
<input id="id_field_1_1" name="field_1_1" type="text">
|
<input id="id_field_1_1" name="field_1_1" type="text">
|
||||||
</td>
|
</fieldset>
|
||||||
</tr>
|
</div>
|
||||||
""",
|
""",
|
||||||
)
|
)
|
||||||
form = SplitForm(
|
form = SplitForm(
|
||||||
@ -788,13 +786,13 @@ class TestFormField(PostgreSQLSimpleTestCase):
|
|||||||
self.assertHTMLEqual(
|
self.assertHTMLEqual(
|
||||||
str(RangeForm()),
|
str(RangeForm()),
|
||||||
"""
|
"""
|
||||||
<tr>
|
<div>
|
||||||
<th><label>Ints:</label></th>
|
<fieldset>
|
||||||
<td>
|
<legend>Ints:</legend>
|
||||||
<input id="id_ints_0" name="ints_0" type="number">
|
<input id="id_ints_0" name="ints_0" type="number">
|
||||||
<input id="id_ints_1" name="ints_1" type="number">
|
<input id="id_ints_1" name="ints_1" type="number">
|
||||||
</td>
|
</fieldset>
|
||||||
</tr>
|
</div>
|
||||||
""",
|
""",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -243,6 +243,9 @@ def setup_collect_tests(start_at, start_after, test_labels=None):
|
|||||||
"fields.W342", # ForeignKey(unique=True) -> OneToOneField
|
"fields.W342", # ForeignKey(unique=True) -> OneToOneField
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# RemovedInDjango50Warning
|
||||||
|
settings.FORM_RENDERER = "django.forms.renderers.DjangoDivFormRenderer"
|
||||||
|
|
||||||
# Load all the ALWAYS_INSTALLED_APPS.
|
# Load all the ALWAYS_INSTALLED_APPS.
|
||||||
django.setup()
|
django.setup()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user