Python 2.7 has reached end of support
and will be deprecated
on January 31, 2026. After deprecation, you won't be able to deploy Python 2.7
applications, even if your organization previously used an organization policy to
re-enable deployments of legacy runtimes. Your existing Python
2.7 applications will continue to run and receive traffic after their
deprecation date. We recommend that
you migrate to the latest supported version of Python.
Stay organized with collections
Save and categorize content based on your preferences.
Region ID
The REGION_ID is an abbreviated code that Google assigns
based on the region you select when you create your app. The code does not
correspond to a country or province, even though some region IDs may appear
similar to commonly used country and province codes. For apps created after
February 2020, REGION_ID.r is included in
App Engine URLs. For existing apps created before this date, the
region ID is optional in the URL.
Learn how to upload, transform, store, and serve images dynamically using the Images API. This
example describes how to post messages to a public message board and upload an
avatar with your greeting.
Creating an Image model in Datastore
You need to update the model from the guestbook sample to store the uploaded image as a blob.
classGreeting(ndb.Model):"""Models a Guestbook entry with an author, content, avatar, and date."""author=ndb.StringProperty()content=ndb.TextProperty()avatar=ndb.BlobProperty()date=ndb.DateTimeProperty(auto_now_add=True)
Uploading user images
You will need to modify the HTML form to enable the user to upload an image:
Add a field that enables the user to select a file from their computer to upload.
Add the enctype attribute to the form tag and specify this is a multi-part form post.
You will need to update the Guestbook's HTML to pass the key of the greeting to the image handler as
it gets the img_id from the request.
Deploying the app to App Engine
To upload the guestbook app, run the following command from within the
guestbook directory of your application where the app.yaml and
index.yaml files are located:
gcloudappdeployapp.yamlindex.yaml
The Datastore indexes might take some time to
generate before your application is available. If the indexes are still in the
process of being generated, you will receive a NeedIndexError
message when accessing your app. This error is transient, so try a little later
if at first you receive this error.
To learn more about deploying your app from the command line, see
Deploying A Python App.
Viewing your deployed application
To launch your browser and view the app at
https://PROJECT_ID.REGION_ID.r.appspot.com, run the following command:
[[["Easy to understand","easyToUnderstand","thumb-up"],["Solved my problem","solvedMyProblem","thumb-up"],["Other","otherUp","thumb-up"]],[["Hard to understand","hardToUnderstand","thumb-down"],["Incorrect information or sample code","incorrectInformationOrSampleCode","thumb-down"],["Missing the information/samples I need","missingTheInformationSamplesINeed","thumb-down"],["Other","otherDown","thumb-down"]],["Last updated 2025-08-25 UTC."],[[["\u003cp\u003eRegion IDs are codes assigned by Google based on the selected region when creating an app, and they do not necessarily correspond to country or province codes.\u003c/p\u003e\n"],["\u003cp\u003eThe Images API allows for the dynamic uploading, transforming, storing, and serving of images, as demonstrated by the example of posting messages and uploading avatars to a public message board.\u003c/p\u003e\n"],["\u003cp\u003eTo store uploaded images, the Guestbook model in Datastore needs to be updated to include a blob property, enabling users to select files for upload through an HTML form with specific attributes.\u003c/p\u003e\n"],["\u003cp\u003eImage transformation involves importing the \u003ccode\u003egoogle.appengine.api.images\u003c/code\u003e module and using the \u003ccode\u003eresize\u003c/code\u003e function to adjust image dimensions, such as creating 32x32 avatars.\u003c/p\u003e\n"],["\u003cp\u003eDeploying the guestbook application to App Engine involves using the \u003ccode\u003egcloud app deploy app.yaml index.yaml\u003c/code\u003e command, and accessing the deployed application can be done via \u003ccode\u003egcloud app browse\u003c/code\u003e, noting that Datastore indexes might take time to generate.\u003c/p\u003e\n"]]],[],null,["# Images API examples\n\n### Region ID\n\nThe \u003cvar translate=\"no\"\u003eREGION_ID\u003c/var\u003e is an abbreviated code that Google assigns\nbased on the region you select when you create your app. The code does not\ncorrespond to a country or province, even though some region IDs may appear\nsimilar to commonly used country and province codes. For apps created after\nFebruary 2020, \u003cvar translate=\"no\"\u003eREGION_ID\u003c/var\u003e`.r` is included in\nApp Engine URLs. For existing apps created before this date, the\nregion ID is optional in the URL.\n\nLearn more\n[about region IDs](/appengine/docs/legacy/standard/python/how-requests-are-routed#region-id). \nOK\n\nLearn how to upload, transform, store, and serve images dynamically using the [Images API](/appengine/docs/legacy/standard/python/refdocs/google.appengine.api.images). This\nexample describes how to post messages to a public message board and upload an\navatar with your greeting.\n| This page describes how to use the legacy bundled services and APIs. This API can only run in first-generation runtimes in the App Engine standard environment. If you are updating to the App Engine Python 3 runtime, refer to the [migration guide](/appengine/migration-center/standard/migrate-to-second-gen/python-differences) to learn about your migration options for legacy bundled services.\n\nCreating an Image model in Datastore\n------------------------------------\n\nYou need to update the model from the guestbook sample to store the uploaded image as a blob. \n\n class Greeting(ndb.Model):\n \"\"\"Models a Guestbook entry with an author, content, avatar, and date.\"\"\"\n author = ndb.StringProperty()\n content = ndb.TextProperty()\n avatar = ndb.BlobProperty()\n date = ndb.DateTimeProperty(auto_now_add=True)\n\nUploading user images\n---------------------\n\nYou will need to modify the HTML form to enable the user to upload an image:\n\n1. Add a field that enables the user to select a file from their computer to upload.\n\n2. Add the `enctype` attribute to the form tag and specify this is a multi-part form post.\n\n self.response.out.write(\"\"\"\n \u003cform action=\"/sign?%s\"\n enctype=\"multipart/form-data\"\n method=\"post\"\u003e\n \u003cdiv\u003e\n \u003ctextarea name=\"content\" rows=\"3\" cols=\"60\"\u003e\u003c/textarea\u003e\n \u003c/div\u003e\n \u003cdiv\u003e\u003clabel\u003eAvatar:\u003c/label\u003e\u003c/div\u003e\n \u003cdiv\u003e\u003cinput type=\"file\" name=\"img\"/\u003e\u003c/div\u003e\n \u003cdiv\u003e\u003cinput type=\"submit\" value=\"Sign Guestbook\"\u003e\u003c/div\u003e\n \u003c/form\u003e\n \u003chr\u003e\n \u003cform\u003eGuestbook name: \u003cinput value=\"%s\" name=\"guestbook_name\"\u003e\n \u003cinput type=\"submit\" value=\"switch\"\u003e\u003c/form\u003e\n \u003c/body\u003e\n \u003c/html\u003e\"\"\" % (urllib.urlencode({'guestbook_name': guestbook_name}),\n cgi.escape(guestbook_name)))\n\n3. Update the Guestbook handler to get the image data from the form post and store it as a blob in\n the datastore.\n\n class Guestbook(webapp2.RequestHandler):\n def post(self):\n guestbook_name = self.request.get('guestbook_name')\n greeting = Greeting(parent=guestbook_key(guestbook_name))\n\n if users.get_current_user():\n greeting.author = users.get_current_user().nickname()\n\n greeting.content = self.request.get('content')\n\n avatar = self.request.get('img')\n avatar = images.resize(avatar, 32, 32)\n greeting.avatar = avatar\n greeting.put()\n\n self.redirect('/?' + urllib.urlencode(\n {'guestbook_name': guestbook_name}))\n\nTransforming images\n-------------------\n\nTo create 32x32 avatars you will need to:\n\n1. Import the [`google.appengine.api.images`](/appengine/docs/legacy/standard/python/refdocs/google.appengine.api.images) module.\n\n from google.appengine.api import images\n\n2. Call the `resize` function and pass in the image data.\n\n avatar = images.resize(avatar, 32, 32)\n\nDynamically serving images\n--------------------------\n\nTo serve images, you will need to:\n\n1. Create an image handler that dynamically serves images off the `/img` path.\n\n class Image(webapp2.RequestHandler):\n def get(self):\n greeting_key = ndb.Key(urlsafe=self.request.get('img_id'))\n greeting = greeting_key.get()\n if greeting.avatar:\n self.response.headers['Content-Type'] = 'image/png'\n self.response.out.write(greeting.avatar)\n else:\n self.response.out.write('No image')\n\n2. Update the HTML to display these dynamically served images.\n\n self.response.out.write('\u003cdiv\u003e\u003cimg src=\"/img?img_id=%s\"\u003e\u003c/img\u003e' %\n greeting.key.urlsafe())\n self.response.out.write('\u003cblockquote\u003e%s\u003c/blockquote\u003e\u003c/div\u003e' %\n cgi.escape(greeting.content))\n\nYou will need to update the Guestbook's HTML to pass the key of the greeting to the image handler as\nit gets the `img_id` from the request.\n\nDeploying the app to App Engine\n-------------------------------\n\nTo upload the guestbook app, run the following command from within the\n`guestbook` directory of your application where the `app.yaml` and\n`index.yaml` files are located: \n\n```bash\ngcloud app deploy app.yaml index.yaml\n```\n\nThe [Datastore indexes](/appengine/docs/standard/python3/building-app/storing-and-retrieving-data) might take some time to\ngenerate before your application is available. If the indexes are still in the\nprocess of being generated, you will receive a `NeedIndexError`\nmessage when accessing your app. This error is transient, so try a little later\nif at first you receive this error.\n\nTo learn more about deploying your app from the command line, see\n[Deploying A Python App](/appengine/docs/legacy/standard/python/tools/uploadinganapp).\n\nViewing your deployed application\n---------------------------------\n\nTo launch your browser and view the app at\n\n`https://`\u003cvar translate=\"no\"\u003ePROJECT_ID\u003c/var\u003e`.`\u003cvar translate=\"no\"\u003e\u003ca href=\"#appengine-urls\" style=\"border-bottom: 1px dotted #999\" class=\"devsite-dialog-button\" data-modal-dialog-id=\"regional_url\" track-type=\"progressiveHelp\" track-name=\"modalHelp\" track-metadata-goal=\"regionalURL\"\u003eREGION_ID\u003c/a\u003e\u003c/var\u003e`.r.appspot.com`, run the following command: \n\n```bash\ngcloud app browse\n```"]]