2

I am trying to let a user upload an image, save the image to disk, and then have it display on a webpage, but I can't get the image to display properly. Here is my bin/app.py:

import web                                                                         

urls = (                                                                           
        '/hello', 'index'                                                          
        )                                                                          

app = web.application(urls, globals())                                             

render = web.template.render('templates/', base="layout")                          

class index:                                                                       
    def GET(self):                                                                 
        return render.hello_form()                                                 

    def POST(self):                                                                
        form = web.input(greet="Hello", name="Nobody", datafile={})                
        greeting = "%s, %s" % (form.greet, form.name)                                                                
        filedir = 'absolute/path/to/directory'
        filename = None                                                            
        if form.datafile:                                                     
            # replaces the windows-style slashes with linux ones.                  
            filepath = form.datafile.filename.replace('\\','/')                    
            # splits the and chooses the last part (the filename with extension)
            filename = filepath.split('/')[-1]                                     
            # creates the file where the uploaded file should be stored            
            fout = open(filedir +'/'+ filename,'w')                                
            # writes the uploaded file to the newly created file.                  
            fout.write(form.datafile.file.read())                                  
            # closes the file, upload complete.                                    
            fout.close()                                                           
            filename = filedir + "/" + filename                                    
        return render.index(greeting, filename)                                    

if __name__ == "__main__":                                                         
    app.run()     

and here is templates/index.html:

$def with (greeting, datafile)                                                     

$if greeting:                                                                      
    I just wanted to say <em style="color: green; font-size: 2em;">$greeting</em>
$else:                                                                             
    <em>Hello</em>, world!                                                         
<br>                                                                               
$if datafile:                                                                      
    <img src=$datafile alt="your picture">                                         
<br>                                                                               
<a href="/hello">Go Back</a>  

When I do this, I get a broken link for the image. How do I get the image to display properly? Ideally, I wouldn't have to read from disk to display it, although I'm not sure if that's possible. Also, is there a way to write the file to the relative path, instead of the absolute path?

2 Answers 2

1

You can also insert a path to all images in a folder by adding an entry to your URL.

URL = ('/hello','Index',
       '/hello/image/(.*)','ImageDisplay'
      )
...
class ImageDisplay(object):
   def GET(self,fileName):
      imageBinary = open("/relative/path/from/YourApp}"+fileName,'rb').read()
      return imageBinary

Not the ../YourApp, not ./YourApp. It looks up one directory from where your prgram is. Now, in the html, you can use

<img src="/image/"+$datafile alt="your picture">

I would recommend using with or try with the "imageBinary = open("{..." line.

Let me know if more info is needed. This is my first response.

Sorry to ask a question in a responce, but is there a way to use a regular expression, like (.jpg) in place of the (.) I have in the URL definition?

Sign up to request clarification or add additional context in comments.

Comments

0

web.py doesn't automatically serve all of the files from the directory your application is running in — if it did, anyone could be able to read your application's source code. It does, however, have a directory it serves files out of: static.

To answer your other question: yes, there is a way to avoid using an absolute path: give it a relative path!

Here's how your code might look afterwards:

filename = form.datafile.filename.replace('\\', '/').split('/')[-1]
# It might be a good idea to sanitize filename further.

# A with statement ensures that the file will be closed even if an exception is
# thrown.
with open(os.path.join('static', filename), 'wb') as f:
    # shutil.copyfileobj copies the file in chunks, so it will still work if the
    # file is too large to fit into memory
    shutil.copyfileobj(form.datafile.file, f)

Do omit the filename = filedir + "/" + filename line. Your template need not include the absolute path: in fact, it should not; you must include static/; no more, no less:

<img src="static/$datafile" alt="your picture">

5 Comments

What is os? I get global name 'os' is not defined when I try that.
@fvrghl: It's the os module. Import it at the top of your file. (Import shutil, too, for that matter.)
This still displays a broken file on the page. The file is successfully being written. Should the link http://0.0.0.0:8080/static/my_file.jpg display the image?
@fvrghl: That URL should display the image, yes.
I tried opening it from the command line, and I got The file “my_file.jpg” could not be opened because it is empty

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.