diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py
index 527a3c0..c7cb731 100644
a
|
b
|
class Field(object):
|
66 | 66 | u'already exists.'), |
67 | 67 | } |
68 | 68 | |
| 69 | defer_save = False # If true, defer saving until after other fields. |
| 70 | |
69 | 71 | # Generic field type description, usually overriden by subclasses |
70 | 72 | def _description(self): |
71 | 73 | return _(u'Field of type: %(field_type)s') % { |
diff --git a/django/db/models/fields/files.py b/django/db/models/fields/files.py
index 6f1f183..ae4d526 100644
a
|
b
|
class FileDescriptor(object):
|
203 | 203 | def __set__(self, instance, value): |
204 | 204 | instance.__dict__[self.field.name] = value |
205 | 205 | |
| 206 | |
206 | 207 | class FileField(Field): |
207 | 208 | # The class to wrap instance attributes in. Accessing the file object off |
208 | 209 | # the instance will always return an instance of attr_class. |
… |
… |
class FileField(Field):
|
211 | 212 | # The descriptor to use for accessing the attribute off of the class. |
212 | 213 | descriptor_class = FileDescriptor |
213 | 214 | |
| 215 | defer_save = True |
| 216 | |
214 | 217 | description = _("File") |
215 | 218 | |
216 | 219 | def __init__(self, verbose_name=None, name=None, upload_to='', storage=None, **kwargs): |
diff --git a/django/forms/fields.py b/django/forms/fields.py
index 16007e5..21ac628 100644
a
|
b
|
class Field(object):
|
51 | 51 | 'invalid': _(u'Enter a valid value.'), |
52 | 52 | } |
53 | 53 | |
| 54 | # If true, clean() takes initial value as well as data. |
| 55 | clean_takes_initial = False |
| 56 | |
54 | 57 | # Tracks each time a Field instance is created. Used to retain order. |
55 | 58 | creation_counter = 0 |
56 | 59 | |
… |
… |
class FileField(Field):
|
489 | 492 | 'contradiction': _(u'Please either submit a file or check the clear checkbox, not both.') |
490 | 493 | } |
491 | 494 | |
| 495 | clean_takes_initial = True |
| 496 | |
492 | 497 | def __init__(self, *args, **kwargs): |
493 | 498 | self.max_length = kwargs.pop('max_length', None) |
494 | 499 | self.allow_empty_file = kwargs.pop('allow_empty_file', False) |
… |
… |
class MultiValueField(Field):
|
843 | 848 | "compressed" version of those values -- a single value. |
844 | 849 | |
845 | 850 | You'll probably want to use this with MultiWidget. |
| 851 | |
| 852 | If your MultiValueField subclass includes a FileField or derivative as one |
| 853 | of its fields, there will be subtle differences in behavior (particularly |
| 854 | displaying a bound form with initial data) unless you set your subclasses' |
| 855 | ``clean_takes_initial`` attribute to True and override the clean() method |
| 856 | to accept an ``initial`` arg and pass it (or an appropriate part of it) on |
| 857 | to the member FileField. |
846 | 858 | """ |
847 | 859 | default_error_messages = { |
848 | 860 | 'invalid': _(u'Enter a list of values.'), |
diff --git a/django/forms/forms.py b/django/forms/forms.py
index 94eb22d..61d11d1 100644
a
|
b
|
class BaseForm(StrAndUnicode):
|
280 | 280 | # widgets split data over several HTML fields. |
281 | 281 | value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name)) |
282 | 282 | try: |
283 | | if isinstance(field, FileField): |
| 283 | if field.clean_takes_initial: |
284 | 284 | initial = self.initial.get(name, field.initial) |
285 | 285 | value = field.clean(value, initial) |
286 | 286 | else: |
diff --git a/django/forms/models.py b/django/forms/models.py
index cd8f027..d37d393 100644
a
|
b
|
def construct_instance(form, instance, fields=None, exclude=None):
|
34 | 34 | opts = instance._meta |
35 | 35 | |
36 | 36 | cleaned_data = form.cleaned_data |
37 | | file_field_list = [] |
| 37 | deferred_list = [] |
38 | 38 | for f in opts.fields: |
39 | 39 | if not f.editable or isinstance(f, models.AutoField) \ |
40 | 40 | or not f.name in cleaned_data: |
… |
… |
def construct_instance(form, instance, fields=None, exclude=None):
|
45 | 45 | continue |
46 | 46 | # Defer saving file-type fields until after the other fields, so a |
47 | 47 | # callable upload_to can use the values from other fields. |
48 | | if isinstance(f, models.FileField): |
49 | | file_field_list.append(f) |
| 48 | if f.defer_save: |
| 49 | deferred_list.append(f) |
50 | 50 | else: |
51 | 51 | f.save_form_data(instance, cleaned_data[f.name]) |
52 | 52 | |
53 | | for f in file_field_list: |
| 53 | for f in deferred_list: |
54 | 54 | f.save_form_data(instance, cleaned_data[f.name]) |
55 | 55 | |
56 | 56 | return instance |