Fixed #6302. FileField no longer requires a value if one already exists. Thanks Brian Rosner and Øyvind Saltvik.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@7021 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Joseph Kocherhans 2008-01-17 18:03:21 +00:00
parent 93c8e94bd6
commit fd20365b27
5 changed files with 128 additions and 10 deletions

View File

@ -797,13 +797,17 @@ class FileField(Field):
return os.path.normpath(f) return os.path.normpath(f)
def save_form_data(self, instance, data): def save_form_data(self, instance, data):
if data: from django.newforms.fields import UploadedFile
if data and isinstance(data, UploadedFile):
getattr(instance, "save_%s_file" % self.name)(data.filename, data.content, save=False) getattr(instance, "save_%s_file" % self.name)(data.filename, data.content, save=False)
def formfield(self, **kwargs): def formfield(self, **kwargs):
defaults = {'form_class': forms.FileField} defaults = {'form_class': forms.FileField}
# If a file has been provided previously, then the form doesn't require # If a file has been provided previously, then the form doesn't require
# that a new file is provided this time. # that a new file is provided this time.
# The code to mark the form field as not required is used by
# form_for_instance, but can probably be removed once form_for_instance
# is gone. ModelForm uses a different method to check for an existing file.
if 'initial' in kwargs: if 'initial' in kwargs:
defaults['required'] = False defaults['required'] = False
defaults.update(kwargs) defaults.update(kwargs)

View File

@ -437,10 +437,12 @@ class FileField(Field):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(FileField, self).__init__(*args, **kwargs) super(FileField, self).__init__(*args, **kwargs)
def clean(self, data): def clean(self, data, initial=None):
super(FileField, self).clean(data) super(FileField, self).clean(initial or data)
if not self.required and data in EMPTY_VALUES: if not self.required and data in EMPTY_VALUES:
return None return None
elif not data and initial:
return initial
try: try:
f = UploadedFile(data['filename'], data['content']) f = UploadedFile(data['filename'], data['content'])
except TypeError: except TypeError:
@ -456,12 +458,12 @@ class ImageField(FileField):
'invalid_image': _(u"Upload a valid image. The file you uploaded was either not an image or a corrupted image."), 'invalid_image': _(u"Upload a valid image. The file you uploaded was either not an image or a corrupted image."),
} }
def clean(self, data): def clean(self, data, initial=None):
""" """
Checks that the file-upload field data contains a valid image (GIF, JPG, Checks that the file-upload field data contains a valid image (GIF, JPG,
PNG, possibly others -- whatever the Python Imaging Library supports). PNG, possibly others -- whatever the Python Imaging Library supports).
""" """
f = super(ImageField, self).clean(data) f = super(ImageField, self).clean(data, initial)
if f is None: if f is None:
return None return None
from PIL import Image from PIL import Image

View File

@ -9,7 +9,7 @@ from django.utils.html import escape
from django.utils.encoding import StrAndUnicode, smart_unicode, force_unicode from django.utils.encoding import StrAndUnicode, smart_unicode, force_unicode
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from fields import Field from fields import Field, FileField
from widgets import TextInput, Textarea from widgets import TextInput, Textarea
from util import flatatt, ErrorDict, ErrorList, ValidationError from util import flatatt, ErrorDict, ErrorList, ValidationError
@ -182,7 +182,11 @@ class BaseForm(StrAndUnicode):
# widgets split data over several HTML fields. # widgets split data over several HTML fields.
value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name)) value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))
try: try:
value = field.clean(value) if isinstance(field, FileField):
initial = self.initial.get(name, field.initial)
value = field.clean(value, initial)
else:
value = field.clean(value)
self.cleaned_data[name] = value self.cleaned_data[name] = value
if hasattr(self, 'clean_%s' % name): if hasattr(self, 'clean_%s' % name):
value = getattr(self, 'clean_%s' % name)() value = getattr(self, 'clean_%s' % name)()

View File

@ -7,6 +7,9 @@ examples are probably a poor fit for the ModelForm syntax. In other words,
most of these tests should be rewritten. most of these tests should be rewritten.
""" """
import os
import tempfile
from django.db import models from django.db import models
ARTICLE_STATUS = ( ARTICLE_STATUS = (
@ -55,6 +58,13 @@ class PhoneNumber(models.Model):
def __unicode__(self): def __unicode__(self):
return self.phone return self.phone
class TextFile(models.Model):
description = models.CharField(max_length=20)
file = models.FileField(upload_to=tempfile.gettempdir())
def __unicode__(self):
return self.description
__test__ = {'API_TESTS': """ __test__ = {'API_TESTS': """
>>> from django import newforms as forms >>> from django import newforms as forms
>>> from django.newforms.models import ModelForm >>> from django.newforms.models import ModelForm
@ -701,4 +711,75 @@ ValidationError: [u'Select a valid choice. 4 is not one of the available choices
True True
>>> f.cleaned_data >>> f.cleaned_data
{'phone': u'312-555-1212', 'description': u'Assistance'} {'phone': u'312-555-1212', 'description': u'Assistance'}
# FileField ###################################################################
>>> class TextFileForm(ModelForm):
... class Meta:
... model = TextFile
Test conditions when files is either not given or empty.
>>> f = TextFileForm(data={'description': u'Assistance'})
>>> f.is_valid()
False
>>> f = TextFileForm(data={'description': u'Assistance'}, files={})
>>> f.is_valid()
False
Upload a file and ensure it all works as expected.
>>> f = TextFileForm(data={'description': u'Assistance'}, files={'file': {'filename': 'test1.txt', 'content': 'hello world'}})
>>> f.is_valid()
True
>>> type(f.cleaned_data['file'])
<class 'django.newforms.fields.UploadedFile'>
>>> instance = f.save()
>>> instance.file
u'.../test1.txt'
Edit an instance that already has the file defined in the model. This will not
save the file again, but leave it exactly as it is.
>>> f = TextFileForm(data={'description': u'Assistance'}, instance=instance)
>>> f.is_valid()
True
>>> f.cleaned_data['file']
u'.../test1.txt'
>>> instance = f.save()
>>> instance.file
u'.../test1.txt'
Delete the current file since this is not done by Django.
>>> os.unlink(instance.get_file_filename())
Override the file by uploading a new one.
>>> f = TextFileForm(data={'description': u'Assistance'}, files={'file': {'filename': 'test2.txt', 'content': 'hello world'}}, instance=instance)
>>> f.is_valid()
True
>>> instance = f.save()
>>> instance.file
u'.../test2.txt'
>>> instance.delete()
Test the non-required FileField
>>> f = TextFileForm(data={'description': u'Assistance'})
>>> f.fields['file'].required = False
>>> f.is_valid()
True
>>> instance = f.save()
>>> instance.file
''
>>> f = TextFileForm(data={'description': u'Assistance'}, files={'file': {'filename': 'test3.txt', 'content': 'hello world'}}, instance=instance)
>>> f.is_valid()
True
>>> instance = f.save()
>>> instance.file
u'.../test3.txt'
>>> instance.delete()
"""} """}

View File

@ -749,32 +749,59 @@ Traceback (most recent call last):
... ...
ValidationError: [u'This field is required.'] ValidationError: [u'This field is required.']
>>> f.clean('', '')
Traceback (most recent call last):
...
ValidationError: [u'This field is required.']
>>> f.clean('', 'files/test1.pdf')
'files/test1.pdf'
>>> f.clean(None) >>> f.clean(None)
Traceback (most recent call last): Traceback (most recent call last):
... ...
ValidationError: [u'This field is required.'] ValidationError: [u'This field is required.']
>>> f.clean(None, '')
Traceback (most recent call last):
...
ValidationError: [u'This field is required.']
>>> f.clean(None, 'files/test2.pdf')
'files/test2.pdf'
>>> f.clean({}) >>> f.clean({})
Traceback (most recent call last): Traceback (most recent call last):
... ...
ValidationError: [u'No file was submitted.'] ValidationError: [u'No file was submitted.']
>>> f.clean({}, '')
Traceback (most recent call last):
...
ValidationError: [u'No file was submitted.']
>>> f.clean({}, 'files/test3.pdf')
'files/test3.pdf'
>>> f.clean('some content that is not a file') >>> f.clean('some content that is not a file')
Traceback (most recent call last): Traceback (most recent call last):
... ...
ValidationError: [u'No file was submitted. Check the encoding type on the form.'] ValidationError: [u'No file was submitted. Check the encoding type on the form.']
>>> f.clean({'filename': 'name', 'content':None}) >>> f.clean({'filename': 'name', 'content': None})
Traceback (most recent call last): Traceback (most recent call last):
... ...
ValidationError: [u'The submitted file is empty.'] ValidationError: [u'The submitted file is empty.']
>>> f.clean({'filename': 'name', 'content':''}) >>> f.clean({'filename': 'name', 'content': ''})
Traceback (most recent call last): Traceback (most recent call last):
... ...
ValidationError: [u'The submitted file is empty.'] ValidationError: [u'The submitted file is empty.']
>>> type(f.clean({'filename': 'name', 'content':'Some File Content'})) >>> type(f.clean({'filename': 'name', 'content': 'Some File Content'}))
<class 'django.newforms.fields.UploadedFile'>
>>> type(f.clean({'filename': 'name', 'content': 'Some File Content'}, 'files/test4.pdf'))
<class 'django.newforms.fields.UploadedFile'> <class 'django.newforms.fields.UploadedFile'>
# URLField ################################################################## # URLField ##################################################################