diff options
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/newforms.txt | 4 | ||||
| -rw-r--r-- | docs/request_response.txt | 27 | ||||
| -rw-r--r-- | docs/settings.txt | 39 | ||||
| -rw-r--r-- | docs/sitemaps.txt | 11 | ||||
| -rw-r--r-- | docs/templates.txt | 4 | ||||
| -rw-r--r-- | docs/upload_handling.txt | 346 |
6 files changed, 421 insertions, 10 deletions
diff --git a/docs/newforms.txt b/docs/newforms.txt index 8386c0507c..be3a0b6a2a 100644 --- a/docs/newforms.txt +++ b/docs/newforms.txt @@ -808,12 +808,12 @@ ContactForm to include an ``ImageField`` called ``mugshot``, we need to bind the file data containing the mugshot image:: # Bound form with an image field + >>> from django.core.files.uploadedfile import SimpleUploadedFile >>> data = {'subject': 'hello', ... 'message': 'Hi there', ... 'sender': 'foo@example.com', ... 'cc_myself': True} - >>> file_data = {'mugshot': {'filename':'face.jpg' - ... 'content': <file data>}} + >>> file_data = {'mugshot': SimpleUploadedFile('face.jpg', <file data>)} >>> f = ContactFormWithMugshot(data, file_data) In practice, you will usually specify ``request.FILES`` as the source diff --git a/docs/request_response.txt b/docs/request_response.txt index 866a697e31..54fc24df9e 100644 --- a/docs/request_response.txt +++ b/docs/request_response.txt @@ -80,19 +80,36 @@ All attributes except ``session`` should be considered read-only. strings. ``FILES`` + + .. admonition:: Changed in Django development version + + In previous versions of Django, ``request.FILES`` contained + simple ``dict`` objects representing uploaded files. This is + no longer true -- files are represented by ``UploadedFile`` + objects as described below. + + These ``UploadedFile`` objects will emulate the old-style ``dict`` + interface, but this is deprecated and will be removed in the next + release of Django. + A dictionary-like object containing all uploaded files. Each key in ``FILES`` is the ``name`` from the ``<input type="file" name="" />``. Each - value in ``FILES`` is a standard Python dictionary with the following three - keys: + value in ``FILES`` is an ``UploadedFile`` object containing the following + attributes: - * ``filename`` -- The name of the uploaded file, as a Python string. - * ``content-type`` -- The content type of the uploaded file. - * ``content`` -- The raw content of the uploaded file. + * ``read(num_bytes=None)`` -- Read a number of bytes from the file. + * ``file_name`` -- The name of the uploaded file. + * ``file_size`` -- The size, in bytes, of the uploaded file. + * ``chunk()`` -- A generator that yields sequential chunks of data. + See `File Uploads`_ for more information. + Note that ``FILES`` will only contain data if the request method was POST and the ``<form>`` that posted to the request had ``enctype="multipart/form-data"``. Otherwise, ``FILES`` will be a blank dictionary-like object. + + .. _File Uploads: ../upload_handling/ ``META`` A standard Python dictionary containing all available HTTP headers. diff --git a/docs/settings.txt b/docs/settings.txt index 3fe999d0d2..a68d2ff92f 100644 --- a/docs/settings.txt +++ b/docs/settings.txt @@ -279,7 +279,7 @@ Default: ``''`` (Empty string) The database backend to use. The build-in database backends are ``'postgresql_psycopg2'``, ``'postgresql'``, ``'mysql'``, ``'mysql_old'``, -``'sqlite3'`` and ``'oracle'``. +``'sqlite3'``, ``'oracle'``, and ``'oracle'``. In the Django development version, you can use a database backend that doesn't ship with Django by setting ``DATABASE_ENGINE`` to a fully-qualified path (i.e. @@ -530,6 +530,43 @@ Default: ``'utf-8'`` The character encoding used to decode any files read from disk. This includes template files and initial SQL data files. +FILE_UPLOAD_HANDLERS +-------------------- + +**New in Django development version** + +Default:: + + ("django.core.files.fileuploadhandler.MemoryFileUploadHandler", + "django.core.files.fileuploadhandler.TemporaryFileUploadHandler",) + +A tuple of handlers to use for uploading. See `file uploads`_ for details. + +.. _file uploads: ../upload_handling/ + +FILE_UPLOAD_MAX_MEMORY_SIZE +--------------------------- + +**New in Django development version** + +Default: ``2621440`` (i.e. 2.5 MB). + +The maximum size (in bytes) that an upload will be before it gets streamed to +the file system. See `file uploads`_ for details. + +FILE_UPLOAD_TEMP_DIR +-------------------- + +**New in Django development version** + +Default: ``None`` + +The directory to store data temporarily while uploading files. If ``None``, +Django will use the standard temporary directory for the operating system. For +example, this will default to '/tmp' on *nix-style operating systems. + +See `file uploads`_ for details. + FIXTURE_DIRS ------------- diff --git a/docs/sitemaps.txt b/docs/sitemaps.txt index eb749dda2f..6a16e61879 100644 --- a/docs/sitemaps.txt +++ b/docs/sitemaps.txt @@ -317,3 +317,14 @@ A more efficient solution, however, would be to call ``ping_google()`` from a cron script, or some other scheduled task. The function makes an HTTP request to Google's servers, so you may not want to introduce that network overhead each time you call ``save()``. + +Pinging Google via `manage.py` +------------------------------ + +**New in Django development version** + +Once the sitemaps application is added to your project, you may also +ping the Google server's through the command line manage.py interface:: + + python manage.py ping_google [/sitemap.xml] + diff --git a/docs/templates.txt b/docs/templates.txt index 3a557c1476..04a46580c5 100644 --- a/docs/templates.txt +++ b/docs/templates.txt @@ -477,11 +477,11 @@ escaped when the template is written. This means you would write :: - {{ data|default:"3 > 2" }} + {{ data|default:"3 < 2" }} ...rather than :: - {{ data|default:"3 > 2" }} <-- Bad! Don't do this. + {{ data|default:"3 < 2" }} <-- Bad! Don't do this. This doesn't affect what happens to data coming from the variable itself. The variable's contents are still automatically escaped, if necessary, because diff --git a/docs/upload_handling.txt b/docs/upload_handling.txt new file mode 100644 index 0000000000..068acf3a42 --- /dev/null +++ b/docs/upload_handling.txt @@ -0,0 +1,346 @@ +============ +File Uploads +============ + +**New in Django development version** + +Most Web sites wouldn't be complete without a way to upload files. When Django +handles a file upload, the file data ends up placed in ``request.FILES`` (for +more on the ``request`` object see the documentation for `request and response +objects`_). This document explains how files are stored on disk an in memory, +and how to customize the default behavior. + +.. _request and response objects: ../request_response/#attributes + +Basic file uploads +================== + +Consider a simple form containing a ``FileField``:: + + from django import newforms as forms + + class UploadFileForm(forms.Form): + title = forms.CharField(max_length=50) + file = forms.FileField() + +A view handling this form will receive the file data in ``request.FILES``, which +is a dictionary containing a key for each ``FileField`` (or ``ImageField``, or +other ``FileField`` subclass) in the form. So the data from the above form would +be accessible as ``request.FILES['file']``. + +Most of the time, you'll simply pass the file data from ``request`` into the +form as described in `binding uploaded files to a form`_. This would look +something like:: + + from django.http import HttpResponseRedirect + from django.shortcuts import render_to_response + + # Imaginary function to handle an uploaded file. + from somewhere import handle_uploaded_file + + def upload_file(request): + if request.method == 'POST': + form = UploadFileForm(request.POST, request.FILES) + if form.is_valid(): + handle_uploaded_file(request.FILES['file']) + return HttpResponseRedirect('/success/url/') + else: + form = UploadFileForm() + return render_to_response('upload.html', {'form': form}) + +.. _binding uploaded files to a form: ../newforms/#binding-uploaded-files-to-a- form + +Notice that we have to pass ``request.FILES`` into the form's constructor; this +is how file data gets bound into a form. + +Handling uploaded files +----------------------- + +The final piece of the puzzle is handling the actual file data from +``request.FILES``. Each entry in this dictionary is an ``UploadedFile`` object +-- a simple wrapper around an uploaded file. You'll usually use one of these +methods to access the uploaded content: + + ``UploadedFile.read()`` + Read the entire uploaded data from the file. Be careful with this + method: if the uploaded file is huge it can overwhelm your system if you + try to read it into memory. You'll probably want to use ``chunk()`` + instead; see below. + + ``UploadedFile.multiple_chunks()`` + Returns ``True`` if the uploaded file is big enough to require + reading in multiple chunks. By default this will be any file + larger than 2.5 megabytes, but that's configurable; see below. + + ``UploadedFile.chunks()`` + A generator returning chunks of the file. If ``multiple_chunks()`` is + ``True``, you should use this method in a loop instead of ``read()``. + + In practice, it's often easiest simply to use ``chunks()`` all the time; + see the example below. + + ``UploadedFile.file_name`` + The name of the uploaded file (e.g. ``my_file.txt``). + + ``UploadedFile.file_size`` + The size, in bytes, of the uploaded file. + +There are a few other methods and attributes available on ``UploadedFile`` +objects; see `UploadedFile objects`_ for a complete reference. + +Putting it all together, here's a common way you might handle an uploaded file:: + + def handle_uploaded_file(f): + destination = open('some/file/name.txt', 'wb') + for chunk in f.chunks(): + destination.write(chunk) + +Looping over ``UploadedFile.chunks()`` instead of using ``read()`` ensures that +large files don't overwhelm your system's memory. + +Where uploaded data is stored +----------------------------- + +Before you save uploaded files, the data needs to be stored somewhere. + +By default, if an uploaded file is smaller than 2.5 megabytes, Django will hold +the entire contents of the upload in memory. This means that saving the file +involves only a read from memory and a write to disk and thus is very fast. + +However, if an uploaded file is too large, Django will write the uploaded file +to a temporary file stored in your system's temporary directory. On a Unix-like +platform this means you can expect Django to generate a file called something +like ``/tmp/tmpzfp6I6.upload``. If an upload is large enough, you can watch this +file grow in size as Django streams the data onto disk. + +These specifics -- 2.5 megabytes; ``/tmp``; etc. -- are simply "reasonable +defaults". Read on for details on how you can customize or completely replace +upload behavior. + +Changing upload handler behavior +-------------------------------- + +Three `settings`_ control Django's file upload behavior: + + ``FILE_UPLOAD_MAX_MEMORY_SIZE`` + The maximum size, in bytes, for files that will be uploaded + into memory. Files larger than ``FILE_UPLOAD_MAX_MEMORY_SIZE`` + will be streamed to disk. + + Defaults to 2.5 megabytes. + + ``FILE_UPLOAD_TEMP_DIR`` + The directory where uploaded files larger than ``FILE_UPLOAD_TEMP_DIR`` + will be stored. + + Defaults to your system's standard temporary directory (i.e. ``/tmp`` on + most Unix-like systems). + + ``FILE_UPLOAD_HANDLERS`` + The actual handlers for uploaded files. Changing this setting + allows complete customization -- even replacement -- of + Django's upload process. See `upload handlers`_, below, + for details. + + Defaults to:: + + ("django.core.files.uploadhandler.MemoryFileUploadHandler", + "django.core.files.uploadhandler.TemporaryFileUploadHandler",) + + Which means "try to upload to memory first, then fall back to temporary + files." + +.. _settings: ../settings/ + +``UploadedFile`` objects +======================== + +All ``UploadedFile`` objects define the following methods/attributes: + + ``UploadedFile.read(self, num_bytes=None)`` + Returns a byte string of length ``num_bytes``, or the complete file if + ``num_bytes`` is ``None``. + + ``UploadedFile.chunk(self, chunk_size=None)`` + A generator yielding small chunks from the file. If ``chunk_size`` isn't + given, chunks will be 64 kb. + + ``UploadedFile.multiple_chunks(self, chunk_size=None)`` + Returns ``True`` if you can expect more than one chunk when calling + ``UploadedFile.chunk(self, chunk_size)``. + + ``UploadedFile.file_size`` + The size, in bytes, of the uploaded file. + + ``UploadedFile.file_name`` + The name of the uploaded file as provided by the user. + + ``UploadedFile.content_type`` + The content-type header uploaded with the file (e.g. ``text/plain`` or + ``application/pdf``). Like any data supplied by the user, you shouldn't + trust that the uploaded file is actually this type. You'll still need to + validate that the file contains the content that the content-type header + claims -- "trust but verify." + + ``UploadedFile.charset`` + For ``text/*`` content-types, the character set (i.e. ``utf8``) supplied + by the browser. Again, "trust but verify" is the best policy here. + + ``UploadedFile.temporary_file_path()`` + Only files uploaded onto disk will have this method; it returns the full + path to the temporary uploaded file. + +Upload Handlers +=============== + +When a user uploads a file, Django passes off the file data to an *upload +handler* -- a small class that handles file data as it gets uploaded. Upload +handlers are initially defined in the ``FILE_UPLOAD_HANDLERS`` setting, which +defaults to:: + + ("django.core.files.uploadhandler.MemoryFileUploadHandler", + "django.core.files.uploadhandler.TemporaryFileUploadHandler",) + +Together the ``MemoryFileUploadHandler`` and ``TemporaryFileUploadHandler`` +provide Django's default file upload behavior of reading small files into memory +and large ones onto disk. + +You can write custom handlers that customize how Django handles files. You +could, for example, use custom handlers to enforce user-level quotas, compress +data on the fly, render progress bars, and even send data to another storage +location directly without storing it locally. + +Modifying upload handlers on the fly +------------------------------------ + +Sometimes particular views require different upload behavior. In these cases, +you can override upload handlers on a per-request basis by modifying +``request.upload_handlers``. By default, this list will contain the upload +handlers given by ``FILE_UPLOAD_HANDLERS``, but you can modify the list as you +would any other list. + +For instance, suppose you've written a ``ProgressBarUploadHandler`` that +provides feedback on upload progress to some sort of AJAX widget. You'd add this +handler to your upload handers like this:: + + request.upload_handlers.insert(0, ProgressBarUploadHandler()) + +You'd probably want to use ``list.insert()`` in this case (instead of +``append()``) because a progress bar handler would need to run *before* any +other handlers. Remember, the upload handlers are processed in order. + +If you want to replace the upload handlers completely, you can just assign a new +list:: + + request.upload_handlers = [ProgressBarUploadHandler()] + +.. note:: + + You can only modify upload handlers *before* accessing ``request.FILES`` -- + it doesn't make sense to change upload handlers after upload handling has + already started. If you try to modify ``request.upload_handlers`` after + reading from ``request.FILES`` Django will throw an error. + + Thus, you should always modify uploading handlers as early in your view as + possible. + +Writing custom upload handlers +------------------------------ + +All file upload handlers should be subclasses of +``django.core.files.uploadhandler.FileUploadHandler``. You can define upload +handlers wherever you wish. + +Required methods +~~~~~~~~~~~~~~~~ + +Custom file upload handlers **must** define the following methods: + + ``FileUploadHandler.receive_data_chunk(self, raw_data, start)`` + Receives a "chunk" of data from the file upload. + + ``raw_data`` is a byte string containing the uploaded data. + + ``start`` is the position in the file where this ``raw_data`` chunk + begins. + + The data you return will get fed into the subsequent upload handlers' + ``receive_data_chunk`` methods. In this way, one handler can be a + "filter" for other handlers. + + Return ``None`` from ``receive_data_chunk`` to sort-circuit remaining + upload handlers from getting this chunk.. This is useful if you're + storing the uploaded data yourself and don't want future handlers to + store a copy of the data. + + If you raise a ``StopUpload`` or a ``SkipFile`` exception, the upload + will abort or the file will be completely skipped. + + ``FileUploadHandler.file_complete(self, file_size)`` + Called when a file has finished uploading. + + The handler should return an ``UploadedFile`` object that will be stored + in ``request.FILES``. Handlers may also return ``None`` to indicate that + the ``UploadedFile`` object should come from subsequent upload handlers. + +Optional methods +~~~~~~~~~~~~~~~~ + +Custom upload handlers may also define any of the following optional methods or +attributes: + + ``FileUploadHandler.chunk_size`` + Size, in bytes, of the "chunks" Django should store into memory and feed + into the handler. That is, this attribute controls the size of chunks + fed into ``FileUploadHandler.receive_data_chunk``. + + For maximum performance the chunk sizes should be divisible by ``4`` and + should not exceed 2 GB (2\ :sup:`31` bytes) in size. When there are + multiple chunk sizes provided by multiple handlers, Django will use the + smallest chunk size defined by any handler. + + The default is 64*2\ :sup:`10` bytes, or 64 Kb. + + ``FileUploadHandler.new_file(self, field_name, file_name, content_type, content_length, charset)`` + Callback signaling that a new file upload is starting. This is called + before any data has been fed to any upload handlers. + + ``field_name`` is a string name of the file ``<input>`` field. + + ``file_name`` is the unicode filename that was provided by the browser. + + ``content_type`` is the MIME type provided by the browser -- E.g. + ``'image/jpeg'``. + + ``content_length`` is the length of the image given by the browser. + Sometimes this won't be provided and will be ``None``., ``None`` + otherwise. + + ``charset`` is the character set (i.e. ``utf8``) given by the browser. + Like ``content_length``, this sometimes won't be provided. + + This method may raise a ``StopFutureHandlers`` exception to prevent + future handlers from handling this file. + + ``FileUploadHandler.upload_complete(self)`` + Callback signaling that the entire upload (all files) has completed. + + ``FileUploadHandler.``handle_raw_input(self, input_data, META, content_length, boundary, encoding)`` + Allows the handler to completely override the parsing of the raw + HTTP input. + + ``input_data`` is a file-like object that supports ``read()``-ing. + + ``META`` is the same object as ``request.META``. + + ``content_length`` is the length of the data in ``input_data``. Don't + read more than ``content_length`` bytes from ``input_data``. + + ``boundary`` is the MIME boundary for this request. + + ``encoding`` is the encoding of the request. + + Return ``None`` if you want upload handling to continue, or a tuple of + ``(POST, FILES)`` if you want to return the new data structures suitable + for the request directly. + |
