310 'There is no "%(name)s" where %(pairs)s.') % { |
310 'There is no "%(name)s" where %(pairs)s.') % { |
311 'name': self._name, 'pairs': joined_pairs} |
311 'name': self._name, 'pairs': joined_pairs} |
312 |
312 |
313 raise out_of_band.Error(msg, status=404) |
313 raise out_of_band.Error(msg, status=404) |
314 |
314 |
|
315 def prefetchField(self, field, data): |
|
316 """Prefetches all fields in data from the datastore in one fetch. |
|
317 |
|
318 Args: |
|
319 field: the field that should be fetched |
|
320 data: the data for which the prefetch should be done |
|
321 """ |
|
322 |
|
323 prop = getattr(self._model, field, None) |
|
324 |
|
325 if not prop: |
|
326 logging.exception("Model %s does not have attribute %s" % |
|
327 (self._model, field)) |
|
328 return |
|
329 |
|
330 if not isinstance(prop, db.ReferenceProperty): |
|
331 logging.exception("Property %s of %s is not a ReferenceProperty but a %s" % |
|
332 (field, self._model.kind(), prop.__class__.__name__)) |
|
333 return |
|
334 |
|
335 keys = [prop.get_value_for_datastore(i) for i in data] |
|
336 |
|
337 prefetched_entities = db.get(keys) |
|
338 prefetched_dict = dict((i.key(), i) for i in prefetched_entities) |
|
339 |
|
340 for i in data: |
|
341 value = prefetched_dict[prop.get_value_for_datastore(i)] |
|
342 setattr(i, field, value) |
|
343 |
315 def getForFields(self, filter=None, unique=False, limit=1000, offset=0, |
344 def getForFields(self, filter=None, unique=False, limit=1000, offset=0, |
316 ancestors=None, order=None): |
345 ancestors=None, order=None, prefetch=None): |
317 """Returns all entities that have the specified properties. |
346 """Returns all entities that have the specified properties. |
318 |
347 |
319 Args: |
348 Args: |
320 filter: a dict for the properties that the entities should have |
349 filter: a dict for the properties that the entities should have |
321 unique: if set, only the first item from the resultset will be returned |
350 unique: if set, only the first item from the resultset will be returned |
322 limit: the amount of entities to fetch at most |
351 limit: the amount of entities to fetch at most |
323 offset: the position to start at |
352 offset: the position to start at |
324 ancestors: list of ancestors properties to set for this query |
353 ancestors: list of ancestors properties to set for this query |
325 order: a list with the sort order |
354 order: a list with the sort order |
|
355 prefetch: the fields of the data that should be pre-fetched, |
|
356 has no effect if unique is True |
326 """ |
357 """ |
327 |
358 |
328 if unique: |
359 if unique: |
329 limit = 1 |
360 limit = 1 |
|
361 |
|
362 if not prefetch: |
|
363 prefetch = [] |
330 |
364 |
331 query = self.getQueryForFields(filter=filter, |
365 query = self.getQueryForFields(filter=filter, |
332 ancestors=ancestors, order=order) |
366 ancestors=ancestors, order=order) |
333 |
367 |
334 try: |
368 try: |
339 (exception, self._model, filter, ancestors, order)) |
373 (exception, self._model, filter, ancestors, order)) |
340 # TODO: send email |
374 # TODO: send email |
341 |
375 |
342 if unique: |
376 if unique: |
343 return result[0] if result else None |
377 return result[0] if result else None |
|
378 |
|
379 for field in prefetch: |
|
380 self.prefetchField(field, result) |
344 |
381 |
345 return result |
382 return result |
346 |
383 |
347 def getQueryForFields(self, filter=None, ancestors=None, order=None): |
384 def getQueryForFields(self, filter=None, ancestors=None, order=None): |
348 """Returns a query with the specified properties. |
385 """Returns a query with the specified properties. |