From ff35c33c74f5d364e16182609a273a90498b3abb Mon Sep 17 00:00:00 2001 From: Jeff Mendoza Date: Thu, 21 May 2015 11:25:27 -0700 Subject: [PATCH] Copy from appengine-memcache-guestbook-python repo. --- appengine/__init__.py | 0 appengine/memcache/__init__.py | 0 appengine/memcache/guestbook/README.md | 57 ++++++++++ appengine/memcache/guestbook/__init__.py | 0 appengine/memcache/guestbook/app.yaml | 22 ++++ appengine/memcache/guestbook/favicon.ico | Bin 0 -> 8348 bytes appengine/memcache/guestbook/index.yaml | 17 +++ appengine/memcache/guestbook/main.py | 138 +++++++++++++++++++++++ 8 files changed, 234 insertions(+) create mode 100644 appengine/__init__.py create mode 100644 appengine/memcache/__init__.py create mode 100644 appengine/memcache/guestbook/README.md create mode 100644 appengine/memcache/guestbook/__init__.py create mode 100644 appengine/memcache/guestbook/app.yaml create mode 100644 appengine/memcache/guestbook/favicon.ico create mode 100644 appengine/memcache/guestbook/index.yaml create mode 100644 appengine/memcache/guestbook/main.py diff --git a/appengine/__init__.py b/appengine/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/appengine/memcache/__init__.py b/appengine/memcache/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/appengine/memcache/guestbook/README.md b/appengine/memcache/guestbook/README.md new file mode 100644 index 000000000000..c51b3eec8ed5 --- /dev/null +++ b/appengine/memcache/guestbook/README.md @@ -0,0 +1,57 @@ +## Memcache Guestbook Sample + +This is a sample app for Google App Engine that exercises the [memcache Python API](https://cloud.google.com/appengine/docs/python/memcache/usingmemcache). + +See our other [Google Cloud Platform github +repos](https://github.com/GoogleCloudPlatform) for sample applications and +scaffolding for other python frameworks and use cases. + +## Run Locally +1. Install the [Google Cloud SDK](https://cloud.google.com/sdk/), including the [gcloud tool](https://cloud.google.com/sdk/gcloud/), and [gcloud app component](https://cloud.google.com/sdk/gcloud-app). +2. Setup the gcloud tool. + + ``` + gcloud components update app + gcloud auth login + gcloud config set project + ``` + You don't need a valid app-id to run locally, but will need a valid id to deploy below. + +1. Clone this repo. + + ``` + git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git + cd appengine/memcache/guestbook/ + ``` +1. Run this project locally from the command line. + + ``` + gcloud preview app run ./app.yaml + ``` + +1. Visit the application at [http://localhost:8080](http://localhost:8080). + +## Deploying + +1. Use the [Cloud Developer Console](https://console.developer.google.com) to create a project/app id. (App id and project id are identical) +2. Configure gcloud with your app id. + + ``` + gcloud config set project + ``` +1. Use the [Admin Console](https://appengine.google.com) to view data, queues, and other App Engine specific administration tasks. +1. Use gcloud to deploy your app. + + ``` + gcloud preview app deploy ./app.yaml + ``` + +1. Congratulations! Your application is now live at your-app-id.appspot.com + +## Contributing changes + +* See [CONTRIBUTING.md](../../../CONTRIBUTING.md) + +## Licensing + +* See [LICENSE](../../../LICENSE) diff --git a/appengine/memcache/guestbook/__init__.py b/appengine/memcache/guestbook/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/appengine/memcache/guestbook/app.yaml b/appengine/memcache/guestbook/app.yaml new file mode 100644 index 000000000000..5227472ff0cf --- /dev/null +++ b/appengine/memcache/guestbook/app.yaml @@ -0,0 +1,22 @@ +# This file specifies your Python application's runtime configuration +# including URL routing, versions, static file uploads, etc. See +# https://developers.google.com/appengine/docs/python/config/appconfig +# for details. + +version: 1 +runtime: python27 +api_version: 1 +threadsafe: yes + +# Handlers define how to route requests to your application. +handlers: + +# This handler tells app engine how to route requests to a WSGI application. +# The script value is in the format . +# where is a WSGI application object. +- url: .* # This regex directs all routes to main.app + script: main.app + +libraries: +- name: webapp2 + version: "2.5.2" diff --git a/appengine/memcache/guestbook/favicon.ico b/appengine/memcache/guestbook/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..23c553a2966ca4cecf146093f33d8114b4f1e368 GIT binary patch literal 8348 zcmeI0du&tJ8Ng3Vwv|ewX4Hu@my&|vCD%DN@CLnxyptBT_%HjatoYr7%N3zGPed#@ckvA><;HWecDU4&2}*2(h%gm&WgCftWj zkQfW;&mXr@0S&(csd+cjaImbXSy=NC<10}z(efGwgi=;B$dt=HkKYCvp-#3KX+qIu zxx$>zcwk+N=c%1^J9)sO44lmS0##~wzU(43f>wW-p_YXwj>s>3{gHI*^oo1lmJ!X*bw{3UBAKRut zUh5Uy4_94IIkdxC^v{_g%FjuEI+f&;9KQ3i+nK7pU_RivFjP_DTl-&gP_qr$nD=M{ z@z;C3#y5Jsh77svGQ4u$ZX)t}=e52{#Xvk;4qIxNh86kR$OhCAie%&e`U{r{ACQZ@ z-)1#sItef{2L za&U;nm+_lo@lbR7vat&^EcECsH)uSnhlht@etsV4LE5B`j#GW*iur~}xpYlTtc;FC{nl|LK^miZ0y3WU>MIM zmc}94VzEFx9?#&?4l+h;ggzvOeCI$ob=`tBp*&EtirH2xU z4a#KB)IMa{_YdYrnxq>-DrrQ>rfpYe8@|Nc-oHnG*L(HR$}d4Eo2&X@o1~9l@%@W) zU{%rv$`tBAOHJH+?zcv7`!T~x;=<#7@4R5T^5$-%Pz-NAYt+5{d;>R+9W24y&`;ZkZqFGQ6_)<35Z_$5V#ga#=N9985-M0KR*fl@h4M0BxWvbYQr6t zULtYBAMJ%iU>x|?U8z_Zyv1jg_VcZ^kO)pd_)jk`_~2MHZmybbloW?l)lnMrb~TAX zV&%#e+VLvM4!%js+%B6}N!=udFlN5Jv;yQm0sdW({6ny+{{$_b`%pI&q3%#p3R?q( z%3@zpafPo4-GA}ErIfU@j?gpfdgeyI);;S-otz(GefQbXvG3J6hbwD_0*YOuqb1V8 zpQm{(oT|g$!tcw;Ck6l>=mo$z0J@0f0^U0{x?+mD8}QB{9yV7qQ;&$5^%*fb@qUB& zX(O<{D-aZ493K;1xH%!}9+}vt8Sshs4os9)d132glTa=lIJv}MJyU_Y!ZFl62j9@l zggg2y{y~c&Vm0cMa@}r@bbn?HR4Sa|66p;nlMl_6D%_%EjCNRq)NBvx!R!t`@zUoW zKV#O#EhZy4>~?VU+rfg@_W_4Kt~zS<|3JjVMcZ#exy;pDUypq|xjpD&0#H{BHgrvM zI=z9nnTN~NCX?mf@DOU;!82-#gXGsw5CSSf22lJ>u8duE&igGuZq4lVZf*LH2%QqOqkv@O{w`Y}q~yWm0EP zeSP~Hau49ZBU@&hWwH5YG0dnGVN1^iztQFh>rIvj5$iQ;q^nyuSuXo`U~{E8DpuIS zA{kR5oC9o=_>jhfRX@QTs1KRm{@F31 zFKP1!w?51@R^I~kA%H*B0W^sKnyVIsv`_2;=zbUGR9pOTqUhV{{^UH=RQ2@S?`uaQ zEy`)Gsd}1IEedW&4lAe0Sg5h`nQXqaZ}RyEzX{FT?hmF3>0_QQT1V~jI$wc&1@aZh ZS0G=3d706zJ{{SaIO|Jj| literal 0 HcmV?d00001 diff --git a/appengine/memcache/guestbook/index.yaml b/appengine/memcache/guestbook/index.yaml new file mode 100644 index 000000000000..f933a1c8e6d2 --- /dev/null +++ b/appengine/memcache/guestbook/index.yaml @@ -0,0 +1,17 @@ +indexes: + +# AUTOGENERATED + +# This index.yaml is automatically updated whenever the dev_appserver +# detects that a new type of query is run. If you want to manage the +# index.yaml file manually, remove the above marker line (the line +# saying "# AUTOGENERATED"). If you want to manage some indexes +# manually, move them above the marker line. The index.yaml file is +# automatically uploaded to the admin console when you next deploy +# your application using appcfg.py. + +- kind: Greeting + ancestor: yes + properties: + - name: date + direction: desc diff --git a/appengine/memcache/guestbook/main.py b/appengine/memcache/guestbook/main.py new file mode 100644 index 000000000000..958c5e7230fc --- /dev/null +++ b/appengine/memcache/guestbook/main.py @@ -0,0 +1,138 @@ +# Copyright 2015 Google Inc. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# [START all] +import cgi +import cStringIO +import logging +import urllib +import webapp2 + +from google.appengine.ext import ndb +from google.appengine.api import memcache +from google.appengine.api import users + + +class Greeting(ndb.Model): + """Models an individual Guestbook entry with author, content, and date.""" + author = ndb.StringProperty() + content = ndb.StringProperty() + date = ndb.DateTimeProperty(auto_now_add=True) + + +def guestbook_key(guestbook_name=None): + """Constructs a Datastore key for a Guestbook entity with guestbook_name.""" + return ndb.Key('Guestbook', guestbook_name or 'default_guestbook') + + +class MainPage(webapp2.RequestHandler): + def get(self): + self.response.out.write('') + guestbook_name = self.request.get('guestbook_name') + + greetings = self.get_greetings(guestbook_name) + stats = memcache.get_stats() + + self.response.write('Cache Hits:{}
'.format(stats['hits'])) + self.response.write('Cache Misses:{}

'.format( + stats['misses'])) + self.response.write(greetings) + + self.response.write(""" +
+
+
+
+
+
Guestbook name: +
+ + """.format(urllib.urlencode({'guestbook_name': guestbook_name}), + cgi.escape(guestbook_name))) + + # [START check_memcache] + def get_greetings(self, guestbook_name): + """ + get_greetings() + Checks the cache to see if there are cached greetings. + If not, call render_greetings and set the cache + + Args: + guestbook_name: Guestbook entity group key (string). + + Returns: + A string of HTML containing greetings. + """ + greetings = memcache.get('{}:greetings'.format(guestbook_name)) + if greetings is None: + greetings = self.render_greetings(guestbook_name) + if not memcache.add('{}:greetings'.format(guestbook_name), + greetings, 10): + logging.error('Memcache set failed.') + return greetings + # [END check_memcache] + + # [START query_datastore] + def render_greetings(self, guestbook_name): + """ + render_greetings() + Queries the database for greetings, iterate through the + results and create the HTML. + + Args: + guestbook_name: Guestbook entity group key (string). + + Returns: + A string of HTML containing greetings + """ + greetings = ndb.gql('SELECT * ' + 'FROM Greeting ' + 'WHERE ANCESTOR IS :1 ' + 'ORDER BY date DESC LIMIT 10', + guestbook_key(guestbook_name)) + output = cStringIO.StringIO() + for greeting in greetings: + if greeting.author: + output.write('{} wrote:'.format(greeting.author)) + else: + output.write('An anonymous person wrote:') + output.write('
{}
'.format( + cgi.escape(greeting.content))) + return output.getvalue() + # [END query_datastore] + + +class Guestbook(webapp2.RequestHandler): + def post(self): + # We set the same parent key on the 'Greeting' to ensure each greeting + # is in the same entity group. Queries across the single entity group + # are strongly consistent. However, the write rate to a single entity + # group is limited to ~1/second. + guestbook_name = self.request.get('guestbook_name') + greeting = Greeting(parent=guestbook_key(guestbook_name)) + + if users.get_current_user(): + greeting.author = users.get_current_user().nickname() + + greeting.content = self.request.get('content') + greeting.put() + self.redirect('/?' + + urllib.urlencode({'guestbook_name': guestbook_name})) + + +app = webapp2.WSGIApplication([('/', MainPage), + ('/sign', Guestbook)], + debug=True) + +# [END all]