How to order an NDB request by key?

I am trying to use task queues in Google App Engine. I want to use the Mapper class specified in the App Engine documentation " Background work with deferred library ". I get an exception when ordering the result of a query with a key

def get_query(self): ... q = q.order("__key__") ... 

An exception:

 File "C:... mapper.py", line 41, in get_query q = q.order("__key__") File "C:\Program Files (x86)\Google\google_appengine\google\appengine\ext\ndb\query.py", line 1124, in order 'received %r' % arg) TypeError: order() expects a Property or query Order; received '__key__' INFO 2017-03-09 11:56:32,448 module.py:806] default: "POST /_ah/queue/deferred HTTP/1.1" 500 114 

An article from 2009, so I think something could have changed. My environment: Windows 7, Python 2.7.9, Google App Engine 1.9.50 SDK

some similar questions about ordering at NDB on SO. What bothers me is this code from an official document supposedly updated in February 2017 (recently) and published by someone from the top 0.1% of SO users by reputation.

So I have to do something wrong. What is the solution?

+5
source share
1 answer

Bingo. Avinash Raj is right. If that were the answer, I would agree. Here is the full class code

 #!/usr/bin/python2.7 # -*- coding: utf-8 -*- from google.appengine.ext import deferred from google.appengine.ext import ndb from google.appengine.runtime import DeadlineExceededError import logging class Mapper(object): """ from https://cloud.google.com/appengine/docs/standard/python/ndb/queries corrected with suggestions from Stack Overflow http://stackoverflow.com/questions/42692319/how-to-order-ndb-query-by-the-key """ # Subclasses should replace this with a model class (eg, model.Person). KIND = None # Subclasses can replace this with a list of (property, value) tuples to filter by. FILTERS = [] def __init__(self): logging.info("Mapper.__init__: {}") self.to_put = [] self.to_delete = [] def map(self, entity): """Updates a single entity. Implementers should return a tuple containing two iterables (to_update, to_delete). """ return ([], []) def finish(self): """Called when the mapper has finished, to allow for any final work to be done.""" pass def get_query(self): """Returns a query over the specified kind, with any appropriate filters applied.""" q = self.KIND.query() for prop, value in self.FILTERS: q = q.filter(prop == value) if __name__ == '__main__': q = q.order(self.KIND.key) # the fixed version. The original q.order('__key__') failed # see http://stackoverflow.com/questions/42692319/how-to-order-ndb-query-by-the-key return q def run(self, batch_size=100): """Starts the mapper running.""" logging.info("Mapper.run: batch_size: {}".format(batch_size)) self._continue(None, batch_size) def _batch_write(self): """Writes updates and deletes entities in a batch.""" if self.to_put: ndb.put_multi(self.to_put) self.to_put = [] if self.to_delete: ndb.delete_multi(self.to_delete) self.to_delete = [] def _continue(self, start_key, batch_size): q = self.get_query() # If we're resuming, pick up where we left off last time. if start_key: key_prop = getattr(self.KIND, '_key') q = q.filter(key_prop > start_key) # Keep updating records until we run out of time. try: # Steps over the results, returning each entity and its index. for i, entity in enumerate(q): map_updates, map_deletes = self.map(entity) self.to_put.extend(map_updates) self.to_delete.extend(map_deletes) # Do updates and deletes in batches. if (i + 1) % batch_size == 0: self._batch_write() # Record the last entity we processed. start_key = entity.key self._batch_write() except DeadlineExceededError: # Write any unfinished updates to the datastore. self._batch_write() # Queue a new task to pick up where we left off. deferred.defer(self._continue, start_key, batch_size) return self.finish() 
+1
source

Source: https://habr.com/ru/post/1265223/


All Articles