GAE Datastore ID - google-app-engine

I've created two different Entities, one a User and one a Message they can create. I assign each user an ID and then want to assign this ID to each message which that user creates. How can I go about this? Do I have to do it in a query?
Thanks

Assuming that you are using Python NDB, you can having something like the following:
class User(ndb.Model):
# put your fileds here
class Message(ndb.Model):
owner = ndb.KeyProperty()
# other fields
Create and save a User:
user = User(field1=value1, ....)
user.put()
Create and save a Message:
message = Message(owner=user.key, ...)
message.put()
Query a message based on user:
messages = Message.query().filter(Message.owner==user.key).fetch() # returns a list of messages that have this owner
For more information about NDB, take a look at Python NDB API.
Also, you should take a look at Python Datastore in order to get a better understanding of data modeling in App Engine.

Related

How to insert/get entities from the google cloud Data Store (python)

I am trying to make a python program that uses the google cloud data store in python and i am having some trouble with the DataStore input\output system. this is my first time working with google cloud, and i am also somewhat new to python.
I am trying to build a very simple database, with only 1 type of entity model- 'Command', which has 2 variables- 'name' which i want to be the key, and 'value'. all the entities will have one parent, because the google cloud guide said this will put all the entities in the same entity group, which helps sort them? (i am not sure about this, so explanation will be nice)
class Command(ndb.Model):
value = ndb.IntegerProperty()
# no 'name' variable, since it's the key.
def parent_key():
return ndb.Key(Command, DEFAULT_PARENT_NAME)
when the user uses a 'set' command, the code will either insert a new entity with the given name and value, or if the name exists already, it will change the existing value to the given value.
(assume 'variable_name' is the name and 'variable_value' is the value)
this is the code for the 'set' command:
variable_name = self.request.get('name')
variable_value = self.request.get('value')
newcommand = Command(id=variable_name, value=int(variable_value), parent=parent_key()) # create a new command model
newcommand.put()
this inserts a new command, but doesn't check if it is already in the datastore.
i want the 'get' command to extract the value of an existing name in the database (or return an error, if it doesn't exist), given the name (in a string)
in the online manual i found how to extract stuff from the database given a key, but here i dont have a key, i have a string.
I don't know how to complete the 'set' and 'get' commands and would appreciate some help with this.
Thanks in advance!

Querying datastore with NDB

I'm trying to use Python and NDB to access the datastore, which contains one entity:
I've defined by NDB model with the following code:
class Test(ndb.Model):
name = ndb.StringProperty()
val = ndb.IntegerProperty()
Then I run a query for the entity:
query = Test.get_by_id("Testing")
This returns a NoneType with no val field. I tried setting the argument to name=Testing instead of Testing, but that doesn't help.
What can I do to access my entity in Python? Do I need to identify the project's ID somewhere?
Also, I've been using Flask to serve as the microframework. But all the NDB example code I've seen uses webapp2. Should I use webapp2 instead?
Capitalization matters in Python. Instead of "Test", you need to query from the model "test".

How to flatten a 'friendship' model within User model in GAE?

I recently came across a number of articles pointing out to flatten the data for NoSQL databases. Coming from traditional SQL databases I realized I am replicating a SQL db bahaviour in GAE. So I started to refactor code where possible.
We have e.g. a social media site where users can become friends with each other.
class Friendship(ndb.Model):
from_friend = ndb.KeyProperty(kind=User)
to_friend = ndb.KeyProperty(kind=User)
Effectively the app creates a friendship instance between both users.
friendshipA = Friendship(from_friend = UserA, to_friend = userB)
friendshipB = Friendship(from_friend = UserB, to_friend = userA)
How could I now move this to the actual user model to flatten it. I thought maybe I could use a StructuredProperty. I know it is limited to 5000 entries, but that should be enough for friends.
class User(UserMixin, ndb.Model):
name = ndb.StringProperty()
friends = ndb.StructuredProperty(User, repeated=True)
So I came up with this, however User can't point to itself, so it seems. Because I get a NameError: name 'User' is not defined
Any idea how I could flatten it so that a single User instance would contain all its friends, with all their properties?
You can't create a StructuredProperty that references itself. Also, use of StructuredProperty to store a copy of User has additional problem of needing to perform a manual cascade update if a user ever modifies a property that is stored.
However, as KeyProperty accept String as kind, you can easily store the list of Users using KeyProperty as suggested by #dragonx. You can further optimise read by using ndb.get_multi to avoid multiple round-trip RPC calls when retrieving friends.
Here is a sample code:
class User(ndb.Model):
name = ndb.StringProperty()
friends = ndb.KeyProperty(kind="User", repeated=True)
userB = User(name="User B")
userB_key = userB.put()
userC = User(name="User C")
userC_key = userC.put()
userA = User(name="User A", friends=[userB_key, userC_key])
userA_key = userA.put()
# To retrieve all friends
for user in ndb.get_multi(userA.friends):
print "user: %s" % user.name
Use a KeyProperty that stores the key for the User instance.

Twitter-ish DB structure in Google App Engine

I'm trying to create a site which is quite similar to Twitter. Users will be able to post messages. And users will be able to 'follow' each other. On the homepage, they see the messages from the users they follow, sorted by time.
How do I go about creating the appengine models for this?
In a traditional relational DB, i guess it would be something like this:
Database 'user':
id
username
Database 'follows':
user_id
follow_id
Database 'messages':
user_id
message
And the query will be something like:
SELECT * FROM messages m, follows f WHERE m.user_id = f.follow_id AND f.user_id = current_user_id
I guess i was clear with the example above. How do I replicate this in Google App Engine?
There is a useful presentation at Google I/O a while back by Brett Slatkin which describes building a scalable twitter-like microblog app, and deals with this very question at length: http://www.google.com/events/io/2009/sessions/BuildingScalableComplexApps.html
REVISED:
class AppUser(db.Model):
user_id = db.UserProperty()
username = db.StringProperty()
following = db.ListProperty(db.Key) # list of AppUser keys
class Message(db.Model):
sender = db.ReferenceProperty(AppUser)
body = db.TextProperty()
You would then query the results in two steps:
message_list = []
for followed_user in current_user.following:
subresult = db.GqlQuery("SELECT __key__ FROM Message WHERE sender = :1", followed_user)
message_list.extend(subresult)
results = Message.get(message_list)
(with 'current_user' being the 'AppUser' entity corresponding with your active user)

How to filter users by email in Google App Engine?

I tried User(email = email) and User.all().filter('email = ', email).get(), but both of them don't work for me.
Thanks
The right answer is User(email).
You need to construct a User object for the user you want to filter by - I'm assuming here that your model includes a UserProperty. For example:
User.all().filter("user =", User(email)).get()
Failing that, you can denormalize, and store the user's email in an additional StringProperty field.
If you're using the user as the primary key on your entity, though, you'd be better off fetching the user___id from the User object and using it as the key name for the entity when you create it. Then, you can fetch it with User.get(user_id), which is much more efficient than doing a query.
Assuming you're using the Django variant of GAE, try:
User.all().filter(email = email)

Resources