Inheritance or ownership between ndb entities in google Datastore [duplicate] - google-app-engine

This question already has answers here:
db.ReferenceProperty() vs ndb.KeyProperty in App Engine
(2 answers)
Closed 6 years ago.
I am working on a simple online database for sharing technical equipment between artists.
I would like to let a class User() own entities of other classes such as a Lamp() or a Speaker().
It seems that I could be using ReferenceProperty when using db, but when I look through the documentation for ndb it seems a bit confusing to me, as I can't find ReferenceProperty.
So If, using ndb, I want to let an entity of the class Lamp() be owned by an entity of the class User(), by referencing the id of a User(), what should I do? Wanting it to be something like what I have written below, although I am pretty confident that what I have written below does not in fact work:
class User(ndb.Model):
name = ndb.StringProperty()
email = ndb.....
class Lamp(db.Model):
owner = db.ReferenceProperty(User)

What you're looking for is ndb.KeyProperty(kind="User") as shown in https://cloud.google.com/appengine/docs/python/ndb/entity-property-reference
That way if you have a user u for example and want all the lamps owned by u you could get them this way:
lamps = Lamp.query(Lamp.owner == u.key).fetch()
And if you have a lamp l and want to get the owner of l you could get it this way:
owner = l.owner.get()
You could also use ancestors to reference your clases without specifying the KeyProperty as shown in https://cloud.google.com/appengine/docs/python/ndb/queries

Related

Problems with StructuredProperty and StringProperty

i am doing the finally degree work in Google App Engine, but i am having problems when i try this:
class Predicate(ndb.Model):
name = ndb.StringProperty()
parameters = ndb.JsonProperty()
class State(ndb.Model):
predicates = ndb.StructuredProperty(Predicate, repeated=True)
class Action(ndb.Model):
name = ndb.StringProperty()
parameters = ndb.StringProperty(repeated=True)
preconditions = ndb.StructuredProperty(Predicate, repeated=True)
predicatesToAdd = ndb.StructuredProperty(Predicate, repeated=True)
predicatesToDel = ndb.StructuredProperty(Predicate, repeated=True)
class Plan(ndb.Model):
plan = ndb.StructuredProperty(Predicate, repeated=True)
class Problem(ndb.Model):
initialState = ndb.StructuredProperty(Predicate)
goalState = ndb.StructuredProperty(Predicate)
actions = ndb.StructuredProperty(Action, repeated=True)
i get this error:
TypeError: This StructuredProperty cannot use repeated=True because its model class (Predicate) contains repeated properties (directly or indirectly).
StructuredProperty, if it contains repetitions, can not be replicated another StructuredProperty. But I need this structure models. How can i solve this?
And sorry for my bad english :(
I solved this problem using LocalStructuredProperty, but I think it will not work at all
The problem with your design is that ndb does not allow nested repeated properties. In other words, you cannot have a repeated structured property, which in turn has its own repeated property. If you remove the repeated=True from the parameters property, it will work.
You will need to re-think your design to work around this. One possible solution may be to use a JsonProperty for parameters, and store the list of strings as a JSON string. You won't be able to query them then of course, but it may work out depending on your requirements.

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 +

How to get related to db.Model entity from datastore - what API allows it?

I want to read related to model entity. What API I should use?
For example:
class DeleteMe(db.Model):
x = db.FloatProperty()
DeleteMe(key_name = '1').put()
How to read raw entity from datastore for key_name = '1'?
To get the corresponding model that you just put, use get_by_key_name. (https://developers.google.com/appengine/docs/python/datastore/modelclass#Model_get_by_key_name)
DeleteMe.get_by_key_name('1')
However, I noticed you're using the db package and not ndb. I would encourage you to use ndb as it has many optimizations and a more powerful API to the datastore.
https://developers.google.com/appengine/docs/python/ndb/
Corresponding code for NDB might look like:
from google.appengine.ext import ndb
class DeleteMe(ndb.Model):
x = ndb.FloatProperty()
DeleteMe(id='1').put()
DeleteMe.get_by_id('1')

How to create JSON-Response when Entities are referenced via Ancestor?

Maybe my question is somehow unspecific, sorry for that. I'm learning python and app engine (webapp2) at the moment.
I have this class:
class Ice(db.Model):
"""Models an individual Guestbook entry with an author, content, and date."""
name = db.StringProperty()
description = db.StringProperty(multiline=True)
date = db.DateTimeProperty(auto_now_add=True)
def getTags(self):
return Tag.all().ancestor(self).fetch(10)
Tags are referenced via ancestor.
When I use a jinja-template i can call ice.getTags() foreach Ice.
Now i want to serialize my Ice-object to JSON and want to have all Tags that belong to the Ice-object in my JSON-Output.
This does serialisation for me:
It works okay, but it doesn't include the Tags.
I'm feeling, that i have to declare Tags as Ice-Attribute, but i don't know how.
class IceHandler(basehandler.BaseHandler):
def get(self):
ice_query = model.Ice.all().order('-date')
ices = ice_query.fetch(10)
self.response.write(json.encode(ices))
Thanks!

App Engine Messaging System with Message Status - Design Pattern

I'm building a Threaded Messaging System that will be hosted on Google AppEngine
I've modeled it after the technique described by Brett Slatkin in Building Scalable, Complex Apps on App Engine
class Message(db.Model):
sender = db.StringProperty()
body = db.TextProperty()
class MessageIndex(db.Model):
receivers = db.StringListProperty()
The issue I'm having to determining the most efficient way to track the message state for a User.
For example is a message read, archived, deleted for a particular user.
Here are the solution I have come up with so far.
I'm using Datastore+'s StructuredProperty to add a state to the message MessageIndex
class Message(model.Model):
sender = model.StringProperty()
body = model.TextProperty()
class _DisplayState(model.Model):
user_key = model.KeyProperty()
state = model.IntegerProperty(default=0) # 0-unread, 1-read, 2-archived
class MessageIndex(model.Model):
receivers = model.StructuredProperty(_DisplayState, repeated=True)
This solution, while simple, negates the benefit of the MessageIndex. Additionally since the the MessageIndex is in the same entity group as the message datastore writes will be limited.
Full Source Code
What would be the most efficient way to accomplish this? Would adding an additional entity group be a better solution?
class MessageState(model.Model):
user_key = model.KeyProperty()
message_key = model.KeyPropery()
message_state = model.IntegerProperty(default=0) # 0-unread, 1-read, 2-archived
For the easiest querying - split your 'receivers' list into four different lists - 'unread', 'read', 'archived', 'deleted' and shuffle the receiver record between the lists as appropriate.

Resources