Python 2.7 has reached end of supportand will bedeprecatedon January 31, 2026. After deprecation, you won't be able to deploy Python 2.7applications, even if your organization previously used an organization policy tore-enable deployments of legacy runtimes. Your existing Python2.7 applications will continue to run and receive traffic after theirdeprecation date. We recommend thatyoumigrate to the latest supported version of Python.

Entity Property Reference

This page describes how to use the legacy bundled services and APIs. This API can only run in first-generation runtimes in the App Engine standard environment. If you are updating to the App Engine runtime, refer to themigration guide to learn about your migration options for legacy bundled services.

Firestore in Datastore mode (Datastore) supports a variety ofdata types for property values. These include,among others:

  • Integers
  • Floating-point numbers
  • Strings
  • Dates
  • Binary data

For a full list of types, seeProperties and value types.

Properties and value types

The data values associated with an entity consist of one or moreproperties. Each property has a name and one or more values. A property can have values of more than one type, and two entities can have values of different types for the same property. Properties can be indexed or unindexed (queries that order or filter on a propertyP will ignore entities whereP is unindexed). An entity can have at most 20,000 indexed properties.

Note: Properties with multiple values can be useful, for instance, when performing queries with equality filters: an entity satisfies the query if any of its values for a property matches the value specified in the filter. For more details on multiple-valued properties, including issues you should be aware of, see theDatastore Queries page.

The following value types are supported:

When a query involves a property with values of mixed types, Datastore uses a deterministic ordering based on the internal representations:

  1. Null values
  2. Fixed-point numbers
    • Integers
    • Dates and times
  3. Boolean values
  4. Byte sequences
    • Unicode string
    • Blobstore keys
  5. Floating-point numbers
  6. Datastore keys

Because long text strings and long byte strings are not indexed, they have no ordering defined.

Note: Integers and floating-point numbers are considered separate types in Datastore. If an entity uses a mix of integers and floats for the same property, all integers will be sorted before all floats: for example,

7 <3.2

Property Types

NDB supports the following property types:

Property typeDescription
IntegerProperty64-bit signed integer
FloatPropertyDouble-precision floating-point number
BooleanPropertyBoolean
StringPropertyUnicode string; up to 1500 bytes, indexed
TextPropertyUnicode string; unlimited length, not indexed
BlobPropertyUninterpreted byte string:
if you setindexed=True, up to 1500 bytes, indexed;
ifindexed isFalse (the default), unlimited length, not indexed.
Optional keyword argument:compressed.
DateTimePropertyDate and time (seeDate and Time Properties)
DatePropertyDate (seeDate and Time Properties)
TimePropertyTime (seeDate and Time Properties)
GeoPtPropertyGeographical location. This is andb.GeoPt object. The object has attributeslat andlon, both floats. You can construct one with two floats likendb.GeoPt(52.37, 4.88) or with a stringndb.GeoPt("52.37, 4.88"). (This is actually the same class asdb.GeoPt)
KeyPropertyDatastore key
Optional keyword argument: kind=kind, to require that keysassigned to this property always have the indicated kind. May be astring or a Model subclass.
BlobKeyPropertyBlobstore key
Corresponds toBlobReferenceProperty in the old db API, but the property value is aBlobKey instead of aBlobInfo; you can construct aBlobInfo from it usingBlobInfo(blobkey)
UserPropertyUser object.
StructuredPropertyIncludes one kind of model inside another, by value(seeStructured Properties)
LocalStructuredPropertyLikeStructuredProperty,but on-disk representation is an opaque blob and is not indexed(seeStructured Properties).
Optional keyword argument:compressed.
JsonPropertyValue is a Python object (such as a list or a dict or a string) that is serializable using Python'sjson module; Datastore stores the JSON serialization as a blob. Unindexed by default.
Optional keyword argument:compressed.
PicklePropertyValue is a Python object (such as a list or a dict or a string) that is serializable using Python's pickle protocol; Datastore stores the pickle serialization as a blob. Unindexed by default.
Optional keyword argument:compressed.
GenericPropertyGeneric value
Used mostly by theExpando class, but also usable explicitly. Its type may be any ofint,long,float,bool,str,unicode,datetime,Key,BlobKey,GeoPt,User,None.
ComputedPropertyValue computed from other properties by a user-defined function.(SeeComputed Properties.)

Some of these properties have an optional keyword argument,compressed. If the property hascompressed=True, then its data is compressed with gzip on disk. It takes up less space but needs CPU to encode/decode on write and read operations.

Both compression and decompression are "lazy"; a compressed property value will only be decompressed the first time you access it. If you read an entity containing a compressed property value and write it back without accessing the compressed property, it won't be decompressed and compressed at all. Thein-context cache participates in this lazy scheme as well, butmemcache always stores the compressed value for compressed properties.

Because of the extra CPU time needed for compression, it is usually best to use compressed properties only if the data would be too big to fit without it. Remember that gzip-based compression is typically not effective for images and other media data, since those formats already are compressed using a media-specific compression algorithm (e.g. JPEG for images).

Property Options

Most property types support some standard arguments.The first is an optional positional argument specifying the property'sDatastore name. You can use this to give the property a different name inDatastore than from the application's viewpoint.A common use for this is to reduce space in Datastore, lettingDatastore use abbreviated property names while your code useslonger, more meaningful ones. For example,

classEmployee(ndb.Model):full_name=ndb.StringProperty('n')retirement_age=ndb.IntegerProperty('r')

This is particularly useful for repeated properties for which you expectmany values per entity.

In addition, most property types support the following keyword arguments:

ArgumentTypeDefaultDescription
indexedboolUsuallyTrueInclude property in Datastore's indexes; ifFalse, values cannot be queried but writes are faster. Not all property types support indexing; settingindexed toTrue fails for these.
Unindexed properties cost fewer write ops than indexed properties.
repeatedboolFalseProperty value is a Python list containing values of the underlying type(seeRepeated Properties).
Cannot be combined withrequired=True ordefault=True.
requiredboolFalseProperty must have a value specified.
defaultProperty's underlying typeNoneDefault value of property if none explicitly specified.
choicesList of values of underlying typeNoneOptional list of allowable values.
validatorFunctionNone

Optional function to validate and possibly coerce the value.

Will be called with arguments (prop,value) and should either return the (possibly coerced) value or raise an exception. Calling the function again on a coerced value should not modify the value further. (For example, returningvalue.strip() orvalue.lower() is fine, but notvalue + '$'.)May also returnNone, which means "no change". See alsoWriting Property Subclasses

verbose_namestringNone

Optional HTML label to use in web form frameworks like jinja2.

Repeated Properties

Any property withrepeated=True becomes arepeated property. The property takes a list of values of the underlying type, rather than a single value. For example, the value of a property defined withIntegerProperty(repeated=True) is a list of integers.

Datastore may see multiple values for such a property. A separate index record is created for each value. This affects query semantics; see Querying for Repeated Properties for an example.

This example uses a repeated property:

classArticle(ndb.Model):title=ndb.StringProperty()stars=ndb.IntegerProperty()tags=ndb.StringProperty(repeated=True)
...
article=Article(title='Python versus Ruby',stars=3,tags=['python','ruby'])article.put()

This creates a Datastore entity with the following contents:

assertarticle.title=='Python versus Ruby'assertarticle.stars==3assertsorted(article.tags)==sorted(['python','ruby'])

When querying for thetags property, this entity will satisfy a query for either'python' or'ruby'.

When updating a repeated property, you can either assign it a new list or mutate the existing list in place. When you assign a new list, the types of the list items are validated immediately. Invalid item types (for example, assigning[1, 2] toart.tags above) raise an exception. When you mutate the list, the change is not validated immediately. Instead, the value will be validated when you write the entity to Datastore.

Datastore preserves the order of the list items in a repeated property, so you can assign some meaning to their ordering.

Date and Time Properties

Three property types are available for storing date- and time-related values:

  • DateProperty
  • TimeProperty
  • DateTimeProperty

These take values belonging to the corresponding classes(date,time,datetime)of the standard Pythondatetime module.The most general of the three isDateTimeProperty,which denotes both a calendar date and a time of day;the others are occasionally useful for special purposes requiring just a date(such as a date of birth) or just a time (such as a meeting time).For technical reasons,DateProperty andTimePropertyare subclasses ofDateTimeProperty,but you shouldn't depend on this inheritance relationship(and note that it differs from the inheritance relationships betweenthe underlying classes defined by thedatetime module itself).

Note:App Engine clock times are always expressed in coordinated universaltime (UTC). This becomes relevant if you use the current date or time(datetime.datetime.now()) as a value or convert between datetime objects and POSIX timestamps or time tuples.However, no explicit time zone information is stored in Datastore,so if you are careful you can use these to represent local timesin any timezone—if you use the current time or the conversions.

Each of these properties has two extra Boolean keyword options:

OptionDescription
auto_now_addSet property to current date/time when entity is created. You can manually override this property. When the entity is updated, the property doesn't change. For that behavior, useauto_now.
auto_nowSet property to current date/time when entity is created and whenever it is updated.

These options cannot be combined withrepeated=True. Both of them default toFalse; if both are set toTrue,auto_now takes precedence. It is possible to override the value for a property withauto_now_add=True, but not for one withauto_now=True. The automatic value is not generated until the entity is written; that is, these options don't provide dynamic defaults. (These details differ from the old db API.)

Note:When a transaction writing a property withauto_now_add=Truefails and is later retried, it will reuse the same time value as on the original try rather than update it to the time of the retry. If the transaction fails permanently, the property's value will still be set in the in-memory copy of the entity.

Structured Properties

You can structure a model's properties. For example, you can define a model class Contact containing a list of addresses, each with internal structure.Structured properties (typeStructuredProperty) let you do this; for example:

classAddress(ndb.Model):type=ndb.StringProperty()# E.g., 'home', 'work'street=ndb.StringProperty()city=ndb.StringProperty()
...
classContact(ndb.Model):name=ndb.StringProperty()addresses=ndb.StructuredProperty(Address,repeated=True)
...
guido=Contact(name='Guido',addresses=[Address(type='home',city='Amsterdam'),Address(type='work',street='Spear St',city='SF')])guido.put()

This creates a single Datastore entity with the following properties:

assertguido.name=='Guido'addresses=guido.addressesassertaddresses[0].type=='home'assertaddresses[1].type=='work'assertaddresses[0].streetisNoneassertaddresses[1].street=='Spear St'assertaddresses[0].city=='Amsterdam'assertaddresses[1].city=='SF'

Reading back such an entity reconstructs the originalContact entity exactly. Although theAddress instances are defined using the same syntax as for model classes, they are not full-fledged entities. They don't have their own keys in Datastore. They cannot be retrieved independently of theContact entity to which they belong. An application can, however, query for the values of their individual fields; see Filtering for Structured Property Values. Note thataddress.type,address.street, andaddress.city are viewed as parallel arrays from Datastore's viewpoint, but the NDB library hides this aspect and constructs the corresponding list ofAddress instances.

You can specify the usualproperty options for structured properties (exceptindexed). The Datastore name is thesecond positional argument in this case (the first being the model class used to define the substructure).

When you don't need to query for a substructure's internal properties,you can use a local structured property (LocalStructuredProperty)instead. If you replaceStructuredProperty withLocalStructuredProperty in the example above, the behaviorof the Python code is the same, but Datastore sees just an opaque blobfor each address. Theguido entity created in the example wouldbe stored as follows: name = 'Guido' address = <opaque blob for {'type': 'home', 'city': 'Amsterdam'}> address = <opaque blob for {'type': 'work', 'city': 'SF', 'street': 'Spear St'}>

The entity will be read back correctly. Since properties of this type are always unindexed, you cannot query for address values.

Note: AStructuredProperty with a nested property (whether or not it is structured) supports only a single layer of repeated properties. TheStructuredProperty can be repeated, or the nested property can be repeated, but not both. A work-around is to useLocalStructuredProperty, which does not have this constraint (but does not allow queries on its property values).

Computed Properties

Computed properties (ComputedProperty) areread-only properties whose value is computed from other property valuesby an application-supplied function. Note that a computed property only supportsthe types that are supported by generic properties! The computed value is written toDatastore so that it can be queried and displayed in the Datastoreviewer, but the stored value is ignored when the entity is read backfrom Datastore; rather, the value is recomputed by calling thefunction whenever the value is requested. For example:

classSomeEntity(ndb.Model):name=ndb.StringProperty()name_lower=ndb.ComputedProperty(lambdaself:self.name.lower())
...
entity=SomeEntity(name='Nick')entity.put()

This stores an entity with the following property values:

assertentity.name=='Nick'assertentity.name_lower=='nick'

If we change name to 'Nickie' and ask for the value ofname_lower, it returns 'nickie':

entity.name='Nick'assertentity.name_lower=='nick'entity.name='Nickie'assertentity.name_lower=='nickie'

Note: UseComputedProperty if the applicationqueries for the computed value. If you just want to use the derived version in Python code, define a regular method or use Python's@property built-in.

Note: If you create a model without a key manually specified, and instead rely on Datastore to auto-generate the entity's id, then on your firstput() aComputedProperty will not be able to read the id field since the field is computed before the id is generated. If you need aComputedProperty that uses the entity's id, you can use theallocate_ids method to generate an id and key to create the entity with, so that yourComputedProperty will be able to reference that id on the entity's first put().

Caution:ComputedProperties are not calculated onquery, but rather onput(). If you update a model's schema to include aComputedProperty, you should remember to update existing entities by loading and writing them to Datastore.

Google Protocol RPC Message Properties

Alpha — Google Protocol RPC

This feature is subject to the "Pre-GA Offerings Terms" in the General Service Terms section of theService Specific Terms. Pre-GA features are available "as is" and might have limited support. For more information, see thelaunch stage descriptions.

TheGoogle Protocol RPC library uses Message objects for structured data; they can represent RPC requests, responses, or other things. NDB provides an API for storing Google Protocol RPCMessage objects as entity properties. Suppose you define aMessage subclass:

fromprotorpcimportmessages
...
classNote(messages.Message):text=messages.StringField(1,required=True)when=messages.IntegerField(2)

You can storeNote objects in Datastore as entity property values by using NDB'smsgprop API.

fromgoogle.appengine.extimportndbfromgoogle.appengine.ext.ndbimportmsgprop
...
classNoteStore(ndb.Model):note=msgprop.MessageProperty(Note,indexed_fields=['when'])name=ndb.StringProperty()
...
my_note=Note(text='Excellent note',when=50)ns=NoteStore(note=my_note,name='excellent')key=ns.put()new_notes=NoteStore.query(NoteStore.note.when >=10).fetch()

If you want to query for field names, they must be indexed. You can specify a list of field names that will be indexed with theindexed_fields parameter toMessageProperty.

MessageProperty supports many, but not all,Property options. It supports:

  • name
  • repeated
  • required
  • default
  • choices
  • validator
  • verbose_name

Message properties do not support theindexed property option; you can't indexMessage values. (You can index fields of a message as described above.)

Nested messages (usingMessageField) also work:

classNotebook(messages.Message):notes=messages.MessageField(Note,1,repeated=True)
...
classSignedStorableNotebook(ndb.Model):author=ndb.StringProperty()nb=msgprop.MessageProperty(Notebook,indexed_fields=['notes.text','notes.when'])

MessageProperty has a special property option,protocol, which specifies how the message object is serialized to Datastore. The values are protocol names as used byprotorpc.remote.Protocols class. Supported protocol names areprotobuf andprotojson; the default isprotobuf.

msgprop also definesEnumProperty, a property type which can be used to store aprotorpc.messages.Enum value in an entity. Example:

classColor(messages.Enum):RED=620GREEN=495BLUE=450
...
classPart(ndb.Model):name=ndb.StringProperty()color=msgprop.EnumProperty(Color,required=True)
...
p1=Part(name='foo',color=Color.RED)printp1.color# prints "RED"

EnumProperty stores the value as an integer; in fact,EnumProperty is a subclass ofIntegerProperty.This implies that you can rename your enum values without having to modifyalready-stored entities, but you cannot renumber them.

The EnumProperty supports the followingproperty options:

  • name
  • indexed
  • repeated
  • required
  • default
  • choices
  • validator
  • verbose_name

About NDB entity models

An NDB entity model can defineproperties. Entity properties are a bit like data members of Python classes, a structured way to hold data; they are also a bit like fields in a database schema.

A typical application defines a data model by defining a class that inherits fromModel with some property class attributes. For example,

fromgoogle.appengine.extimportndb
...
classAccount(ndb.Model):username=ndb.StringProperty()userid=ndb.IntegerProperty()email=ndb.StringProperty()

Here,username,userid, andemail are properties ofAccount.

Don't name a property "key." This name is reservedfor a special property used to store the Model key. Though it may worklocally, a property named "key" will prevent deployment to App Engine.

There are several other property types. Some are handy for representing dates and times and have convenient auto-update features.

An application can adjust a property's behavior by specifying options on the property; these can ease validation, set defaults, or change query indexing.

A model can have more complex properties. Repeated properties are list-like. Structured properties are object-like. Read-only computed properties are defined via functions; this makes it easy to define a property in terms of one or more other properties.Expando models can define properties dynamically.

Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2025-12-15 UTC.