Django

Code

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

Revision 8046, 6.8 kB (checked in by adrian, 4 months ago)

Fixed #7847 -- Removed a whole bunch of unused imports from throughout the codebase. Thanks, julien

Line 
1 """
2 Base file upload handler classes, and the built-in concrete subclasses
3 """
4
5 try:
6     from cStringIO import StringIO
7 except ImportError:
8     from StringIO import StringIO
9
10 from django.conf import settings
11 from django.core.exceptions import ImproperlyConfigured
12 from django.core.files.uploadedfile import TemporaryUploadedFile, InMemoryUploadedFile
13
14 __all__ = ['UploadFileException','StopUpload', 'SkipFile', 'FileUploadHandler',
15            'TemporaryFileUploadHandler', 'MemoryFileUploadHandler',
16            'load_handler']
17
18 class UploadFileException(Exception):
19     """
20     Any error having to do with uploading files.
21     """
22     pass
23
24 class StopUpload(UploadFileException):
25     """
26     This exception is raised when an upload must abort.
27     """
28     def __init__(self, connection_reset=False):
29         """
30         If ``connection_reset`` is ``True``, Django knows will halt the upload
31         without consuming the rest of the upload. This will cause the browser to
32         show a "connection reset" error.
33         """
34         self.connection_reset = connection_reset
35
36     def __unicode__(self):
37         if self.connection_reset:
38             return u'StopUpload: Halt current upload.'
39         else:
40             return u'StopUpload: Consume request data, then halt.'
41
42 class SkipFile(UploadFileException):
43     """
44     This exception is raised by an upload handler that wants to skip a given file.
45     """
46     pass
47    
48 class StopFutureHandlers(UploadFileException):
49     """
50     Upload handers that have handled a file and do not want future handlers to
51     run should raise this exception instead of returning None.
52     """
53     pass
54
55 class FileUploadHandler(object):
56     """
57     Base class for streaming upload handlers.
58     """
59     chunk_size = 64 * 2 ** 10 #: The default chunk size is 64 KB.
60
61     def __init__(self, request=None):
62         self.file_name = None
63         self.content_type = None
64         self.content_length = None
65         self.charset = None
66         self.request = request
67
68     def handle_raw_input(self, input_data, META, content_length, boundary, encoding=None):
69         """
70         Handle the raw input from the client.
71
72         Parameters:
73
74             :input_data:
75                 An object that supports reading via .read().
76             :META:
77                 ``request.META``.
78             :content_length:
79                 The (integer) value of the Content-Length header from the
80                 client.
81             :boundary: The boundary from the Content-Type header. Be sure to
82                 prepend two '--'.
83         """
84         pass
85
86     def new_file(self, field_name, file_name, content_type, content_length, charset=None):
87         """
88         Signal that a new file has been started.
89
90         Warning: As with any data from the client, you should not trust
91         content_length (and sometimes won't even get it).
92         """
93         self.field_name = field_name
94         self.file_name = file_name
95         self.content_type = content_type
96         self.content_length = content_length
97         self.charset = charset
98
99     def receive_data_chunk(self, raw_data, start):
100         """
101         Receive data from the streamed upload parser. ``start`` is the position
102         in the file of the chunk.
103         """
104         raise NotImplementedError()
105
106     def file_complete(self, file_size):
107         """
108         Signal that a file has completed. File size corresponds to the actual
109         size accumulated by all the chunks.
110
111         Subclasses must should return a valid ``UploadedFile`` object.
112         """
113         raise NotImplementedError()
114
115     def upload_complete(self):
116         """
117         Signal that the upload is complete. Subclasses should perform cleanup
118         that is necessary for this handler.
119         """
120         pass
121
122 class TemporaryFileUploadHandler(FileUploadHandler):
123     """
124     Upload handler that streams data into a temporary file.
125     """
126     def __init__(self, *args, **kwargs):
127         super(TemporaryFileUploadHandler, self).__init__(*args, **kwargs)
128
129     def new_file(self, file_name, *args, **kwargs):
130         """
131         Create the file object to append to as data is coming in.
132         """
133         super(TemporaryFileUploadHandler, self).new_file(file_name, *args, **kwargs)
134         self.file = TemporaryUploadedFile(self.file_name, self.content_type, 0, self.charset)
135
136     def receive_data_chunk(self, raw_data, start):
137         self.file.write(raw_data)
138
139     def file_complete(self, file_size):
140         self.file.seek(0)
141         self.file.size = file_size
142         return self.file
143
144 class MemoryFileUploadHandler(FileUploadHandler):
145     """
146     File upload handler to stream uploads into memory (used for small files).
147     """
148
149     def handle_raw_input(self, input_data, META, content_length, boundary, encoding=None):
150         """
151         Use the content_length to signal whether or not this handler should be in use.
152         """
153         # Check the content-length header to see if we should
154         # If the the post is too large, we cannot use the Memory handler.
155         if content_length > settings.FILE_UPLOAD_MAX_MEMORY_SIZE:
156             self.activated = False
157         else:
158             self.activated = True
159
160     def new_file(self, *args, **kwargs):
161         super(MemoryFileUploadHandler, self).new_file(*args, **kwargs)
162         if self.activated:
163             self.file = StringIO()
164             raise StopFutureHandlers()
165
166     def receive_data_chunk(self, raw_data, start):
167         """
168         Add the data to the StringIO file.
169         """
170         if self.activated:
171             self.file.write(raw_data)
172         else:
173             return raw_data
174
175     def file_complete(self, file_size):
176         """
177         Return a file object if we're activated.
178         """
179         if not self.activated:
180             return
181
182         return InMemoryUploadedFile(
183             file = self.file,
184             field_name = self.field_name,
185             name = self.file_name,
186             content_type = self.content_type,
187             size = file_size,
188             charset = self.charset
189         )
190
191
192 def load_handler(path, *args, **kwargs):
193     """
194     Given a path to a handler, return an instance of that handler.
195
196     E.g.::
197         >>> load_handler('django.core.files.uploadhandler.TemporaryFileUploadHandler', request)
198         <TemporaryFileUploadHandler object at 0x...>
199
200     """
201     i = path.rfind('.')
202     module, attr = path[:i], path[i+1:]
203     try:
204         mod = __import__(module, {}, {}, [attr])
205     except ImportError, e:
206         raise ImproperlyConfigured('Error importing upload handler module %s: "%s"' % (module, e))
207     except ValueError, e:
208         raise ImproperlyConfigured('Error importing upload handler module. Is FILE_UPLOAD_HANDLERS a correctly defined list or tuple?')
209     try:
210         cls = getattr(mod, attr)
211     except AttributeError:
212         raise ImproperlyConfigured('Module "%s" does not define a "%s" upload handler backend' % (module, attr))
213     return cls(*args, **kwargs)
Note: See TracBrowser for help on using the browser.