app/django/core/files/uploadedfile.py
changeset 323 ff1a9aa48cfd
equal deleted inserted replaced
322:6641e941ef1e 323:ff1a9aa48cfd
       
     1 """
       
     2 Classes representing uploaded files.
       
     3 """
       
     4 
       
     5 import os
       
     6 try:
       
     7     from cStringIO import StringIO
       
     8 except ImportError:
       
     9     from StringIO import StringIO
       
    10 
       
    11 from django.conf import settings
       
    12 from django.core.files.base import File
       
    13 from django.core.files import temp as tempfile
       
    14 from django.utils.encoding import smart_str
       
    15 
       
    16 __all__ = ('UploadedFile', 'TemporaryUploadedFile', 'InMemoryUploadedFile',
       
    17            'SimpleUploadedFile')
       
    18 
       
    19 class UploadedFile(File):
       
    20     """
       
    21     A abstract uploaded file (``TemporaryUploadedFile`` and
       
    22     ``InMemoryUploadedFile`` are the built-in concrete subclasses).
       
    23 
       
    24     An ``UploadedFile`` object behaves somewhat like a file object and
       
    25     represents some file data that the user submitted with a form.
       
    26     """
       
    27     DEFAULT_CHUNK_SIZE = 64 * 2**10
       
    28 
       
    29     def __init__(self, name=None, content_type=None, size=None, charset=None):
       
    30         self.name = name
       
    31         self.size = size
       
    32         self.content_type = content_type
       
    33         self.charset = charset
       
    34 
       
    35     def __repr__(self):
       
    36         return "<%s: %s (%s)>" % (self.__class__.__name__, smart_str(self.name), self.content_type)
       
    37 
       
    38     def _get_name(self):
       
    39         return self._name
       
    40 
       
    41     def _set_name(self, name):
       
    42         # Sanitize the file name so that it can't be dangerous.
       
    43         if name is not None:
       
    44             # Just use the basename of the file -- anything else is dangerous.
       
    45             name = os.path.basename(name)
       
    46 
       
    47             # File names longer than 255 characters can cause problems on older OSes.
       
    48             if len(name) > 255:
       
    49                 name, ext = os.path.splitext(name)
       
    50                 name = name[:255 - len(ext)] + ext
       
    51 
       
    52         self._name = name
       
    53 
       
    54     name = property(_get_name, _set_name)
       
    55 
       
    56     # Abstract methods; subclasses *must* define read() and probably should
       
    57     # define open/close.
       
    58     def read(self, num_bytes=None):
       
    59         raise NotImplementedError()
       
    60 
       
    61     def open(self):
       
    62         pass
       
    63 
       
    64     def close(self):
       
    65         pass
       
    66 
       
    67 class TemporaryUploadedFile(UploadedFile):
       
    68     """
       
    69     A file uploaded to a temporary location (i.e. stream-to-disk).
       
    70     """
       
    71     def __init__(self, name, content_type, size, charset):
       
    72         super(TemporaryUploadedFile, self).__init__(name, content_type, size, charset)
       
    73         if settings.FILE_UPLOAD_TEMP_DIR:
       
    74             self._file = tempfile.NamedTemporaryFile(suffix='.upload', dir=settings.FILE_UPLOAD_TEMP_DIR)
       
    75         else:
       
    76             self._file = tempfile.NamedTemporaryFile(suffix='.upload')
       
    77 
       
    78     def temporary_file_path(self):
       
    79         """
       
    80         Returns the full path of this file.
       
    81         """
       
    82         return self._file.name
       
    83 
       
    84     # Most methods on this object get proxied to NamedTemporaryFile.
       
    85     # We can't directly subclass because NamedTemporaryFile is actually a
       
    86     # factory function
       
    87     def read(self, *args):          return self._file.read(*args)
       
    88     def seek(self, *args):          return self._file.seek(*args)
       
    89     def write(self, s):             return self._file.write(s)
       
    90     def tell(self, *args):          return self._file.tell(*args)
       
    91     def __iter__(self):             return iter(self._file)
       
    92     def readlines(self, size=None): return self._file.readlines(size)
       
    93     def xreadlines(self):           return self._file.xreadlines()
       
    94     def close(self):
       
    95         try:
       
    96             return self._file.close()
       
    97         except OSError, e:
       
    98             if e.errno == 2:
       
    99                 # Means the file was moved or deleted before the tempfile could unlink it.
       
   100                 # Still sets self._file.close_called and calls self._file.file.close()
       
   101                 # before the exception
       
   102                 return
       
   103             else:
       
   104                 raise e
       
   105 
       
   106 class InMemoryUploadedFile(UploadedFile):
       
   107     """
       
   108     A file uploaded into memory (i.e. stream-to-memory).
       
   109     """
       
   110     def __init__(self, file, field_name, name, content_type, size, charset):
       
   111         super(InMemoryUploadedFile, self).__init__(name, content_type, size, charset)
       
   112         self._file = file
       
   113         self.field_name = field_name
       
   114         self._file.seek(0)
       
   115 
       
   116     def open(self):
       
   117         self._file.seek(0)
       
   118 
       
   119     def chunks(self, chunk_size=None):
       
   120         self._file.seek(0)
       
   121         yield self.read()
       
   122 
       
   123     def multiple_chunks(self, chunk_size=None):
       
   124         # Since it's in memory, we'll never have multiple chunks.
       
   125         return False
       
   126 
       
   127     # proxy methods to StringIO
       
   128     def read(self, *args): return self._file.read(*args)
       
   129     def seek(self, *args): return self._file.seek(*args)
       
   130     def tell(self, *args): return self._file.tell(*args)
       
   131     def close(self):       return self._file.close()
       
   132 
       
   133 class SimpleUploadedFile(InMemoryUploadedFile):
       
   134     """
       
   135     A simple representation of a file, which just has content, size, and a name.
       
   136     """
       
   137     def __init__(self, name, content, content_type='text/plain'):
       
   138         self._file = StringIO(content or '')
       
   139         self.name = name
       
   140         self.field_name = None
       
   141         self.size = len(content or '')
       
   142         self.content_type = content_type
       
   143         self.charset = None
       
   144         self._file.seek(0)
       
   145 
       
   146     def from_dict(cls, file_dict):
       
   147         """
       
   148         Creates a SimpleUploadedFile object from
       
   149         a dictionary object with the following keys:
       
   150            - filename
       
   151            - content-type
       
   152            - content
       
   153         """
       
   154         return cls(file_dict['filename'],
       
   155                    file_dict['content'],
       
   156                    file_dict.get('content-type', 'text/plain'))
       
   157 
       
   158     from_dict = classmethod(from_dict)