Fixed #9418 -- When saving a model form, defer saving of file-type fields until after other fields, so that callable upload_to methods can use data from the other fields. Thanks to Bernd Schlapsi for the report and initial patch.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@9334 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
834ca580fc
commit
1515b13d1a
1
AUTHORS
1
AUTHORS
|
@ -344,6 +344,7 @@ answer newbie questions, and generally made Django that much better:
|
||||||
Ivan Sagalaev (Maniac) <http://www.softwaremaniacs.org/>
|
Ivan Sagalaev (Maniac) <http://www.softwaremaniacs.org/>
|
||||||
Vinay Sajip <vinay_sajip@yahoo.co.uk>
|
Vinay Sajip <vinay_sajip@yahoo.co.uk>
|
||||||
David Schein
|
David Schein
|
||||||
|
Bernd Schlapsi
|
||||||
scott@staplefish.com
|
scott@staplefish.com
|
||||||
Ilya Semenov <semenov@inetss.com>
|
Ilya Semenov <semenov@inetss.com>
|
||||||
serbaut@gmail.com
|
serbaut@gmail.com
|
||||||
|
|
|
@ -41,6 +41,7 @@ def save_instance(form, instance, fields=None, fail_message='saved',
|
||||||
raise ValueError("The %s could not be %s because the data didn't"
|
raise ValueError("The %s could not be %s because the data didn't"
|
||||||
" validate." % (opts.object_name, fail_message))
|
" validate." % (opts.object_name, fail_message))
|
||||||
cleaned_data = form.cleaned_data
|
cleaned_data = form.cleaned_data
|
||||||
|
file_field_list = []
|
||||||
for f in opts.fields:
|
for f in opts.fields:
|
||||||
if not f.editable or isinstance(f, models.AutoField) \
|
if not f.editable or isinstance(f, models.AutoField) \
|
||||||
or not f.name in cleaned_data:
|
or not f.name in cleaned_data:
|
||||||
|
@ -49,7 +50,16 @@ def save_instance(form, instance, fields=None, fail_message='saved',
|
||||||
continue
|
continue
|
||||||
if exclude and f.name in exclude:
|
if exclude and f.name in exclude:
|
||||||
continue
|
continue
|
||||||
|
# Defer saving file-type fields until after the other fields, so a
|
||||||
|
# callable upload_to can use the values from other fields.
|
||||||
|
if isinstance(f, models.FileField):
|
||||||
|
file_field_list.append(f)
|
||||||
|
else:
|
||||||
f.save_form_data(instance, cleaned_data[f.name])
|
f.save_form_data(instance, cleaned_data[f.name])
|
||||||
|
|
||||||
|
for f in file_field_list:
|
||||||
|
f.save_form_data(instance, cleaned_data[f.name])
|
||||||
|
|
||||||
# Wrap up the saving of m2m data as a function.
|
# Wrap up the saving of m2m data as a function.
|
||||||
def save_m2m():
|
def save_m2m():
|
||||||
opts = instance._meta
|
opts = instance._meta
|
||||||
|
|
|
@ -99,6 +99,10 @@ class TextFile(models.Model):
|
||||||
return self.description
|
return self.description
|
||||||
|
|
||||||
class ImageFile(models.Model):
|
class ImageFile(models.Model):
|
||||||
|
def custom_upload_path(self, filename):
|
||||||
|
path = self.path or 'tests'
|
||||||
|
return '%s/%s' % (path, filename)
|
||||||
|
|
||||||
description = models.CharField(max_length=20)
|
description = models.CharField(max_length=20)
|
||||||
try:
|
try:
|
||||||
# If PIL is available, try testing PIL.
|
# If PIL is available, try testing PIL.
|
||||||
|
@ -106,9 +110,10 @@ class ImageFile(models.Model):
|
||||||
# for PyPy, you need to check for the underlying modules
|
# for PyPy, you need to check for the underlying modules
|
||||||
# If PIL is not available, this test is equivalent to TextFile above.
|
# If PIL is not available, this test is equivalent to TextFile above.
|
||||||
from PIL import Image, _imaging
|
from PIL import Image, _imaging
|
||||||
image = models.ImageField(storage=temp_storage, upload_to='tests')
|
image = models.ImageField(storage=temp_storage, upload_to=custom_upload_path)
|
||||||
except ImportError:
|
except ImportError:
|
||||||
image = models.FileField(storage=temp_storage, upload_to='tests')
|
image = models.FileField(storage=temp_storage, upload_to=custom_upload_path)
|
||||||
|
path = models.CharField(max_length=16, blank=True, default='')
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return self.description
|
return self.description
|
||||||
|
@ -1122,6 +1127,15 @@ True
|
||||||
<...FieldFile: tests/test3.png>
|
<...FieldFile: tests/test3.png>
|
||||||
>>> instance.delete()
|
>>> instance.delete()
|
||||||
|
|
||||||
|
# Test callable upload_to behavior that's dependent on the value of another field in the model
|
||||||
|
>>> f = ImageFileForm(data={'description': u'And a final one', 'path': 'foo'}, files={'image': SimpleUploadedFile('test4.png', image_data)})
|
||||||
|
>>> f.is_valid()
|
||||||
|
True
|
||||||
|
>>> instance = f.save()
|
||||||
|
>>> instance.image
|
||||||
|
<...FieldFile: foo/test4.png>
|
||||||
|
>>> instance.delete()
|
||||||
|
|
||||||
# Media on a ModelForm ########################################################
|
# Media on a ModelForm ########################################################
|
||||||
|
|
||||||
# Similar to a regular Form class you can define custom media to be used on
|
# Similar to a regular Form class you can define custom media to be used on
|
||||||
|
|
Loading…
Reference in New Issue