App Engine Expando model get_by_id not working - google-app-engine

python 2.7
app engine 1.8.5.1039
for the life of me I can't figure out whey My InventoryItem Expando model is returning None. My id is valid. I've checked the datastore more times than I'd like to remember. Do I have to pass the Expando model a parent to work properly?
class InventoryItem(db.Expando):
def toDict(self):
d = db.to_dict(self)
d['id'] = self.key().id()
return d
inventoryItem = InventoryItem(parent=toon.getInventory())
for k,v in item.iteritems():
setattr(inventoryItem,k,v)
inventoryItem.put()
inventoryItem_id = self.request.get("id")
logging.info(inventoryItem_id)#5770237022568448
item = InventoryItem.get_by_id(long(inventoryItem_id))#returns None

Your call to get_by_id will need a parent to be supplied, because you are supplying a parent when you create the entity. InventoryItem(parent=toon.getInventory())
See the call docs for get_by_id(id, parent=None, app=None, namespace=None, **ctx_options)
I would also suggest you go and read the docs on how key's work as a good understanding on what the use of parent means is pretty fundamental to using appengine.

Related

ndb query by KeyProperty

I'm struggling with a KeyProperty query, and can't see what's wrong.
My model is
class MyList(ndb.Model):
user = ndb.KeyProperty(indexed=True)
status = ndb.BooleanProperty(default=True)
items = ndb.StructuredProperty(MyRef, repeated=True, indexed=False)
I create an instance of MyList with the appropriate data and can run the following properly
cls = MyList
lists = cls.query().fetch()
Returns
[MyList(key=Key('MyList', 12), status=True, items=..., user=Key('User', 11))]
But it fails when I try to filter by user, i.e. finding lists where the user equals a particular entity; even when using the one I've just used for insert, or from the previous query result.
key = lists[0].user
lists = cls.query(cls.user=key).fetch()
Returns
[]
But works fine with status=True as the filter, and I can't see what's missing?
I should add it happens in a unit testing environment with the following v3_stub
self.policy = datastore_stub_util.PseudoRandomHRConsistencyPolicy(probability=0)
self.testbed.init_datastore_v3_stub(
require_indexes=True,
root_path="%s/../"%(os.path.dirname(__file__)),
consistency_policy=self.policy
)
user=Key('User', 11) is a key to a different class: User. Not MyList
Perhaps you meant:
user = ndb.KeyProperty(kind='User', indexed=True)
Your code looks fine, but I have noticed some data integrity issues when developing locally with NDB. I copied your model and code, and I also got the empty list at first, but then after a few more attempts, the data is there.
Try it a few times?
edit: possibly related?
google app engine ndb: put() and then query(), there is always one less item

get_by_id in google app engine python ndb responds with None

I'm having trouble using get_by_id in google app engine python ndb.
Python Code
Attempt 1
resource = Content.get_by_id(6093630880088064)
resource is None
Attempt 2
resource = Content.get_by_id(6093630880088064, parent = 5249205949956096)
BadValueError: Expected Key instance, got 5249205949956096L
Attempt 3
key_parent = ndb.Key('Subject', '5249205949956096')
resource = Content.get_by_id(6093630880088064, parent = key_parent)
resource is None
Datastore
Entity Kind Content
Entity Key ahBkZXZ-YnJhaW5ib290ZWNocigLEgdTdWJqZWN0GICAgICAxKkJDAsSB0NvbnRlbnQYgICAgIDE6QoM
ID 6093630880088064
Parent ahBkZXZ-YnJhaW5ib290ZWNochQLEgdTdWJqZWN0GICAgICAxKkJDA
Subject:id=5249205949956096
Any suggestions would be greatly appreciated. My goal is that resource will be an object where I can do something like resource.name to retrieve the name property.
This problem occur when you have the key as string, the simplest solution is:
Model.get_by_id(int(id))
This problem is most likely to appear is when you read the id from url and the like:
class MyHandler(webapp2.RequestHandler):
def get(self, id):
instance = Model.get_by_id(int(id))
Solved :)
key = int(key)
key_parent = ndb.Key(Subject, 5249205949956096)
resource = Content.get_by_id(key, parent = key_parent)
Attempt 1:
You get None because no instance exists with this ID. Either the ID is wrong or it's a string not an integer like you’re passing to the function.
Attempt 2:
get_by_id actually expects the parent before the ID (if the parent is passed). If you wanna keep that order then use
resource = Content.get_by_id(id = 6093630880088064, parent = parent_key)
More importantly, the parent argument is the key of the parent not its ID.
Attempt 3:
In your code the ID of the parent is passed as a string and that of the content is passed as an integer. I'm guessing that the problem lies there. You pass either as strings of integers.
Hope that helps.

Datastore: Is it possible to only save to memcache when using ndb API?

dear all
Currently I'm using ndb API to store some statistic information. Unfortunately, this becomes the major source of my cost. I'm thinking it should be much cheaper if I only save them to memcache. It doesn't matter if data is lost due to cache expire.
After read the manual, I assume _use_datastore class variable can be used to configure this behaviour:
class StaticModel(ndb.Model):
_use_datastore = False
userid = ndb.StringProperty()
created_at = ndb.DateTimeProperty(auto_now_add=True)
May I know if above statement is the right solution?
Cheers!
I think there are three ways to achieve what you want.
The first is to set _use_datastore = False on the NDB model class as per your question.
The second would be to pass use_datastore=False whenever you put / get / delete a StaticModel. An example would be:
model = StaticModel(userid="foo")
key = model.put(use_datastore=False)
n = key.get(use_datastore=False)
The third option would be to set a datastore policy in the NDB Context which returns false for any StaticModel keys. Something like:
context.set_datastore_policy(lambda key: True if key.kind() == 'StaticModel' else False)

one to many relationship in Objectify4

I am working with GAE with java. i am just creating a sample application with Student and Course relationships. I am having many branches and many students. Each branch can have many students, i tried like
ObjectifyService.register(Course.class);
ObjectifyService.register(Student.class);
Course course = new Course();
course.setName("ss");
course.setBranch("cs");
ofy().save().entity(course).now();
Student stu = new Student();
stu.setName("student1");
Key<Course> courseKey = new Key<Course>(Course.class, course.getId()); // getting error here
stu.setCourse(courseKey);
System.out.println("saving");
ofy().save().entity(stu).now();
I am not sure how to define this relationship in objecitfy4. I followed the tutorial http://www.eteration.com/objectify-an-easy-way-to-use-google-datastore/
Thanks.
Look at the Javadocs for Key. Instead of a public constructor, there is a more convenient creator method which requires less typing of <> generics:
Key<Course> courseKey = Key.create(Course.class, course.getId());
There are two keys that you might use:
first the GAE low-level com.google.appengine.api.datastore.Key and
second, the objectify's com.googlecode.objectify.Key.
You can use both with Objectify (as under the hood they are ultimately converted to low-level API).
Neither has a public constructor so you can not use new with them.
With low-level keys you'd use KeyFactory.createKey("Course", course.getId()).
With objectify key you'd use com.googlecode.objectify.Key.create(Course.class, course.getId())
When we use Objectify , if we need any Key to be created for condition(KeyFactory.createKey("Course", course.getId()) , In course object, Id field should be specified with index. It will work fine.

Google App Engine - Is this also a Put method? Or something else

Was wondering if I'm unconsciously using the Put method in my last line of code ( Please have a look). Thanks.
class User(db.Model):
name = db.StringProperty()
total_points = db.IntegerProperty()
points_activity_1 = db.IntegerProperty(default=100)
points_activity_2 = db.IntegerProperty(default=200)
def calculate_total_points(self):
self.total_points = self.points_activity_1 + self.points_activity_2
#initialize a user ( this is obviously a Put method )
User(key_name="key1",name="person1").put()
#get user by keyname
user = User.get_by_key_name("key1")
# QUESTION: is this also a Put method? It worked and updated my user entity's total points.
User.calculate_total_points(user)
While that method will certainly update the copy of the object that is in-memory, I do not see any reason to believe that the change will be persisted to the the datastore. Datastore write operations are costly, so they are not going to happen implicitly.
After running this code, use the datastore viewer to look at the copy of the object in the datastore. I think that you may find that it does not have the changed total_point value.

Resources