Fixed #31118 -- Made FileInput to avoid the required attribute when initial data exists.

This commit is contained in:
Shubham singh 2020-01-05 13:21:33 +05:30 committed by Mariusz Felisiak
parent 53d8646f79
commit ffcf1a8ebf
5 changed files with 46 additions and 13 deletions

View File

@ -387,6 +387,9 @@ class FileInput(Input):
def value_omitted_from_data(self, data, files, name): def value_omitted_from_data(self, data, files, name):
return name not in files return name not in files
def use_required_attribute(self, initial):
return super().use_required_attribute(initial) and not initial
FILE_INPUT_CONTRADICTION = object() FILE_INPUT_CONTRADICTION = object()
@ -451,9 +454,6 @@ class ClearableFileInput(FileInput):
return False return False
return upload return upload
def use_required_attribute(self, initial):
return super().use_required_attribute(initial) and not initial
def value_omitted_from_data(self, data, files, name): def value_omitted_from_data(self, data, files, name):
return ( return (
super().value_omitted_from_data(data, files, name) and super().value_omitted_from_data(data, files, name) and

View File

@ -325,17 +325,22 @@ foundation for custom widgets.
to display the ``required`` attribute for each field. to display the ``required`` attribute for each field.
By default, returns ``False`` for hidden widgets and ``True`` By default, returns ``False`` for hidden widgets and ``True``
otherwise. Special cases are :class:`~django.forms.ClearableFileInput`, otherwise. Special cases are :class:`~django.forms.FileInput` and
which returns ``False`` when ``initial`` is set, and :class:`~django.forms.ClearableFileInput`, which return ``False`` when
:class:`~django.forms.CheckboxSelectMultiple`, which always returns ``initial`` is set, and :class:`~django.forms.CheckboxSelectMultiple`,
``False`` because browser validation would require all checkboxes to be which always returns ``False`` because browser validation would require
checked instead of at least one. all checkboxes to be checked instead of at least one.
Override this method in custom widgets that aren't compatible with Override this method in custom widgets that aren't compatible with
browser validation. For example, a WSYSIWG text editor widget backed by browser validation. For example, a WSYSIWG text editor widget backed by
a hidden ``textarea`` element may want to always return ``False`` to a hidden ``textarea`` element may want to always return ``False`` to
avoid browser validation on the hidden field. avoid browser validation on the hidden field.
.. versionchanged:: 3.1
In older versions, ``True`` was returned for
:class:`~django.forms.FileInput` when ``initial`` was set.
``MultiWidget`` ``MultiWidget``
--------------- ---------------

View File

@ -406,6 +406,9 @@ Miscellaneous
* Date-only formats are removed from the default list for * Date-only formats are removed from the default list for
:setting:`DATETIME_INPUT_FORMATS`. :setting:`DATETIME_INPUT_FORMATS`.
* The :class:`~django.forms.FileInput` widget no longer renders with the
``required`` HTML attribute when initial data exists.
.. _deprecated-features-3.1: .. _deprecated-features-3.1:
Features deprecated in 3.1 Features deprecated in 3.1

View File

@ -8,11 +8,11 @@ from django.core.files.uploadedfile import SimpleUploadedFile
from django.core.validators import MaxValueValidator, RegexValidator from django.core.validators import MaxValueValidator, RegexValidator
from django.forms import ( from django.forms import (
BooleanField, CharField, CheckboxSelectMultiple, ChoiceField, DateField, BooleanField, CharField, CheckboxSelectMultiple, ChoiceField, DateField,
DateTimeField, EmailField, FileField, FloatField, Form, HiddenInput, DateTimeField, EmailField, FileField, FileInput, FloatField, Form,
ImageField, IntegerField, MultipleChoiceField, MultipleHiddenInput, HiddenInput, ImageField, IntegerField, MultipleChoiceField,
MultiValueField, NullBooleanField, PasswordInput, RadioSelect, Select, MultipleHiddenInput, MultiValueField, NullBooleanField, PasswordInput,
SplitDateTimeField, SplitHiddenDateTimeWidget, Textarea, TextInput, RadioSelect, Select, SplitDateTimeField, SplitHiddenDateTimeWidget,
TimeField, ValidationError, forms, Textarea, TextInput, TimeField, ValidationError, forms,
) )
from django.forms.renderers import DjangoTemplates, get_default_renderer from django.forms.renderers import DjangoTemplates, get_default_renderer
from django.forms.utils import ErrorList from django.forms.utils import ErrorList
@ -2486,6 +2486,25 @@ Password: <input type="password" name="password" required>
self.assertEqual(f.errors, {}) self.assertEqual(f.errors, {})
self.assertEqual(f.cleaned_data['file1'], 'resume.txt') self.assertEqual(f.cleaned_data['file1'], 'resume.txt')
def test_filefield_with_fileinput_required(self):
class FileForm(Form):
file1 = forms.FileField(widget=FileInput)
f = FileForm(auto_id=False)
self.assertHTMLEqual(
f.as_table(),
'<tr><th>File1:</th><td>'
'<input type="file" name="file1" required></td></tr>',
)
# A required file field with initial data doesn't contain the required
# HTML attribute. The file input is left blank by the user to keep the
# existing, initial value.
f = FileForm(initial={'file1': 'resume.txt'}, auto_id=False)
self.assertHTMLEqual(
f.as_table(),
'<tr><th>File1:</th><td><input type="file" name="file1"></td></tr>',
)
def test_basic_processing_in_view(self): def test_basic_processing_in_view(self):
class UserRegistration(Form): class UserRegistration(Form):
username = CharField(max_length=10) username = CharField(max_length=10)

View File

@ -18,3 +18,9 @@ class FileInputTest(WidgetTest):
def test_value_omitted_from_data(self): def test_value_omitted_from_data(self):
self.assertIs(self.widget.value_omitted_from_data({}, {}, 'field'), True) self.assertIs(self.widget.value_omitted_from_data({}, {}, 'field'), True)
self.assertIs(self.widget.value_omitted_from_data({}, {'field': 'value'}, 'field'), False) self.assertIs(self.widget.value_omitted_from_data({}, {'field': 'value'}, 'field'), False)
def test_use_required_attribute(self):
# False when initial data exists. The file input is left blank by the
# user to keep the existing, initial value.
self.assertIs(self.widget.use_required_attribute(None), True)
self.assertIs(self.widget.use_required_attribute('resume.txt'), False)