*將Python Tutorial專案分解成Django樣式,範例程式
Google App Engine 提供一套易於延展的資料存放區,它是以Big-Table為基礎,與目前關聯式資料庫不同,在儲存設備上,資料物件稱為"資料實體"(entity),資料物件中有欄位資料,稱為該實體中的屬性(property),每一個資料實體的屬性,可以根據資料存放區所提供的資料型態來定義資料欄位。
資料欄位型態的定義可參考 https://developers.google.com/appengine/docs/python/datastore/entities
在程式中要表式資料實體的類別,可以用"模型"(model)程式來表示。
在程式碼中,所建立用來產生資料實體的類別必須繼承自db.Model母類別,資料實體可利用類別的方法put()來儲存資料。
from google.appengine.ext import db
class Account(db.Model):
name=db.StringProperty(required=True)
email=db.EmailProperty(required=True)
created=db.DateTimeProperty(auto_now_add=True)
account=Account(name='Eric',email='litong@must.edu.tw')
account.put()
print account.created
每一個類別中的資料欄位型態必須正確的定義,才能將資料正確的儲存。以下介紹幾種資料欄位的型態。
儲存文字資料,可單行或多行文字,資料大小不可超過500bytes。其選項multiline可為True或False,用來設定是否可儲存多行文字,若設定為False,則儲存的資料就不能有換行字元\r或\n,預設為False
是用來儲存500byte大小以內的資料,可以是純文字或二進位資料,與StringProperty不同的地方在於,在ByteStringProperty欄位內的資料是尚未使用文字編碼過的byte資料。
from google.appengine.ext import db
class User(db.Model):
name=db.StringProperty()
class Article(db.Model):
author=db.ReferenceProperty(reference_class=User)
title=db.StringProperty()
content=db.TextProperty()
query=db.GqlQuery("SELECT * FROM Article WHERE title = 'title1'")
articles=query.fetch(10)
print articles
for article in articles:
print article.title,article.content
================================================
可以使用參數編號或指定名稱來進行條件比對
query=db.GqlQuery("SELECT * FROM Article WHERE title = :1",'title1')
or
query=db.GqlQuery("SELECT * FROM Article WHERE title = :title",title='title1')
=======================================================
也可以透過資料模型來操作GQL,在方法中就不必再加入資料種類。
query=Article.gql("WHERE title = 'title1'")
or
query=Article.gql("WHERE title = :1",'title1')
or
query=Article.gql("WHERE title = :title",title='title1')
另外,你也可以直接讀取資料的key值,以節省查詢的時間
keys=db.Query(Article,keys_only=True)
print keys
for key in keys:
print key
或
keys=db.GqlQuery('SELECT __key__ FROM Article')
在上述範例中,我們可以直接利用Contact.all( )來Query出繼承自它的所有Person與Company資料模型所產生的物件。
若想要只取出某個資料模型的物件,也可以使用各自的all( )方法。
Google App Engine 提供一套易於延展的資料存放區,它是以Big-Table為基礎,與目前關聯式資料庫不同,在儲存設備上,資料物件稱為"資料實體"(entity),資料物件中有欄位資料,稱為該實體中的屬性(property),每一個資料實體的屬性,可以根據資料存放區所提供的資料型態來定義資料欄位。
資料欄位型態的定義可參考 https://developers.google.com/appengine/docs/python/datastore/entities
在程式中要表式資料實體的類別,可以用"模型"(model)程式來表示。
在程式碼中,所建立用來產生資料實體的類別必須繼承自db.Model母類別,資料實體可利用類別的方法put()來儲存資料。
from google.appengine.ext import db
class Account(db.Model):
name=db.StringProperty(required=True)
email=db.EmailProperty(required=True)
created=db.DateTimeProperty(auto_now_add=True)
account=Account(name='Eric',email='litong@must.edu.tw')
account.put()
print account.created
Model欄位的資料型能定義
每一個類別中的資料欄位型態必須正確的定義,才能將資料正確的儲存。以下介紹幾種資料欄位的型態。
- StringProperty
儲存文字資料,可單行或多行文字,資料大小不可超過500bytes。其選項multiline可為True或False,用來設定是否可儲存多行文字,若設定為False,則儲存的資料就不能有換行字元\r或\n,預設為False
from google.appengine.ext import db
class StringSample(db.Model):
title=db.StringProperty(required=True)
content=db.StringProperty(multiline=True,default='')
created=db.DateTimeProperty(auto_now_add=True)
stringSample=StringSample(title='string property sample',content='''
Hi this is a String Property
Sample''')
stringSample.put()
print stringSample.content
print stringSample.created
- ByteStringProperty
是用來儲存500byte大小以內的資料,可以是純文字或二進位資料,與StringProperty不同的地方在於,在ByteStringProperty欄位內的資料是尚未使用文字編碼過的byte資料。
from google.appengine.ext import db
class ByteStringSample(db.Model):
content=db.ByteStringProperty(required=True)
byteStringSample=ByteStringSample(content='sometext')
byteStringSample.put()
print byteStringSample.content
- TextProperty
是用來儲存較長的文字資料,但它無法製作索引、排序與條件比對。
from google.appengine.ext import db
class TextSample(db.Model):
content=db.TextProperty()
textSample=TextSample(content=u'sometext')
textSample.put()
print textSample.content
儲存True或是False的資料型態
import datetime
from google.appengine.ext import db
class BooleanSample(db.Model):
enabled=db.BooleanProperty(required=True,default=False)
booleanSample=BooleanSample()
booleanSample.put()
print booleanSample.enabled
booleanSample.enabled=True
booleanSample.put()
print booleanSample.enabled
儲存整數型態的資料
import datetime
from google.appengine.ext import db
class Sample(db.Model):
value=db.IntegerProperty(required=True,default=0)
sample=Sample(value=123)
sample.put()
print sample.value
儲存浮點數資料型態
import datetime
from google.appengine.ext import db
class Sample(db.Model):
value=db.FloatProperty(required=True,default=0.0)
sample=Sample(value=123.456)
sample.put()
print sample.value
用來儲存日期及時間資料型態的資料,需要使用python中的datetime.datetime、datetime.date或是datetime.time物件。
其選項
import datetime
from google.appengine.ext import db
import datetime
class Sample(db.Model):
setDay=db.DateProperty()
created=db.DateTimeProperty(auto_now_add=True)
updated=db.DateTimeProperty(auto_now=True)
sample=Sample()
sample.setDay=datetime.date(2014,7,5)
sample.put()
print sample.key(),sample.setDay,sample.created,sample.updated
getSample=db.get(sample.key())
getSample.setDay=datetime.date(2009,1,1)
getSample.put()
print getSample.key(),getSample.setDay,getSample.created,getSample.updated
可以用來儲存list的資料型態,在ListProperty 中可放入要存放list內元素的資料型態,StringListProperty則無此選項。
import datetime
from google.appengine.ext import db
import datetime
class Sample(db.Model):
order=db.ListProperty(int)
tags=db.StringListProperty()
sample=Sample()
sample.order=[1,2,4,5,7,2]
sample.tags=[u'item',u'bar',u'data']
sample.put()
print sample.order,sample.tags
用來指向其它資料實體的資料欄位,儲存資料的資料型態為db.Key物件,可以使用這個欄位來作出各實體物件間的關聯。其選項:
import datetime
from google.appengine.ext import db
class User(db.Model):
name=db.StringProperty()
class Article(db.Model):
author=db.ReferenceProperty(reference_class=User)
title=db.StringProperty()
content=db.TextProperty()
u=User(name='Eric')
u.put()
article1=Article(author=u,title='title1',content='content1')
article1.put()
article2=Article(author=u,title='title2',content='content2')
article2.put()
article3=Article(author=u,title='title3',content='content3')
article3.put()
print article1.author.name
user=db.get('ahJkZXZ-Z2Fld2VhdGhlcnJpc2tyEQsSBFVzZXIYgICAgIDkmQkM')
print user.name
for article in u.article_set:
print 'Article: %s'%article.title
但若有兩個資料欄位都要參考到同一個資料模型時,就會發生錯誤。
class Article(db.Model):
author=db.ReferenceProperty(reference_class=User)
reviewer=db.ReferenceProperty(reference_class=User)
就必須要設定不同的collection_name
import datetime
from google.appengine.ext import db
class User(db.Model):
name=db.StringProperty()
class Article(db.Model):
author=db.ReferenceProperty(reference_class=User,collection_name='writings')
reviewer=db.ReferenceProperty(reference_class=User,collection_name='reviews')
title=db.StringProperty()
content=db.TextProperty()
'''
u1=User(name='Eric1')
u1.put()
u2=User(name='Eric2')
u2.put()
article1=Article(author=u1,reviewer=u1,title='title1',content='content1')
article1.put()
article2=Article(author=u2,reviewer=u1,title='title2',content='content2')
article2.put()
article3=Article(author=u1,reviewer=u2,title='title3',content='content3')
article3.put()
article4=Article(author=u2,reviewer=u2,title='title4',content='content4')
article4.put()
'''
u=db.get('ahJkZXZ-Z2Fld2VhdGhlcnJpc2tyEQsSBFVzZXIYgICAgIDUkQgM')
print dir(u.writings.order)
for article in u.writings.order('title'):
print article.title
========================================================
如果要參考到相同的資料模型,可以使用SelfReferenceProperty,並用collection_name來設定欄位名稱。
class User(db.Model):
name=db.StringProperty()
employer=db.SelfReferenceProperty(collection_name='employees')
當資料儲存之後,GAE會配給每一個資料實體一個Key值(是經過加密的),這個值內容包含資料種類及ID,另外您也可以自己命名一個獨一無二的鍵值名稱key_name。ID值則是系統自動配發的數字。
由上述的例子我們可以得知,資料的儲存可以利用put( )的方法,資料的取得可以利用db.get( )的方法,其中必須加入資料實體的key值:
#u_key 為某個資料實體的key值
db.get(u_key)
同樣的,資料實體的刪除,我們可以利用db.delete( )的方法
#u_key 為某個資料實體的key值
db.delete(u_key)
資料實體entity的建立作法,是必須要先定義資料模型的類別,然後再去產生資料物件。產生資料物件的方法有二:
import datetime
from google.appengine.ext import db
class Sample(db.Model):
value=db.IntegerProperty(default=0)
sample=Sample()
sample.value=456
sample.put()
print sample.value
資料的儲存可以利用物件類別put( )的方法或是透過db.put( )的方法
import datetime
from google.appengine.ext import db
class Sample(db.Model):
value=db.IntegerProperty(default=0)
sample=Sample()
sample.value=777
db.put(sample)
print sample.value
我們可以利用order( )方法來排序資料
query=Article.all()
query.order('title')
articles=query.fetch(3,0)
for article in articles:
print article.title
或是order內的參數加減號(- )取得相反順序的排序資料。
- BooleanProperty
儲存True或是False的資料型態import datetime
from google.appengine.ext import db
class BooleanSample(db.Model):
enabled=db.BooleanProperty(required=True,default=False)
booleanSample=BooleanSample()
booleanSample.put()
print booleanSample.enabled
booleanSample.enabled=True
booleanSample.put()
print booleanSample.enabled
- IntegerProperty
儲存整數型態的資料
import datetime
from google.appengine.ext import db
class Sample(db.Model):
value=db.IntegerProperty(required=True,default=0)
sample=Sample(value=123)
sample.put()
print sample.value
- FloatProperty
儲存浮點數資料型態
import datetime
from google.appengine.ext import db
class Sample(db.Model):
value=db.FloatProperty(required=True,default=0.0)
sample=Sample(value=123.456)
sample.put()
print sample.value
- DateTimeProperty、DateProperty、TimeProperty
用來儲存日期及時間資料型態的資料,需要使用python中的datetime.datetime、datetime.date或是datetime.time物件。
其選項
- auto_now_add:可為True或False,來設定物件實體產生時,是否會自動寫入目前的日期或時間。
- auto_now:可為True或False,來設定物件實體更新時,是否會自動寫入目前的日期或時間。
import datetime
from google.appengine.ext import db
import datetime
class Sample(db.Model):
setDay=db.DateProperty()
created=db.DateTimeProperty(auto_now_add=True)
updated=db.DateTimeProperty(auto_now=True)
sample=Sample()
sample.setDay=datetime.date(2014,7,5)
sample.put()
print sample.key(),sample.setDay,sample.created,sample.updated
getSample=db.get(sample.key())
getSample.setDay=datetime.date(2009,1,1)
getSample.put()
print getSample.key(),getSample.setDay,getSample.created,getSample.updated
- ListProperty、StringListProperty
可以用來儲存list的資料型態,在ListProperty 中可放入要存放list內元素的資料型態,StringListProperty則無此選項。
import datetime
from google.appengine.ext import db
import datetime
class Sample(db.Model):
order=db.ListProperty(int)
tags=db.StringListProperty()
sample=Sample()
sample.order=[1,2,4,5,7,2]
sample.tags=[u'item',u'bar',u'data']
sample.put()
print sample.order,sample.tags
- ReferenceProperty、SelfReferenceProperty
用來指向其它資料實體的資料欄位,儲存資料的資料型態為db.Key物件,可以使用這個欄位來作出各實體物件間的關聯。其選項:
- reference_class:為參考資料實體的資料模型
- collection_name:在參考資料模型中建立的list資料欄位名稱,若不指定則會使用"模型名稱_set"來作為資料欄位名稱。
import datetime
from google.appengine.ext import db
class User(db.Model):
name=db.StringProperty()
class Article(db.Model):
author=db.ReferenceProperty(reference_class=User)
title=db.StringProperty()
content=db.TextProperty()
u=User(name='Eric')
u.put()
article1=Article(author=u,title='title1',content='content1')
article1.put()
article2=Article(author=u,title='title2',content='content2')
article2.put()
article3=Article(author=u,title='title3',content='content3')
article3.put()
print article1.author.name
user=db.get('ahJkZXZ-Z2Fld2VhdGhlcnJpc2tyEQsSBFVzZXIYgICAgIDkmQkM')
print user.name
for article in u.article_set:
print 'Article: %s'%article.title
但若有兩個資料欄位都要參考到同一個資料模型時,就會發生錯誤。
class Article(db.Model):
author=db.ReferenceProperty(reference_class=User)
reviewer=db.ReferenceProperty(reference_class=User)
就必須要設定不同的collection_name
import datetime
from google.appengine.ext import db
class User(db.Model):
name=db.StringProperty()
class Article(db.Model):
author=db.ReferenceProperty(reference_class=User,collection_name='writings')
reviewer=db.ReferenceProperty(reference_class=User,collection_name='reviews')
title=db.StringProperty()
content=db.TextProperty()
'''
u1=User(name='Eric1')
u1.put()
u2=User(name='Eric2')
u2.put()
article1=Article(author=u1,reviewer=u1,title='title1',content='content1')
article1.put()
article2=Article(author=u2,reviewer=u1,title='title2',content='content2')
article2.put()
article3=Article(author=u1,reviewer=u2,title='title3',content='content3')
article3.put()
article4=Article(author=u2,reviewer=u2,title='title4',content='content4')
article4.put()
'''
u=db.get('ahJkZXZ-Z2Fld2VhdGhlcnJpc2tyEQsSBFVzZXIYgICAgIDUkQgM')
print dir(u.writings.order)
for article in u.writings.order('title'):
print article.title
========================================================
如果要參考到相同的資料模型,可以使用SelfReferenceProperty,並用collection_name來設定欄位名稱。
class User(db.Model):
name=db.StringProperty()
employer=db.SelfReferenceProperty(collection_name='employees')
當資料儲存之後,GAE會配給每一個資料實體一個Key值(是經過加密的),這個值內容包含資料種類及ID,另外您也可以自己命名一個獨一無二的鍵值名稱key_name。ID值則是系統自動配發的數字。
由上述的例子我們可以得知,資料的儲存可以利用put( )的方法,資料的取得可以利用db.get( )的方法,其中必須加入資料實體的key值:
#u_key 為某個資料實體的key值
db.get(u_key)
同樣的,資料實體的刪除,我們可以利用db.delete( )的方法
#u_key 為某個資料實體的key值
db.delete(u_key)
資料的操作
- 資料實體的建立
- 直接在物件產生的同時就定義欄位值
import datetime
from google.appengine.ext import db
class Sample(db.Model):
value=db.IntegerProperty(default=0)
sample=Sample(value=123)
sample.put()
print sample.value
- 先產生物件再指定欄位值
import datetime
from google.appengine.ext import db
class Sample(db.Model):
value=db.IntegerProperty(default=0)
sample=Sample()
sample.value=456
sample.put()
print sample.value
資料的儲存可以利用物件類別put( )的方法或是透過db.put( )的方法
import datetime
from google.appengine.ext import db
class Sample(db.Model):
value=db.IntegerProperty(default=0)
sample=Sample()
sample.value=777
db.put(sample)
print sample.value
透過Query物件來取得資料實體
我們可以透過資料模型的all( )方法取得一個Query物件,然後利用fetch(limit,offset)的方法來取得我們所要的資料。
from google.appengine.ext import db
class User(db.Model):
name=db.StringProperty()
class Article(db.Model):
author=db.ReferenceProperty(reference_class=User)
title=db.StringProperty()
content=db.TextProperty()
query=Article.all()
articles=query.fetch(2,0)
for article in articles:
print article.title
我們可以利用filter( )方法來比對我們想要的資料
query=Article.all()
query.filter('title =','title1')
articles=query.fetch(2,0)
for article in articles:
print article.title
==============
query=Article.all()
query.filter('title >','title1')
articles=query.fetch(2,0)
for article in articles:
print article.title
我們可以利用order( )方法來排序資料
query=Article.all()
query.order('title')
articles=query.fetch(3,0)
for article in articles:
print article.title
或是order內的參數加減號(- )取得相反順序的排序資料。
query=Article.all()
query.order('-title')
articles=query.fetch(3,0)
for article in articles:
print article.title
query.order('-title')
articles=query.fetch(3,0)
for article in articles:
print article.title
GQL查詢語言
除了利用資料模型的all( )方法產生Query物件來讀取資料外,我們也可以使用一組資料查詢語言GQL來讀取資料。GQL是一個與SQL相似的查詢語言,目前GQL只提供資料的查詢讀取,不支援資料新增、刪除與修改。from google.appengine.ext import db
class User(db.Model):
name=db.StringProperty()
class Article(db.Model):
author=db.ReferenceProperty(reference_class=User)
title=db.StringProperty()
content=db.TextProperty()
query=db.GqlQuery("SELECT * FROM Article WHERE title = 'title1'")
articles=query.fetch(10)
print articles
for article in articles:
print article.title,article.content
================================================
可以使用參數編號或指定名稱來進行條件比對
query=db.GqlQuery("SELECT * FROM Article WHERE title = :1",'title1')
or
query=db.GqlQuery("SELECT * FROM Article WHERE title = :title",title='title1')
=======================================================
也可以透過資料模型來操作GQL,在方法中就不必再加入資料種類。
query=Article.gql("WHERE title = 'title1'")
or
query=Article.gql("WHERE title = :1",'title1')
or
query=Article.gql("WHERE title = :title",title='title1')
在GQL中可以指定LIMIT及OFFSET關鍵字,回傳的資料就直接是list了,而不是Query物件,因此就可以不必再呼叫fetch方法了
articles=Article.gql("WHERE title = :1 LIMIT 10 OFFSET 0",'title1')
另外,你也可以直接讀取資料的key值,以節省查詢的時間
keys=db.Query(Article,keys_only=True)
print keys
for key in keys:
print key
或
keys=db.GqlQuery('SELECT __key__ FROM Article')
鍵值名稱
一般來說鍵值是經過加密過後所產生的一串無義意的編碼字串,即便內部包含資料種類的相關資訊,我們也無法從鍵值直接看出來,我們可以利用鍵值名稱key_name來自行命名每一個資料實體名稱,之後透過get_by_key_name( )方法來將資料取出。
import datetime
from google.appengine.ext import db
class Sample(db.Model):
value=db.FloatProperty(required=True,default=0.0)
sample=Sample(key_name='555.5_sample',value=555.5)
sample.put()
sample=Sample.get_by_key_name('555.5_sample')
print sample.value
鍵值名稱與鍵值相同,必須是唯一的字串,使用鍵值名稱的好處是命名規則可以自訂,方便程式讀取資料實體。
import datetime
from google.appengine.ext import db
class Sample(db.Model):
value=db.FloatProperty(required=True,default=0.0)
sample=Sample(key_name='555.5_sample',value=555.5)
sample.put()
sample=Sample.get_by_key_name('555.5_sample')
print sample.value
鍵值名稱與鍵值相同,必須是唯一的字串,使用鍵值名稱的好處是命名規則可以自訂,方便程式讀取資料實體。
刪除資料
要刪除資料可以用db.delete( )或物件實體delete( )方法來將資料刪除
db.delete(sample)
or
sample.delete()
您也可以使用db.delete( )的方法來刪除多筆資料(list)
import datetime
from google.appengine.ext import db
class Sample(db.Model):
value=db.FloatProperty(required=True,default=0.0)
'''
sample1=Sample(key_name='555.5_sample',value=555.5)
sample1.put()
sample2=Sample(key_name='666.6_sample',value=666.6)
sample2.put()
print 'befere delete'
query=Sample.all()
query.filter('value >',555.0)
samples=query.fetch(10)
for sample in samples:
print sample.value
'''
db.delete(samples)
print 'after delete'
query=Sample.all()
query.filter('value >',555.0)
samples=query.fetch(10)
for sample in samples:
print sample.value
當你在設計郵件或電話通訊錄時,每一個使用者user可能會有一個以上的郵件或電話,這時你可以使用一對一關聯性將這些資料收集起來。
from google.appengine.ext import db
class User(db.Model):
strName=db.StringProperty()
class Email(db.Model):
user=db.ReferenceProperty(User,collection_name='emails')
strType=db.StringProperty(required=True)
emailAddr=db.EmailProperty(required=True)
u=User(strName='eric',key_name='eric_weng')
u.put()
office_mail=Email(user=u,strType='Office',emailAddr=db.Email('eric1@office.com'))
office_mail.put()
personal_mail=Email(user=u,strType='Personal',emailAddr=db.Email('eric2@personal.com'))
personal_mail.put()
在Email的資料模型中,有一個ReferenceProperty資料型態user指向類別User資料模型,並且在有一個emailAddr欄位來記錄email相關資料,如此就這兩個資料模型就具有一對多的關聯性。
我們可以透過user資料實體來取得與它相關的email資料實體,如下所示:
u=User.get_by_key_name('eric_weng')
for email in u.emails:
print 'strType:%s, emailAddr:%s'%(email.strType,email.emailAddr)
另外我們也可以從email資料實體來取得與它相關的user資料實體
u=User.get_by_key_name('eric_weng')
for email in u.emails:
print 'strType:%s, emailAddr:%s, owner:%s'%(email.strType,email.emailAddr,email.user.strName)
db.delete(sample)
or
sample.delete()
您也可以使用db.delete( )的方法來刪除多筆資料(list)
import datetime
from google.appengine.ext import db
class Sample(db.Model):
value=db.FloatProperty(required=True,default=0.0)
'''
sample1=Sample(key_name='555.5_sample',value=555.5)
sample1.put()
sample2=Sample(key_name='666.6_sample',value=666.6)
sample2.put()
print 'befere delete'
query=Sample.all()
query.filter('value >',555.0)
samples=query.fetch(10)
for sample in samples:
print sample.value
'''
db.delete(samples)
print 'after delete'
query=Sample.all()
query.filter('value >',555.0)
samples=query.fetch(10)
for sample in samples:
print sample.value
一對一(多)與多對多資料關聯
- 一對一資料關聯
當你在設計郵件或電話通訊錄時,每一個使用者user可能會有一個以上的郵件或電話,這時你可以使用一對一關聯性將這些資料收集起來。from google.appengine.ext import db
class User(db.Model):
strName=db.StringProperty()
class Email(db.Model):
user=db.ReferenceProperty(User,collection_name='emails')
strType=db.StringProperty(required=True)
emailAddr=db.EmailProperty(required=True)
u=User(strName='eric',key_name='eric_weng')
u.put()
office_mail=Email(user=u,strType='Office',emailAddr=db.Email('eric1@office.com'))
office_mail.put()
personal_mail=Email(user=u,strType='Personal',emailAddr=db.Email('eric2@personal.com'))
personal_mail.put()
在Email的資料模型中,有一個ReferenceProperty資料型態user指向類別User資料模型,並且在有一個emailAddr欄位來記錄email相關資料,如此就這兩個資料模型就具有一對多的關聯性。
我們可以透過user資料實體來取得與它相關的email資料實體,如下所示:
u=User.get_by_key_name('eric_weng')
for email in u.emails:
print 'strType:%s, emailAddr:%s'%(email.strType,email.emailAddr)
另外我們也可以從email資料實體來取得與它相關的user資料實體
u=User.get_by_key_name('eric_weng')
for email in u.emails:
print 'strType:%s, emailAddr:%s, owner:%s'%(email.strType,email.emailAddr,email.user.strName)
- 多對多關聯
當你在設計文章系統時,可能會有一篇文章屬於多個分類及一個分類有多篇文章之類的情形,此時你就需要將不同的資料模型建立多對多關聯。
from google.appengine.ext import db
class Article(db.Model):
strTitle=db.StringProperty()
strContent=db.TextProperty()
lstCategories=db.ListProperty(db.Key)
created=db.DateTimeProperty(auto_now_add=True)
class Category(db.Model):
strName=db.StringProperty()
strDescription=db.StringProperty(multiline=True)
@property
def getArticles(self):
return Article.gql('WHERE lstCategories = :1',self.key())
上述例子中,Article資料模型使用了ListProperty的資料型態來記錄文章分類Category的key值,我們可以透過list取得每一個Category資料實體。
在Category的資料模型中,我們則建立一個getArticles的屬性,它可以根據Category資料實體的key值查詢到含有該鍵值的所有Article資料實體。
由此可知,對ListProperty欄位做" = "的運算,可以查詢到該資料是否存在list之中。
from google.appengine.ext import db
class Article(db.Model):
strTitle=db.StringProperty()
strContent=db.TextProperty()
lstCategories=db.ListProperty(db.Key)
created=db.DateTimeProperty(auto_now_add=True)
class Category(db.Model):
strName=db.StringProperty()
strDescription=db.StringProperty(multiline=True)
@property
def getArticles(self):
return Article.gql('WHERE lstCategories = :1',self.key())
上述例子中,Article資料模型使用了ListProperty的資料型態來記錄文章分類Category的key值,我們可以透過list取得每一個Category資料實體。
在Category的資料模型中,我們則建立一個getArticles的屬性,它可以根據Category資料實體的key值查詢到含有該鍵值的所有Article資料實體。
由此可知,對ListProperty欄位做" = "的運算,可以查詢到該資料是否存在list之中。
category1=Category(strName='Science',strDescription='About Science')
category1.put()
category2=Category(strName='Information',strDescription='About Information')
category2.put()
article1=Article(strTitle='Article1',strContent=db.Text('Article1 Content'))
article1.lstCategories=[category1.key(),category2.key()]
article1.put()
article2=Article(strTitle='Article2',strContent=db.Text('Article2 Content'))
article2.lstCategories=[category1.key()]
article2.put()
article3=Article(strTitle='Article3',strContent=db.Text('Article3 Content'))
article3.lstCategories=[category2.key()]
article1.put()
我們可以透過Article資料實體來取得它的所有分類。
for key in article1.lstCategories:
print 'Category: %s'% db.get(key).strName
也可以透過某一個分類來取得所有該分類的所有文章,如此一來多對多的關聯查詢就容易許多了。
for article in category1.getArticles:
print '[%s] %s'%(category1.strName,article.strTitle)
category1.put()
category2=Category(strName='Information',strDescription='About Information')
category2.put()
article1=Article(strTitle='Article1',strContent=db.Text('Article1 Content'))
article1.lstCategories=[category1.key(),category2.key()]
article1.put()
article2=Article(strTitle='Article2',strContent=db.Text('Article2 Content'))
article2.lstCategories=[category1.key()]
article2.put()
article3=Article(strTitle='Article3',strContent=db.Text('Article3 Content'))
article3.lstCategories=[category2.key()]
article1.put()
我們可以透過Article資料實體來取得它的所有分類。
for key in article1.lstCategories:
print 'Category: %s'% db.get(key).strName
也可以透過某一個分類來取得所有該分類的所有文章,如此一來多對多的關聯查詢就容易許多了。
for article in category1.getArticles:
print '[%s] %s'%(category1.strName,article.strTitle)
Expando 類別
當程式開發者希望使用一些比較彈性、鬆散的方式來定義資料型態時,可以使用Expando類別,它一樣繼承自Model類別,但它比Model 類別更具彈性,使用Expando所產生的資料物件,可以任意加上所要儲存的資料欄位,而且資料型態可以不固定,因此我們可以寫出下列程式
import datetime
from google.appengine.ext import db
class Song(db.Expando):
title = db.StringProperty()
crazy = Song(title='Crazy like a diamond',author='Lucy Sky',publish_date='yesterday',rating=5.0)
crazy.put()
hoboken = Song(title='The man from Hoboken',author=['Anthony', 'Lou'],publish_date=datetime.datetime(1977, 5, 3))
hoboken.put()
crazy.last_minute_note=db.Text('Get a train to the station.')
crazy.put()
c=db.GqlQuery('SELECT * FROM Song WHERE publish_date = :1','yesterday').get()
print c.title
要刪除某一個欄位的資料,可以利用del關鍵字
c=db.GqlQuery('SELECT * FROM Song WHERE publish_date = :1','yesterday').get()
print dir(c)
print c.last_minute_note
del c.last_minute_note
c.put()
print c.last_minute_note
PolyModel類別
假設我們要製作一個通訊錄的資料模型,其中每一個聯絡人可能是個人或公司,雖然看起來是兩個不同的類別,但在通訊錄中可能會有相同欄位的存在,如電話號碼、地址等。在物件導向程式設計中,我們可能會利用"多型"(polymorphism)的概念來設計這樣的關係,如建立一個Contact類別,然後再建立Person及Company類別,再分別繼承自Contact類別。
from google.appengine.ext import db
from google.appengine.ext.db import polymodel
class Contact(polymodel.PolyModel):
phone_number = db.PhoneNumberProperty()
address = db.PostalAddressProperty()
class Person(Contact):
first_name = db.StringProperty()
last_name = db.StringProperty()
mobile_number = db.PhoneNumberProperty()
class Company(Contact):
name = db.StringProperty()
fax_number = db.PhoneNumberProperty()
p = Person(phone_number='1-206-555-9234',
address='123 First Ave., Seattle, WA, 98101',
first_name='Alfred',
last_name='Smith',
mobile_number='1-206-555-0117')
p.put()
c = Company(phone_number='1-503-555-9123',
address='P.O. Box 98765, Salem, OR, 97301',
name='Data Solutions, LLC',
fax_number='1-503-555-6622')
c.put()
for contact in Contact.all():
print '%s : %s'%(contact.phone_number,contact.address)
for person in Person.all():
print '%s %s: %s'%(person.first_name,person.last_name,person.phone_number)
在上述範例中,我們可以直接利用Contact.all( )來Query出繼承自它的所有Person與Company資料模型所產生的物件。
若想要只取出某個資料模型的物件,也可以使用各自的all( )方法。
沒有留言:
張貼留言