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?
views:
187answers:
2Docs: http://docs.djangoproject.com/en/dev/topics/http/file-uploads/
Short version:
- Your upload form needs to have a
forms.FileField
field. - 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 namedrequest
). - 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 filesize
: 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()
: ReturnsTrue
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'),
# ...
)