views:

187

answers:

2

How can I have a form with a FileField, where the uploaded file will not be saved but instead its text contents will be extracted and displayed?

+3  A: 

Docs: http://docs.djangoproject.com/en/dev/topics/http/file-uploads/

Short version:

  1. Your upload form needs to have a forms.FileField field.
  2. When the form is submitted, it goes to a URL which goes to a view function you have written. That view function takes an HttpRequest (usually named request).
  3. Fetch the file from request.FILES[].

For example, if your form has:

upFile = forms.FileField

Then your view can get to the file with:

def uploadView(request):
    upFile = request.FILES["upFile"]

where upFile is an UploadedFile object, which is not a file-like object. An UploadedFile has the following properties:

  • name: name of the uploaded file
  • size: size in bytes

and the following methods:

  • read(): Read the entire file and return as a string. Probably good for you, but not recommended for files over 2.5 MB.
  • multiple_chunks(): Returns True if the file should be handled as multiple chunks.
  • chunks(): Returns a generator (use it like an iterator) which returns the file data one chunk at a time.

So, continuing the example, if you just wanted to save the file to disk, you could write:

outFile = open("/tmp/uploadTest.txt", "w")
if not upFile.multiple_chunks():
    outFile.write(upFile.read())
else:
    for chunk in upFile.chunks():
        outFile.write(chunk)
outFile.close()

In your case, you could probably just show an error message and discard the file if multiple_chunks() returns True, since you probably aren't looking to put over 2.5 MB of text on your page.

EDIT: Well, your question entirely changed while I was writing my answer. So, spelling out how to put the file contents in the page, and assuming the file isn't over 2.5 MB, your view function could look like:

def uploadView(request):
    upFile = request.FILES["upFile"]
    context = {}
    if upFile.multiple_chunks():
        context["uploadError"] = "Uploaded file is too big (%.2f MB)." % (upFile.size,)
    else:
        context["uploadedFile"] = upFile.read()
    return render_to_response('fileUploadPage.html', context)

Adding, of course, whatever other view processing you need.

Then your fileUploadPage.html template needs to have somewhere:

<div id="uploaded">
    {% if uploadError %}
    <span class="error">{{ uploadError }}</span>
    {% else %}
    {{ uploadedFile }}
    {% endif %}
</div>

EDIT 2: Dominic has a good point. Here's the generic template code for setting the form tag right. Use this in the template that has the form:

<form method="post" action="{% url uploadFile %}"
{% if form.is_multipart %}
    enctype="multipart/form-data"
{% endif %}>
{{ form }}
</form>

In your case, since you know the form will have a file in it, you can lose the if block:

<form method="post" action="{% url uploadFile %}" enctype="multipart/form-data">
{{ form }}
</form>

Note: The {% url ___ %} command will put in the URL for a view or named URL. The parameter is either the name of the view function as used in your urls.py file, or the name given to the url object, like so:

urlpatterns = patterns('',
    url('^uploadform$', 'myapp.views.uploadFormView', name='uploadForm'),
    url('^upload$', 'myapp.views.uploadView', name='uploadFile'),
    # ...
)
Mike D.
Can you add something in about `enctype` on the `<form>` tag? Save the OP running into trouble!
Dominic Rodger
@Mike D. - I rewrote the question - I don't *think* I changed the meaning, just hopefully made it easier to parse.
Dominic Rodger
That doesn't look like a very "short" version...
T. Stone
Like so many projects, it started out small... but grew... ;_; And it's still short compared to the web page I referenced in he first line.
Mike D.
A: 

Thanks guys for hints/sample codes. i now got it working.

Ron