Django

Code

root/django/trunk/django/core/files/uploadedfile.py

Revision 8636, 5.2 kB (checked in by jacob, 3 months ago)

FIxed #8156: UploadedFile.__repr__ now returns a string, a good __repr__ should.

Line 
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)
Note: See TracBrowser for help on using the browser.