8

I have an HTML form and I am using Python to generate a log file based on the input. I'd like to also be able to allow the user to upload an image if they choose. I can figure out how to manipulate it with Python once it's there, but I'm not sure how to get the image uploaded. This has most certainly been done before, but I'm having a hard time finding any examples. Can any of you point me in the right direction?

Basically, I'm using cgi.FieldStorage and csv.writer to make the log. I want to get an image from the user's computer and then save it to a directory on my server. I will then rename it and append the title to the CSV file.

I know there are a lot of options for this. I just don't know what they are. If anyone could direct me toward some resources I would be very appreciative.

Jackson Egan
  • 2,715
  • 4
  • 18
  • 26
  • you're more likely to get an answer if you post some code that's not working, rather than asking broadly "how do i do this" – Emmett Butler Aug 28 '12 at 19:28
  • 1
    There are so many ways this could be done, with different libs...We need to know exactly what you are working with. – jdi Aug 28 '12 at 19:30
  • I'm not asking "how do I do this." I know that is frowned upon. I'm asking for direction toward some resources so I don't waste everyone's time. I'll edit to make that more clear. – Jackson Egan Aug 28 '12 at 19:31
  • There is a huge list of web frameworks available here: http://wiki.python.org/moin/WebFrameworks . If you knew exactly what you were using already to handle web requests, then people could give you a specific example. Otherwise, people will just have to pick a random approach to handling web requests and show examples of that lib or framework. – jdi Aug 28 '12 at 19:37
  • I see. Forgive my naiveté, but does the fact that I'm using cgi (specifically .FieldStorage) to get the form info help? Also, thanks for the link! – Jackson Egan Aug 28 '12 at 19:44
  • 1
    Yep. That was the missing piece :-) – jdi Aug 28 '12 at 19:45
  • 1
    Edited in. Sorry for the initial defensiveness. Ignorance. :/ Thanks again! – Jackson Egan Aug 28 '12 at 19:47

2 Answers2

8

Since you said that your specific application is for use with the python cgi module, a quick google turns up plenty of examples. Here is the first one:

Minimal http upload cgi (Python recipe) (snip)

def save_uploaded_file (form_field, upload_dir):
    """This saves a file uploaded by an HTML form.
       The form_field is the name of the file input field from the form.
       For example, the following form_field would be "file_1":
           <input name="file_1" type="file">
       The upload_dir is the directory where the file will be written.
       If no file was uploaded or if the field does not exist then
       this does nothing.
    """
    form = cgi.FieldStorage()
    if not form.has_key(form_field): return
    fileitem = form[form_field]
    if not fileitem.file: return
    fout = file (os.path.join(upload_dir, fileitem.filename), 'wb')
    while 1:
        chunk = fileitem.file.read(100000)
        if not chunk: break
        fout.write (chunk)
    fout.close()

This code will grab the file input field, which will be a file-like object. Then it will read it, chunk by chunk, into an output file.

Update 04/12/15: Per comments, I have added in the updates to this old activestate snippet:

import shutil

def save_uploaded_file (form_field, upload_dir):
    form = cgi.FieldStorage()
    if not form.has_key(form_field): return
    fileitem = form[form_field]
    if not fileitem.file: return

    outpath = os.path.join(upload_dir, fileitem.filename)

    with open(outpath, 'wb') as fout:
        shutil.copyfileobj(fileitem.file, fout, 100000)
jdi
  • 90,542
  • 19
  • 167
  • 203
  • 1
    `fout = open(pathname, 'wb')` is better than `fout = file(pathname, 'wb')`; see [Why is open() preferable over file() in Python?](http://stackoverflow.com/q/11942482/4014959). Even better: `with open(pathname, 'wb') as fout:`, and then `fout` will be closed automatically when you leave the context of the `with` block. – PM 2Ring Apr 11 '15 at 15:21
  • also use [`shutil.copyfileobj`](https://docs.python.org/2/library/shutil.html) to copy the file contents – Antti Haapala -- Слава Україні Apr 11 '15 at 15:30
  • Thanks for the comments. It was an old activestate recipe that I copied the snip from. I've updated it. – jdi Apr 11 '15 at 20:53
  • `if not form.has_key(form_field)` did not work with Python 3.5. Use `if form_field not in form` instead. – MCF Jan 02 '16 at 21:18
  • @MCF yes as I recall they deprecated has_key in py3 – jdi Jan 03 '16 at 00:09
3

The web frame work Pyramid has a good example. http://docs.pylonsproject.org/projects/pyramid_cookbook/en/latest/forms/file_uploads.html

Here is my example code that I use with a working project.

    extension = os.path.splitext(request.POST[form_id_name].filename)[1]
    short_id = str(random.randint(1, 999999999))
    new_file_name =  short_id + extension
    input_file = request.POST[form_id_name].file
    file_path = os.path.join(os.environ['PROJECT_PATH'] + '/static/memberphotos/', new_file_name)

    output_file = open(file_path, 'wb')
    input_file.seek(0)
    while 1:
        data = input_file.read(2<<16)
        if not data:
            break
        output_file.write(data)
    output_file.close()
Brandon Poole
  • 382
  • 2
  • 7