Ticket #7614: 7814_cleanups.diff
File 7814_cleanups.diff, 25.5 KB (added by , 16 years ago) |
---|
-
django/db/models/base.py
536 536 # This is a normal uploadedfile that we can stream. 537 537 fp = open(full_filename, 'wb') 538 538 locks.lock(fp, locks.LOCK_EX) 539 for chunk in raw_field.chunk ():539 for chunk in raw_field.chunks(): 540 540 fp.write(chunk) 541 541 locks.unlock(fp) 542 542 fp.close() -
django/db/models/fields/__init__.py
766 766 def get_db_prep_save(self, value): 767 767 "Returns field's value prepared for saving into a database." 768 768 # Need to convert UploadedFile objects provided via a form to unicode for database insertion 769 if value is None: 769 if hasattr(value, 'name'): 770 return value.name 771 elif value is None: 770 772 return None 771 return unicode(value) 773 else: 774 return unicode(value) 772 775 773 776 def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True): 774 777 field_list = Field.get_manipulator_fields(self, opts, manipulator, change, name_prefix, rel, follow) … … 842 845 # We don't need to raise a warning because Model._save_FIELD_file will 843 846 # do so for us. 844 847 try: 845 file_name = file. file_name848 file_name = file.name 846 849 except AttributeError: 847 850 file_name = file['filename'] 848 851 … … 857 860 return os.path.normpath(f) 858 861 859 862 def save_form_data(self, instance, data): 860 from django. newforms.fieldsimport UploadedFile863 from django.core.files.uploadedfile import UploadedFile 861 864 if data and isinstance(data, UploadedFile): 862 getattr(instance, "save_%s_file" % self.name)(data. filename, data.data, save=False)865 getattr(instance, "save_%s_file" % self.name)(data.name, data, save=False) 863 866 864 867 def formfield(self, **kwargs): 865 868 defaults = {'form_class': forms.FileField} -
django/oldforms/__init__.py
686 686 if upload_errors: 687 687 raise validators.CriticalValidationError, upload_errors 688 688 try: 689 file_size = new_data. file_size689 file_size = new_data.size 690 690 except AttributeError: 691 691 file_size = len(new_data['content']) 692 692 if not file_size: -
django/core/files/uploadedfile.py
3 3 """ 4 4 5 5 import os 6 import tempfile 7 import warnings 6 8 try: 7 9 from cStringIO import StringIO 8 10 except ImportError: 9 11 from StringIO import StringIO 10 12 11 __all__ = ('UploadedFile', 'TemporaryUploadedFile', 'InMemoryUploadedFile') 13 from django.conf import settings 12 14 15 16 __all__ = ('UploadedFile', 'TemporaryUploadedFile', 'InMemoryUploadedFile', 'SimpleUploadedFile') 17 13 18 class UploadedFile(object): 14 19 """ 15 20 A abstract uploaded file (``TemporaryUploadedFile`` and … … 20 25 """ 21 26 DEFAULT_CHUNK_SIZE = 64 * 2**10 22 27 23 def __init__(self, file_name=None, content_type=None, file_size=None, charset=None):24 self. file_name = file_name25 self. file_size = file_size28 def __init__(self, name=None, content_type=None, size=None, charset=None): 29 self.name = name 30 self.size = size 26 31 self.content_type = content_type 27 32 self.charset = charset 28 33 29 34 def __repr__(self): 30 return "<%s: %s (%s)>" % (self.__class__.__name__, self. file_name, self.content_type)35 return "<%s: %s (%s)>" % (self.__class__.__name__, self.name, self.content_type) 31 36 32 def _set_file_name(self, name): 37 def _get_name(self): 38 return self._name 39 40 def _set_name(self, name): 33 41 # Sanitize the file name so that it can't be dangerous. 34 42 if name is not None: 35 43 # Just use the basename of the file -- anything else is dangerous. 36 44 name = os.path.basename(name) 37 45 38 46 # File names longer than 255 characters can cause problems on older OSes. 39 47 if len(name) > 255: 40 48 name, ext = os.path.splitext(name) 41 49 name = name[:255 - len(ext)] + ext 42 43 self._file_name = name 44 50 51 self._name = name 52 53 name = property(_get_name, _set_name) 54 55 45 56 def _get_file_name(self): 46 return self._file_name 47 48 file_name = property(_get_file_name, _set_file_name) 57 warnings.warn( 58 message = "To access the file name, please use the .name attribute.", 59 category = DeprecationWarning, 60 stacklevel = 2 61 ) 62 return self.name 49 63 50 def chunk(self, chunk_size=None): 64 def _set_file_name(self, name): 65 warnings.warn( 66 message = "To access the file name, please use the .name attribute.", 67 category = DeprecationWarning, 68 stacklevel = 2 69 ) 70 self.name = name 71 72 file_name = filename = property(_get_file_name, _set_file_name) 73 74 75 def _get_file_size(self): 76 warnings.warn( 77 message = "To access the file size, please use the .size attribute.", 78 category = DeprecationWarning, 79 stacklevel = 2 80 ) 81 return self.size 82 83 def _set_file_size(self, size): 84 warnings.warn( 85 message = "To access the file size, please use the .size attribute.", 86 category = DeprecationWarning, 87 stacklevel = 2 88 ) 89 self.size = size 90 91 file_size = property(_get_file_size, _set_file_size) 92 93 94 def _get_data(self): 95 warnings.warn( 96 message = "To access the data, please use the new UploadedFile API.", 97 category = DeprecationWarning, 98 stacklevel = 2 99 ) 100 data = self.read() 101 if hasattr(self, 'seek'): 102 self.seek(0) 103 return data 104 105 data = property(_get_data) 106 107 108 def chunks(self, chunk_size=None): 51 109 """ 52 110 Read the file and yield chucks of ``chunk_size`` bytes (defaults to 53 111 ``UploadedFile.DEFAULT_CHUNK_SIZE``). … … 58 116 if hasattr(self, 'seek'): 59 117 self.seek(0) 60 118 # Assume the pointer is at zero... 61 counter = self. file_size119 counter = self.size 62 120 63 121 while counter > 0: 64 122 yield self.read(chunk_size) 65 123 counter -= chunk_size 66 124 125 def chunk(self, *args, **kwargs): 126 warnings.warn( 127 message = "Please use .chunks() instead of .chunk().", 128 category = DeprecationWarning, 129 stacklevel = 2 130 ) 131 for chunk in self.chunks(): 132 yield chunk 133 67 134 def multiple_chunks(self, chunk_size=None): 68 135 """ 69 136 Returns ``True`` if you can expect multiple chunks. … … 74 141 """ 75 142 if not chunk_size: 76 143 chunk_size = UploadedFile.DEFAULT_CHUNK_SIZE 77 return self. file_size <chunk_size144 return self.size > chunk_size 78 145 79 # Abstract methods; subclasses *must* def aultread() and probably should146 # Abstract methods; subclasses *must* define read() and probably should 80 147 # define open/close. 81 148 def read(self, num_bytes=None): 82 149 raise NotImplementedError() … … 87 154 def close(self): 88 155 pass 89 156 157 def xreadlines(self): 158 return self 159 160 def readlines(self): 161 return list(self.xreadlines()) 162 163 def __iter__(self): 164 # Iterate over this file-like object by newlines 165 buffer_ = None 166 for chunk in self.chunks(): 167 chunk_buffer = StringIO(chunk) 168 169 for line in chunk_buffer: 170 if buffer_: 171 line = buffer_ + line 172 buffer_ = None 173 174 # If this is the end of a line, yield 175 # otherwise, wait for the next round 176 if line[-1] in ('\n', '\r'): 177 yield line 178 else: 179 buffer_ = line 180 181 if buffer_ is not None: 182 yield buffer_ 183 90 184 # Backwards-compatible support for uploaded-files-as-dictionaries. 91 185 def __getitem__(self, key): 92 import warnings93 186 warnings.warn( 94 187 message = "The dictionary access of uploaded file objects is deprecated. Use the new object interface instead.", 95 188 category = DeprecationWarning, 96 189 stacklevel = 2 97 190 ) 98 191 backwards_translate = { 99 'filename': ' file_name',192 'filename': 'name', 100 193 'content-type': 'content_type', 101 194 } 102 195 103 196 if key == 'content': 104 197 return self.read() 105 198 elif key == 'filename': 106 return self. file_name199 return self.name 107 200 elif key == 'content-type': 108 201 return self.content_type 109 202 else: 110 203 return getattr(self, key) 111 204 205 206 def _proxy_to_file(method_name): 207 # Function factory to build proxy methods for the _file object. 208 def __inner_function(self, *args, **kwargs): 209 return getattr(self._file, method_name)(*args, **kwargs) 210 __inner_function.__name__ = method_name 211 return __inner_function 212 213 112 214 class TemporaryUploadedFile(UploadedFile): 113 215 """ 114 216 A file uploaded to a temporary location (i.e. stream-to-disk). 115 217 """ 218 def __init__(self, name, content_type, size, charset): 219 super(TemporaryUploadedFile, self).__init__(name, content_type, size, charset) 220 if settings.FILE_UPLOAD_TEMP_DIR: 221 self._file = tempfile.NamedTemporaryFile(suffix='.upload', dir=settings.FILE_UPLOAD_TEMP_DIR) 222 else: 223 self._file = tempfile.NamedTemporaryFile(suffix='.upload') 116 224 117 def __init__(self, file, file_name, content_type, file_size, charset):118 super(TemporaryUploadedFile, self).__init__(file_name, content_type, file_size, charset)119 self.file = file120 self.path = file.name121 self.file.seek(0)122 123 225 def temporary_file_path(self): 124 226 """ 125 227 Returns the full path of this file. 126 228 """ 127 return self. path229 return self.name 128 230 129 def read(self, *args, **kwargs): 130 return self.file.read(*args, **kwargs) 231 # Functions from the local file object 232 read = _proxy_to_file('read') 233 seek = _proxy_to_file('seek') 234 write = _proxy_to_file('write') 235 close = _proxy_to_file('close') 236 __iter__ = _proxy_to_file('__iter__') 237 readlines = _proxy_to_file('readlines') 238 xreadlines = _proxy_to_file('xreadlines') 131 239 132 def open(self):133 self.seek(0)134 240 135 def seek(self, *args, **kwargs):136 self.file.seek(*args, **kwargs)137 138 241 class InMemoryUploadedFile(UploadedFile): 139 242 """ 140 243 A file uploaded into memory (i.e. stream-to-memory). 141 244 """ 142 def __init__(self, file, field_name, file_name, content_type, file_size, charset):143 super(InMemoryUploadedFile, self).__init__( file_name, content_type, file_size, charset)245 def __init__(self, file, field_name, name, content_type, size, charset): 246 super(InMemoryUploadedFile, self).__init__(name, content_type, size, charset) 144 247 self.file = file 145 248 self.field_name = field_name 146 249 self.file.seek(0) … … 154 257 def read(self, *args, **kwargs): 155 258 return self.file.read(*args, **kwargs) 156 259 157 def chunk (self, chunk_size=None):260 def chunks(self, chunk_size=None): 158 261 self.file.seek(0) 159 262 yield self.read() 160 263 … … 168 271 """ 169 272 def __init__(self, name, content, content_type='text/plain'): 170 273 self.file = StringIO(content or '') 171 self. file_name = name274 self.name = name 172 275 self.field_name = None 173 self. file_size = len(content or '')276 self.size = len(content or '') 174 277 self.content_type = content_type 175 278 self.charset = None 176 279 self.file.seek(0) -
django/core/files/uploadhandler.py
132 132 Create the file object to append to as data is coming in. 133 133 """ 134 134 super(TemporaryFileUploadHandler, self).new_file(file_name, *args, **kwargs) 135 self.file = TemporaryFile(settings.FILE_UPLOAD_TEMP_DIR) 136 self.write = self.file.write 135 self.file = TemporaryUploadedFile(self.file_name, self.content_type, 0, self.charset) 137 136 138 137 def receive_data_chunk(self, raw_data, start): 139 self. write(raw_data)138 self.file.write(raw_data) 140 139 141 140 def file_complete(self, file_size): 142 141 self.file.seek(0) 143 return TemporaryUploadedFile( 144 file = self.file, 145 file_name = self.file_name, 146 content_type = self.content_type, 147 file_size = file_size, 148 charset = self.charset 149 ) 142 self.file.size = file_size 143 return self.file 150 144 151 145 class MemoryFileUploadHandler(FileUploadHandler): 152 146 """ … … 189 183 return InMemoryUploadedFile( 190 184 file = self.file, 191 185 field_name = self.field_name, 192 file_name = self.file_name,186 name = self.file_name, 193 187 content_type = self.content_type, 194 file_size = file_size,188 size = file_size, 195 189 charset = self.charset 196 190 ) 197 191 198 class TemporaryFile(object):199 """200 A temporary file that tries to delete itself when garbage collected.201 """202 def __init__(self, dir):203 if not dir:204 dir = tempfile.gettempdir()205 try:206 (fd, name) = tempfile.mkstemp(suffix='.upload', dir=dir)207 self.file = os.fdopen(fd, 'w+b')208 except (OSError, IOError):209 raise OSError("Could not create temporary file for uploading, have you set settings.FILE_UPLOAD_TEMP_DIR correctly?")210 self.name = name211 192 212 def __getattr__(self, name):213 a = getattr(self.__dict__['file'], name)214 if type(a) != type(0):215 setattr(self, name, a)216 return a217 218 def __del__(self):219 try:220 os.unlink(self.name)221 except OSError:222 pass223 224 193 def load_handler(path, *args, **kwargs): 225 194 """ 226 195 Given a path to a handler, return an instance of that handler. -
django/newforms/fields.py
27 27 28 28 from util import ErrorList, ValidationError 29 29 from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, FileInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple, DateTimeInput 30 from django.core.files.uploadedfile import SimpleUploadedFile as UploadedFile 30 31 31 32 32 __all__ = ( 33 33 'Field', 'CharField', 'IntegerField', 34 34 'DEFAULT_DATE_INPUT_FORMATS', 'DateField', … … 419 419 # It's OK if Django settings aren't configured. 420 420 URL_VALIDATOR_USER_AGENT = 'Django (http://www.djangoproject.com/)' 421 421 422 class UploadedFile(StrAndUnicode):423 "A wrapper for files uploaded in a FileField"424 def __init__(self, filename, data):425 self.filename = filename426 self.data = data427 422 428 def __unicode__(self):429 """430 The unicode representation is the filename, so that the pre-database-insertion431 logic can use UploadedFile objects432 """433 return self.filename434 435 423 class FileField(Field): 436 424 widget = FileInput 437 425 default_error_messages = { … … 460 448 category = DeprecationWarning, 461 449 stacklevel = 2 462 450 ) 451 data = UploadedFile(data['filename'], data['content']) 463 452 464 453 try: 465 file_name = data. file_name466 file_size = data. file_size454 file_name = data.name 455 file_size = data.size 467 456 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']) 457 raise ValidationError(self.error_messages['invalid']) 473 458 474 459 if not file_name: 475 460 raise ValidationError(self.error_messages['invalid']) 476 461 if not file_size: 477 462 raise ValidationError(self.error_messages['empty']) 478 463 479 return UploadedFile(file_name, data)464 return data 480 465 481 466 class ImageField(FileField): 482 467 default_error_messages = { -
tests/modeltests/model_forms/models.py
803 803 >>> f.is_valid() 804 804 True 805 805 >>> type(f.cleaned_data['file']) 806 <class 'django. newforms.fields.UploadedFile'>806 <class 'django.core.files.uploadedfile.SimpleUploadedFile'> 807 807 >>> instance = f.save() 808 808 >>> instance.file 809 809 u'...test1.txt' … … 814 814 >>> f.is_valid() 815 815 True 816 816 >>> type(f.cleaned_data['file']) 817 <class 'django. newforms.fields.UploadedFile'>817 <class 'django.core.files.uploadedfile.SimpleUploadedFile'> 818 818 >>> instance = f.save() 819 819 >>> instance.file 820 820 u'...test1.txt' … … 906 906 >>> f.is_valid() 907 907 True 908 908 >>> type(f.cleaned_data['image']) 909 <class 'django. newforms.fields.UploadedFile'>909 <class 'django.core.files.uploadedfile.SimpleUploadedFile'> 910 910 >>> instance = f.save() 911 911 >>> instance.image 912 912 u'...test.png' … … 918 918 >>> f.is_valid() 919 919 True 920 920 >>> type(f.cleaned_data['image']) 921 <class 'django. newforms.fields.UploadedFile'>921 <class 'django.core.files.uploadedfile.SimpleUploadedFile'> 922 922 >>> instance = f.save() 923 923 >>> instance.image 924 924 u'...test.png' -
tests/regressiontests/forms/fields.py
800 800 ValidationError: [u'The submitted file is empty.'] 801 801 802 802 >>> type(f.clean(SimpleUploadedFile('name', 'Some File Content'))) 803 <class 'django. newforms.fields.UploadedFile'>803 <class 'django.core.files.uploadedfile.SimpleUploadedFile'> 804 804 805 805 >>> type(f.clean(SimpleUploadedFile('name', 'Some File Content'), 'files/test4.pdf')) 806 <class 'django. newforms.fields.UploadedFile'>806 <class 'django.core.files.uploadedfile.SimpleUploadedFile'> 807 807 808 808 # URLField ################################################################## 809 809 -
docs/upload_handling.txt
22 22 class UploadFileForm(forms.Form): 23 23 title = forms.CharField(max_length=50) 24 24 file = forms.FileField() 25 25 26 26 A view handling this form will receive the file data in ``request.FILES``, which 27 27 is a dictionary containing a key for each ``FileField`` (or ``ImageField``, or 28 28 other ``FileField`` subclass) in the form. So the data from the above form would … … 64 64 ``UploadedFile.read()`` 65 65 Read the entire uploaded data from the file. Be careful with this 66 66 method: if the uploaded file is huge it can overwhelm your system if you 67 try to read it into memory. You'll probably want to use ``chunk ()``67 try to read it into memory. You'll probably want to use ``chunks()`` 68 68 instead; see below. 69 69 70 70 ``UploadedFile.multiple_chunks()`` 71 71 Returns ``True`` if the uploaded file is big enough to require 72 72 reading in multiple chunks. By default this will be any file 73 73 larger than 2.5 megabytes, but that's configurable; see below. 74 74 75 75 ``UploadedFile.chunk()`` 76 76 A generator returning chunks of the file. If ``multiple_chunks()`` is 77 77 ``True``, you should use this method in a loop instead of ``read()``. 78 78 79 79 In practice, it's often easiest simply to use ``chunks()`` all the time; 80 80 see the example below. 81 81 82 82 ``UploadedFile.file_name`` 83 83 The name of the uploaded file (e.g. ``my_file.txt``). 84 84 85 85 ``UploadedFile.file_size`` 86 86 The size, in bytes, of the uploaded file. 87 87 88 88 There are a few other methods and attributes available on ``UploadedFile`` 89 89 objects; see `UploadedFile objects`_ for a complete reference. 90 90 91 91 Putting it all together, here's a common way you might handle an uploaded file:: 92 92 93 93 def handle_uploaded_file(f): 94 94 destination = open('some/file/name.txt', 'wb') 95 95 for chunk in f.chunks(): … … 126 126 The maximum size, in bytes, for files that will be uploaded 127 127 into memory. Files larger than ``FILE_UPLOAD_MAX_MEMORY_SIZE`` 128 128 will be streamed to disk. 129 129 130 130 Defaults to 2.5 megabytes. 131 131 132 132 ``FILE_UPLOAD_TEMP_DIR`` 133 133 The directory where uploaded files larger than ``FILE_UPLOAD_TEMP_DIR`` 134 134 will be stored. 135 135 136 136 Defaults to your system's standard temporary directory (i.e. ``/tmp`` on 137 137 most Unix-like systems). 138 138 139 139 ``FILE_UPLOAD_HANDLERS`` 140 140 The actual handlers for uploaded files. Changing this setting 141 141 allows complete customization -- even replacement -- of 142 142 Django's upload process. See `upload handlers`_, below, 143 143 for details. 144 144 145 145 Defaults to:: 146 146 147 147 ("django.core.files.uploadhandler.MemoryFileUploadHandler", 148 148 "django.core.files.uploadhandler.TemporaryFileUploadHandler",) 149 149 150 150 Which means "try to upload to memory first, then fall back to temporary 151 151 files." 152 152 … … 161 161 Returns a byte string of length ``num_bytes``, or the complete file if 162 162 ``num_bytes`` is ``None``. 163 163 164 ``UploadedFile.chunk (self, chunk_size=None)``164 ``UploadedFile.chunks(self, chunk_size=None)`` 165 165 A generator yielding small chunks from the file. If ``chunk_size`` isn't 166 given, chunks will be 64 kb.166 given, chunks will be 64 KB. 167 167 168 168 ``UploadedFile.multiple_chunks(self, chunk_size=None)`` 169 169 Returns ``True`` if you can expect more than one chunk when calling 170 ``UploadedFile.chunk (self, chunk_size)``.170 ``UploadedFile.chunks(self, chunk_size)``. 171 171 172 172 ``UploadedFile.file_size`` 173 173 The size, in bytes, of the uploaded file. 174 174 175 175 ``UploadedFile.file_name`` 176 176 The name of the uploaded file as provided by the user. 177 177 178 178 ``UploadedFile.content_type`` 179 179 The content-type header uploaded with the file (e.g. ``text/plain`` or 180 180 ``application/pdf``). Like any data supplied by the user, you shouldn't 181 181 trust that the uploaded file is actually this type. You'll still need to 182 182 validate that the file contains the content that the content-type header 183 183 claims -- "trust but verify." 184 184 185 185 ``UploadedFile.charset`` 186 186 For ``text/*`` content-types, the character set (i.e. ``utf8``) supplied 187 187 by the browser. Again, "trust but verify" is the best policy here. 188 188 189 ``UploadedFile.__iter__()`` 190 Iterates over the lines in the file. 191 189 192 ``UploadedFile.temporary_file_path()`` 190 193 Only files uploaded onto disk will have this method; it returns the full 191 194 path to the temporary uploaded file. 192 195 196 193 197 Upload Handlers 194 198 =============== 195 199 -
docs/newforms.txt
1331 1331 * Validates that non-empty file data has been bound to the form. 1332 1332 * Error message keys: ``required``, ``invalid``, ``missing``, ``empty`` 1333 1333 1334 An ``UploadedFile`` object has two attributes: 1334 To learn more about the ``UploadedFile`` object, see the `file uploads documentation`_. 1335 1335 1336 ====================== ====================================================1337 Attribute Description1338 ====================== ====================================================1339 ``filename`` The name of the file, provided by the uploading1340 client.1341 1342 ``content`` The array of bytes comprising the file content.1343 ====================== ====================================================1344 1345 The string representation of an ``UploadedFile`` is the same as the filename1346 attribute.1347 1348 1336 When you use a ``FileField`` in a form, you must also remember to 1349 1337 `bind the file data to the form`_. 1350 1338 1339 .. _file uploads documentation: ../upload_handling/ 1351 1340 .. _`bind the file data to the form`: `Binding uploaded files to a form`_ 1352 1341 1353 1342 ``FilePathField`` -
docs/settings.txt
279 279 280 280 The database backend to use. The build-in database backends are 281 281 ``'postgresql_psycopg2'``, ``'postgresql'``, ``'mysql'``, ``'mysql_old'``, 282 ``'sqlite3'``, ``'oracle'``,and ``'oracle'``.282 ``'sqlite3'``, and ``'oracle'``. 283 283 284 284 In the Django development version, you can use a database backend that doesn't 285 285 ship with Django by setting ``DATABASE_ENGINE`` to a fully-qualified path (i.e.