Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 3720b9e

Browse files
engelkeTakashi Matsuo
andauthored
New sample: Cloud ndb with redis cache (GoogleCloudPlatform#4477)
* Added caching to sample * Reminder to deploy index.yaml * Fixed date Co-authored-by: Takashi Matsuo <[email protected]>
1 parent 616ad7a commit 3720b9e

File tree

11 files changed

+247
-0
lines changed

11 files changed

+247
-0
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
## App Engine Datastore NDB Overview Sample
2+
3+
[![Open in Cloud Shell][shell_img]][shell_link]
4+
5+
[shell_img]: http://gstatic.com/cloudssh/images/open-btn.png
6+
[shell_link]: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=appengine/standard/migration/ndb/overview/README.md
7+
8+
This is a sample app for Google App Engine that demonstrates how to replace
9+
use of the [Datastore NDB Python API](https://cloud.google.com/appengine/docs/python/ndb/)
10+
with the [Google Cloud NDB library](https://googleapis.dev/python/python-ndb/latest/index.html).
11+
This library can be used not only on App Engine, but also other Python 3
12+
platforms.
13+
14+
This sample also uses
15+
[Memorystore for Redis](https://cloud.google.com/memorystore/docs/redis/redis-overview)
16+
caching to improve NDB performance in some situations.
17+
18+
Prior to deploying this sample, a
19+
[serverless VPC connector](https://cloud.google.com/vpc/docs/configure-serverless-vpc-access)
20+
must be created and then a
21+
[Memorystore for Redis instance](https://cloud.google.com/memorystore/docs/redis/quickstart-console)
22+
on the same VPC. The IP address and port number of the Redis instance, and
23+
the name of the VPC connector should be entered in either app.yaml
24+
(for Python 2.7) or app3.yaml (for Python 3).
25+
26+
To deploy and run this sample in App Engine standard for Python 2.7:
27+
28+
pip install -t lib -r requirements.txt
29+
gcloud app deploy app.yaml index.yaml
30+
31+
To deploy and run this sample in App Engine standard for Python 3.7:
32+
33+
gcloud app deploy app3.yaml index.yaml
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
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+
runtime: python27
7+
api_version: 1
8+
threadsafe: yes
9+
10+
# Handlers define how to route requests to your application.
11+
handlers:
12+
# This handler tells app engine how to route requests to a WSGI application.
13+
# The script value is in the format <path.to.module>.<wsgi_application>
14+
# where <wsgi_application> is a WSGI application object.
15+
- url: .* # This regex directs all routes to main.app
16+
script: main.app
17+
18+
libraries:
19+
- name: setuptools
20+
version: 36.6.0
21+
- name: grpcio
22+
version: 1.0.0
23+
24+
env_variables:
25+
REDIS_CACHE_URL: 'redis://<REDIS_HOST>:<REDIS_PORT>'
26+
27+
vpc_access_connector:
28+
name: 'projects/<PROJECT_ID>/locations/<REGION>/connectors/<CONNECTOR_NAME>'
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
runtime: python38
2+
3+
env_variables:
4+
REDIS_CACHE_URL: 'redis://<REDIS_HOST>:<REDIS_PORT>'
5+
6+
vpc_access_connector:
7+
name: 'projects/<PROJECT_ID>/locations/<REGION>/connectors/<CONNECTOR_NAME>'
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import pkg_resources
2+
from google.appengine.ext import vendor
3+
4+
# Set path to your libraries folder.
5+
path = 'lib'
6+
# Add libraries installed in the path folder.
7+
vendor.add(path)
8+
# Add libraries to pkg_resources working set to find the distribution.
9+
pkg_resources.working_set.add_entry(path)
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
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# Copyright 2020 Google LLC
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+
from flask import Flask, redirect, render_template, request
17+
from google.cloud import ndb
18+
import logging
19+
20+
try:
21+
from urllib import urlencode
22+
except Exception:
23+
from urllib.parse import urlencode
24+
25+
app = Flask(__name__)
26+
client = ndb.Client()
27+
28+
try:
29+
global_cache = ndb.RedisCache.from_environment()
30+
except Exception:
31+
logging.warning('Redis not available.')
32+
global_cache = None
33+
34+
35+
# [START greeting]
36+
class Greeting(ndb.Model):
37+
"""Models an individual Guestbook entry with content and date."""
38+
content = ndb.StringProperty()
39+
date = ndb.DateTimeProperty(auto_now_add=True)
40+
# [END greeting]
41+
42+
# [START query]
43+
with client.context(global_cache=global_cache):
44+
@classmethod
45+
def query_book(cls, ancestor_key):
46+
return cls.query(ancestor=ancestor_key).order(-cls.date)
47+
48+
49+
@app.route('/', methods=['GET'])
50+
def display_guestbook():
51+
guestbook_name = request.args.get('guestbook_name', '')
52+
print('GET guestbook name is {}'.format(guestbook_name))
53+
with client.context(global_cache=global_cache):
54+
ancestor_key = ndb.Key("Book", guestbook_name or "*notitle*")
55+
greetings = Greeting.query_book(ancestor_key).fetch(20)
56+
# [END query]
57+
58+
greeting_blockquotes = [greeting.content for greeting in greetings]
59+
return render_template(
60+
'index.html',
61+
greeting_blockquotes=greeting_blockquotes,
62+
guestbook_name=guestbook_name
63+
)
64+
65+
66+
# [START submit]
67+
@app.route('/sign', methods=['POST'])
68+
def update_guestbook():
69+
# We set the parent key on each 'Greeting' to ensure each guestbook's
70+
# greetings are in the same entity group.
71+
guestbook_name = request.form.get('guestbook_name', '')
72+
print('Guestbook name from the form: {}'.format(guestbook_name))
73+
74+
with client.context(global_cache=global_cache):
75+
print('Guestbook name from the URL: {}'.format(guestbook_name))
76+
greeting = Greeting(
77+
parent=ndb.Key("Book", guestbook_name or "*notitle*"),
78+
content=request.form.get('content', None)
79+
)
80+
greeting.put()
81+
# [END submit]
82+
83+
return redirect('/?' + urlencode({'guestbook_name': guestbook_name}))
84+
85+
86+
if __name__ == '__main__':
87+
# This is used when running locally.
88+
app.run(host='127.0.0.1', port=8080, debug=True)
89+
# [END all]
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
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+
import pytest
16+
17+
18+
@pytest.fixture
19+
def app():
20+
import main
21+
main.app.testing = True
22+
return main.app.test_client()
23+
24+
25+
@pytest.mark.skip
26+
def test_app(app):
27+
response = app.get('/')
28+
assert response.status_code == 200
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pytest==4.6.11; python_version < '3.0'
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Newer versions of rsa module are incompatible with Python 2.7
2+
rsa==4.5; python_version < '3'
3+
googleapis_common_protos
4+
google-cloud-ndb
5+
flask==1.1.2
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<!doctype html>
2+
<html>
3+
<head>
4+
<title>Guestbook</title>
5+
</head>
6+
7+
<body>
8+
{% for greeting in greeting_blockquotes %}
9+
<blockquote>{{ greeting }}</blockquote>
10+
{% endfor %}
11+
12+
<form action="/sign" method="post">
13+
<div>
14+
<textarea name="content" rows="3" cols="60"></textarea>
15+
</div>
16+
<div>
17+
<input type="submit" value="Sign Guestbook" />
18+
<input type="hidden" name="guestbook_name" value="{{ guestbook_name }}"/>
19+
</div>
20+
</form>
21+
22+
<hr>
23+
24+
<form action="/" method="GET">
25+
Guestbook name:
26+
<input name="guestbook_name" value="{{guestbook_name}}" />
27+
<input type="submit" value="switch" />
28+
</form>
29+
</body>
30+
</html >

0 commit comments

Comments
 (0)