Each value data type supported by the datastore is represented by a
primitive type in the language for the runtime or a class provided by the
API. The data types and their
language-specific equivalents are listed in Table 4-1. In this table,
db is the Python package
datastore is the
Table 4-1. Datastore property value types and equivalent language types
|Data type||Python type||Java type|
|Unicode text string (up to 500 bytes, indexed)|
|Long Unicode text string (not indexed)|
|Short byte string (up to 500 bytes, indexed)|
|Long byte string (not indexed)|
|Float (double precision)|
|A Google account|
|A category (GD)|
|A URL (GD)|
|An email address (GD)|
|A geographical point (GD)|
|An instant messaging handle (GD)|
|A phone number (GD)|
|A postal address (GD)|
|A user rating (GD)|
The datastore types in this table labeled “(GD)” are types borrowed
from the Google Data protocol. These are supported as distinct native data
types in the datastore, though most of them are implemented as text
strings. Notable exceptions are
GeoPt, which is a pair of
floating-point values for latitude (–90 to +90) and longitude (–180 to
Rating, which is an integer between 1 and
Example 4-2 demonstrates the use of several of these data types in Python.
Example 4-2. Python code to set property values of various types
from google.appengine.ext import webapp from google.appengine.ext import db from google.appengine.api import users import datetime class Comment(db.Expando): pass class CommentHandler(webapp.RequestHandler): def post(self): c = Comment() c.commenter = users.get_current_user() # returns a users.User object c.message = db.Text(self.request.get('message')) c.date = datetime.datetime.now() c.put() # Display the result page...
When you use Python’s
db.Expando or Java’s low-level
datastore API, types that are widened to other types when stored come
back as the wider datastore types when you retrieve the entity. For
instance, a Java
Integer comes back as a
If you use these APIs in your app, it’s best to use the native datastore
types, so the value types stay consistent.
The datastore has two distinct data types for storing strings of
text: short strings and long strings. Short strings are indexed; that
is, they can be the subject of queries, such as a search for every
Person entity with a given value for a
last_name property. Short string values must be less
than 500 bytes in length. Long strings can be longer than 500 bytes, but
are not indexed.
Text strings, short and long, are strings of characters from the Unicode character set. Internally, the datastore stores Unicode strings using the UTF-8 encoding, which represents some characters using multiple bytes. This means that the 500-byte limit for short strings is not necessarily the same as 500 Unicode characters. The actual limit on the number of characters depends on which characters are in the string.
The Python API distinguishes between short strings and long
strings using Python data types. The Python built-in types
str represent short string values.
str values are assumed to be text encoded as ASCII, and are
treated as UTF-8 (which is equivalent to ASCII for the first 128
characters in the character set). For long strings, the Python API
db.Text class, which takes a
str value as an argument for its
# Short strings. e.prop = "a short string, as an ASCII str" e.prop = unicode("a short string, as a unicode value") # A long string. e.prop = db.Text("a long string, can be longer than 500 bytes")
The datastore also supports two additional classes for strings of
bytes, or “blobs.” Blobs are not assumed to be of any particular format,
and their bytes are preserved. This makes them good for nontext data,
such as images, movies, or other media. As with text strings, the blob
types come in indexed and nonindexed varieties. The Python API provides
db.Blob class to represent blob values, which takes a
str value as an argument for its constructor.
# A blob. self.request.body is the body of the request in a # webapp request handler, such as an uploaded file. e.prop = db.Blob(self.request.body)
class Entity(db.Expando): pass a = Entity() a.prop1 = 'abc' a.prop2 = None a.put() b = Entity() b.prop1 = 'def' b.put()
This creates two entities of the kind
Both entities have a property named
prop1. The first
entity has a property named
prop2; the second does
Of course, an unset property can be set later:
b.prop2 = 123 b.put() # b now has a property named "prop2."
Similarly, a set property can be made unset. In the Python API,
you delete the property by deleting the attribute from the object, using
del b.prop2 b.put() # b no longer has a property named "prop2."
As we mentioned earlier, a property can have multiple values. We’ll discuss the more substantial aspects of multivalued properties when we talk about queries and data modeling. But for now, it’s worth a brief mention.
A property can have one or more values. A property cannot have zero values; a property without a value is simply unset. Each value for a property can be of a different type, and can be the null value.
The datastore preserves the order of values as they are assigned. The Python API returns the values in the same order as they were set.
e.prop = [1, 2, 'a', None, 'b']
Because a property must have at least one value, it is an error
to assign an empty list (
 in Python) to a property on
an entity whose Python class is based on the
class Entity(db.Expando): pass e = Entity() e.prop =  # ERROR
In contrast, the
Model base class includes a
feature that automatically translates between the empty list value and
“no property set.” You’ll see this feature in Chapter 7.
In the Java low-level datastore API, you can store multiple values
for a property using a
Collection type. The low-level API
returns the values as a
java.util.List. The items are
stored in the order provided by the
iterator. For many types, such as
TreeSet, this order is deterministic. For others, such as
HashSet, it is not. If the app needs the original data
structure, it must convert the
List returned by the
datastore to the appropriate type.