Changeset 7814
- Timestamp:
- 07/01/08 10:10:51 (2 months ago)
- Files:
-
- django/trunk/AUTHORS (modified) (2 diffs)
- django/trunk/django/conf/global_settings.py (modified) (1 diff)
- django/trunk/django/core/files (added)
- django/trunk/django/core/files/__init__.py (added)
- django/trunk/django/core/files/locks.py (added)
- django/trunk/django/core/files/move.py (added)
- django/trunk/django/core/files/uploadedfile.py (added)
- django/trunk/django/core/files/uploadhandler.py (added)
- django/trunk/django/core/handlers/modpython.py (modified) (1 diff)
- django/trunk/django/core/handlers/wsgi.py (modified) (1 diff)
- django/trunk/django/db/models/base.py (modified) (4 diffs)
- django/trunk/django/db/models/fields/__init__.py (modified) (3 diffs)
- django/trunk/django/http/__init__.py (modified) (3 diffs)
- django/trunk/django/http/multipartparser.py (added)
- django/trunk/django/newforms/fields.py (modified) (4 diffs)
- django/trunk/django/oldforms/__init__.py (modified) (2 diffs)
- django/trunk/django/test/client.py (modified) (3 diffs)
- django/trunk/django/utils/datastructures.py (modified) (1 diff)
- django/trunk/django/utils/text.py (modified) (2 diffs)
- django/trunk/docs/newforms.txt (modified) (1 diff)
- django/trunk/docs/request_response.txt (modified) (1 diff)
- django/trunk/docs/settings.txt (modified) (2 diffs)
- django/trunk/docs/upload_handling.txt (added)
- django/trunk/tests/modeltests/model_forms/models.py (modified) (13 diffs)
- django/trunk/tests/regressiontests/bug639/tests.py (modified) (2 diffs)
- django/trunk/tests/regressiontests/datastructures/tests.py (modified) (1 diff)
- django/trunk/tests/regressiontests/file_uploads (added)
- django/trunk/tests/regressiontests/file_uploads/__init__.py (added)
- django/trunk/tests/regressiontests/file_uploads/models.py (added)
- django/trunk/tests/regressiontests/file_uploads/tests.py (added)
- django/trunk/tests/regressiontests/file_uploads/uploadhandler.py (added)
- django/trunk/tests/regressiontests/file_uploads/urls.py (added)
- django/trunk/tests/regressiontests/file_uploads/views.py (added)
- django/trunk/tests/regressiontests/forms/error_messages.py (modified) (2 diffs)
- django/trunk/tests/regressiontests/forms/fields.py (modified) (3 diffs)
- django/trunk/tests/regressiontests/forms/forms.py (modified) (3 diffs)
- django/trunk/tests/regressiontests/test_client_regress/models.py (modified) (3 diffs)
- django/trunk/tests/regressiontests/test_client_regress/urls.py (modified) (1 diff)
- django/trunk/tests/regressiontests/test_client_regress/views.py (modified) (3 diffs)
- django/trunk/tests/urls.py (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
django/trunk/AUTHORS
r7800 r7814 60 60 av0000@mail.ru 61 61 David Avsajanishvili <avsd05@gmail.com> 62 axiak@mit.edu62 Mike Axiak <axiak@mit.edu> 63 63 Niran Babalola <niran@niran.org> 64 64 Morten Bagai <m@bagai.com> … … 142 142 Szilveszter Farkas <szilveszter.farkas@gmail.com> 143 143 favo@exoweb.net 144 fdr <drfarina@gmail.com> 144 145 Dmitri Fedortchenko <zeraien@gmail.com> 146 Jonathan Feignberg <jdf@pobox.com> 145 147 Liang Feng <hutuworm@gmail.com> 146 148 Bill Fenner <fenner@gmail.com> django/trunk/django/conf/global_settings.py
r7698 r7814 232 232 MEDIA_URL = '' 233 233 234 # List of upload handler classes to be applied in order. 235 FILE_UPLOAD_HANDLERS = ( 236 'django.core.files.uploadhandler.MemoryFileUploadHandler', 237 'django.core.files.uploadhandler.TemporaryFileUploadHandler', 238 ) 239 240 # Maximum size, in bytes, of a request before it will be streamed to the 241 # file system instead of into memory. 242 FILE_UPLOAD_MAX_MEMORY_SIZE = 2621440 # i.e. 2.5 MB 243 244 # Directory in which upload streamed files will be temporarily saved. A value of 245 # `None` will make Django use the operating system's default temporary directory 246 # (i.e. "/tmp" on *nix systems). 247 FILE_UPLOAD_TEMP_DIR = None 248 234 249 # Default formatting for date objects. See all available format strings here: 235 250 # http://www.djangoproject.com/documentation/templates/#now django/trunk/django/core/handlers/modpython.py
r7200 r7814 54 54 "Populates self._post and self._files" 55 55 if 'content-type' in self._req.headers_in and self._req.headers_in['content-type'].startswith('multipart'): 56 self._post, self._files = http.parse_file_upload(self._req.headers_in, self.raw_post_data) 56 self._raw_post_data = '' 57 self._post, self._files = self.parse_file_upload(self.META, self._req) 57 58 else: 58 59 self._post, self._files = http.QueryDict(self.raw_post_data, encoding=self._encoding), datastructures.MultiValueDict() django/trunk/django/core/handlers/wsgi.py
r6826 r7814 113 113 if self.method == 'POST': 114 114 if self.environ.get('CONTENT_TYPE', '').startswith('multipart'): 115 header_dict = dict([(k, v) for k, v in self.environ.items() if k.startswith('HTTP_')]) 116 header_dict['Content-Type'] = self.environ.get('CONTENT_TYPE', '') 117 self._post, self._files = http.parse_file_upload(header_dict, self.raw_post_data) 115 self._raw_post_data = '' 116 self._post, self._files = self.parse_file_upload(self.META, self.environ['wsgi.input']) 118 117 else: 119 118 self._post, self._files = http.QueryDict(self.raw_post_data, encoding=self._encoding), datastructures.MultiValueDict() django/trunk/django/db/models/base.py
r7795 r7814 20 20 from django.utils.functional import curry 21 21 from django.utils.encoding import smart_str, force_unicode, smart_unicode 22 from django.core.files.move import file_move_safe 23 from django.core.files import locks 22 24 from django.conf import settings 23 25 … … 470 472 return os.path.getsize(self._get_FIELD_filename(field)) 471 473 472 def _save_FIELD_file(self, field, filename, raw_ contents, save=True):474 def _save_FIELD_file(self, field, filename, raw_field, save=True): 473 475 directory = field.get_directory_name() 474 476 try: # Create the date-based directory if it doesn't exist. … … 476 478 except OSError: # Directory probably already exists. 477 479 pass 480 481 # 482 # Check for old-style usage (files-as-dictionaries). Warn here first 483 # since there are multiple locations where we need to support both new 484 # and old usage. 485 # 486 if isinstance(raw_field, dict): 487 import warnings 488 warnings.warn( 489 message = "Representing uploaded files as dictionaries is"\ 490 " deprected. Use django.core.files.SimpleUploadedFile"\ 491 " instead.", 492 category = DeprecationWarning, 493 stacklevel = 2 494 ) 495 from django.core.files.uploadedfile import SimpleUploadedFile 496 raw_field = SimpleUploadedFile.from_dict(raw_field) 497 498 elif isinstance(raw_field, basestring): 499 import warnings 500 warnings.warn( 501 message = "Representing uploaded files as strings is "\ 502 " deprecated. Use django.core.files.SimpleUploadedFile "\ 503 " instead.", 504 category = DeprecationWarning, 505 stacklevel = 2 506 ) 507 from django.core.files.uploadedfile import SimpleUploadedFile 508 raw_field = SimpleUploadedFile(filename, raw_field) 509 510 if filename is None: 511 filename = raw_field.file_name 512 478 513 filename = field.get_filename(filename) 479 514 515 # 480 516 # If the filename already exists, keep adding an underscore to the name of 481 517 # the file until the filename doesn't exist. 518 # 482 519 while os.path.exists(os.path.join(settings.MEDIA_ROOT, filename)): 483 520 try: … … 487 524 else: 488 525 filename = filename[:dot_index] + '_' + filename[dot_index:] 489 490 # Write the file to disk. 526 # 527 # Save the file name on the object and write the file to disk 528 # 529 491 530 setattr(self, field.attname, filename) 492 531 493 532 full_filename = self._get_FIELD_filename(field) 494 fp = open(full_filename, 'wb') 495 fp.write(raw_contents) 496 fp.close() 533 534 if hasattr(raw_field, 'temporary_file_path'): 535 # This file has a file path that we can move. 536 raw_field.close() 537 file_move_safe(raw_field.temporary_file_path(), full_filename) 538 539 else: 540 # This is a normal uploadedfile that we can stream. 541 fp = open(full_filename, 'wb') 542 locks.lock(fp, locks.LOCK_EX) 543 for chunk in raw_field.chunk(): 544 fp.write(chunk) 545 locks.unlock(fp) 546 fp.close() 497 547 498 548 # Save the width and/or height, if applicable. django/trunk/django/db/models/fields/__init__.py
r7797 r7814 812 812 setattr(cls, 'get_%s_url' % self.name, curry(cls._get_FIELD_url, field=self)) 813 813 setattr(cls, 'get_%s_size' % self.name, curry(cls._get_FIELD_size, field=self)) 814 setattr(cls, 'save_%s_file' % self.name, lambda instance, filename, raw_ contents, save=True: instance._save_FIELD_file(self, filename, raw_contents, save))814 setattr(cls, 'save_%s_file' % self.name, lambda instance, filename, raw_field, save=True: instance._save_FIELD_file(self, filename, raw_field, save)) 815 815 dispatcher.connect(self.delete_file, signal=signals.post_delete, sender=cls) 816 816 … … 835 835 func = getattr(new_object, 'save_%s_file' % self.name) 836 836 if rel: 837 f unc(new_data[upload_field_name][0]["filename"], new_data[upload_field_name][0]["content"], save)837 file = new_data[upload_field_name][0] 838 838 else: 839 func(new_data[upload_field_name]["filename"], new_data[upload_field_name]["content"], save) 839 file = new_data[upload_field_name] 840 841 # Backwards-compatible support for files-as-dictionaries. 842 # We don't need to raise a warning because Model._save_FIELD_file will 843 # do so for us. 844 try: 845 file_name = file.file_name 846 except AttributeError: 847 file_name = file['filename'] 848 849 func(file_name, file, save) 840 850 841 851 def get_directory_name(self): … … 850 860 from django.newforms.fields import UploadedFile 851 861 if data and isinstance(data, UploadedFile): 852 getattr(instance, "save_%s_file" % self.name)(data.filename, data. content, save=False)862 getattr(instance, "save_%s_file" % self.name)(data.filename, data.data, save=False) 853 863 854 864 def formfield(self, **kwargs): django/trunk/django/http/__init__.py
r7334 r7814 10 10 from cgi import parse_qsl 11 11 12 from django.utils.datastructures import MultiValueDict, FileDict12 from django.utils.datastructures import MultiValueDict, ImmutableList 13 13 from django.utils.encoding import smart_str, iri_to_uri, force_unicode 14 14 from django.http.multipartparser import MultiPartParser 15 from django.conf import settings 16 from django.core.files import uploadhandler 15 17 from utils import * 16 18 17 19 RESERVED_CHARS="!*'();:@&=+$,/?%#[]" 18 19 20 20 21 class Http404(Exception): … … 26 27 # The encoding used in GET/POST dicts. None means use default setting. 27 28 _encoding = None 29 _upload_handlers = [] 28 30 29 31 def __init__(self): … … 103 105 encoding = property(_get_encoding, _set_encoding) 104 106 105 def parse_file_upload(header_dict, post_data): 106 """Returns a tuple of (POST QueryDict, FILES MultiValueDict).""" 107 import email, email.Message 108 from cgi import parse_header 109 raw_message = '\r\n'.join(['%s:%s' % pair for pair in header_dict.items()]) 110 raw_message += '\r\n\r\n' + post_data 111 msg = email.message_from_string(raw_message) 112 POST = QueryDict('', mutable=True) 113 FILES = MultiValueDict() 114 for submessage in msg.get_payload(): 115 if submessage and isinstance(submessage, email.Message.Message): 116 name_dict = parse_header(submessage['Content-Disposition'])[1] 117 # name_dict is something like {'name': 'file', 'filename': 'test.txt'} for file uploads 118 # or {'name': 'blah'} for POST fields 119 # We assume all uploaded files have a 'filename' set. 120 if 'filename' in name_dict: 121 assert type([]) != type(submessage.get_payload()), "Nested MIME messages are not supported" 122 if not name_dict['filename'].strip(): 123 continue 124 # IE submits the full path, so trim everything but the basename. 125 # (We can't use os.path.basename because that uses the server's 126 # directory separator, which may not be the same as the 127 # client's one.) 128 filename = name_dict['filename'][name_dict['filename'].rfind("\\")+1:] 129 FILES.appendlist(name_dict['name'], FileDict({ 130 'filename': filename, 131 'content-type': 'Content-Type' in submessage and submessage['Content-Type'] or None, 132 'content': submessage.get_payload(), 133 })) 134 else: 135 POST.appendlist(name_dict['name'], submessage.get_payload()) 136 return POST, FILES 137 107 def _initialize_handlers(self): 108 self._upload_handlers = [uploadhandler.load_handler(handler, self) 109 for handler in settings.FILE_UPLOAD_HANDLERS] 110 111 def _set_upload_handlers(self, upload_handlers): 112 if hasattr(self, '_files'): 113 raise AttributeError("You cannot set the upload handlers after the upload has been processed.") 114 self._upload_handlers = upload_handlers 115 116 def _get_upload_handlers(self): 117 if not self._upload_handlers: 118 # If thre are no upload handlers defined, initialize them from settings. 119 self._initialize_handlers() 120 return self._upload_handlers 121 122 upload_handlers = property(_get_upload_handlers, _set_upload_handlers) 123 124 def parse_file_upload(self, META, post_data): 125 """Returns a tuple of (POST QueryDict, FILES MultiValueDict).""" 126 self.upload_handlers = ImmutableList( 127 self.upload_handlers, 128 warning = "You cannot alter upload handlers after the upload has been processed." 129 ) 130 parser = MultiPartParser(META, post_data, self.upload_handlers, self.encoding) 131 return parser.parse() 138 132 139 133 class QueryDict(MultiValueDict): django/trunk/django/newforms/fields.py
r7799 r7814 8 8 import re 9 9 import time 10 try: 11 from cStringIO import StringIO 12 except ImportError: 13 from StringIO import StringIO 14 10 15 # Python 2.3 fallbacks 11 16 try: … … 417 422 class UploadedFile(StrAndUnicode): 418 423 "A wrapper for files uploaded in a FileField" 419 def __init__(self, filename, content):424 def __init__(self, filename, data): 420 425 self.filename = filename 421 self. content = content426 self.data = data 422 427 423 428 def __unicode__(self): … … 445 450 elif not data and initial: 446 451 return initial 452 453 if isinstance(data, dict): 454 # We warn once, then support both ways below. 455 import warnings 456 warnings.warn( 457 message = "Representing uploaded files as dictionaries is"\ 458 " deprecated. Use django.core.files.SimpleUploadedFile "\ 459 " instead.", 460 category = DeprecationWarning, 461 stacklevel = 2 462 ) 463 447 464 try: 448 f = UploadedFile(data['filename'], data['content']) 449 except TypeError: 465 file_name = data.file_name 466 file_size = data.file_size 467 except AttributeError: 468 try: 469 file_name = data.get('filename') 470 file_size = bool(data['content']) 471 except (AttributeError, KeyError): 472 raise ValidationError(self.error_messages['invalid']) 473 474 if not file_name: 450 475 raise ValidationError(self.error_messages['invalid']) 451 except KeyError: 452 raise ValidationError(self.error_messages['missing']) 453 if not f.content: 476 if not file_size: 454 477 raise ValidationError(self.error_messages['empty']) 455 return f 478 479 return UploadedFile(file_name, data) 456 480 457 481 class ImageField(FileField): … … 471 495 return initial 472 496 from PIL import Image 473 from cStringIO import StringIO 497 498 # We need to get a file object for PIL. We might have a path or we might 499 # have to read the data into memory. 500 if hasattr(data, 'temporary_file_path'): 501 file = data.temporary_file_path() 502 else: 503 if hasattr(data, 'read'): 504 file = StringIO(data.read()) 505 else: 506 file = StringIO(data['content']) 507 474 508 try: 475 509 # load() is the only method that can spot a truncated JPEG, 476 510 # but it cannot be called sanely after verify() 477 trial_image = Image.open( StringIO(f.content))511 trial_image = Image.open(file) 478 512 trial_image.load() 513 514 # Since we're about to use the file again we have to reset the 515 # file object if possible. 516 if hasattr(file, 'reset'): 517 file.reset() 518 479 519 # verify() is the only method that can spot a corrupt PNG, 480 520 # but it must be called immediately after the constructor 481 trial_image = Image.open( StringIO(f.content))521 trial_image = Image.open(file) 482 522 trial_image.verify() 483 523 except Exception: # Python Imaging Library doesn't recognize it as an image django/trunk/django/oldforms/__init__.py
r6671 r7814 681 681 self.validator_list = [self.isNonEmptyFile] + validator_list 682 682 683 def isNonEmptyFile(self, field_data, all_data): 684 try: 685 content = field_data['content'] 686 except TypeError: 687 raise validators.CriticalValidationError, ugettext("No file was submitted. Check the encoding type on the form.") 688 if not content: 683 def isNonEmptyFile(self, new_data, all_data): 684 if hasattr(new_data, 'upload_errors'): 685 upload_errors = new_data.upload_errors() 686 if upload_errors: 687 raise validators.CriticalValidationError, upload_errors 688 try: 689 file_size = new_data.file_size 690 except AttributeError: 691 file_size = len(new_data['content']) 692 if not file_size: 689 693 raise validators.CriticalValidationError, ugettext("The submitted file is empty.") 690 694 … … 692 696 return mark_safe(u'<input type="file" id="%s" class="v%s" name="%s" />' % \ 693 697 (self.get_id(), self.__class__.__name__, self.field_name)) 698 699 def prepare(self, new_data): 700 if hasattr(new_data, 'upload_errors'): 701 upload_errors = new_data.upload_errors() 702 new_data[self.field_name] = { '_file_upload_error': upload_errors } 694 703 695 704 def html2python(data): django/trunk/django/test/client.py
r7583 r7814 2 2 import sys 3 3 import os 4 from cStringIO import StringIO 4 try: 5 from cStringIO import StringIO 6 except ImportError: 7 from StringIO import StringIO 5 8 from django.conf import settings 6 9 from django.contrib.auth import authenticate, login … … 19 22 BOUNDARY = 'BoUnDaRyStRiNg' 20 23 MULTIPART_CONTENT = 'multipart/form-data; boundary=%s' % BOUNDARY 24 25 class FakePayload(object): 26 """ 27 A wrapper around StringIO that restricts what can be read since data from 28 the network can't be seeked and cannot be read outside of its content 29 length. This makes sure that views can't do anything under the test client 30 that wouldn't work in Real Life. 31 """ 32 def __init__(self, content): 33 self.__content = StringIO(content) 34 self.__len = len(content) 35 36 def read(self, num_bytes=None): 37 if num_bytes is None: 38 num_bytes = self.__len or 1 39 assert self.__len >= num_bytes, "Cannot read more than the available bytes from the HTTP incoming data." 40 content = self.__content.read(num_bytes) 41 self.__len -= num_bytes 42 return content 21 43 22 44 class ClientHandler(BaseHandler): … … 237 259 'PATH_INFO': urllib.unquote(path), 238 260 'REQUEST_METHOD': 'POST', 239 'wsgi.input': StringIO(post_data),261 'wsgi.input': FakePayload(post_data), 240 262 } 241 263 r.update(extra) django/trunk/django/utils/datastructures.py
r7743 r7814 333 333 current = {bits[-1]: v} 334 334 335 class FileDict(dict): 336 """ 337 A dictionary used to hold uploaded file contents. The only special feature 338 here is that repr() of this object won't dump the entire contents of the 339 file to the output. A handy safeguard for a large file upload. 340 """ 341 def __repr__(self): 342 if 'content' in self: 343 d = dict(self, content='<omitted>') 344 return dict.__repr__(d) 345 return dict.__repr__(self) 335 class ImmutableList(tuple): 336 """ 337 A tuple-like object that raises useful errors when it is asked to mutate. 338 339 Example:: 340 341 >>> a = ImmutableList(range(5), warning="You cannot mutate this.") 342 >>> a[3] = '4' 343 Traceback (most recent call last): 344 ... 345 AttributeError: You cannot mutate this. 346 """ 347 348 def __new__(cls, *args, **kwargs): 349 if 'warning' in kwargs: 350 warning = kwargs['warning'] 351 del kwargs['warning'] 352 else: 353 warning = 'ImmutableList object is immutable.' 354 self = tuple.__new__(cls, *args, **kwargs) 355 self.warning = warning 356 return self 357 358 def complain(self, *wargs, **kwargs): 359 if isinstance(self.warning, Exception): 360 raise self.warning 361 else: 362 raise AttributeError, self.warning 363 364 # All list mutation functions complain. 365 __delitem__ = complain 366 __delslice__ = complain 367 __iadd__ = complain 368 __imul__ = complain 369 __setitem__ = complain 370 __setslice__ = complain 371 append = complain 372 extend = complain 373 insert = complain 374 pop = complain 375 remove = complain 376 sort = complain 377 reverse = complain 346 378 347 379 class DictWrapper(dict): django/trunk/django/utils/text.py
r7581 r7814 4 4 from django.utils.functional import allow_lazy 5 5 from django.utils.translation import ugettext_lazy 6 from htmlentitydefs import name2codepoint 6 7 7 8 # Capitalizes the first letter of a string. … … 223 224 smart_split = allow_lazy(smart_split, unicode) 224 225 226 def _replace_entity(match): 227 text = match.group(1) 228 if text[0] == u'#': 229 text = text[1:] 230 try: 231 if text[0] in u'xX': 232 c = int(text[1:], 16) 233 else: 234 c = int(text) 235 return unichr(c) 236 except ValueError: 237 return match.group(0) 238 else: 239 try: 240 return unichr(name2codepoint[text]) 241 except (ValueError, KeyError): 242 return match.group(0) 243 244 _entity_re = re.compile(r"&(#?[xX]?(?:[0-9a-fA-F]+|\w{1,8}));") 245 246 def unescape_entities(text): 247 return _entity_re.sub(_replace_entity, text) 248 unescape_entities = allow_lazy(unescape_entities, unicode) django/trunk/docs/newforms.txt
r7677 r7814 806 806 807 807 # Bound form with an image field 808 >>> from django.core.files.uploadedfile import SimpleUploadedFile 808 809 >>> data = {'subject': 'hello', 809 810 ... 'message': 'Hi there', 810 811 ... 'sender': 'foo@example.com', 811 812 ... 'cc_myself': True} 812 >>> file_data = {'mugshot': {'filename':'face.jpg' 813 ... 'content': <file data>}} 813 >>> file_data = {'mugshot': SimpleUploadedFile('face.jpg', <file data>)} 814 814 >>> f = ContactFormWithMugshot(data, file_data) 815 815 django/trunk/docs/request_response.txt
r7510 r7814 81 81 82 82 ``FILES`` 83 84 .. admonition:: Changed in Django development version 85 86 In previous versions of Django, ``request.FILES`` contained 87 simple ``dict`` objects representing uploaded files. This is 88 no longer true -- files are represented by ``UploadedFile`` 89 objects as described below. 90 91 These ``UploadedFile`` objects will emulate the old-style ``dict`` 92 interface, but this is deprecated and will be removed in the next 93 release of Django. 94 83 95 A dictionary-like object containing all uploaded files. Each key in 84 96 ``FILES`` is the ``name`` from the ``<input type="file" name="" />``. Each 85 value in ``FILES`` is a standard Python dictionary with the following three 86 keys: 87 88 * ``filename`` -- The name of the uploaded file, as a Python string. 89 * ``content-type`` -- The content type of the uploaded file. 90 * ``content`` -- The raw content of the uploaded file. 91 97 value in ``FILES`` is an ``UploadedFile`` object containing the following 98 attributes: 99 100 * ``read(num_bytes=None)`` -- Read a number of bytes from the file. 101 * ``file_name`` -- The name of the uploaded file. 102 * ``file_size`` -- The size, in bytes, of the uploaded file. 103 * ``chunk()`` -- A generator that yields sequential chunks of data. 104 105 See `File Uploads`_ for more information. 106 92 107 Note that ``FILES`` will only contain data if the request method was POST 93 108 and the ``<form>`` that posted to the request had 94 109 ``enctype="multipart/form-data"``. Otherwise, ``FILES`` will be a blank 95 110 dictionary-like object. 111 112 .. _File Uploads: ../upload_handling/ 96 113 97 114 ``META`` django/trunk/docs/settings.txt
r7702 r7814 280 280 The database backend to use. The build-in database backends are 281 281 ``'postgresql_psycopg2'``, ``'postgresql'``, ``'mysql'``, ``'mysql_old'``, 282 ``'sqlite3'`` and ``'oracle'``.282 ``'sqlite3'``, ``'oracle'``, and ``'oracle'``. 283 283 284 284 In the Django development version, you can use a database backend that doesn't … … 530 530 The character encoding used to decode any files read from disk. This includes 531 531 template files and initial SQL data files. 532 533 FILE_UPLOAD_HANDLERS 534 -------------------- 535 536 **New in Django development version** 537 538 Default:: 539 540 ("django.core.files.fileuploadhandler.MemoryFileUploadHandler", 541 "django.core.files.fileuploadhandler.TemporaryFileUploadHandler",) 542 543 A tuple of handlers to use for uploading. See `file uploads`_ for details. 544 545 .. _file uploads: ../upload_handling/ 546 547 FILE_UPLOAD_MAX_MEMORY_SIZE 548 --------------------------- 549 550 **New in Django development version** 551 552 Default: ``2621440`` (i.e. 2.5 MB). 553 554 The maximum size (in bytes) that an upload will be before it gets streamed to 555 the file system. See `file uploads`_ for details. 556 557 FILE_UPLOAD_TEMP_DIR 558 -------------------- 559 560 **New in Django development version** 561 562 Default: ``None`` 563 564 The directory to store data temporarily while uploading files. If ``None``, 565 Django will use the standard temporary directory for the operating system. For 566 example, this will default to '/tmp' on *nix-style operating systems. 567 568 See `file uploads`_ for details. 532 569 533 570 FIXTURE_DIRS django/trunk/tests/modeltests/model_forms/models.py
r7335 r7814 68 68 class ImageFile(models.Model): 69 69 description = models.CharField(max_length=20) 70 image = models.FileField(upload_to=tempfile.gettempdir()) 70 try: 71 # If PIL is available, try testing PIL. 72 # Otherwise, it's equivalent to TextFile above. 73 import Image 74 image = models.ImageField(upload_to=tempfile.gettempdir()) 75 except ImportError: 76 image = models.FileField(upload_to=tempfile.gettempdir()) 71 77 72 78 def __unicode__(self): … … 76 82 >>> from django import newforms as forms 77 83 >>> from django.newforms.models import ModelForm 84 >>> from django.core.files.uploadedfile import SimpleUploadedFile 78 85 79 86 The bare bones, absolutely nothing custom, basic case. … … 793 800 # Upload a file and ensure it all works as expected. 794 801 795 >>> f = TextFileForm(data={'description': u'Assistance'}, files={'file': {'filename': 'test1.txt', 'content': 'hello world'}})802 >>> f = TextFileForm(data={'description': u'Assistance'}, files={'file': SimpleUploadedFile('test1.txt', 'hello world')}) 796 803 >>> f.is_valid() 797 804 True … … 802 809 u'...test1.txt' 803 810 811 >>> os.unlink(instance.get_file_filename()) 812 813 >>> f = TextFileForm(data={'description': u'Assistance'}, files={'file': SimpleUploadedFile('test1.txt', 'hello world')}) 814 >>> f.is_valid() 815 True 816 >>> type(f.cleaned_data['file']) 817 <class 'django.newforms.fields.UploadedFile'> 818 >>> instance = f.save() 819 >>> instance.file 820 u'...test1.txt' 821 804 822 # Edit an instance that already has the file defined in the model. This will not 805 823 # save the file again, but leave it exactly as it is. … … 815 833 816 834 # Delete the current file since this is not done by Django. 817 818 835 >>> os.unlink(instance.get_file_filename()) 819 836 820 837 # Override the file by uploading a new one. 821 838 822 >>> f = TextFileForm(data={'description': u'Assistance'}, files={'file': {'filename': 'test2.txt', 'content': 'hello world'}}, instance=instance)839 >>> f = TextFileForm(data={'description': u'Assistance'}, files={'file': SimpleUploadedFile('test2.txt', 'hello world')}, instance=instance) 823 840 >>> f.is_valid() 824 841 True … … 827 844 u'...test2.txt' 828 845 846 # Delete the current file since this is not done by Django. 847 >>> os.unlink(instance.get_file_filename()) 848 849 >>> f = TextFileForm(data={'description': u'Assistance'}, files={'file': SimpleUploadedFile('test2.txt', 'hello world')}) 850 >>> f.is_valid() 851 True 852 >>> instance = f.save() 853 >>> instance.file 854 u'...test2.txt' 855 856 # Delete the current file since this is not done by Django. 857 >>> os.unlink(instance.get_file_filename()) 858 829 859 >>> instance.delete() 830 860 … … 839 869 '' 840 870 841 >>> f = TextFileForm(data={'description': u'Assistance'}, files={'file': {'filename': 'test3.txt', 'content': 'hello world'}}, instance=instance)871 >>> f = TextFileForm(data={'description': u'Assistance'}, files={'file': SimpleUploadedFile('test3.txt', 'hello world')}, instance=instance) 842 872 >>> f.is_valid() 843 873 True … … 845 875 >>> instance.file 846 876 u'...test3.txt' 877 878 # Delete the current file since this is not done by Django. 879 >>> os.unlink(instance.get_file_filename()) 880 >>> instance.delete() 881 882 >>> f = TextFileForm(data={'description': u'Assistance'}, files={'file': SimpleUploadedFile('test3.txt', 'hello world')}) 883 >>> f.is_valid() 884 True 885 >>> instance = f.save() 886 >>> instance.file 887 u'...test3.txt' 888 889 # Delete the current file since this is not done by Django. 890 >>> os.unlink(instance.get_file_filename()) 847 891 >>> instance.delete() 848 892 … … 859 903 >>> image_data = open(os.path.join(os.path.dirname(__file__), "test.png")).read() 860 904 861 >>> f = ImageFileForm(data={'description': u'An image'}, files={'image': {'filename': 'test.png', 'content': image_data}})905 >>> f = ImageFileForm(data={'description': u'An image'}, files={'image': SimpleUploadedFile('test.png', image_data)}) 862 906 >>> f.is_valid() 863 907 True … … 868 912 u'...test.png' 869 913 914 # Delete the current file since this is not done by Django. 915 >>> os.unlink(instance.get_image_filename()) 916 917 >>> f = ImageFileForm(data={'description': u'An image'}, files={'image': SimpleUploadedFile('test.png', image_data)}) 918 >>> f.is_valid() 919 True 920 >>> type(f.cleaned_data['image']) 921 <class 'django.newforms.fields.UploadedFile'> 922 >>> instance = f.save() 923 >>> instance.image 924 u'...test.png' 925 870 926 # Edit an instance that already has the image defined in the model. This will not 871 927 # save the image again, but leave it exactly as it is. … … 886 942 # Override the file by uploading a new one. 887 943 888 >>> f = ImageFileForm(data={'description': u'Changed it'}, files={'image': {'filename': 'test2.png', 'content': image_data}}, instance=instance)944 >>> f = ImageFileForm(data={'description': u'Changed it'}, files={'image': SimpleUploadedFile('test2.png', image_data)}, instance=instance) 889 945 >>> f.is_valid() 890 946 True … … 893 949 u'...test2.png' 894 950 951 # Delete the current file since this is not done by Django. 952 >>> os.unlink(instance.get_image_filename()) 953 >>> instance.delete() 954 955 >>> f = ImageFileForm(data={'description': u'Changed it'}, files={'image': SimpleUploadedFile('test2.png', image_data)}) 956 >>> f.is_valid() 957 True 958 >>> instance = f.save() 959 >>> instance.image 960 u'...test2.png' 961 962 # Delete the current file since this is not done by Django. 963 >>> os.unlink(instance.get_image_filename()) 895 964 >>> instance.delete() 896 965 … … 905 974 '' 906 975 907 >>> f = ImageFileForm(data={'description': u'And a final one'}, files={'image': {'filename': 'test3.png', 'content': image_data}}, instance=instance) 976 >>> f = ImageFileForm(data={'description': u'And a final one'}, files={'image': SimpleUploadedFile('test3.png', image_data)}, instance=instance) 977 >>> f.is_valid()&nbs
