-2

TL;DR: Image button responds to clicks but does not display the image when app is deployed on App Engine.


I have a python script that displays a web form in response to http request. The form contains a couple of image buttons. The Python code displays the form itself just fine but the button images show blank squares with broken link icon (see below).

If I click on one of the blank squares, a response is sent back Ok to the server, so the button aspect is Ok.
Also, if I double click on the html template file in file explorer it shows with the image buttons displayed properly, so the html is 'valid' in that sense).

I have tried having the html template and the image files in the application root directory and in a templates subdirectory, and get the same results, and just about everything else I can think of, but no luck. I have also tried the images as jpg files as well as the original png again, that doesnt matter.

Code etc below. I have tried searching on this problem and got quite a few posts sort of related to this but none seem to relate exactly - they have more to do with images stored in blob store or other google storage not as application files.

Im giving below the original, simplest version of the code etc with all the files in the application root. Id actually prefer the html and image files to be in the templates folder, but that wasn’t working either. (The code is in two modules as this is actually part of a bigger overall application, I though it better to isolate the code relating to this problem)

The main module handles the GET request

import SailsTestSpin
class sails_spin(webapp2.RequestHandler):
    def get(self):
            SailsTestSpin.sails_spin_pick(self)

SailsTestSpin.py

def sails_spin_pick(handler):
    logging.info("sails_spin_pick: begin ...")
    page = "sails_test_spin3.html"
    ##template_dir = os.path.join(os.path.dirname(__file__), 'templates')
    template_dir = os.path.join(os.path.dirname(__file__))
    logging.info("... template dir: "+str(template_dir))
    
    jinja_env = jinja2.Environment(loader =
                   jinja2.FileSystemLoader(template_dir), autoescape=True)
    template = jinja_env.get_template(page)
    logging.info("... template: "+str(template))
    
    render = template.render({})
    logging.info("... render: "+rebder)
    handler.response.out.write(render)

    #this didn’t work either
    #img1 = os.path.join(template_dir, "spin-glasses3.png")
    #img2 = os.path.join(template_dir, "spin-spiral3.png")
    #logging.info("... img1: "+img1)
    #render = template.render({
                        'image1': img1,
                        'image2': img2}
                        )
    #logging.info("... render: "+render)
    #handler.response.out.write(render)

sails_test_spin3.html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40"><head>
<style type="text/css">
h1 { font-family: Cambria; font-size:32pt; color:SteelBlue; text-align:center; margin:0;}
a { font-family: Cambria; font-size:14pt; color:DarkBlue; font-weight:bold; line-height:135%; margin-top:28px; margin-bottom:15px; margin-left:5; margin-right:5}
</style>
<script type="text/javascript">
function goTop()
{
window.location.assign("#Top")
}
</script><title>J Class Spinnaker</title>

</head>
<body style="" lang="EN-CA" link="SteelBlue" vlink="moccasin">
<h1>J Class Customiser - Spinnaker Selection ... [3]</h1> 
<br>
<form action="/sails_spin_set" method="post">
<input name="parm1" value="Button1" style="font-size: 12pt; color: Navy; font-weight: bold;"type="image" src="spin-glasses3.jpg" height="256" width="256">
<input name="parm1" value="Button2" style="font-size: 12pt; color: Navy; font-weight: bold;"type="image" src="spin-spiral3.jpg" height="256" width="256">
<br>
<br>
<input name = "parm1" value="Cancel" style="font-size: 16pt; color: DarkRed; font-weight: bold;" type="submit"> 
</form>
</body></html>

app.yaml

runtime: python27
api_version: 1
threadsafe: false

handlers:
- url: /favicon\.ico
  static_files: favicon.ico
  upload: favicon\.ico

- url: /bootstrap
  static_dir: bootstrap

- url: /.*
  script: sails_test_server.app

- url: /.*
  script: SailsTest.py
  
- url: /.*
  script: emailer2.pyc
  
 # [START libraries]
libraries:
- name: webapp2 
  version: latest
- name: jinja2
  version: latest
- name: ssl
  version: 2.7.11
# [END libraries]

application directory the relevant files are are at the bottom

Results

Expected result

Actual result

page file info

PS: Please NO comments on the images suitability for spinnakers, it's too long a story - the short version involves the word virtual!

Donnald Cucharo
  • 3,866
  • 1
  • 10
  • 17
RFlack
  • 436
  • 1
  • 5
  • 19
  • Does this answer your question? [Static image folder with google app engine](https://stackoverflow.com/questions/41685729/static-image-folder-with-google-app-engine) – new name Jan 22 '21 at 13:08

1 Answers1

1

App Engine does not serve files directly out of your application's source directory unless configured to do so. You have to configure your app to use the static files via app.yaml.

A solution is to create a directory (ex. images), and move your button images to that directory. Afterwards, add this URL handler on your app.yaml:

- url: /(.*\.(jpg|png))
  static_files: images/\1
  upload: images/(.*\.(jpg|png))

Or you can follow the docs and use static_dir since you prefer the image files to be in the templates folder. In that case you have to rename the image src on your HTML file:

<input name="parm1" value="Button1" style="font-size: 12pt; color: Navy; font-weight: bold;"type="image" src="templates/images/spin-glasses3.jpg" height="256" width="256">
<input name="parm1" value="Button2" style="font-size: 12pt; color: Navy; font-weight: bold;"type="image" src="templates/images/spin-spiral3.jpg" height="256" width="256">

And then use this handler on your app.yaml:

- url: /templates
  static_dir: templates

Reference: https://cloud.google.com/appengine/docs/standard/python/getting-started/serving-static-files

Donnald Cucharo
  • 3,866
  • 1
  • 10
  • 17
  • Many thanks. One of the things I tried was moving the images but also the html into templates; and then the problem was template file was 'not found'' - I tried every way I could think of to point Jinja at the template folder but none worked. I will try leaving the template where it is and move just the images. Your second approach seems cleaner (to me). – RFlack Jan 22 '21 at 05:02
  • @RFlack I was able to make it work with the details you've provided so if you need clarifications, please let me know. – Donnald Cucharo Jan 22 '21 at 05:54
  • me too --- Im up voting and accepting! we havent tried moving the html; but putting the images with other images works fine. – RFlack Jan 22 '21 at 06:21
  • This question https://stackoverflow.com/questions/41685729/static-image-folder-with-google-app-engine has been proposed as answering my question. My response would be "not exactly" - the solution here is more specific I think, and I have accepted this answer. Im not sure if I should reply Yes or No as to whether the other question answers my problem? And Im not quite sure what accepting the other question does? – RFlack Jan 26 '21 at 05:42
  • @ Donald - Thank you! I have accepted the suggested TL;DR at the top. Im not sure if its a slight over simplification as the button was there (ie responding to clicks) it just didnt display the image. – RFlack Jan 26 '21 at 05:44
  • @RFlack if you think that the proposed thread does not exactly answer your question and the answer here is more specific, then you shouldn't accept the proposed answer. You should [review this meta](https://meta.stackexchange.com/a/194495) and explain on your post why that question does not contain the answer you're looking for. – Donnald Cucharo Jan 26 '21 at 07:59