zope.generations提供在數據庫中更新對象的方式,當該應用程序的模式更改 應用模式基本上是數據的結構中,類ZODB的情況下,或在的情況下,該表的描述的結構一個關係數據庫。
詳細文檔STRONG>
代是在應用模式變化時更新數據庫的對象的一種方式。應用模式基本上是數據的結構中,類ZODB或在關係數據庫中的情況下,該表的描述的情況下的結構。
當你改變你的應用程序的數據結構,例如,你改變一個類的現有字段的語義,你將與你的變化之前創建的數據庫的問題。有關更詳盡的討論和可能的解決方案,請參閱http://wiki.zope.org/zope3/DatabaseGenerations
我們將使用的組件體系結構,我們需要一個數據庫和一個連接:
  >>>進口CGI
 從>>>進口pprint pprint
 從>>>進口zope.interface工具
 從>>>進口ZODB.tests.util DB
  >>> DB = DB()
  >>>康恩= db.open()
  >>>根= conn.root()
試想一下,我們的應用程序是一個Oracle:你可以教它反應詞組。讓我們保持它的簡單,並存儲在一個字典中的數據:
  >>>根['答案'] = {'你好':'嗨&你怎麼辦“,
  ......'?人生的意義“:”42“,
&NBSP; ......“四<?”:“四<五'}
&NBSP; >>>進口交易
&NBSP; >>>器transaction.commit()
初始設置
下面是一些代特定的代碼。我們將創建並註冊一個SchemaManager。 SchemaManagers負責數據庫的實際更新。這其中將只是一個假人。這裡的關鍵是使幾代模塊意識到,我們的應用程序支持代。
SchemaManager的默認實現不適合這個測試,因為它使用Python模塊來管理代。就目前而言,這將是蠻好的,因為我們不希望它做任何事情,只是還沒有。
&NBSP;從>>>進口zope.generations.interfaces ISchemaManager
&NBSP;從>>>進口zope.generations.generations SchemaManager
&NBSP; >>>進口zope.component
&NBSP; >>> dummy_manager = SchemaManager(minimum_generation = 0,代= 0)
&NBSP; >>> zope.component.provideUtility(
&NBSP; ... dummy_manager,ISchemaManager,名稱='some.app“)
'some.app'是一個唯一的標識符。您應該使用URI或你的包的帶點名稱。
當您啟動Zope和打開一個數據庫,一個事件IDatabaseOpenedWithRoot發送。 Zope的註冊evolveMinimumSubscriber默認的處理此事件。讓我們來模擬這個:
&NBSP; >>>類DatabaseOpenedEventStub(對象):
&NBSP; ...高清__init __(個體經營,數據庫):
&NBSP; ... self.database =數據庫
&NBSP; >>>事件= DatabaseOpenedEventStub(DB)
&NBSP;從>>>進口zope.generations.generations evolveMinimumSubscriber
&NBSP; >>> evolveMinimumSubscriber(事件)
這個動作的結果是,現在該數據庫包含一個事實,即我們的當前模式號為0。當我們更新架構,Zope3將有什麼樣的出發點是一個想法。在這裡,看到了嗎?
&NBSP;從>>>進口zope.generations.generations generations_key
&NBSP; >>>根[generations_key] ['some.app']
&NBSP; 0
在現實生活中你不應該直接用此鍵來打擾,但你應該知道它的存在。
升級方案
回到故事。一段時間的推移和我們的客戶之一,被黑客攻擊,因為我們忘記了逃跑HTML特殊字符!恐怖!我們必須盡快解決這個問題,而不會丟失任何數據。我們決定使用代來打動我們的同行。
讓我們更新架構管理器(刪除舊之一,安裝一個新的自定義的):
&NBSP;從>>>進口zope.component globalregistry
&NBSP; >>> GSM = globalregistry.getGlobalSiteManager()
&NBSP; >>> gsm.unregisterUtility(前提= ISchemaManager,名稱='some.app“)
&NBSP;真
&NBSP; >>>類MySchemaManager(對象):
&NBSP; ...工具(ISchemaManager)
&NBSP; ...
&NBSP; ... minimum_generation = 1
&NBSP; ...代= 2
&NBSP; ...
&NBSP; ...高清演進(個體經營,背景,代):
&NBSP; ...根= context.connection.root()
&NBSP; ...答案=根['答案']
&NBSP; ...如果代== 1:
&NBSP; ...的問題,在answers.items答案():
&NBSP; ...答案[問題] = cgi.escape(答案)
&NBSP; ... ELIF代== 2:
&NBSP; ...的問題,在answers.items答案():
&NBSP; ...德爾答案[問題]
&NBSP; ...答案[cgi.escape(問題)] =答案
&NBSP; ...其他:
&NBSP; ...提高ValueError錯誤(“無賴”)
&NBSP;根... ['答案'] =#答案持久性平
&NBSP; ...器transaction.commit()
&NBSP; >>>經理= MySchemaManager()
&NBSP; >>> zope.component.provideUtility(經理,ISchemaManager,名稱='some.app“)
我們已經設置minimum_generation為1。這意味著,我們的應用將拒絕與舊的數據庫比一代1.代屬性被設置為2,這意味著,這個SchemaManager知道最新一代的大約為2運行。
演變()是重負荷這裡。它的任務是獲取數據庫一代-1的產生。它得到的上下文有屬性'連接',這是對ZODB的連接。你可以用它來改變物體就像這個例子。
在這個特殊的實施產生1逸出的答案(例如,關鍵的,因為它們可以被任何人輸入!),生成2逸出的問題(比如說,不太重要的,因為這些都可以通過授權personell僅輸入)。
其實,你並不真正需要自定義實現ISchemaManager的。一個是可用的,我們已經使用了一個虛擬的前面。它使用Python模塊組織的Evolver功能。看到它的文檔字符串以獲取更多信息。
在現實生活中,你將有更複雜的對象結構比這裡的人。為了使您的生活更輕鬆,也有zope.generations.utility提供了兩個非常有用的功能:findObjectsMatching()和findObjectsProviding()。他們將通過集裝箱掏遞歸來幫助你尋找你要更新,通過接口或其他一些標準的老物件。他們很容易理解,檢查他們的文檔字符串。
代行動
因此,我們的憤怒的客戶端下載我們最新的代碼,並重新啟動Zope的。該事件再次自動發送:
&NBSP; >>>事件= DatabaseOpenedEventStub(DB)
&NBSP; >>> evolveMinimumSubscriber(事件)
Shazam的!客戶端是幸福的了!
&NBSP; >>> pprint(根['答案'])
&NBSP; {'你好':'嗨&你怎麼辦?“,
&NBSP;“生命的意義?':'42',
&NBSP;“四”?“:”四<五'}
由於evolveMinimumSubscriber很懶惰,只更新數據庫足夠讓你的應用程序可以使用它(到minimum_generation,那是)。事實上,該標記表明該數據庫生成已被撞至1:
&NBSP; >>>根[generations_key] ['some.app']
&NBSP; 1
我們看到,幾代人的努力,所以我們決定採取下一步演進到新一代2.讓我們看看如何可以手動完成:
&NBSP;從>>>進口zope.generations.generations發展
&NBSP; >>>進化(DB)
&NBSP; >>> pprint(根['答案'])
&NBSP; {'你好':'嗨&你怎麼辦?“,
&NBSP;“生命的意義?':'42',
&NBSP;“四”?“:”四<五'}
&NBSP; >>>根[generations_key] ['some.app']
&NBSP; 2
進化升級的默認行為,由SchemaManager提供的最新一代。您可以使用參數如何演變()當你想只是為了檢查是否需要更新或者如果你想偷懶像我們以前所謂的用戶。
序架構經理
頻繁的子系統用於組成一個應用程序依賴於其它子系統正常工作。如果這兩個子系統提供的模式管理器,它往往有助於了解在其中evolvers將被調用的順序。這允許一個框架,它的客戶端能夠在音樂會演變,並且客戶端可以知道,該框架將之前或之後進行自身進化。
這可通過控制的模式管理實用程序的名稱來完成。架構經理通過整理自己的名字確定的順序運行。
&NBSP; >>> manager1 = SchemaManager(minimum_generation = 0,代= 0)
&NBSP; >>> manager2 = SchemaManager(minimum_generation = 0,代= 0)
&NBSP; >>> zope.component.provideUtility(
&NBSP; ... manager1,ISchemaManager,名稱='another.app“)
&NBSP; >>> zope.component.provideUtility(
&NBSP; ... manager2,ISchemaManager,名稱='another.app擴展“)
請注意第一包的名稱是用於創建相關程序包命名空間。這不是框架的要求,但方便的圖案為這個用法。
讓我們進化的數據庫,以確定這些世代:
&NBSP; >>>事件= DatabaseOpenedEventStub(DB)
&NBSP; >>> evolveMinimumSubscriber(事件)
&NBSP; >>>根[generations_key] ['another.app']
&NBSP; 0
&NBSP; >>>根[generations_key] ['another.app擴展']
&NBSP; 0
讓我們假設由於某種原因,每個子系統都需要添加一個世代,和'another.app延伸“的那一代1取決於”another.app“的第1代。我們需要為每一個他們一直跑,所以我們可以驗證結果記錄架構經理:
&NBSP; >>> gsm.unregisterUtility(前提= ISchemaManager,名稱='another.app“)
&NBSP;真
&NBSP; >>> gsm.unregisterUtility(
&NBSP; ...提供= ISchemaManager,名稱='another.app擴展“)
&NBSP;真
&NBSP; >>>類FoundationSchemaManager(對象):
&NBSP; ...工具(ISchemaManager)
&NBSP; ...
&NBSP; ... minimum_generation = 1
&NBSP; ...代= 1
&NBSP; ...
&NBSP; ...高清演進(個體經營,背景,代):
&NBSP; ...根= context.connection.root()
&NBSP; ...訂購= root.get('排序',[])
&NBSP; ...如果代== 1:
&NBSP; ... ordering.append(“基礎1)
&NBSP; ...打印“基礎代1'
&NBSP; ...其他:
&NBSP; ...提高ValueError錯誤(“無賴”)
&NBSP;根... ['訂購'] =訂貨#平持久性
&NBSP; ...器transaction.commit()
&NBSP; >>>類DependentSchemaManager(對象):
&NBSP; ...工具(ISchemaManager)
&NBSP; ...
&NBSP; ... minimum_generation = 1
&NBSP; ...代= 1
&NBSP; ...
&NBSP; ...高清演進(個體經營,背景,代):
&NBSP; ...根= context.connection.root()
&NBSP; ...訂購= root.get('排序',[])
&NBSP; ...如果代== 1:
&NBSP; ... ordering.append('依賴1)
&NBSP; ...打印“依賴性產生1'
&NBSP; ...其他:
&NBSP; ...提高ValueError錯誤(“無賴”)
&NBSP;根... ['訂購'] =訂貨#平持久性
&NBSP; ...器transaction.commit()
&NBSP; >>> manager1 = FoundationSchemaManager()
&NBSP; >>> manager2 = DependentSchemaManager()
&NBSP; >>> zope.component.provideUtility(
&NBSP; ... manager1,ISchemaManager,名稱='another.app“)
&NBSP; >>> zope.component.provideUtility(
&NBSP; ... manager2,ISchemaManager,名稱='another.app擴展“)
現在不斷發展的數據庫的Evolver之前,“another.app擴展”的Evolver將一直運行'another.app“:
&NBSP; >>>事件= DatabaseOpenedEventStub(DB)
&NBSP; >>> evolveMinimumSubscriber(事件)
&NBSP;地基產生1
&NBSP;依賴性產生1
&NBSP; >>>根['訂購']
&NBSP; ['地基1','從屬1']
安裝
在上述的例子中,我們手動初始化的答案。我們不應該這樣做手工。該應用程序應能夠自動做到這一點。
IInstallableSchemaManager延伸ISchemaManager,提供用於執行intial安裝的應用程序的安裝方法。這比註冊數據庫的用戶打開一個更好的選擇。
讓我們定義一個新的模式管理器,包括安裝:
&NBSP; >>> gsm.unregisterUtility(前提= ISchemaManager,名稱='some.app“)
&NBSP;真
&NBSP;從>>>進口zope.generations.interfaces IInstallableSchemaManager
&NBSP; >>>類MySchemaManager(對象):
&NBSP; ...工具(IInstallableSchemaManager)
&NBSP; ...
&NBSP; ... minimum_generation = 1
&NBSP; ...代= 2
&NBSP; ...
&NBSP; ... DEF安裝(個體經營,上下文):
&NBSP; ...根= context.connection.root()
&NBSP;根... ['答案'] = {'你好':'嗨&你怎麼辦“,
&NBSP; ......'?人生的意義“:”42“,
&NBSP; ......“四<?”:“四<五'}
&NBSP; ...器transaction.commit()
&NBSP; ...
&NBSP; ...高清演進(個體經營,背景,代):
&NBSP; ...根= context.connection.root()
&NBSP; ...答案=根['答案']
&NBSP; ...如果代== 1:
&NBSP; ...的問題,在answers.items答案():
&NBSP; ...答案[問題] = cgi.escape(答案)
&NBSP; ... ELIF代== 2:
&NBSP; ...的問題,在answers.items答案():
&NBSP; ...德爾答案[問題]
&NBSP; ...答案[cgi.escape(問題)] =答案
&NBSP; ...其他:
&NBSP; ...提高ValueError錯誤(“無賴”)
&NBSP;根... ['答案'] =#答案持久性平
&NBSP; ...器transaction.commit()
&NBSP; >>>經理= MySchemaManager()
&NBSP; >>> zope.component.provideUtility(經理,ISchemaManager,名稱='some.app“)
現在,讓我們打開一個新的數據庫:
&NBSP; >>> db.close()
&NBSP; >>> DB = DB()
&NBSP; >>>康恩= db.open()
&NBSP; >>>'答案'的conn.root()
&NBSP;假
&NBSP; >>>事件= DatabaseOpenedEventStub(DB)
&NBSP; >>> evolveMinimumSubscriber(事件)
&NBSP; >>> conn.sync()
&NBSP; >>>根= conn.root()
&NBSP; >>> pprint(根['答案'])
&NBSP; {'你好':'嗨&你怎麼辦?“,
&NBSP;“生命的意義?':'42',
&NBSP;“四”?“:”四<五'}
&NBSP; >>>根[generations_key] ['some.app']
&NBSP; 2
在ZODB事務日誌指出,我們的安裝腳本執行
&NBSP; >>> [。在conn.db it.description它()storage.iterator()] [ - 2]
&NBSP; u'some.app:運行安裝代“
(小注:這是不是最後一個記錄,因為有兩個提交:MySchemaManager進行之一,evolveMinimumSubscriber執行第二個MySchemaManager並不真正需要提交。)
什麼是新的在此版本中:
- 在增加了對Python的支持,3.3
- 在替換棄用zope.interface.implements使用具有同等zope.interface.implementer裝飾。
- 在丟棄的Python 2.4和2.5的支持。
什麼在3.7.1版本新:
- 這是在開發過程中使用,但確實
- 在刪除擴建部分沒有編制的Windows。
- 在生成腳本中添加一張交易單據。
要求:
- 在Python中
評論沒有發現