views:

291

answers:

6

I'm using google app engine, and am having trouble writing querys to filter ReferenceProperties.

eg.

class Group(db.Model):
    name = db.StringProperty(required=True)
    creator = db.ReferenceProperty(User)

class GroupMember(db.Model):
    group = db.ReferenceProperty(Group)
    user = db.ReferenceProperty(User)

And I have tried writing something like this:

members = models.GroupMember.all().filter('group.name =', group_name)

and various other things that don't work. Hopefully someone can give me a prod in the right direction...

+1  A: 

This would require a join, which isn't possible in App Engine. If you want to filter by a property of another model, you need to include that property on the model you're querying against.

Nick Johnson
A: 

Thanks for the answer. Is it possible to somehow filter it using a set of keys? ie. Using keys from the Group class. If not, can someone tell me what use would there be for the ReferenceProperty class?

wodemoneke
I looked beyond the syntax question to guess what you wanted to do. If I guessed right, given a group, find the members. I added that as another answer.
Thomas L Holaday
+1  A: 

This would result in two datastore hits but should work. If you use memcache shouldnt be a problem.

group = models.Group.all().filter("name =", group_name).get()
members = models.GroupMember.all().filter('group =', group)
Sam
+3  A: 

If your groups are uniquely named, then your "group.name" is a unique identifier of a Group entity.

That means you can write:

  members = models.GroupMember.all().filter(
    "group =",model.Group.gql("WHERE name=:1", group_name).get()
    )

though you only need to do that if you don't already have the group entity lying around in the stack somewhere.

Google's essay on many-to-many with appengine is here.

Thomas L Holaday
+2  A: 

If what you want is to get the members of a group, ReferenceProperties have that built-in.

class GroupMember(db.Model):
    group = db.ReferenceProperty(Group, collection_name="groupMembers")
    user = db.ReferenceProperty(User, collection_name="groupMembers")

Then you can write:

# get the group entity somehow
group = Group.get(group_key)     
# do something with the members, such as list the nicknames
nicknames = [x.user.nickname for x in group.groupMembers]
Thomas L Holaday
A: 

Using the Models that you defined in your question, lets say you want to list all members of a group called "Space monkeys".

mygroup = Group.gql("WHERE name = :1",'Space monkeys')

for group_member in mygroup.groupmember_set:
    print 'group members name is: %s' % (group_member.user.name)

The "groupmember_set" is called a "implicit collection property" and is very useful. You can call it whatever you want by over-riding the default name using the collection_name keyword parameter to ReferenceProperty. For an example see the answer by Thomas L Holaday.

This is all explained in a very good paper by Rafe Kapla: Modeling Entity Relationships.

Tom