From 3353889ae85cc21890469cf00f7073d1ea5c2070 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Tue, 7 May 2013 13:27:27 +0100 Subject: [PATCH] Docs for FileUploadParser --- docs/api-guide/parsers.md | 14 +++++++++----- docs/topics/2.3-announcement.md | 4 ++++ docs/topics/release-notes.md | 1 + rest_framework/parsers.py | 5 +++-- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/docs/api-guide/parsers.md b/docs/api-guide/parsers.md index 205186477..7d2c056e3 100644 --- a/docs/api-guide/parsers.md +++ b/docs/api-guide/parsers.md @@ -104,13 +104,18 @@ You will typically want to use both `FormParser` and `MultiPartParser` together ## FileUploadParser -Parses raw file upload content. Returns a `DataAndFiles` object. Since we expect the whole request body to be a file content `request.DATA` will be None, and `request.FILES` will contain the only one key `'file'` matching the uploaded file. +Parses raw file upload content. The `request.DATA` property will be an empty `QueryDict`, and `request.FILES` will be a dictionary with a single key `'file'` containing the uploaded file. -The `filename` property of uploaded file would be set to the result of `.get_filename()` method. By default it tries first to take it's value from the `filename` URL kwarg, and then from `Content-Disposition` HTTP header. You can implement other behaviour be overriding this method. +If the view used with `FileUploadParser` is called with a `filename` URL keyword argument, then that argument will be used as the filename. If it is called without a `filename` URL keyword argument, then the client must set the filename in the `Content-Disposition` HTTP header. For example `Content-Disposition: attachment; filename=upload.jpg`. -Note that since this parser's `media_type` matches every HTTP request it imposes restrictions on usage in combination with other parsers for the same API view. +**.media_type**: `*/*` -Basic usage expamle: +##### Notes: + +* The `FileUploadParser` is for usage with native clients that can upload the file as a raw data request. For web-based uploads, or for native clients with multipart upload support, you should use the `MultiPartParser` parser instead. +* Since this parser's `media_type` matches any content type, `FileUploadParser` should generally be the only parser set on an API view. + +##### Basic usage example: class FileUploadView(views.APIView): parser_classes = (FileUploadParser,) @@ -122,7 +127,6 @@ Basic usage expamle: # ... return Response(status=204) -**.media_type**: `*/*` --- diff --git a/docs/topics/2.3-announcement.md b/docs/topics/2.3-announcement.md index 746d3ff7d..6677c800f 100644 --- a/docs/topics/2.3-announcement.md +++ b/docs/topics/2.3-announcement.md @@ -187,6 +187,10 @@ For example, you might have a field that references it's relationship by a hyper Usage of the old-style attributes continues to be supported, but will raise a `PendingDeprecationWarning`. +## FileUploadParser + +2.3 adds a `FileUploadParser` parser class, that supports raw file uploads, in addition to the existing multipart upload support. + ## DecimalField 2.3 introduces a `DecimalField` serializer field, which returns `Decimal` instances. diff --git a/docs/topics/release-notes.md b/docs/topics/release-notes.md index 1081ea4fd..d77bebb0f 100644 --- a/docs/topics/release-notes.md +++ b/docs/topics/release-notes.md @@ -47,6 +47,7 @@ You can determine your currently installed version using `pip freeze`: * HyperLinkedModelSerializers support 'id' field in 'fields' option. * Cleaner generic views. * Support for multiple filter classes. +* FileUploadParser support for raw file uploads. * DecimalField support. * Bugfix: Fix issue with depth>1 on ModelSerializer. diff --git a/rest_framework/parsers.py b/rest_framework/parsers.py index 27a0db65e..614531a16 100644 --- a/rest_framework/parsers.py +++ b/rest_framework/parsers.py @@ -246,7 +246,7 @@ class FileUploadParser(BaseParser): return DataAndFiles(None, {'file': result[1]}) possible_sizes = [x.chunk_size for x in upload_handlers if x.chunk_size] - chunk_size = min([2**31-4] + possible_sizes) + chunk_size = min([2 ** 31 - 4] + possible_sizes) chunks = ChunkIter(stream, chunk_size) counters = [0] * len(upload_handlers) @@ -280,9 +280,10 @@ class FileUploadParser(BaseParser): return parser_context['kwargs']['filename'] except KeyError: pass + try: meta = parser_context['request'].META disposition = parse_header(meta['HTTP_CONTENT_DISPOSITION']) return disposition[1]['filename'] except (AttributeError, KeyError): - pass + raise ParseError("Filename must be set in Content-Disposition header.")