I want to split my App Engine implementation into several files. So I wrote in my app.yaml file:
runtime: python27
api_version: 1
threadsafe: true
handlers:
- url: /imageuploader
script: imageuploader.app
- url: /search
script: main.app
- url: /
static_files: index.html
upload: index.html
libraries:
- name: MySQLdb
version: "latest"
Basically I search and image upload to be on different paths and root path to have index file.
Here are my handlers:
main.py:
class MainPage(webapp2.RequestHandler):
def get(self):
#Implementation
app = webapp2.WSGIApplication([
('/', MainPage),
], debug=True)
imageuploader.py:
class UserPhoto(ndb.Model):
blob_key = ndb.BlobKeyProperty()
class PhotoUploadFormHandler(webapp2.RequestHandler):
def get(self):
# [START upload_url]
upload_url = blobstore.create_upload_url('/upload_photo')
# [END upload_url]
# [START upload_form]
# To upload files to the blobstore, the request method must be "POST"
# and enctype must be set to "multipart/form-data".
self.response.out.write("""
<html><body>
<form action="{0}" method="POST" enctype="multipart/form-data">
Upload File: <input type="file" name="file"><br>
<input type="submit" name="submit" value="Submit">
</form>
</body></html>""".format(upload_url))
# [END upload_form]
# [START upload_handler]
class PhotoUploadHandler(blobstore_handlers.BlobstoreUploadHandler):
def post(self):
try:
upload = self.get_uploads()[0]
user_photo = UserPhoto(
user=users.get_current_user().user_id(),
blob_key=upload.key())
user_photo.put()
self.redirect('/view_photo/%s' % upload.key())
except:
self.error(500)
# [END upload_handler]
# [START download_handler]
class ViewPhotoHandler(blobstore_handlers.BlobstoreDownloadHandler):
def get(self, photo_key):
if not blobstore.get(photo_key):
self.error(404)
else:
self.send_blob(photo_key)
# [END download_handler]
app = webapp2.WSGIApplication([
('/', PhotoUploadFormHandler),
('/upload_photo', PhotoUploadHandler),
('/view_photo/([^/]+)?', ViewPhotoHandler),
], debug=True)
# [END all]
Now, the weird thing is that if I set
-url: /.*
script: main.app
It all works. I also tried /search/.+
and /imageuploader/.+
. I must have forgotten something completely obvious but I cant figure out what is it.
Each
app.yaml
route script config (likescript: imageuploader.app
) requires a python file with a matching name (imageuploader.py
in this case) which is defining an app calledapp
(just like themain.py
does) with app routes being, of course, a subset of (or equal to) the corresponding path from theapp.yaml
file (/imageuploader
in this case).So, problems with your implementation:
main.py
app path is/
- doesn't match the corresponding/search
path inapp.yaml
imageuploader.py
matches the corresponding/imageuploader
path inapp.yaml
/
path inapp.yaml
is actually mapped to the static resourceindex.html
, so it'll be served by GAE directly - no point adding a handler for it as that handler should never be invoked (you may want to revisit the static resources mapping).Your attempt using
/.*
mapped tomain.app
could only have worked before you removed the handler code now inimageuploader.py
, but should not be working with themain.py
content from your question.Assuming your patterns in the
app.yaml
are the ones you desire, these would be the app configs you'd need (to continue with your approach):main.py:
imageuploader.py:
But I'd suggest a simpler to manage approach, using webapp2's lazy loading of the handler code.
You keep a single, generic mapping in the
app.yaml
, which would match any url pattern in themain.py
file:You have a single app route mapping definition in
main.py
, but which can lazy-load handlers from bothmain.py
as well as other modules/files. For example something like this:A middle-ground approach is also possible, allowing you to completely de-couple
imageuploader.py
frommain.py
but with a slightly more careful url pattern choice.You could have in
app.yaml
:And in
imageuploader.py
have url patterns matching that/photo.*
one: