Skip to content

Commit 8661575

Browse files
authored
Ndb migration sample (GoogleCloudPlatform#4067)
* Use google.cloud ndb for overview * Moved NDB migration to migration/ path * New NDB sample * Pulled page out to a template * Added requirements-test spec * Lint fixes, switched to pytest * Lint fixes * Lint fix * Python 2.7 library specified
1 parent 70677d2 commit 8661575

File tree

12 files changed

+220
-4
lines changed

12 files changed

+220
-4
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
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+
To deploy and run this sample in App Engine standard for Python 2.7:
15+
16+
pip install -t lib -r requirements.txt
17+
gcloud app deploy
18+
19+
To deploy and run this sample in App Engine standard for Python 3.7:
20+
21+
gcloud app deploy app3.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+
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
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
runtime: python38
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)
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
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
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+
from flask import Flask, redirect, render_template, request
17+
from google.cloud import ndb
18+
19+
try:
20+
from urllib import urlencode
21+
except Exception:
22+
from urllib.parse import urlencode
23+
24+
app = Flask(__name__)
25+
client = ndb.Client()
26+
27+
28+
# [START greeting]
29+
class Greeting(ndb.Model):
30+
"""Models an individual Guestbook entry with content and date."""
31+
content = ndb.StringProperty()
32+
date = ndb.DateTimeProperty(auto_now_add=True)
33+
# [END greeting]
34+
35+
# [START query]
36+
with client.context():
37+
@classmethod
38+
def query_book(cls, ancestor_key):
39+
return cls.query(ancestor=ancestor_key).order(-cls.date)
40+
41+
42+
@app.route('/', methods=['GET'])
43+
def display_guestbook():
44+
guestbook_name = request.args.get('guestbook_name', '')
45+
print('GET guestbook name is {}'.format(guestbook_name))
46+
with client.context():
47+
ancestor_key = ndb.Key("Book", guestbook_name or "*notitle*")
48+
greetings = Greeting.query_book(ancestor_key).fetch(20)
49+
# [END query]
50+
51+
greeting_blockquotes = [greeting.content for greeting in greetings]
52+
return render_template(
53+
'index.html',
54+
greeting_blockquotes=greeting_blockquotes,
55+
guestbook_name=guestbook_name
56+
)
57+
58+
59+
# [START submit]
60+
@app.route('/sign', methods=['POST'])
61+
def update_guestbook():
62+
# We set the parent key on each 'Greeting' to ensure each guestbook's
63+
# greetings are in the same entity group.
64+
guestbook_name = request.form.get('guestbook_name', '')
65+
print('Guestbook name from the form: {}'.format(guestbook_name))
66+
67+
with client.context():
68+
print('Guestbook name from the URL: {}'.format(guestbook_name))
69+
greeting = Greeting(
70+
parent=ndb.Key("Book", guestbook_name or "*notitle*"),
71+
content=request.form.get('content', None)
72+
)
73+
greeting.put()
74+
# [END submit]
75+
76+
return redirect('/?' + urlencode({'guestbook_name': guestbook_name}))
77+
78+
79+
if __name__ == '__main__':
80+
# This is used when running locally.
81+
app.run(host='127.0.0.1', port=8080, debug=True)
82+
# [END all]
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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+
def test_app(app):
26+
response = app.get('/')
27+
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.9
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Newer versions of rsa module are incompatible with Python 2.7
2+
rsa==4.0
3+
4+
googleapis_common_protos
5+
google-cloud-ndb
6+
flask==1.1.2

0 commit comments

Comments
 (0)