[2.0.x] Fixed #29375 -- Removed empty action attribute on HTML forms.

Backport of 4660ce5a69 from master
This commit is contained in:
CHI Cheng 2018-05-02 23:20:04 +10:00 committed by Tim Graham
parent 3003830008
commit 482ba9246e
9 changed files with 36 additions and 36 deletions

View File

@ -74,7 +74,7 @@ editing content:
.. code-block:: html+django .. code-block:: html+django
<form action="" method="post">{% csrf_token %} <form method="post">{% csrf_token %}
{{ form.as_p }} {{ form.as_p }}
<input type="submit" value="Send message" /> <input type="submit" value="Send message" />
</form> </form>
@ -130,7 +130,7 @@ editing content:
.. code-block:: html+django .. code-block:: html+django
<form action="" method="post">{% csrf_token %} <form method="post">{% csrf_token %}
{{ form.as_p }} {{ form.as_p }}
<input type="submit" value="Save" /> <input type="submit" value="Save" />
</form> </form>
@ -187,7 +187,7 @@ editing content:
.. code-block:: html+django .. code-block:: html+django
<form action="" method="post">{% csrf_token %} <form method="post">{% csrf_token %}
{{ form.as_p }} {{ form.as_p }}
<input type="submit" value="Update" /> <input type="submit" value="Update" />
</form> </form>
@ -238,7 +238,7 @@ editing content:
.. code-block:: html+django .. code-block:: html+django
<form action="" method="post">{% csrf_token %} <form method="post">{% csrf_token %}
<p>Are you sure you want to delete "{{ object }}"?</p> <p>Are you sure you want to delete "{{ object }}"?</p>
<input type="submit" value="Confirm" /> <input type="submit" value="Confirm" />
</form> </form>

View File

@ -41,7 +41,7 @@ To take advantage of CSRF protection in your views, follow these steps:
.. code-block:: html+django .. code-block:: html+django
<form action="" method="post">{% csrf_token %} <form method="post">{% csrf_token %}
This should not be done for POST forms that target external URLs, since This should not be done for POST forms that target external URLs, since
that would cause the CSRF token to be leaked, leading to a vulnerability. that would cause the CSRF token to be leaked, leading to a vulnerability.
@ -179,7 +179,7 @@ to ``{% csrf_token %}`` in the Django template language. For example:
.. code-block:: html+jinja .. code-block:: html+jinja
<form action="" method="post">{{ csrf_input }} <form method="post">{{ csrf_input }}
The decorator method The decorator method
-------------------- --------------------

View File

@ -630,7 +630,7 @@ The ``manage_articles.html`` template might look like this:
.. code-block:: html+django .. code-block:: html+django
<form method="post" action=""> <form method="post">
{{ formset.management_form }} {{ formset.management_form }}
<table> <table>
{% for form in formset %} {% for form in formset %}
@ -644,7 +644,7 @@ deal with the management form:
.. code-block:: html+django .. code-block:: html+django
<form method="post" action=""> <form method="post">
<table> <table>
{{ formset }} {{ formset }}
</table> </table>
@ -662,7 +662,7 @@ If you manually render fields in the template, you can render
.. code-block:: html+django .. code-block:: html+django
<form method="post" action=""> <form method="post">
{{ formset.management_form }} {{ formset.management_form }}
{% for form in formset %} {% for form in formset %}
<ul> <ul>

View File

@ -1064,14 +1064,14 @@ There are three ways to render a formset in a Django template.
First, you can let the formset do most of the work:: First, you can let the formset do most of the work::
<form method="post" action=""> <form method="post">
{{ formset }} {{ formset }}
</form> </form>
Second, you can manually render the formset, but let the form deal with Second, you can manually render the formset, but let the form deal with
itself:: itself::
<form method="post" action=""> <form method="post">
{{ formset.management_form }} {{ formset.management_form }}
{% for form in formset %} {% for form in formset %}
{{ form }} {{ form }}
@ -1084,7 +1084,7 @@ form as shown above. See the :ref:`management form documentation
Third, you can manually render each field:: Third, you can manually render each field::
<form method="post" action=""> <form method="post">
{{ formset.management_form }} {{ formset.management_form }}
{% for form in formset %} {% for form in formset %}
{% for field in form %} {% for field in form %}
@ -1097,7 +1097,7 @@ If you opt to use this third method and you don't iterate over the fields with
a ``{% for %}`` loop, you'll need to render the primary key field. For example, a ``{% for %}`` loop, you'll need to render the primary key field. For example,
if you were rendering the ``name`` and ``age`` fields of a model:: if you were rendering the ``name`` and ``age`` fields of a model::
<form method="post" action=""> <form method="post">
{{ formset.management_form }} {{ formset.management_form }}
{% for form in formset %} {% for form in formset %}
{{ form.id }} {{ form.id }}

View File

@ -1,6 +1,6 @@
<html> <html>
<body> <body>
<form method="post" action="">{% csrf_token %} <form method="post">{% csrf_token %}
{{ form.as_p }}<br> {{ form.as_p }}<br>
<input id="submit" type="submit"> <input id="submit" type="submit">
</form> </form>

View File

@ -2482,13 +2482,13 @@ Password: <input type="password" name="password" required />
return 'VALID: %r' % sorted(form.cleaned_data.items()) return 'VALID: %r' % sorted(form.cleaned_data.items())
t = Template( t = Template(
'<form action="" method="post">\n' '<form method="post">\n'
'<table>\n{{ form }}\n</table>\n<input type="submit" required />\n</form>' '<table>\n{{ form }}\n</table>\n<input type="submit" required />\n</form>'
) )
return t.render(Context({'form': form})) return t.render(Context({'form': form}))
# Case 1: GET (an empty form, with no errors).) # Case 1: GET (an empty form, with no errors).)
self.assertHTMLEqual(my_function('GET', {}), """<form action="" method="post"> self.assertHTMLEqual(my_function('GET', {}), """<form method="post">
<table> <table>
<tr><th>Username:</th><td><input type="text" name="username" maxlength="10" required /></td></tr> <tr><th>Username:</th><td><input type="text" name="username" maxlength="10" required /></td></tr>
<tr><th>Password1:</th><td><input type="password" name="password1" required /></td></tr> <tr><th>Password1:</th><td><input type="password" name="password1" required /></td></tr>
@ -2499,7 +2499,7 @@ Password: <input type="password" name="password" required />
# Case 2: POST with erroneous data (a redisplayed form, with errors).) # Case 2: POST with erroneous data (a redisplayed form, with errors).)
self.assertHTMLEqual( self.assertHTMLEqual(
my_function('POST', {'username': 'this-is-a-long-username', 'password1': 'foo', 'password2': 'bar'}), my_function('POST', {'username': 'this-is-a-long-username', 'password1': 'foo', 'password2': 'bar'}),
"""<form action="" method="post"> """<form method="post">
<table> <table>
<tr><td colspan="2"><ul class="errorlist nonfield"><li>Please make sure your passwords match.</li></ul></td></tr> <tr><td colspan="2"><ul class="errorlist nonfield"><li>Please make sure your passwords match.</li></ul></td></tr>
<tr><th>Username:</th><td><ul class="errorlist"> <tr><th>Username:</th><td><ul class="errorlist">
@ -2535,13 +2535,13 @@ Password: <input type="password" name="password" required />
# fields. Note, however, that this flexibility comes with the responsibility of # fields. Note, however, that this flexibility comes with the responsibility of
# displaying all the errors, including any that might not be associated with a # displaying all the errors, including any that might not be associated with a
# particular field. # particular field.
t = Template('''<form action=""> t = Template('''<form>
{{ form.username.errors.as_ul }}<p><label>Your username: {{ form.username }}</label></p> {{ form.username.errors.as_ul }}<p><label>Your username: {{ form.username }}</label></p>
{{ form.password1.errors.as_ul }}<p><label>Password: {{ form.password1 }}</label></p> {{ form.password1.errors.as_ul }}<p><label>Password: {{ form.password1 }}</label></p>
{{ form.password2.errors.as_ul }}<p><label>Password (again): {{ form.password2 }}</label></p> {{ form.password2.errors.as_ul }}<p><label>Password (again): {{ form.password2 }}</label></p>
<input type="submit" required /> <input type="submit" required />
</form>''') </form>''')
self.assertHTMLEqual(t.render(Context({'form': UserRegistration(auto_id=False)})), """<form action=""> self.assertHTMLEqual(t.render(Context({'form': UserRegistration(auto_id=False)})), """<form>
<p><label>Your username: <input type="text" name="username" maxlength="10" required /></label></p> <p><label>Your username: <input type="text" name="username" maxlength="10" required /></label></p>
<p><label>Password: <input type="password" name="password1" required /></label></p> <p><label>Password: <input type="password" name="password1" required /></label></p>
<p><label>Password (again): <input type="password" name="password2" required /></label></p> <p><label>Password (again): <input type="password" name="password2" required /></label></p>
@ -2549,7 +2549,7 @@ Password: <input type="password" name="password" required />
</form>""") </form>""")
self.assertHTMLEqual( self.assertHTMLEqual(
t.render(Context({'form': UserRegistration({'username': 'django'}, auto_id=False)})), t.render(Context({'form': UserRegistration({'username': 'django'}, auto_id=False)})),
"""<form action=""> """<form>
<p><label>Your username: <input type="text" name="username" value="django" maxlength="10" required /></label></p> <p><label>Your username: <input type="text" name="username" value="django" maxlength="10" required /></label></p>
<ul class="errorlist"><li>This field is required.</li></ul><p> <ul class="errorlist"><li>This field is required.</li></ul><p>
<label>Password: <input type="password" name="password1" required /></label></p> <label>Password: <input type="password" name="password1" required /></label></p>
@ -2563,13 +2563,13 @@ Password: <input type="password" name="password" required />
# a field by using the 'label' argument to a Field class. If you don't specify # a field by using the 'label' argument to a Field class. If you don't specify
# 'label', Django will use the field name with underscores converted to spaces, # 'label', Django will use the field name with underscores converted to spaces,
# and the initial letter capitalized. # and the initial letter capitalized.
t = Template('''<form action=""> t = Template('''<form>
<p><label>{{ form.username.label }}: {{ form.username }}</label></p> <p><label>{{ form.username.label }}: {{ form.username }}</label></p>
<p><label>{{ form.password1.label }}: {{ form.password1 }}</label></p> <p><label>{{ form.password1.label }}: {{ form.password1 }}</label></p>
<p><label>{{ form.password2.label }}: {{ form.password2 }}</label></p> <p><label>{{ form.password2.label }}: {{ form.password2 }}</label></p>
<input type="submit" required /> <input type="submit" required />
</form>''') </form>''')
self.assertHTMLEqual(t.render(Context({'form': UserRegistration(auto_id=False)})), """<form action=""> self.assertHTMLEqual(t.render(Context({'form': UserRegistration(auto_id=False)})), """<form>
<p><label>Username: <input type="text" name="username" maxlength="10" required /></label></p> <p><label>Username: <input type="text" name="username" maxlength="10" required /></label></p>
<p><label>Password1: <input type="password" name="password1" required /></label></p> <p><label>Password1: <input type="password" name="password1" required /></label></p>
<p><label>Password2: <input type="password" name="password2" required /></label></p> <p><label>Password2: <input type="password" name="password2" required /></label></p>
@ -2580,19 +2580,19 @@ Password: <input type="password" name="password" required />
# wrapped around it, but *only* if the given field has an "id" attribute. # wrapped around it, but *only* if the given field has an "id" attribute.
# Recall from above that passing the "auto_id" argument to a Form gives each # Recall from above that passing the "auto_id" argument to a Form gives each
# field an "id" attribute. # field an "id" attribute.
t = Template('''<form action=""> t = Template('''<form>
<p>{{ form.username.label_tag }} {{ form.username }}</p> <p>{{ form.username.label_tag }} {{ form.username }}</p>
<p>{{ form.password1.label_tag }} {{ form.password1 }}</p> <p>{{ form.password1.label_tag }} {{ form.password1 }}</p>
<p>{{ form.password2.label_tag }} {{ form.password2 }}</p> <p>{{ form.password2.label_tag }} {{ form.password2 }}</p>
<input type="submit" required /> <input type="submit" required />
</form>''') </form>''')
self.assertHTMLEqual(t.render(Context({'form': UserRegistration(auto_id=False)})), """<form action=""> self.assertHTMLEqual(t.render(Context({'form': UserRegistration(auto_id=False)})), """<form>
<p>Username: <input type="text" name="username" maxlength="10" required /></p> <p>Username: <input type="text" name="username" maxlength="10" required /></p>
<p>Password1: <input type="password" name="password1" required /></p> <p>Password1: <input type="password" name="password1" required /></p>
<p>Password2: <input type="password" name="password2" required /></p> <p>Password2: <input type="password" name="password2" required /></p>
<input type="submit" required /> <input type="submit" required />
</form>""") </form>""")
self.assertHTMLEqual(t.render(Context({'form': UserRegistration(auto_id='id_%s')})), """<form action=""> self.assertHTMLEqual(t.render(Context({'form': UserRegistration(auto_id='id_%s')})), """<form>
<p><label for="id_username">Username:</label> <p><label for="id_username">Username:</label>
<input id="id_username" type="text" name="username" maxlength="10" required /></p> <input id="id_username" type="text" name="username" maxlength="10" required /></p>
<p><label for="id_password1">Password1:</label> <p><label for="id_password1">Password1:</label>
@ -2604,7 +2604,7 @@ Password: <input type="password" name="password" required />
# User form.[field].help_text to output a field's help text. If the given field # User form.[field].help_text to output a field's help text. If the given field
# does not have help text, nothing will be output. # does not have help text, nothing will be output.
t = Template('''<form action=""> t = Template('''<form>
<p>{{ form.username.label_tag }} {{ form.username }}<br />{{ form.username.help_text }}</p> <p>{{ form.username.label_tag }} {{ form.username }}<br />{{ form.username.help_text }}</p>
<p>{{ form.password1.label_tag }} {{ form.password1 }}</p> <p>{{ form.password1.label_tag }} {{ form.password1 }}</p>
<p>{{ form.password2.label_tag }} {{ form.password2 }}</p> <p>{{ form.password2.label_tag }} {{ form.password2 }}</p>
@ -2612,7 +2612,7 @@ Password: <input type="password" name="password" required />
</form>''') </form>''')
self.assertHTMLEqual( self.assertHTMLEqual(
t.render(Context({'form': UserRegistration(auto_id=False)})), t.render(Context({'form': UserRegistration(auto_id=False)})),
"""<form action=""> """<form>
<p>Username: <input type="text" name="username" maxlength="10" required /><br /> <p>Username: <input type="text" name="username" maxlength="10" required /><br />
Good luck picking a username that doesn&#39;t already exist.</p> Good luck picking a username that doesn&#39;t already exist.</p>
<p>Password1: <input type="password" name="password1" required /></p> <p>Password1: <input type="password" name="password1" required /></p>
@ -2629,7 +2629,7 @@ Good luck picking a username that doesn&#39;t already exist.</p>
# the errors caused by Form.clean() -- use {{ form.non_field_errors }} in the # the errors caused by Form.clean() -- use {{ form.non_field_errors }} in the
# template. If used on its own, it is displayed as a <ul> (or an empty string, if # template. If used on its own, it is displayed as a <ul> (or an empty string, if
# the list of errors is empty). You can also use it in {% if %} statements. # the list of errors is empty). You can also use it in {% if %} statements.
t = Template('''<form action=""> t = Template('''<form>
{{ form.username.errors.as_ul }}<p><label>Your username: {{ form.username }}</label></p> {{ form.username.errors.as_ul }}<p><label>Your username: {{ form.username }}</label></p>
{{ form.password1.errors.as_ul }}<p><label>Password: {{ form.password1 }}</label></p> {{ form.password1.errors.as_ul }}<p><label>Password: {{ form.password1 }}</label></p>
{{ form.password2.errors.as_ul }}<p><label>Password (again): {{ form.password2 }}</label></p> {{ form.password2.errors.as_ul }}<p><label>Password (again): {{ form.password2 }}</label></p>
@ -2639,14 +2639,14 @@ Good luck picking a username that doesn&#39;t already exist.</p>
t.render(Context({ t.render(Context({
'form': UserRegistration({'username': 'django', 'password1': 'foo', 'password2': 'bar'}, auto_id=False) 'form': UserRegistration({'username': 'django', 'password1': 'foo', 'password2': 'bar'}, auto_id=False)
})), })),
"""<form action=""> """<form>
<p><label>Your username: <input type="text" name="username" value="django" maxlength="10" required /></label></p> <p><label>Your username: <input type="text" name="username" value="django" maxlength="10" required /></label></p>
<p><label>Password: <input type="password" name="password1" required /></label></p> <p><label>Password: <input type="password" name="password1" required /></label></p>
<p><label>Password (again): <input type="password" name="password2" required /></label></p> <p><label>Password (again): <input type="password" name="password2" required /></label></p>
<input type="submit" required /> <input type="submit" required />
</form>""" </form>"""
) )
t = Template('''<form action=""> t = Template('''<form>
{{ form.non_field_errors }} {{ form.non_field_errors }}
{{ form.username.errors.as_ul }}<p><label>Your username: {{ form.username }}</label></p> {{ form.username.errors.as_ul }}<p><label>Your username: {{ form.username }}</label></p>
{{ form.password1.errors.as_ul }}<p><label>Password: {{ form.password1 }}</label></p> {{ form.password1.errors.as_ul }}<p><label>Password: {{ form.password1 }}</label></p>
@ -2657,7 +2657,7 @@ Good luck picking a username that doesn&#39;t already exist.</p>
t.render(Context({ t.render(Context({
'form': UserRegistration({'username': 'django', 'password1': 'foo', 'password2': 'bar'}, auto_id=False) 'form': UserRegistration({'username': 'django', 'password1': 'foo', 'password2': 'bar'}, auto_id=False)
})), })),
"""<form action=""> """<form>
<ul class="errorlist nonfield"><li>Please make sure your passwords match.</li></ul> <ul class="errorlist nonfield"><li>Please make sure your passwords match.</li></ul>
<p><label>Your username: <input type="text" name="username" value="django" maxlength="10" required /></label></p> <p><label>Your username: <input type="text" name="username" value="django" maxlength="10" required /></label></p>
<p><label>Password: <input type="password" name="password1" required /></label></p> <p><label>Password: <input type="password" name="password1" required /></label></p>

View File

@ -2,7 +2,7 @@
{% block title %}Submit data{% endblock %} {% block title %}Submit data{% endblock %}
{% block content %} {% block content %}
<h1>{{ message }}</h1> <h1>{{ message }}</h1>
<form method="post" action=""> <form method="post">
{% if form.errors %} {% if form.errors %}
<p class='warning'>Please correct the errors below:</p> <p class='warning'>Please correct the errors below:</p>
{% endif %} {% endif %}

View File

@ -5,7 +5,7 @@
<p>Your username and password didn't match. Please try again.</p> <p>Your username and password didn't match. Please try again.</p>
{% endif %} {% endif %}
<form method="post" action=""> <form method="post">
<table> <table>
<tr><td><label for="id_username">Username:</label></td><td>{{ form.username }}</td></tr> <tr><td><label for="id_username">Username:</label></td><td>{{ form.username }}</td></tr>
<tr><td><label for="id_password">Password:</label></td><td>{{ form.password }}</td></tr> <tr><td><label for="id_password">Password:</label></td><td>{{ form.password }}</td></tr>

View File

@ -695,15 +695,15 @@ class HTMLEqualTests(SimpleTestCase):
def test_contains_html(self): def test_contains_html(self):
response = HttpResponse('''<body> response = HttpResponse('''<body>
This is a form: <form action="" method="get"> This is a form: <form method="get">
<input type="text" name="Hello" /> <input type="text" name="Hello" />
</form></body>''') </form></body>''')
self.assertNotContains(response, "<input name='Hello' type='text'>") self.assertNotContains(response, "<input name='Hello' type='text'>")
self.assertContains(response, '<form action="" method="get">') self.assertContains(response, '<form method="get">')
self.assertContains(response, "<input name='Hello' type='text'>", html=True) self.assertContains(response, "<input name='Hello' type='text'>", html=True)
self.assertNotContains(response, '<form action="" method="get">', html=True) self.assertNotContains(response, '<form method="get">', html=True)
invalid_response = HttpResponse('''<body <bad>>''') invalid_response = HttpResponse('''<body <bad>>''')