How to retrieve Google App Engine entities by ancestor - google-app-engine

I have the following 2 models in my Google App Engine datastore:
class Search(db.Model):
what = db.StringProperty()
class SearchResult(db.Model):
search = db.ReferenceProperty(Search)
title = db.StringProperty()
content = db.StringProperty()
And, I am trying to retrieve all SearchResult entities for a given Search entity in the following function:
def get_previous_search_results(what='', where=''):
search_results = None
search = db.GqlQuery("SELECT * FROM Search WHERE what = :1", what).fetch(1)
if search:
search_results = db.GqlQuery("SELECT * FROM SearchResult WHERE ANCESTOR IS :1", search[0].key()).fetch(10)
return search_results
However, it always returns an empty set.
Any ideas what I am doing wrong? I've read through the Python Datastore API docs and this seem like the correct way to do this, but it's not working.

Are you creating the Search entities with a parent? The ReferenceProperty doesn't create an ancestor relationship, and it seems likely you might want search.searchresult_set, which will be a Query for SearchResult objects that have a reference to the Search object 'search'.

Related

NDB: How can I retrieve next/previous entity?

I'm writing an application for a factory where I need to provide a way for the user to retrieve the next (or previous) entity of a kind in NDB and can't figure out how to do this. Any help /tips will be appreciated!
Assume I have the following simplified model:
from google.appengine.ext import ndb
class Product(ndb.Model):
prod_id = ndb.StringProperty(required = True)
prod_desc = ndb.StringProperty(required = True)
prod_units = ndb.StringProperty(required = True)
... other properties
To allow the user to find a particular product I use the query below ('find' comes from a form filled in by the user).
Products_Str = 'Products' # The string ID for the common products ancestor
...
def get_products_key(products_key_str = Products_Str):
return ndb.Key('Products', Products_Str)
class DisplayProduct(BaseHandler): # Displays a product found on exact prod_id property
def post(self):
search_key = self.request.get('find')
find_query = Product.query(Product.prod_id == search_key, ancestor = get_products_key()).get()
... here I display the one result of the query, i.e. the requested product
So far so good: I provide the user with a way to find a specific product based on code (or description).
Now I need to place two buttons on the display page named "previous" and "next" and I can't figure out how to retrieve the next and previous products.
I would welcome any suggestions.

Datastore query two entity kinds, on a common property?

Say I have two entity kinds:
class image(db.Model):
url = db.LinkProperty()
date= db.DateTimeProperty()
class video(db.Model):
url = db.LinkProperty()
date= db.DateTimeProperty()
Which each may have some other (unimportant here) properties.
What I want to do is somehow merge the queries:
i = image.gql('ORDER BY date LIMIT 10')
v = video.gql('ORDER BY date LIMIT 10')
Such that I am left with a single GqlQuery object that is the result as if image and video were the same kind.
Is it possible without doing something like:
merged = ([a for a in i] + [b for b in v]).sort(key=lambda x: x.date)[:10]
Being left with an actual GqlQuery object instead of a list of entities would be a plus, though I have everything I need from the latter.
The only way with inheritance and different classes is to use a PolyModel then your class hierarchy would be
class Media(db.Model):
url = db.LinkProperty()
date= db.DateTimeProperty()
class Image(Media):
pass
class Video(Media):
pass
Then in GQL and preferably Query objects
To get all media types
query = Media.query().order(Media.date)
To just get Video
query = Video.query().order(Video.date)
Or don't have different classes. Have a single Media class and a field that denotes a media type.
Docs for PolyModel can be found here - https://developers.google.com/appengine/docs/python/ndb/polymodelclass

Retrieving Datastore Object With Key

Using examples from the GAE documentation I have successfully put and object to the datastore as I can view it in the admin console. Retrieving has been difficult, here is my code.
import webapp2
from google.appengine.ext import ndb
user_key = ndb.Key('Info_model', 'Bill')
class Info_model(ndb.Model):
username = ndb.StringProperty()
phone = ndb.IntegerProperty()
active = ndb.BooleanProperty()
class Create_entity(webapp2.RequestHandler):
def get(self):
user1 = Info_model(username = 'Bill',
phone = 1231231234,
active = False)
user1.put()
self.response.write('<!doctype html><html><body>Entity created.<pre>')
self.response.write('</pre></body></html>')
class MainPage(webapp2.RequestHandler):
def get(self):
self.response.out.write('<html><body>')
#get object from datastore using example from GAE Documentation.
user_key = ndb.Key('Info_model', 'Bill')
user1 = user_key.get()
self.response.write(user1.username)
self.response.write(user1.phone)
self.response.write(user1.active)
self.response.write('</body></html>')
application = webapp2.WSGIApplication([
('/', MainPage),
('/create', Create_entity)
], debug=True)
From datastore documentation:
It says:
Retrieving Entities from Keys
Given an entity's key, you can retrieve the entity from the Datastore:
sandy = sandy_key.get()
I believe this example assumes we have set a variable named sandy_key as an ndb.Key() but it doesn't really say.
I have successfully run all the ndb tutorial examples but they create a new object for each entry. I want to have only one object, call it up, edit it and put() it again. I suspect I have made the key incorrectly or called it incorrectly. I have also tried:
user1 = ndb.get('agxkZXZ-aWZnYWxlcnRyFwsSCkluZm9fbW9kZWwYgICAgICAgAkM')
Having copied the key from the admin console. This does not work, Eclipse code editor says, "Undefined variable frome import:get". I have tried a different example from the GAE documentation:
# Create an entity and write it to the Datastore.
ent = MyModel(name='booh', xyz=[10**100, 6**666])
assert ent.abc == 0
key = ent.put()
# Read an entity back from the Datastore and update it.
ent = key.get()
ent.abc += 1
ent.xyz.append(ent.abc//3)
ent.put()
But this seems to be made for all being in one scope. If I create an object in one class then try to retrieve it in another class, the variable ent in ent=key.get() is undefined.
As well I have tried many other examples in the documentation but many are incomplete and assume the reader is not a novice.
Given I have an object in the datastore, how can I retrieve that object specifically and print it out like the following:
class MainPage(webapp2.RequestHandler):
def get(self):
self.response.out.write('<html><body>')
#get object from datastore using example from GAE Documentation.
user_key = ndb.Key('Info_model', 'Bill')
user1 = user_key.get()
self.response.write(user1.username)
self.response.write(user1.phone)
self.response.write(user1.active)
self.response.write('</body></html>')
Sorry for the noob question, if there is a more appropriate forum for beginner GAE programmers please let me know.
The problem is, that you have created a key here ...
user_key = ndb.Key('Info_model', 'Bill')
... but this is never put() to the datastore.
Later (in your Create_entity get method) you are using ...
user1 = Info_model(username = 'Bill',
phone = 1231231234,
active = False)
user1.put()
... and this is correctly 'putting' the Info_model entity into the datastore.
However, this code ...
user_key = ndb.Key('Info_model', 'Bill')
user1 = user_key.get()
... attempts to get an entity of kind Info_model from the datastore with key_name "Bill", but this is not what you put into the datastore in the first place.
Maybe what you are trying to achieve, is to create an entity of kind Info_model, with key_name 'Bill', which you can then later get by keyname? If that is the case, try this code ...
user1 = Info_model.get_or_insert('Bill',
username='Bill',
phone=1231231234,
active=False)
user2_key = ndb.Key('Info_model', 'Bill')
user2 = user2_key.get()
assert user1.key == user2.key
Do be aware, however, that an entities key_name is final - you cannot change this later. You may want to consider how you would handle the scenario where Bill wanted to change his username.
As a side note, I would recommend using an ndb.StringProperty for the phone property, as often phone numbers start with a 0, or contain spaces or characters such as +

Updating existing entity in endpoints-proto-datastore

I am using Endpoints-proto-datastore written by Danny Hermes for Google App Engine and need help figuring out how to update an entity.. My model for what I need to update is the following
class Topic(EndpointsModel):
#_message_fields_schema = ('id','topic_name','topic_author')
topic_name = ndb.StringProperty(required=True)
topic_date = ndb.DateTimeProperty(auto_now_add=True)
topic_author = ndb.KeyProperty(required=True)
topic_num_views = ndb.IntegerProperty(default=0)
topic_num_replies = ndb.IntegerProperty(default=0)
topic_flagged = ndb.BooleanProperty(default=False)
topic_followers = ndb.KeyProperty(repeated=True)
topic_avg_rating = ndb.FloatProperty(default=0.0)
topic_total_rating = ndb.FloatProperty(default=0.0)
topic_num_ratings = ndb.IntegerProperty(default=0)
topic_raters = ndb.KeyProperty(repeated=True)
And as you can see, the rating properties have a default of 0. So each time a topic is rated, I need to update each of the rating properties. However, none of my properties is the actual rating being provided by the user. How can i pass in the value the user rated the topic to be able to update the properties in the model? Thanks!
You can do this by having an "alias" property called rating associated with your UserModel:
from endpoints_proto_datastore.ndb import EndpointsAliasProperty
class UserModel(EndpointsModel):
...
def rating_set(self, value):
# Do some validation
self._rating = value
#EndpointsAliasProperty(setter=rating_set)
def rating(self):
return self._rating
This will allow ratings to be sent with UserModels in requests but won't require those ratings to be stored.
You're better off using the OAuth 2.0 token for the user and calling endpoints.get_current_user() to determine who the user is in the request.
Something like a dedicated model for ratings could be much easier:
from endpoints_proto_datastore.ndb import EndpointsUserProperty
class Rating(EndpointsModel):
rater = EndpointsUserProperty(raise_unauthorized=True)
rating = ndb.IntegerProperty()
topic = ndb.KeyProperty(kind=Topic)
and then transactionally retrieving the Topic from the datastore and updating it in a request method decorated by #Rating.method.

How to retrieve entity from key value in GQL

I am using Google App Engine's datastore and wants to retrieve an entity whose key value is written as
ID/Name
id=1
Can anyone suggest me a GQL query to view that entity in datastore admin console and also in my python program?
From your application use the get_by_id() class method of the Model:
entity = YourModel.get_by_id(1)
From Datastore viewer you should use the KEY function:
SELECT * FROM YourModel WHERE __key__ = KEY('YourModel',1)
An application can retrieve a model instance for a given Key using the get() function.
class member(db.Model):
firstName=db.StringProperty(verbose_name='First Name',required=False)
lastName=db.StringProperty(verbose_name='Last Name',required=False)
...
id = int(self.request.get('id'))
entity= member.get(db.Key.from_path('member', id))
I'm not sure how to return a specific entity in the admin console.

Resources