web/lib/django/core/files/uploadedfile.py
changeset 38 77b6da96e6f1
parent 0 0d40e90630ef
equal deleted inserted replaced
37:8d941af65caf 38:77b6da96e6f1
       
     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, file=None, name=None, content_type=None, size=None, charset=None):
       
    30         super(UploadedFile, self).__init__(file, 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)>" % (
       
    37             self.__class__.__name__, smart_str(self.name), self.content_type)
       
    38 
       
    39     def _get_name(self):
       
    40         return self._name
       
    41 
       
    42     def _set_name(self, name):
       
    43         # Sanitize the file name so that it can't be dangerous.
       
    44         if name is not None:
       
    45             # Just use the basename of the file -- anything else is dangerous.
       
    46             name = os.path.basename(name)
       
    47 
       
    48             # File names longer than 255 characters can cause problems on older OSes.
       
    49             if len(name) > 255:
       
    50                 name, ext = os.path.splitext(name)
       
    51                 name = name[:255 - len(ext)] + ext
       
    52 
       
    53         self._name = name
       
    54 
       
    55     name = property(_get_name, _set_name)
       
    56 
       
    57 class TemporaryUploadedFile(UploadedFile):
       
    58     """
       
    59     A file uploaded to a temporary location (i.e. stream-to-disk).
       
    60     """
       
    61     def __init__(self, name, content_type, size, charset):
       
    62         if settings.FILE_UPLOAD_TEMP_DIR:
       
    63             file = tempfile.NamedTemporaryFile(suffix='.upload',
       
    64                 dir=settings.FILE_UPLOAD_TEMP_DIR)
       
    65         else:
       
    66             file = tempfile.NamedTemporaryFile(suffix='.upload')
       
    67         super(TemporaryUploadedFile, self).__init__(file, name, content_type, size, charset)
       
    68 
       
    69     def temporary_file_path(self):
       
    70         """
       
    71         Returns the full path of this file.
       
    72         """
       
    73         return self.file.name
       
    74 
       
    75     def close(self):
       
    76         try:
       
    77             return self.file.close()
       
    78         except OSError, e:
       
    79             if e.errno != 2:
       
    80                 # Means the file was moved or deleted before the tempfile
       
    81                 # could unlink it.  Still sets self.file.close_called and
       
    82                 # calls self.file.file.close() before the exception
       
    83                 raise
       
    84 
       
    85 class InMemoryUploadedFile(UploadedFile):
       
    86     """
       
    87     A file uploaded into memory (i.e. stream-to-memory).
       
    88     """
       
    89     def __init__(self, file, field_name, name, content_type, size, charset):
       
    90         super(InMemoryUploadedFile, self).__init__(file, name, content_type, size, charset)
       
    91         self.field_name = field_name
       
    92 
       
    93     def open(self, mode=None):
       
    94         self.file.seek(0)
       
    95 
       
    96     def close(self):
       
    97         pass
       
    98 
       
    99     def chunks(self, chunk_size=None):
       
   100         self.file.seek(0)
       
   101         yield self.read()
       
   102 
       
   103     def multiple_chunks(self, chunk_size=None):
       
   104         # Since it's in memory, we'll never have multiple chunks.
       
   105         return False
       
   106 
       
   107 
       
   108 class SimpleUploadedFile(InMemoryUploadedFile):
       
   109     """
       
   110     A simple representation of a file, which just has content, size, and a name.
       
   111     """
       
   112     def __init__(self, name, content, content_type='text/plain'):
       
   113         content = content or ''
       
   114         super(SimpleUploadedFile, self).__init__(StringIO(content), None, name,
       
   115                                                  content_type, len(content), None)
       
   116 
       
   117     def from_dict(cls, file_dict):
       
   118         """
       
   119         Creates a SimpleUploadedFile object from
       
   120         a dictionary object with the following keys:
       
   121            - filename
       
   122            - content-type
       
   123            - content
       
   124         """
       
   125         return cls(file_dict['filename'],
       
   126                    file_dict['content'],
       
   127                    file_dict.get('content-type', 'text/plain'))
       
   128     from_dict = classmethod(from_dict)