Metadata
The App Engine Datastore provides programmatic access to some of its metadata to support metaprogramming, implementing backend administrative functions, simplify consistent caching, and similar purposes; you can use it, for instance, to build a custom datastore viewer for your application. The metadata available includes information about the entity groups, namespaces, entity kinds, and properties your application uses, as well as the property representations for each property.The Datastore Statistics tab of the App Engine Administration Console also provides some metadata about your application, but the data displayed there differs in some important respects from that returned by these functions.
- Freshness. Reading metadata using the API gets current data, whereas data in the Datastore Statistics tab is updated only once daily.
- Contents. Some metadata in the Datastore Statistics tab is not available via the APIs; the reverse is also true.
- Speed. Metadata gets and queries are billed in the same way as datastore gets and queries . Metadata queries that fetch information on namespaces, kinds, and properties are generally slow to execute. As a rule of thumb, expect a metadata query that returns N entities to take about the same time as N ordinary queries each returning a single entity. Furthermore, property representation queries (non-keys-only property queries) are slower than keys-only property queries . Metadata gets of entity group metadata are somewhat faster than getting a regular entity.
Contents
Helper Functions
The following functions obtain metadata information:
-
get_entity_group_version()
gets a version number for an entity group; this is useful for finding out if any entity in the group has changed since the last time you got the version number. -
get_namespaces()
returns a list containing the names of all of an application's namespaces (or those in a specified range). -
get_kinds()
returns a list containing the names of all of an application's entity kinds (or those in a specified range). -
get_properties_of_kind()
returns a list containing the names of all of an application's indexed properties (or those in a specified range) associated with a given entity kind. Unindexed properties are not included. -
get_representations_of_kind()
returns a dictionary containing the representations for all of an application's indexed properties (or those in a specified range) associated with a given entity kind. The dictionary maps the name of each property to a list of that property's representations. Unindexed properties are not included.
Entity group metadata
The High-Replication Datastore provides access to the "version" of an entity group, a strictly positive number that is guaranteed to increase on every change to the entity group. Entity group versions can be used, e.g., to easily write code to keep a consistent cache of a complex ancestor query on an entity group.
The following simple example shows how to get an entity group's version:
from google.appengine.ext import db
from google.appengine.ext.db import metadata
class Simple(db.Model):
x = db.IntegerProperty()
entity1 = Simple(x=11)
entity1.put()
# Print entity1's entity group version
print 'version', metadata.get_entity_group_version(entity1)
# Write to a different entity group
entity2 = Simple(x=22)
entity2.put()
# Will print the same version, as entity1's entity group has not changed
print 'version', metadata.get_entity_group_version(entity1)
# Change entity1's entity group by adding a new child entity
entity3 = Simple(x=33, parent=entity1.key())
entity3.put()
# Will print a higher version, as entity1's entity group has changed
print metadata.get_entity_group_version(entity1)
This example caches query results (a count of matching results) and uses entity group versions to ensure that it only uses the cached value if current:
from google.appengine.api import memcache
from google.appengine.ext import db
from google.appengine.ext.db import metadata
def count_entity_group(entity_group_key):
"""Count the entities in the specified entity group."""
# Check if we have a cached version of the current entity group count
cached = memcache.get(str(entity_group_key))
if cached:
(version, count) = cached
# Is the cached value for the current version?
if version == metadata.get_entity_group_version(entity_group_key):
return count
def tx():
# Need to actually count entities. Using a transaction to get a consistent
# count and entity group version.
count = db.Query(keys_only=True).ancestor(entity_group_key).count(limit=5000)
# Cache the count and the entity group version
version = metadata.get_entity_group_version(entity_group_key)
memcache.set(str(entity_group_key), (version, count))
return count
return db.run_in_transaction(tx)
get_entity_group_version()
may return
None
for an entity group which has
never been written to.
Entity group versions are obtained by calling
get()
on a special pseudo-entity
that contains a
__version__
property. See the reference documentation on
EntityGroup
for details.
The entity group version is guaranteed to increase on any change to the entity group; it may also (rarely) increase in the absence of user-visible changes.
Metadata queries
If the helper functions described in the preceding section don't meet your
needs, you can issue more elaborate or flexible metadata requests with an
explicit metadata query. In Python, the model classes for such queries are
defined in the
google.appengine.ext.db.metadata
package. These models provide special entity kinds that are reserved for
metadata queries:
Model class | Entity kind |
---|---|
Namespace
|
__namespace__
|
Kind
|
__kind__
|
Property
|
__property__
|
These models and kinds will not conflict with others of the same names that may already exist in your application. By querying on these special kinds, you can retrieve entities containing the desired metadata.
The entities returned by metadata queries are generated dynamically, based on
the current state of the Datastore. While you can create local
instances of the
Namespace
,
Kind
, or
Property
model classes, any
attempt to store them in the Datastore will fail with a
BadRequestError
exception.
You can issue metadata queries using a query object belonging to either of two classes:
-
A
Query
object returned by the class methodNamespace.all()
,Kind.all()
, orProperty.all()
(inherited from the superclass methodModel.all()
) -
A
GqlQuery
object for GQL-style queries
The following example returns the names of all entity kinds in an application:
from google.appengine.ext import db
from google.appengine.ext.db.metadata import Kind
for k in Kind.all():
print "kind: '%s'" % k.kind_name