How to create a query for key mapping?

I use the key of another user, the sponsor, to indicate who is the sponsor of the User, and creates a link in the data store for those users who have a sponsor, and there can be no more than one, but the sponsor can sponsor many users like ID 2002 in this case that sponsored three other users:

enter image description here

In this case, this query does what I want: SELECT * FROM User where sponsor =KEY('agtzfmJuYW5vLXd3d3ILCxIEVXNlchjSDww') , but I don't know how to program it with python, I can only use it in the data store. How can I execute a query by key when I want to map a set of users who have the same user as the key in the same field? A user in my model can have no more than one sponsor, and I just want to know who sponsored a particular person, which can be a list of users, and then they sponsored users, in turn, who I also want to request.

The field sponsor is the key, and it has a link to the sponsor in the data warehouse. I set the key in exactly the same way as user2.sponsor = user1.key and now I want to find everything that user1 sponsored with a request that should be like

User.All().filter('sponsor = ', user1.key)

but the sponsor is a key type field, so I don’t know how to match it to see, for example, a list of people whose active user is the sponsor and how it becomes a tree when the second generation also has links. How to choose a list of users for which this user is a sponsor, and then the second generation? When I modeled the relation simply as u1 = u2.key ie user2.sponsor = user1.key. Thanks for any hint.

The following workaround is bad practice, but my last and only resort:

 def get(self): auser = self.auth.get_user_by_session() realuser = auth_models.User.get_by_id(long( auser['user_id'] )) q = auth_models.User.query() people = [] for p in q: try: if p.sponsor == realuser.key: people.append(p) except Exception, e: pass if auser: self.render_jinja('my_organization.html', people=people, user=realuser,) 

Update

The problems are that a key property is not required and that Guido Van Rossum reported it as an error in ndb when I think it is an error in my code. This is what I am using now, which is a very acceptable solution, since every real user in the organization, with the possible exception of programmers, testers and administrators, must have a sponsor identifier, which is a user identifier.

 from ndb import query class Myorg(NewBaseHandler): @user_required def get(self): user = auth_models.User.get_by_id(long(self.auth.get_user_by_session()['user_id'])) people = auth_models.User.query(auth_models.User.sponsor == user.key).fetch() self.render_jinja('my_organization.html', people=people, user=user) class User(model.Expando): """Stores user authentication credentials or authorization ids.""" #: The model used to ensure uniqueness. unique_model = Unique #: The model used to store tokens. token_model = UserToken sponsor = KeyProperty() created = model.DateTimeProperty(auto_now_add=True) updated = model.DateTimeProperty(auto_now=True) # ID for third party authentication, eg 'google:username'. UNIQUE. auth_ids = model.StringProperty(repeated=True) # Hashed password. Not required because third party authentication # doesn't use password. password = model.StringProperty() ... 
+7
source share
2 answers

The user model is NDB Expando, which is a bit complicated to query.

From docs

Another useful trick is an Expando type query for dynamic property. You cannot use class.query (class.propname == value) because the class does not have a property object. Instead, you can use the ndb.query.FilterNode class to build a filter expression, as follows:

 from ndb import model, query class X(model.Expando): @classmethod def query_for(cls, name, value): return cls.query(query.FilterNode(name, '=', value)) print X.query_for('blah', 42).fetch() 

So try:

 form ndb import query def get(self): auser = self.auth.get_user_by_session() realuser = auth_models.User.get_by_id(long( auser['user_id'] )) people = auth_models.User.query(query.FilterNode('sponsor', '=', realuser.key)).fetch() if auser: self.render_jinja('my_organization.html', people=people, user=realuser,) 
+5
source

Option number 2

This option is a bit cleaner. You subclass the model and pass its location to webapp2. This will allow you to add special attributes and custom queries to the class.

 # custom_models.py from webapp2_extras.appengine.auth.models import User from google.appengine.ext.ndb import model class CustomUser(User): sponsor = model.KeyProperty() @classmethod def get_by_sponsor_key(cls, sponsor): # How you handle this is up to you. You can return a query # object as shown, or you could return the results. return cls.query(cls.sponsor == sponsor) # handlers.py def get(self): auser = self.auth.get_user_by_session() realuser = custom_models.CustomUser.get_by_id(long( auser['user_id'] )) people = custom_models.CustomUser.get_by_sponsor_key(realuser.key).fetch() if auser: self.render_jinja('my_organization.html', people=people, user=realuser,) # main.py config = { # ... 'webapp2_extras.auth': { # Tell webapp2 where it can find your CustomUser 'user_model': 'custom_models.CustomUser', }, } application = webapp2.WSGIApplication(routes, config=config) 
+2
source

All Articles