You'd use something like this to query by ID: review = Review.get_by_id(book.key.id())
.
Your approach of setting the ID only works if there is a 1 to 1 relationship between a book and a review, as Keys are unique. The above operation will only return one entity.
I'd recommend setting the most used query as the Ancestor for the review. My guess is that he Book the review belongs to is the most relevant here, unless your users are famous critics.
If you set the Review's parent as the Book, you can use Ancestor queries to get all of the reviews with guaranteed consistency. Then user can be a property of the review and you could simply filter by that property. I'd suggest using KeyProperty for the reference.
If you want guaranteed consistency for the queries by user, keep a list of reviewed books for each user (repeated KeyProperty), and then run ancestor queries against the reviews, filtered by that user.
UPDATE:
@JimmyKane is right - the get_by_id won't work at all because it apparently requires the parent to be specified, and in your case that doesn't seem very practical.
Code that proves that the get_by_id won't work:
from flask import Flask
from google.appengine.ext import ndb
app = Flask(__name__)
class User(ndb.Model):
name = ndb.StringProperty()
class Book(ndb.Model):
name = ndb.StringProperty()
class Review(ndb.Model):
name = ndb.StringProperty()
@app.route('/')
def hello_main():
user = User()
user.name = 'Test User1'
user.put()
book = Book()
book.name = 'Test Book1'
book.put()
review = Review(id=book.key.id(), parent=user.key)
review.name = 'Test Review1'
review.put()
return 'Review saved!'
@app.route('/reviews/')
def reviews():
book = Book.query(Book.name == 'Test Book1').get()
user = User.query(User.name == 'Test User1').get()
if book:
review = Review.get_by_id(book.key.id(), parent=user.key)
if review:
return review.name
else:
return 'no review'
else:
return 'no books'
if __name__ == "__main__":
app.run()
And here's sample code for my recommended approach:
from flask import Flask
from google.appengine.ext import ndb
class User(ndb.Model):
name = ndb.StringProperty()
reviews = ndb.KeyProperty(repeated=True)
class Book(ndb.Model):
name = ndb.StringProperty()
class Review(ndb.Model):
name = ndb.StringProperty()
app = Flask(__name__)
@app.route('/')
def hello_main():
user = User()
user.name = 'Test User1'
user.put()
book = Book()
book.name = 'Test Book1'
book.put()
review = Review(parent=book.key)
review.name = 'Test Review1'
review.put()
user.reviews.append(review.key)
user.put()
return 'Review saved!'
@app.route('/add_review/')
def add_review():
book = Book.query(Book.name == 'Test Book1').get()
user = User.query(User.name == 'Test User1').get()
if book:
review = Review(parent=book.key)
review.name = 'Test Review'
review.put()
user.reviews.append(review.key)
user.put()
return 'review added'
else:
return 'no books'
@app.route('/reviews/')
def reviews():
book = Book.query(Book.name == 'Test Book1').get()
user = User.query(User.name == 'Test User1').get()
if book:
reviews = Review.query(ancestor=book.key)
for review in reviews:
print(review.name)
print('<br/>')
return ''
else:
return 'no books'
@app.route('/reviews_by_user/')
def reviews_by_user():
user = User.query(User.name == 'Test User1').get()
for review_key in user.reviews:
review = review_key.get()
print(review.name)
print('<br/>')
return ''
if __name__ == "__main__":
app.run()