Skip to content

Commit ff35c33

Browse files
committed
Copy from appengine-memcache-guestbook-python repo.
1 parent 4e4a1d8 commit ff35c33

File tree

8 files changed

+234
-0
lines changed

8 files changed

+234
-0
lines changed

appengine/__init__.py

Whitespace-only changes.

appengine/memcache/__init__.py

Whitespace-only changes.
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
## Memcache Guestbook Sample
2+
3+
This is a sample app for Google App Engine that exercises the [memcache Python API](https://cloud.google.com/appengine/docs/python/memcache/usingmemcache).
4+
5+
See our other [Google Cloud Platform github
6+
repos](https://github.com/GoogleCloudPlatform) for sample applications and
7+
scaffolding for other python frameworks and use cases.
8+
9+
## Run Locally
10+
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).
11+
2. Setup the gcloud tool.
12+
13+
```
14+
gcloud components update app
15+
gcloud auth login
16+
gcloud config set project <your-app-id>
17+
```
18+
You don't need a valid app-id to run locally, but will need a valid id to deploy below.
19+
20+
1. Clone this repo.
21+
22+
```
23+
git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git
24+
cd appengine/memcache/guestbook/
25+
```
26+
1. Run this project locally from the command line.
27+
28+
```
29+
gcloud preview app run ./app.yaml
30+
```
31+
32+
1. Visit the application at [http://localhost:8080](http://localhost:8080).
33+
34+
## Deploying
35+
36+
1. Use the [Cloud Developer Console](https://console.developer.google.com) to create a project/app id. (App id and project id are identical)
37+
2. Configure gcloud with your app id.
38+
39+
```
40+
gcloud config set project <your-app-id>
41+
```
42+
1. Use the [Admin Console](https://appengine.google.com) to view data, queues, and other App Engine specific administration tasks.
43+
1. Use gcloud to deploy your app.
44+
45+
```
46+
gcloud preview app deploy ./app.yaml
47+
```
48+
49+
1. Congratulations! Your application is now live at your-app-id.appspot.com
50+
51+
## Contributing changes
52+
53+
* See [CONTRIBUTING.md](../../../CONTRIBUTING.md)
54+
55+
## Licensing
56+
57+
* See [LICENSE](../../../LICENSE)

appengine/memcache/guestbook/__init__.py

Whitespace-only changes.

appengine/memcache/guestbook/app.yaml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# This file specifies your Python application's runtime configuration
2+
# including URL routing, versions, static file uploads, etc. See
3+
# https://developers.google.com/appengine/docs/python/config/appconfig
4+
# for details.
5+
6+
version: 1
7+
runtime: python27
8+
api_version: 1
9+
threadsafe: yes
10+
11+
# Handlers define how to route requests to your application.
12+
handlers:
13+
14+
# This handler tells app engine how to route requests to a WSGI application.
15+
# The script value is in the format <path.to.module>.<wsgi_application>
16+
# where <wsgi_application> is a WSGI application object.
17+
- url: .* # This regex directs all routes to main.app
18+
script: main.app
19+
20+
libraries:
21+
- name: webapp2
22+
version: "2.5.2"
8.15 KB
Binary file not shown.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
indexes:
2+
3+
# AUTOGENERATED
4+
5+
# This index.yaml is automatically updated whenever the dev_appserver
6+
# detects that a new type of query is run. If you want to manage the
7+
# index.yaml file manually, remove the above marker line (the line
8+
# saying "# AUTOGENERATED"). If you want to manage some indexes
9+
# manually, move them above the marker line. The index.yaml file is
10+
# automatically uploaded to the admin console when you next deploy
11+
# your application using appcfg.py.
12+
13+
- kind: Greeting
14+
ancestor: yes
15+
properties:
16+
- name: date
17+
direction: desc

appengine/memcache/guestbook/main.py

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
# Copyright 2015 Google Inc. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
# [START all]
16+
import cgi
17+
import cStringIO
18+
import logging
19+
import urllib
20+
import webapp2
21+
22+
from google.appengine.ext import ndb
23+
from google.appengine.api import memcache
24+
from google.appengine.api import users
25+
26+
27+
class Greeting(ndb.Model):
28+
"""Models an individual Guestbook entry with author, content, and date."""
29+
author = ndb.StringProperty()
30+
content = ndb.StringProperty()
31+
date = ndb.DateTimeProperty(auto_now_add=True)
32+
33+
34+
def guestbook_key(guestbook_name=None):
35+
"""Constructs a Datastore key for a Guestbook entity with guestbook_name."""
36+
return ndb.Key('Guestbook', guestbook_name or 'default_guestbook')
37+
38+
39+
class MainPage(webapp2.RequestHandler):
40+
def get(self):
41+
self.response.out.write('<html><body>')
42+
guestbook_name = self.request.get('guestbook_name')
43+
44+
greetings = self.get_greetings(guestbook_name)
45+
stats = memcache.get_stats()
46+
47+
self.response.write('<b>Cache Hits:{}</b><br>'.format(stats['hits']))
48+
self.response.write('<b>Cache Misses:{}</b><br><br>'.format(
49+
stats['misses']))
50+
self.response.write(greetings)
51+
52+
self.response.write("""
53+
<form action="/sign?{}" method="post">
54+
<div><textarea name="content" rows="3" cols="60"></textarea></div>
55+
<div><input type="submit" value="Sign Guestbook"></div>
56+
</form>
57+
<hr>
58+
<form>Guestbook name: <input value="{}" name="guestbook_name">
59+
<input type="submit" value="switch"></form>
60+
</body>
61+
</html>""".format(urllib.urlencode({'guestbook_name': guestbook_name}),
62+
cgi.escape(guestbook_name)))
63+
64+
# [START check_memcache]
65+
def get_greetings(self, guestbook_name):
66+
"""
67+
get_greetings()
68+
Checks the cache to see if there are cached greetings.
69+
If not, call render_greetings and set the cache
70+
71+
Args:
72+
guestbook_name: Guestbook entity group key (string).
73+
74+
Returns:
75+
A string of HTML containing greetings.
76+
"""
77+
greetings = memcache.get('{}:greetings'.format(guestbook_name))
78+
if greetings is None:
79+
greetings = self.render_greetings(guestbook_name)
80+
if not memcache.add('{}:greetings'.format(guestbook_name),
81+
greetings, 10):
82+
logging.error('Memcache set failed.')
83+
return greetings
84+
# [END check_memcache]
85+
86+
# [START query_datastore]
87+
def render_greetings(self, guestbook_name):
88+
"""
89+
render_greetings()
90+
Queries the database for greetings, iterate through the
91+
results and create the HTML.
92+
93+
Args:
94+
guestbook_name: Guestbook entity group key (string).
95+
96+
Returns:
97+
A string of HTML containing greetings
98+
"""
99+
greetings = ndb.gql('SELECT * '
100+
'FROM Greeting '
101+
'WHERE ANCESTOR IS :1 '
102+
'ORDER BY date DESC LIMIT 10',
103+
guestbook_key(guestbook_name))
104+
output = cStringIO.StringIO()
105+
for greeting in greetings:
106+
if greeting.author:
107+
output.write('<b>{}</b> wrote:'.format(greeting.author))
108+
else:
109+
output.write('An anonymous person wrote:')
110+
output.write('<blockquote>{}</blockquote>'.format(
111+
cgi.escape(greeting.content)))
112+
return output.getvalue()
113+
# [END query_datastore]
114+
115+
116+
class Guestbook(webapp2.RequestHandler):
117+
def post(self):
118+
# We set the same parent key on the 'Greeting' to ensure each greeting
119+
# is in the same entity group. Queries across the single entity group
120+
# are strongly consistent. However, the write rate to a single entity
121+
# group is limited to ~1/second.
122+
guestbook_name = self.request.get('guestbook_name')
123+
greeting = Greeting(parent=guestbook_key(guestbook_name))
124+
125+
if users.get_current_user():
126+
greeting.author = users.get_current_user().nickname()
127+
128+
greeting.content = self.request.get('content')
129+
greeting.put()
130+
self.redirect('/?' +
131+
urllib.urlencode({'guestbook_name': guestbook_name}))
132+
133+
134+
app = webapp2.WSGIApplication([('/', MainPage),
135+
('/sign', Guestbook)],
136+
debug=True)
137+
138+
# [END all]

0 commit comments

Comments
 (0)