Disable client-side validation on Django 1.10 for multipart forms

Client-side validation fails on forms with prefilled file upload fields -
see https://code.djangoproject.com/ticket/27037. This is fixed in Django 1.10.1,
so as a workaround we disable client-side validation (using the 'novalidate'
attribute) for forms with enctype="multipart/form-data" on Django 1.10 only.

Fixes #2897
pull/2913/merge
Matt Westcott 2016-08-15 13:18:23 +01:00
rodzic e39fb5646c
commit 197d85ce9f
23 zmienionych plików z 54 dodań i 38 usunięć

Wyświetl plik

@ -50,6 +50,7 @@ Changelog
* Fix: Added file handling to support custom user add/edit forms with images/files (Eraldo Energy)
* Fix: Placeholder text in modeladmin search now uses the correct template variable (Adriaan Tijsseling)
* Fix: Fixed bad SQL syntax for updating URL paths on Microsoft SQL Server (Jesse Legg)
* Fix: Added workaround for Django 1.10 bug https://code.djangoproject.com/ticket/27037 causing forms with file upload fields to fail validation (Matt Westcott)
1.5.3 (18.07.2016)

Wyświetl plik

@ -79,6 +79,7 @@ Bug fixes
* Added file handling to support custom user add/edit forms with images/files (Eraldo Energy)
* Placeholder text in modeladmin search now uses the correct template variable (Adriaan Tijsseling)
* Fixed bad SQL syntax for updating URL paths on Microsoft SQL Server (Jesse Legg)
* Added workaround for Django 1.10 bug https://code.djangoproject.com/ticket/27037 causing forms with file upload fields to fail validation (Matt Westcott)
Upgrade considerations

Wyświetl plik

@ -1,5 +1,5 @@
{% extends "wagtailadmin/base.html" %}
{% load i18n %}
{% load i18n wagtailadmin_tags %}
{% block titletag %}{{ view.get_meta_title }}{% endblock %}
@ -19,7 +19,7 @@
{% include "wagtailadmin/shared/header.html" with title=view.get_page_title subtitle=view.get_page_subtitle icon=view.header_icon tabbed=1 merged=1 %}
{% endblock %}
<form action="{% block form_action %}{{ view.create_url }}{% endblock %}"{% if is_multipart %} enctype="multipart/form-data"{% endif %} method="POST">
<form action="{% block form_action %}{{ view.create_url }}{% endblock %}"{% if is_multipart %} enctype="multipart/form-data" {% novalidate_on_django_1_10 %}{% endif %} method="POST">
{% csrf_token %}
{% block form %}{{ edit_handler.render_form_content }}{% endblock %}

Wyświetl plik

@ -1,5 +1,5 @@
{% extends "wagtailadmin/base.html" %}
{% load i18n %}
{% load i18n wagtailadmin_tags %}
{% block titletag %}{% blocktrans %}Editing {{ setting_type_name}} - {{ instance }}{% endblocktrans %}{% endblock %}
{% block bodyclass %}menu-settings{% endblock %}
{% block content %}
@ -26,7 +26,7 @@
</div>
</header>
<form action="{% url 'wagtailsettings:edit' opts.app_label opts.model_name site.pk %}" method="POST"{% if form.is_multipart %} enctype="multipart/form-data"{% endif %}>
<form action="{% url 'wagtailsettings:edit' opts.app_label opts.model_name site.pk %}" method="POST"{% if form.is_multipart %} enctype="multipart/form-data" {% novalidate_on_django_1_10 %}{% endif %}>
{% csrf_token %}
{{ edit_handler.render_form_content }}

Wyświetl plik

@ -1,5 +1,5 @@
{% extends "wagtailadmin/base.html" %}
{% load i18n %}
{% load i18n wagtailadmin_tags %}
{% block titletag %}{{ view.page_title }}{% endblock %}
@ -7,7 +7,7 @@
{% include "wagtailadmin/shared/header.html" with title=view.page_title icon=view.header_icon %}
<form action="{{ view.get_add_url }}" method="POST"{% if form.is_multipart %} enctype="multipart/form-data"{% endif %}>
<form action="{{ view.get_add_url }}" method="POST"{% if form.is_multipart %} enctype="multipart/form-data" {% novalidate_on_django_1_10 %}{% endif %}>
{% csrf_token %}
{% block hidden_fields %}

Wyświetl plik

@ -1,5 +1,5 @@
{% extends "wagtailadmin/base.html" %}
{% load i18n %}
{% load i18n wagtailadmin_tags %}
{% block titletag %}{{ view.page_title }} {{ view.get_page_subtitle }}{% endblock %}
@ -8,7 +8,7 @@
{% include "wagtailadmin/shared/header.html" with title=view.page_title subtitle=view.get_page_subtitle icon=view.header_icon %}
<div class="nice-padding">
<form action="{{ view.get_edit_url }}" method="POST"{% if form.is_multipart %} enctype="multipart/form-data"{% endif %}>
<form action="{{ view.get_edit_url }}" method="POST"{% if form.is_multipart %} enctype="multipart/form-data" {% novalidate_on_django_1_10 %}{% endif %}>
{% csrf_token %}
{% block hidden_fields %}

Wyświetl plik

@ -17,7 +17,7 @@
</div>
</header>
<form id="page-edit-form" action="{% url 'wagtailadmin_pages:add' content_type.app_label content_type.model parent_page.id %}" method="POST"{% if form.is_multipart %} enctype="multipart/form-data"{% endif %}>
<form id="page-edit-form" action="{% url 'wagtailadmin_pages:add' content_type.app_label content_type.model parent_page.id %}" method="POST"{% if form.is_multipart %} enctype="multipart/form-data" {% novalidate_on_django_1_10 %}{% endif %}>
{% csrf_token %}
<input type="hidden" name="next" value="{{ next }}">
{{ edit_handler.render_form_content }}

Wyświetl plik

@ -24,7 +24,7 @@
</div>
</header>
<form id="page-edit-form" action="{% url 'wagtailadmin_pages:edit' page.id %}" method="POST"{% if form.is_multipart %} enctype="multipart/form-data"{% endif %}>
<form id="page-edit-form" action="{% url 'wagtailadmin_pages:edit' page.id %}" method="POST"{% if form.is_multipart %} enctype="multipart/form-data" {% novalidate_on_django_1_10 %}{% endif %}>
{% csrf_token %}
<input type="hidden" name="next" value="{{ next }}">
{{ edit_handler.render_form_content }}

Wyświetl plik

@ -312,3 +312,17 @@ def message_tags(message):
return level_tag
else:
return ''
@register.simple_tag
def novalidate_on_django_1_10():
"""
Django 1.10 has a bug that breaks client-side validation on forms that include
prefilled file upload fields. This is due to be fixed in Django 1.10.1; as a
workaround, we apply this tag to disable client-side validation (using the
'novalidate' attribute) on all forms with enctype="multipart/form-data".
"""
if django.VERSION >= (1, 10, 0) and django.VERSION < (1, 10, 1):
return 'novalidate'
else:
return ''

Wyświetl plik

@ -1,4 +1,4 @@
{% load i18n %}
{% load i18n wagtailadmin_tags %}
{% trans "Choose a document" as choose_str %}
{% include "wagtailadmin/shared/header.html" with title=choose_str tabbed=1 merged=1 icon="doc-full-inverse" %}
@ -28,7 +28,7 @@
</section>
{% if uploadform %}
<section id="upload" class="{% if uploadform.errors %}active {% endif %}nice-padding">
<form class="document-upload" action="{% url 'wagtaildocs:chooser_upload' %}" method="POST" enctype="multipart/form-data">
<form class="document-upload" action="{% url 'wagtaildocs:chooser_upload' %}" method="POST" enctype="multipart/form-data" {% novalidate_on_django_1_10 %}>
{% csrf_token %}
<ul class="fields">
{% for field in uploadform %}

Wyświetl plik

@ -1,5 +1,5 @@
{% extends "wagtailadmin/base.html" %}
{% load i18n %}
{% load i18n wagtailadmin_tags %}
{% load wagtailimages_tags %}
{% block titletag %}{% trans "Add a document" %}{% endblock %}
@ -21,7 +21,7 @@
{% include "wagtailadmin/shared/header.html" with title=add_str icon="doc-full-inverse" %}
<div class="nice-padding">
<form action="{% url 'wagtaildocs:add' %}" method="POST" enctype="multipart/form-data">
<form action="{% url 'wagtaildocs:add' %}" method="POST" enctype="multipart/form-data" {% novalidate_on_django_1_10 %}>
{% csrf_token %}
<ul class="fields">
{% for field in form %}

Wyświetl plik

@ -1,5 +1,5 @@
{% extends "wagtailadmin/base.html" %}
{% load i18n %}
{% load i18n wagtailadmin_tags %}
{% load wagtailimages_tags %}
{% block titletag %}{% blocktrans with title=document.title %}Editing {{ title }}{% endblocktrans %}{% endblock %}
@ -23,7 +23,7 @@
<div class="row row-flush nice-padding">
<div class="col10 divider-after">
<form action="{% url 'wagtaildocs:edit' document.id %}" method="POST" enctype="multipart/form-data">
<form action="{% url 'wagtaildocs:edit' document.id %}" method="POST" enctype="multipart/form-data" {% novalidate_on_django_1_10 %}>
{% csrf_token %}
<ul class="fields">
{% for field in form %}

Wyświetl plik

@ -1,5 +1,5 @@
{% extends "wagtailadmin/base.html" %}
{% load i18n staticfiles %}
{% load i18n staticfiles wagtailadmin_tags %}
{% block titletag %}{% trans "Add multiple documents" %}{% endblock %}
{% block extra_css %}
{{ block.super }}
@ -16,7 +16,7 @@
<p>{% trans "Drag and drop documents into this area to upload immediately." %}</p>
<p>{{ help_text }}
<form action="{% url 'wagtaildocs:add_multiple' %}" method="POST" enctype="multipart/form-data">
<form action="{% url 'wagtaildocs:add_multiple' %}" method="POST" enctype="multipart/form-data" {% novalidate_on_django_1_10 %}>
<div class="replace-file-input">
<button class="button bicolor icon icon-plus">{% trans "Or choose from your computer" %}</button>
<input id="fileupload" type="file" name="files[]" data-url="{% url 'wagtaildocs:add_multiple' %}" multiple>

Wyświetl plik

@ -1,6 +1,6 @@
{% load i18n %}
{% load i18n wagtailadmin_tags %}
<form action="{% url 'wagtaildocs:edit_multiple' doc.id %}" method="POST" enctype="multipart/form-data">
<form action="{% url 'wagtaildocs:edit_multiple' doc.id %}" method="POST" enctype="multipart/form-data" {% novalidate_on_django_1_10 %}>
<ul class="fields">
{% csrf_token %}
{% for field in form %}

Wyświetl plik

@ -1,4 +1,4 @@
{% load wagtailimages_tags %}
{% load wagtailimages_tags wagtailadmin_tags %}
{% load i18n %}
{% trans "Choose an image" as choose_str %}
{% include "wagtailadmin/shared/header.html" with title=choose_str merged=1 tabbed=1 icon="image" %}
@ -36,7 +36,7 @@
</section>
{% if uploadform %}
<section id="upload" class="{% if uploadform.errors %}active{% endif %} nice-padding">
<form class="image-upload" action="{% url 'wagtailimages:chooser_upload' %}{% if will_select_format %}?select_format=true{% endif %}" method="POST" enctype="multipart/form-data">
<form class="image-upload" action="{% url 'wagtailimages:chooser_upload' %}{% if will_select_format %}?select_format=true{% endif %}" method="POST" enctype="multipart/form-data" {% novalidate_on_django_1_10 %}>
{% csrf_token %}
<ul class="fields">
{% for field in uploadform %}

Wyświetl plik

@ -1,5 +1,5 @@
{% extends "wagtailadmin/base.html" %}
{% load wagtailimages_tags %}
{% load wagtailimages_tags wagtailadmin_tags %}
{% load i18n %}
{% block titletag %}{% trans "Add an image" %}{% endblock %}
@ -21,7 +21,7 @@
{% include "wagtailadmin/shared/header.html" with title=add_str icon="image" %}
<div class="nice-padding">
<form action="{% url 'wagtailimages:add' %}" method="POST" enctype="multipart/form-data">
<form action="{% url 'wagtailimages:add' %}" method="POST" enctype="multipart/form-data" {% novalidate_on_django_1_10 %}>
{% csrf_token %}
<ul class="fields">
{% for field in form %}

Wyświetl plik

@ -1,5 +1,5 @@
{% extends "wagtailadmin/base.html" %}
{% load wagtailimages_tags staticfiles i18n %}
{% load wagtailimages_tags wagtailadmin_tags staticfiles i18n %}
{% block titletag %}{% blocktrans with title=image.title %}Editing image {{ title }}{% endblocktrans %}{% endblock %}
{% block extra_css %}
{{ block.super }}
@ -34,7 +34,7 @@
<div class="row row-flush nice-padding">
<div class="col5">
<form action="{% url 'wagtailimages:edit' image.id %}" method="POST" enctype="multipart/form-data">
<form action="{% url 'wagtailimages:edit' image.id %}" method="POST" enctype="multipart/form-data" {% novalidate_on_django_1_10 %}>
{% csrf_token %}
<ul class="fields">
{% for field in form %}

Wyświetl plik

@ -1,5 +1,5 @@
{% extends "wagtailadmin/base.html" %}
{% load wagtailimages_tags i18n staticfiles %}
{% load wagtailimages_tags wagtailadmin_tags i18n staticfiles %}
{% block titletag %}{% trans "Add multiple images" %}{% endblock %}
{% block extra_css %}
{{ block.super }}
@ -16,7 +16,7 @@
<p>{% trans "Drag and drop images into this area to upload immediately." %}</p>
<p>{{ help_text }}
<form action="{% url 'wagtailimages:add_multiple' %}" method="POST" enctype="multipart/form-data">
<form action="{% url 'wagtailimages:add_multiple' %}" method="POST" enctype="multipart/form-data" {% novalidate_on_django_1_10 %}>
<div class="replace-file-input">
<button class="button bicolor icon icon-plus">{% trans "Or choose from your computer" %}</button>
<input id="fileupload" type="file" name="files[]" data-url="{% url 'wagtailimages:add_multiple' %}" multiple>

Wyświetl plik

@ -1,6 +1,6 @@
{% load i18n %}
{% load i18n wagtailadmin_tags %}
<form action="{% url 'wagtailimages:edit_multiple' image.id %}" method="POST" enctype="multipart/form-data">
<form action="{% url 'wagtailimages:edit_multiple' image.id %}" method="POST" enctype="multipart/form-data" {% novalidate_on_django_1_10 %}>
<ul class="fields">
{% csrf_token %}
{% for field in form %}

Wyświetl plik

@ -1,11 +1,11 @@
{% extends "wagtailadmin/base.html" %}
{% load i18n %}
{% load i18n wagtailadmin_tags %}
{% block titletag %}{% blocktrans with snippet_type_name=model_opts.verbose_name %}New {{ snippet_type_name }}{% endblocktrans %}{% endblock %}
{% block content %}
{% trans "New" as new_str %}
{% include "wagtailadmin/shared/header.html" with title=new_str subtitle=model_opts.verbose_name icon="snippet" tabbed=1 merged=1 %}
<form action="{% url 'wagtailsnippets:add' model_opts.app_label model_opts.model_name %}" method="POST"{% if form.is_multipart %} enctype="multipart/form-data"{% endif %}>
<form action="{% url 'wagtailsnippets:add' model_opts.app_label model_opts.model_name %}" method="POST"{% if form.is_multipart %} enctype="multipart/form-data" {% novalidate_on_django_1_10 %}{% endif %}>
{% csrf_token %}
{{ edit_handler.render_form_content }}

Wyświetl plik

@ -1,11 +1,11 @@
{% extends "wagtailadmin/base.html" %}
{% load i18n %}
{% load i18n wagtailadmin_tags %}
{% block titletag %}{% blocktrans with snippet_type_name=model_opts.verbose_name %}Editing {{ snippet_type_name }} - {{ instance }}{% endblocktrans %}{% endblock %}
{% block content %}
{% trans "Editing" as editing_str %}
{% include "wagtailadmin/shared/header.html" with title=editing_str subtitle=instance icon="snippet" usage_object=instance tabbed=1 merged=1 %}
<form action="{% url 'wagtailsnippets:edit' model_opts.app_label model_opts.model_name instance.id %}" method="POST"{% if form.is_multipart %} enctype="multipart/form-data"{% endif %}>
<form action="{% url 'wagtailsnippets:edit' model_opts.app_label model_opts.model_name instance.id %}" method="POST"{% if form.is_multipart %} enctype="multipart/form-data" {% novalidate_on_django_1_10 %}{% endif %}>
{% csrf_token %}
{{ edit_handler.render_form_content }}

Wyświetl plik

@ -1,5 +1,5 @@
{% extends "wagtailadmin/base.html" %}
{% load wagtailimages_tags %}
{% load wagtailimages_tags wagtailadmin_tags %}
{% load i18n %}
{% block titletag %}{% trans "Add user" %}{% endblock %}
{% block content %}
@ -12,7 +12,7 @@
<li><a href="#roles">{% trans "Roles" %}</a></li>
</ul>
<form action="{% url 'wagtailusers_users:add' %}" method="POST"{% if form.is_multipart %} enctype="multipart/form-data"{% endif %}>
<form action="{% url 'wagtailusers_users:add' %}" method="POST"{% if form.is_multipart %} enctype="multipart/form-data" {% novalidate_on_django_1_10 %}{% endif %}>
<div class="tab-content">
{% csrf_token %}
<section id="account" class="active nice-padding">

Wyświetl plik

@ -1,5 +1,5 @@
{% extends "wagtailadmin/base.html" %}
{% load wagtailimages_tags %}
{% load wagtailimages_tags wagtailadmin_tags %}
{% load i18n %}
{% block titletag %}{% trans "Editing" %} {{ user.get_username}}{% endblock %}
{% block content %}
@ -12,7 +12,7 @@
<li><a href="#roles">{% trans "Roles" %}</a></li>
</ul>
<form action="{% url 'wagtailusers_users:edit' user.pk %}" method="POST"{% if form.is_multipart %} enctype="multipart/form-data"{% endif %}>
<form action="{% url 'wagtailusers_users:edit' user.pk %}" method="POST"{% if form.is_multipart %} enctype="multipart/form-data" {% novalidate_on_django_1_10 %}{% endif %}>
<div class="tab-content">
{% csrf_token %}