众所周知,google数据存储使用的是BigTable,而非传统意义上的数据库,Google AppEngine也不例外,但为了方便程序员使用,Google提供了数据存储API,来使得大家可以传统意义上的SQL来使用Google的BigTable分布式数据存储系统。
具体的,Google准备了2套查询接口:GQL和查询对象接口,例如
一 数据实体
google AppEngine中每个数据对象被称为实体,每个实体具有几个属性。
每个实体有一个唯一的关键词,最简单的关键词是数字ID,ID也可以是应用所指定的字符串。
应用可以通过关键词,或根据对象的属性来提取数据。
二 模型接口
应用通过模型来定义所需要使用的数据,模型都需要定义为db.Model类的子类。模型定义了数据实体以及对应的属性,每个属性都是Property类的子类,每个属性接受一些参数用来定义该属性是否必须赋值,或者定义默认值。例如:
三 扩展模型接口
基于python的动态性,google app engine提供了不同于传统数据库的功能,该功能基于expando类,使用该类可以动态设置属性,例如:
p是Person的实例,但p可以对一些Person类中没有定义的属性进行赋值。和固定属性不同,对于未定义动态属性的实例而言,对应的属性是不存在的,而不是None(比较绕口,不知道大家明白不明白)。在查询的时候,数据存储系统很智能,只返回定义了动态属性的实例,例如:
四
属性与类型
字符串、长字符串、二进制数据
appengine支持Unicode字符串,因此不需要为中文问题而担忧。
长字符串例子:
二进制数据例子:
注意:长字符串和二进制数据是不被索引的,因此对该字段的查询是不会成功的。
列表:
引用(类似于表间关联):
注意:长字符串、二进制数据不会被索引
五 创建、更新记录(想了半天,还是觉得用记录还描述比较贴切,实体...太奇怪了)
还是很容易了,直接将对应的记录做一个put操作就可以创建、或者更新记录了。
六 查询记录集
对象查询:
GQL查询:
七
获取数据
说真的,这个方式获取数据,比使用Python的DB API还简单呢,不过还有其他方式。
可以很容易地发现,对query直接进行遍历可以不需要设定查询数据的条数。
注意:Google AppEngine中每个查询最多返回1000条数据,不管limit和offset设置的值为多少。例如,对于大于1000条的数据,如果offset设置为100,那么实际返回900条数据。 我想知道的是,如果有1万条数据,那么每次返回100条,不知道是否可以将1万条数据全部遍历,如果不可以的话,那么岂不是非常不妙啊?
要获取一条数据也很简单,如下:
八
删除数据
九 ID Or Key_name
如果没有设置ID的话,可以使用obj.key()获得某条记录的ID
可以使用db.Key(ID)或者Entity.Key(ID)获取obj。
十 索引的配置 Index.yaml 例子:
ancestor如果有源查询或者Query,为True,默认为False
注意:实际上,如果你没有对该文件进行配置,google appengine会对它进行默认的配置,当然是为了优化查询了。
附录:
一 Model Class:(文档:http://code.google.com/intl/zh-CN/appengine/docs/datastore/modelclass.html)
类方法:
二 Query类
实例方法:
三 支持的属性——属性类型
四
异常
http://code.google.com/intl/zh-CN/appengine/docs/datastore/transactions.html
- from google.appengine.ext import db
- from google.appengine.api import users
- #数据库模型
- class Pet(db.Model):
- name = db.StringProperty(required=True)
- type = db.StringProperty(required=True, choices=set(["cat", "dog", "bird"]))
- birthdate = db.DateProperty()
- weight_in_pounds = db.IntegerProperty()
- spayed_or_neutered = db.BooleanProperty()
- owner = db.UserProperty()
- #创建数据对象
- pet = Pet(name="Fluffy",
- type="cat",
- owner=users.get_current_user())
- pet.weight_in_pounds = 24
- #将数据提交到数据存储系统
- pet.put()
- if users.get_current_user():
- user_pets = db.GqlQuery("SELECT * FROM Pet WHERE pet.owner = :1",
- users.get_current_user())
- for pet in user_pets:
- pet.spayed_or_neutered = True
- db.put(user_pets)
google AppEngine中每个数据对象被称为实体,每个实体具有几个属性。
每个实体有一个唯一的关键词,最简单的关键词是数字ID,ID也可以是应用所指定的字符串。
应用可以通过关键词,或根据对象的属性来提取数据。
二 模型接口
应用通过模型来定义所需要使用的数据,模型都需要定义为db.Model类的子类。模型定义了数据实体以及对应的属性,每个属性都是Property类的子类,每个属性接受一些参数用来定义该属性是否必须赋值,或者定义默认值。例如:
- from google.appengine.ext import db
- class Pet(db.Model):
- name = db.StringProperty(required=True)
- type = db.StringProperty(required=True, choices=set(["cat", "dog", "bird"]))
- birthdate = db.DateProperty()
- weight_in_pounds = db.IntegerProperty()
- spayed_or_neutered = db.BooleanProperty()
- owner = db.UserProperty(required=True)
基于python的动态性,google app engine提供了不同于传统数据库的功能,该功能基于expando类,使用该类可以动态设置属性,例如:
- class Person(db.Expando):
- first_name = db.StringProperty()
- last_name = db.StringProperty()
- hobbies = db.StringListProperty()
- p = Person(first_name="Albert", last_name="Johnson")
- p.hobbies = ["chess", "travel"]
- p.chess_elo_rating = 1350
- p.travel_countries_visited = ["Spain", "Italy", "USA", "Brazil"]
- p.travel_trip_count = 13
- p1 = Person()
- p1.favorite = 42
- p1.put()
- p2 = Person()
- p2.favorite = "blue"
- p2.put()
- p3 = Person()
- p3.put()
- people = db.GqlQuery("SELECT * FROM Person WHERE favorite < :1", 50)
- # people has p1, but not p2 or p3
- people = db.GqlQuery("SELECT * FROM Person WHERE favorite > :1", 50)
- # people has no results
字符串、长字符串、二进制数据
appengine支持Unicode字符串,因此不需要为中文问题而担忧。
- class MyModel(db.Model):
- string = db.StringProperty()
- obj = MyModel()
- # Python Unicode literal syntax fully describes characters in a text string.
- obj.string = u"kittens"
- # unicode() converts a byte string to a Unicode value using the named codec.
- obj.string = unicode("kittens", "latin-1")
- # A byte string is assumed to be text encoded as ASCII (the 'ascii' codec).
- obj.string = "kittens"
- # Short string properties can be used in query filters.
- results = db.GqlQuery("SELECT * FROM MyModel WHERE string = :1", u"kittens")
- class MyModel(db.Model):
- text = db.TextProperty()
- obj = MyModel()
- # Text() can take a Unicode value.
- obj.text = db.Text(u"lots of kittens")
- # Text() can take a byte string and the name of an encoding.
- obj.text = db.Text("lots of kittens", "latin-1")
- # If no encoding is specified, a byte string is assumed to be ASCII text.
- obj.text = db.Text("lots of kittens")
- # Text properties can store large values.
- obj.text = db.Text(open("a_tale_of_two_cities.txt").read(), "utf-8")
- class MyModel(db.Model):
- blob = db.BlobProperty()
- obj = MyModel()
- obj.blob = db.Blob(open("image.png").read())
列表:
- class MyModel(db.Model):
- numbers = db.ListProperty(long)
- obj = MyModel()
- obj.numbers = [2, 4, 6, 8, 10]
- obj.numbers = ["hello"] # ERROR: MyModel.numbers must be a list of longs.
- # Get all entities where numbers contains a 6.
- results = db.GqlQuery("SELECT * FROM MyModel WHERE numbers = 6")
- # Get all entities where numbers contains at least one element less than 10.
- results = db.GqlQuery("SELECT * FROM MyModel WHERE numbers < 10")
- class FirstModel(db.Model):
- prop = db.IntegerProperty()
- class SecondModel(db.Model):
- reference = db.ReferenceProperty(FirstModel)
- obj1 = FirstModel()
- obj1.prop = 42
- obj1.put()
- obj2 = SecondModel()
- # A reference value is the key of another entity.
- obj2.reference = obj1.key()
- # Assigning a model instance to a property uses the entity's key as the value.
- obj2.reference = obj1
- obj2.put()
五 创建、更新记录(想了半天,还是觉得用记录还描述比较贴切,实体...太奇怪了)
- pet = Pet(name="Fluffy",
- type="cat",
- owner=users.get_current_user())
- pet.put()
- db.put(pet)
- if users.get_current_user():
- user_pets = db.GqlQuery("SELECT * FROM Pet WHERE pet.owner = :1",
- users.get_current_user())
- for pet in user_pets:
- pet.spayed_or_neutered = True
- db.put(user_pets)
六 查询记录集
对象查询:
- class Story(db.Model):
- title = db.StringProperty()
- date = db.DateTimeProperty()
- query = Story.all()
- query.filter('title =', 'Foo')
- query.order('-date')
- query.ancestor(key)#这句没明白做什么的?先留着吧。
- # These methods can be chained together on one line.
- query.filter('title =', 'Foo').order('-date').ancestor(key)
- # Parameters can be bound with positional arguments.
- query = db.GqlQuery("SELECT * FROM Story WHERE title = :1 "
- "AND ANCESTOR IS :2 "
- "ORDER BY date DESC",
- 'Foo', key)
- # Or, parameters can be bound with keyword arguments.
- query = db.GqlQuery("SELECT * FROM Story WHERE title = :title "
- "AND ANCESTOR IS :parent "
- "ORDER BY date DESC",
- title='Foo', parent=key)
- # String, number and Boolean values can be literal values in the string.
- query = db.GqlQuery("SELECT * FROM Story WHERE title = 'Foo' "
- "AND ANCESTOR IS :parent "
- "ORDER BY date DESC",
- parent=key)
query = Story.gql("WHERE title = :title "
"AND ANCESTOR IS :parent "
"ORDER BY date DESC",
title='Foo', parent=key)
- results = query.fetch(10)
- for result in results:
- print "Title: " + result.title
- for result in query:
- print "Title: " + result.title
注意:Google AppEngine中每个查询最多返回1000条数据,不管limit和offset设置的值为多少。例如,对于大于1000条的数据,如果offset设置为100,那么实际返回900条数据。 我想知道的是,如果有1万条数据,那么每次返回100条,不知道是否可以将1万条数据全部遍历,如果不可以的话,那么岂不是非常不妙啊?
要获取一条数据也很简单,如下:
- entity.put()
- key = entity.key()
- # ...
- entity = db.get(key)
- pets = GqlQuery("SELECT * FROM Pet WHERE name = :1", "Fluffy")
- pet = pets.get()
- owner_name = pet.owner.name
- #在模板中如下使用
- obj = MyModel(name="Foo")
- self.response.write('<a href="/view?key=%s">%s</a>' % (str(obj.key()),
- obj.name()))
- # ...
- #在页面中如下使用
- key_name = self.request.get('key')
- obj = db.get(db.Key(key_name))
- q = db.GqlQuery("SELECT * FROM Message WHERE create_date < :1", earliest_date)
- results = q.fetch(10)
- for result in results:
- result.delete()
- # or...
- q = db.GqlQuery("SELECT * FROM Message WHERE create_date < :1", earliest_date)
- results = q.fetch(10)
- db.delete(results)
如果没有设置ID的话,可以使用obj.key()获得某条记录的ID
可以使用db.Key(ID)或者Entity.Key(ID)获取obj。
十 索引的配置 Index.yaml 例子:
- indexes:
- - kind: Cat
- ancestor: no
- properties:
- - name: name
- - name: age
- direction: desc
- - kind: Cat
- properties:
- - name: name
- direction: asc
- - name: whiskers
- direction: desc
- - kind: Store
- ancestor: yes
- properties:
- - name: business
- direction: asc
- - name: owner
- direction: asc
注意:实际上,如果你没有对该文件进行配置,google appengine会对它进行默认的配置,当然是为了优化查询了。
附录:
一 Model Class:(文档:http://code.google.com/intl/zh-CN/appengine/docs/datastore/modelclass.html)
类方法:
- Model.get()
- Model.get_by_id()
- Model.get_by_key_name()
- Model.get_or_insert()
- Model.all()
- Model.gql()
- Model.kind()
- Model.properties()
二 Query类
实例方法:
三 支持的属性——属性类型
Property class | Value type | Sort order |
---|---|---|
StringProperty | str unicode | Unicode (str is treated as ASCII) |
BooleanProperty | bool | False < True |
IntegerProperty | int long | Numeric |
FloatProperty | float | Numeric |
DateTimeProperty DateProperty TimeProperty | datetime.datetime | Chronological |
ListProperty StringListProperty | list of a supported type | If ascending, by least element; if descending, by greatest element |
ReferenceProperty SelfReferenceProperty | db.Key | By path elements (kind, ID or name, kind, ID or name...) |
UserProperty | users.User | By email address (Unicode) |
BlobProperty | db.Blob | (not orderable) |
TextProperty | db.Text | (not orderable) |
CategoryProperty | db.Category | Unicode |
LinkProperty | db.Link | Unicode |
EmailProperty | db.Email | Unicode |
GeoPtProperty | db.GeoPt | By latitude, then longitude |
IMProperty | db.IM | Unicode |
PhoneNumberProperty | db.PhoneNumber | Unicode |
PostalAddressProperty | db.PostalAddress | Unicode |
RatingProperty | db.Rating | Numeric |
- exception Error()
- exception BadArgumentError()
- exception BadFilterError()
- exception BadKeyError()
- exception BadPropertyError()
- exception BadQueryError()
- exception BadRequestError()
- exception BadValueError()
- exception ConfigurationError()
- exception DuplicatePropertyError()
- exception InternalError()
- exception KindError()
- exception NotSavedError()
- exception PropertyError()
- exception ReservedWordError()
- exception Rollback()
- exception Timeout()
- exception TransactionFailedError()
- exception CapabilityDisabledError()
http://code.google.com/intl/zh-CN/appengine/docs/datastore/transactions.html