Search code examples
python-2.7google-app-engineapp-engine-ndbwebapp2

appengine python NDB sort order has no effect


I try to get the last modified entries using these kind of models in model.py:

class Example(ndb.Model):
    ....
    modified = ndb.DateTimeProperty(auto_now=True)
    created = ndb.DateTimeProperty(auto_now_add=True)

The query code:

for each in ['Example', '...'] 
    model_class = webapp2.import_string('model.%s' % each)
    q = model_class.query()
    q.order(-model_class.modified)
    last_modified_entity = q.get()  # does not sort the entities

I also tried:

for each in ['Example', '...'] 
    model_class = webapp2.import_string('model.%s' % each)
    q = model_class.query()
    sort_prop = ndb.GenericProperty('modified')
    q.order(-sort_prop)
    last_modified_entity = q.get()  # does not sort the entities

Solution

  • Calling .order() on a Query object does NOT alter the Query object. It returns a new Query object with that order on it, but does not alter the original Query object. From NDB Queries (emphasis mine):

    Instead of specifying an entire query filter in a single expression, you may find it more convenient to build it up in steps: for example:

    query1 = Account.query()  # Retrieve all Account entitites
    query2 = query1.filter(Account.userid >= 40)  # Filter on userid >= 40
    query3 = query2.filter(Account.userid < 50)  # Filter on userid < 50 too
    

    query3 is equivalent to the query variable from the previous example. Note that query objects are immutable, so the construction of query2 does not affect query1 and the construction of query3 does not affect query1 or query2.

    Example from the remote api shell:

    >>>> from models.notification import Notification
    >>>> query = Notification.query()
    >>>> query
    Query(kind='Notification')
    >>>>
    >>>> # this returns a new ordered query
    >>>> query.order(Notification.created_on)
    Query(kind='Notification', orders=...)
    >>>> 
    >>>> # but it does not alter the original query
    >>>> query
    Query(kind='Notification')
    >>>>
    >>>> # this is how you get the ordered query in a variable
    >>>> ordered_query = query.order(Notification.created_on)
    >>>> ordered_query
    Query(kind='Notification', orders=...)
    >>>> query
    Query(kind='Notification')
    

    So change your code to use this instead:

    q = q.order(-sort_prop)