zope.generations tarjoaa tapaa päivittää tietokannan objektien kun sovellus rakenteen muutokset. & Nbsp; sovellus skeema on olennaisesti rakennetta datan rakenne luokkien tapauksessa ZODB tai taulukon kuvaukset tapauksessa relaatiotietokanta.
yksityiskohtaiset asiakirjat
Sukupolvet ovat tapa päivittää tietokannan objektien kun sovellus rakenteen muutokset. Sovellus skeema on olennaisesti rakenteen tietojen rakenne luokkien tapauksessa ZODB tai taulukon kuvaukset tapauksessa relaatiotietokanta.
Kun muutat sovelluksen tietorakenteita, esimerkiksi muutat semanttinen merkitys nykyisten kentän luokan, sinulla on ongelma tietokantoja, jotka on luotu ennen muutosta. Saat syvällisempää keskustelua ja mahdollisia ratkaisuja, katso http://wiki.zope.org/zope3/DatabaseGenerations
Käytämme komponenttiarkkitehtuuri, ja tarvitsemme tietokantaan ja liitäntä:
& Nbsp; >>> tuonti cgi
& Nbsp; >>> päässä pprint tuonti pprint
& Nbsp; >>> päässä zope.interface tuonti työkoneet
& Nbsp; >>> päässä ZODB.tests.util tuonti DB
& Nbsp; >>> db = DB ()
& Nbsp; >>> yht = db.open ()
& Nbsp; >>> root = conn.root ()
Kuvittele, että meidän hakemus on oraakkeli: voit opettaa sen reagoida lauseita. Pidetään asiat yksinkertaisina ja tallentaa tietoja dict:
& Nbsp; >>> root [vastauksista '] = {' Hei ':' Hei & miten teet? ",
& Nbsp; ... "elämän tarkoitus?": "42",
& Nbsp; ... "neljä ": "Neljä
& Nbsp; >>> transaction.commit ()
Alkuasennusmenettelyjä
Seuraavassa joitakin sukupolvia-koodilla. Luomme ja rekisteröi SchemaManager. SchemaManagers vastaavat todellista päivitykset tietokantaan. Tämä on vain nukke. Tässä on tehdä sukupolville moduuli tietoinen siitä, että meidän sovellus tukee sukupolvien.
Oletuksena täytäntöönpano SchemaManager ei sovellu tätä testiä, koska se käyttää Python-moduuleja hallita sukupolville. Nyt se on vain hienoa, koska emme halua sitä tehdä mitään vielä.
& Nbsp; >>> päässä zope.generations.interfaces tuoda ISchemaManager
& Nbsp; >>> päässä zope.generations.generations tuoda SchemaManager
& Nbsp; >>> tuonti zope.component
& Nbsp; >>> dummy_manager = SchemaManager (minimum_generation = 0, sukupolvi = 0)
& Nbsp; >>> zope.component.provideUtility (
& Nbsp; ... dummy_manager, ISchemaManager, nimi = 'some.app')
"Some.app" on yksilöllinen tunniste. Sinun tulisi käyttää URI tai pilkullinen nimi paketin.
Kun käynnistät Zope ja tietokanta avataan, tapahtuma IDatabaseOpenedWithRoot lähetetään. Zope rekisteröi evolveMinimumSubscriber oletusarvoisesti käsittelijä tähän tapahtumaan. Katsotaanpa simuloida tätä:
& Nbsp; >>> luokan DatabaseOpenedEventStub (objekti):
& Nbsp; ... def __init __ (self, tietokanta):
& Nbsp; ... self.database = tietokanta
& Nbsp; >>> tapahtuma = DatabaseOpenedEventStub (db)
& Nbsp; >>> päässä zope.generations.generations tuoda evolveMinimumSubscriber
& Nbsp; >>> evolveMinimumSubscriber (tapahtuma)
Tämän tapahtuman seurauksena on, että nyt tietokanta sisältää sen, että meidän nykyinen skeema määrä on 0. Kun päivitämme skeema, Zope3 on käsitys siitä, mitä lähtökohta oli. Täällä näet?
& Nbsp; >>> päässä zope.generations.generations tuoda generations_key
& Nbsp; >>> root [generations_key] ['some.app']
& Nbsp; 0
Tosielämässä sinun ei koskaan tarvitse vaivautua tämän avaimen suoraan, mutta sinun pitäisi olla tietoinen siitä, että se on olemassa.
Päivitä skenaario
Takaisin tarina. Jokin aika kulkee ja yksi asiakkaamme saa hakata koska unohdimme paeta HTML erikoismerkkejä! Kauhu! Meidän täytyy korjata tämä ongelma ASAP menettämättä tietoja. Päätämme käyttää sukupolvien vaikutuksen meidän ikäisensä.
Katsotaanpa päivittää skeema johtaja (pudottaa vanhan ja asentaa uuden mukautetun yksi):
& Nbsp; >>> päässä zope.component tuonti globalregistry
& Nbsp; >>> gsm = globalregistry.getGlobalSiteManager ()
& Nbsp; >>> gsm.unregisterUtility (edellyttäen = ISchemaManager, name = "some.app ')
& Nbsp; True
& Nbsp; >>> luokan MySchemaManager (objekti):
& Nbsp; ... työkoneiden (ISchemaManager)
& Nbsp; ...
& Nbsp; ... minimum_generation = 1
& Nbsp; ... sukupolvi = 2
& Nbsp; ...
& Nbsp; ... def kehittyä (itse, yhteydessä sukupolvi):
& Nbsp; ... root = context.connection.root ()
& Nbsp; ... vastauksia = root [vastaukset ']
& Nbsp; ... jos sukupolvi == 1:
& Nbsp; ... sillä kysymys, vastaus answers.items ():
& Nbsp; ... vastauksia [kysymys] = cgi.escape (vastaus)
& Nbsp; ... elif sukupolvi == 2:
& Nbsp; ... sillä kysymys, vastaus answers.items ():
& Nbsp; ... del vastauksia [kysymys]
& Nbsp; ... vastauksia [cgi.escape (kysymys)] = vastaus
& Nbsp; ... muuta:
& Nbsp; ... nostaa ValueError ("Bummer")
& Nbsp; ... root [vastauksista '] = vastausten # ping pysyvyys
& Nbsp; ... transaction.commit ()
& Nbsp; >>> manager = MySchemaManager ()
& Nbsp; >>> zope.component.provideUtility (johtaja, ISchemaManager, nimi = 'some.app')
Olemme asettaneet minimum_generation 1. Tämä tarkoittaa, että meidän sovellus kieltäytyy ajaa tietokannan vanhempi kuin sukupolvi 1. sukupolvi määrite on asetettu 2, mikä tarkoittaa, että uusimman sukupolven, että tämä SchemaManager tietää on 2.
kehittyä () on työjuhta täällä. Sen tehtävänä on saada tietokantaan sukupolvi-1 polveen. Se saa puitteissa, jotka on määrite "yhteys", joka on yhteys ZODB. Voit käyttää tätä muuttaa esineitä, kuten tässä esimerkissä.
Tässä erityisessä toteutuksessa sukupolvi 1 pakenee vastauksia (vaikkapa kriittinen, koska ne voidaan syöttää ketään!), Sukupolvi 2 pakenee kysymykset (vaikkapa vähemmän tärkeä, koska nämä voidaan syöttää valtuutettu personell vain).
Itse asiassa sinun ei todellakaan tarvitse custom täytäntöönpanon ISchemaManager. Yksi on saatavilla, olemme käyttäneet sitä nuken aiemmin. Se käyttää Python moduulit järjestämisestä Evolver toimintoja. Katso sen docstring lisätietoja.
Tosielämässä sinulla on paljon monimutkaisempi objekti rakenteita kuin yksi täällä. Voit helpottaa elämääsi, on olemassa kaksi erittäin hyödyllisiä toimintoja saatavilla zope.generations.utility: findObjectsMatching () ja findObjectsProviding (). Ne kaivaa säiliöt rekursiivisesti auttaa sinua etsimään vanhoja esineitä, jotka haluat päivittää, jonka käyttöliittymä tai muulla kriteerit. Ne on helppo ymmärtää, tarkistaa niiden docstrings.
Sukupolvet toiminnassa
Niin, meidän raivoissaan client lataa uusin koodi ja käynnistyy uudelleen Zope. Tapahtuma lähetetään automaattisesti uudelleen:
& Nbsp; >>> tapahtuma = DatabaseOpenedEventStub (db)
& Nbsp; >>> evolveMinimumSubscriber (tapahtuma)
Shazam! Asiakas on onnellinen jälleen!
& Nbsp; >>> pprint (root [vastauksista '])
& Nbsp; {"Hei": "Hei ja miten teet?",
& Nbsp; "elämän tarkoitus?": "42",
& Nbsp; "neljä ": "Neljä
& Nbsp; >>> root [generations_key] ['some.app']
& Nbsp; 1
Näemme, että sukupolvet toimivat, joten päätämme ottaa seuraava askel ja kehittyä sukupolven 2. Katsotaanpa, miten tämä voidaan tehdä manuaalisesti:
& Nbsp; >>> päässä zope.generations.generations tuoda kehittyvät
& Nbsp; >>> kehittyä (db)
& Nbsp; >>> pprint (root [vastauksista '])
& Nbsp; {"Hei": "Hei ja miten teet?",
& Nbsp; "elämän tarkoitus?": "42",
& Nbsp; "neljä ": "Neljä
& Nbsp; 2
Default käyttäytyminen kehittyvät päivityksiä uusimman sukupolven tarjoamia SchemaManager. Voit käyttää miten argumentti kehittymään (), kun haluat vain tarkistaa, jos haluat päivittää tai jos haluat olla laiska kuin tilaaja jotka olemme kutsuneet aiemmin.
tilaaminen skeema johtajien
Usein osajärjestelmien käytetään säveltää sovellus luottaa muihin osajärjestelmiin toimimaan oikein. Jos molemmat osajärjestelmät tarjota skeema johtajien, se on usein hyödyllistä tietää, missä järjestyksessä evolvers tulee vedota. Tämä mahdollistaa puitteet ja se on asiakkaiden pystyä kehittymään konsertti, ja asiakkaat voivat tietää, että kehys on kehittynyt ennen tai jälkeen itse.
Tämä voidaan toteuttaa säätämällä nimet skeema johtaja apuohjelmia. Skeema johtajat ajetaan määräämässä järjestyksessä lajittelu niiden nimet.
& Nbsp; >>> manager1 = SchemaManager (minimum_generation = 0, sukupolvi = 0)
& Nbsp; >>> manager2 = SchemaManager (minimum_generation = 0, sukupolvi = 0)
& Nbsp; >>> zope.component.provideUtility (
& Nbsp; ... manager1, ISchemaManager, nimi = 'another.app')
& Nbsp; >>> zope.component.provideUtility (
& Nbsp; ... manager2, ISchemaManager, name = "another.app-laajennus)
Huomaa, miten nimen ensimmäinen paketti käytetään luomaan nimiavaruus huollettavien paketteja. Tämä ei ole vaatimus puitteet, mutta kätevä malli tähän käyttöön.
Katsotaanpa kehittyä tietokantaan perustaa nämä sukupolvet:
& Nbsp; >>> tapahtuma = DatabaseOpenedEventStub (db)
& Nbsp; >>> evolveMinimumSubscriber (tapahtuma)
& Nbsp; >>> root [generations_key] ['another.app']
& Nbsp; 0
& Nbsp; >>> root [generations_key] ['another.app-laajennus']
& Nbsp; 0
Oletetaan, että jostain syystä jokainen näistä osajärjestelmistä on lisätä sukupolvi, ja että sukupolvi 1 "another.app-laajennus" riippuu sukupolvi 1 "another.app". Meidän täytyy tarjota skeema johtajat jokaiselle, että pöytäkirjaan, että he ovat olleet ajaa niin voimme tarkistaa tulos:
& Nbsp; >>> gsm.unregisterUtility (edellyttäen = ISchemaManager, name = "another.app ')
& Nbsp; True
& Nbsp; >>> gsm.unregisterUtility (
& Nbsp; ... edellyttäen = ISchemaManager, name = "another.app-laajennus)
& Nbsp; True
& Nbsp; >>> luokan FoundationSchemaManager (objekti):
& Nbsp; ... työkoneiden (ISchemaManager)
& Nbsp; ...
& Nbsp; ... minimum_generation = 1
& Nbsp; ... sukupolvi = 1
& Nbsp; ...
& Nbsp; ... def kehittyä (itse, yhteydessä sukupolvi):
& Nbsp; ... root = context.connection.root ()
& Nbsp; ... tilaaminen = root.get (tilaus ", [])
& Nbsp; ... jos sukupolvi == 1:
& Nbsp; ... ordering.append ("säätiö 1)
& Nbsp; ... print "säätiö sukupolvi 1 '
& Nbsp; ... muuta:
& Nbsp; ... nostaa ValueError ("Bummer")
& Nbsp; ... root ['tilaaminen'] = tilaaminen # ping pysyvyys
& Nbsp; ... transaction.commit ()
& Nbsp; >>> luokan DependentSchemaManager (objekti):
& Nbsp; ... työkoneiden (ISchemaManager)
& Nbsp; ...
& Nbsp; ... minimum_generation = 1
& Nbsp; ... sukupolvi = 1
& Nbsp; ...
& Nbsp; ... def kehittyä (itse, yhteydessä sukupolvi):
& Nbsp; ... root = context.connection.root ()
& Nbsp; ... tilaaminen = root.get (tilaus ", [])
& Nbsp; ... jos sukupolvi == 1:
& Nbsp; ... ordering.append (riippuu 1)
& Nbsp; ... print "riippuvainen sukupolvi 1 '
& Nbsp; ... muuta:
& Nbsp; ... nostaa ValueError ("Bummer")
& Nbsp; ... root ['tilaaminen'] = tilaaminen # ping pysyvyys
& Nbsp; ... transaction.commit ()
& Nbsp; >>> manager1 = FoundationSchemaManager ()
& Nbsp; >>> manager2 = DependentSchemaManager ()
& Nbsp; >>> zope.component.provideUtility (
& Nbsp; ... manager1, ISchemaManager, nimi = 'another.app')
& Nbsp; >>> zope.component.provideUtility (
& Nbsp; ... manager2, ISchemaManager, name = "another.app-laajennus)
Kehittyvä tietokanta nyt aina ajaa "another.app" evolver ennen "another.app-laajennus 'Evolver:
& Nbsp; >>> tapahtuma = DatabaseOpenedEventStub (db)
& Nbsp; >>> evolveMinimumSubscriber (tapahtuma)
& Nbsp; säätiö sukupolvi 1
& Nbsp; riippuvaisia sukupolvi 1
& Nbsp; >>> root ['tilaaminen']
& Nbsp; ['säätiö 1', 'huollettavana 1']
Asennus
Vuonna esimerkissä edellä, me käsin alustettu vastauksia. Meidän ei pitäisi olla tehdä, että käsin. Hakemus pitäisi pystyä tekemään automaattisesti.
IInstallableSchemaManager ulottuu ISchemaManager tarjoaa asennustapa suorittamiseksi intial asentaa sovelluksen. Tämä on parempi vaihtoehto kuin rekisteröitymättä tietokanta avattu tilaajille.
Määritellään uusi skeema johtaja, joka sisältää asennus:
& Nbsp; >>> gsm.unregisterUtility (edellyttäen = ISchemaManager, name = "some.app ')
& Nbsp; True
& Nbsp; >>> päässä zope.generations.interfaces tuoda IInstallableSchemaManager
& Nbsp; >>> luokan MySchemaManager (objekti):
& Nbsp; ... työkoneiden (IInstallableSchemaManager)
& Nbsp; ...
& Nbsp; ... minimum_generation = 1
& Nbsp; ... sukupolvi = 2
& Nbsp; ...
& Nbsp; ... def asentaa (itse, yhteydessä):
& Nbsp; ... root = context.connection.root ()
& Nbsp; ... root [vastauksista '] = {' Hei ':' Hei & miten teet? ",
& Nbsp; ... "elämän tarkoitus?": "42",
& Nbsp; ... "neljä ": "Neljä
& Nbsp; ...
& Nbsp; ... def kehittyä (itse, yhteydessä sukupolvi):
& Nbsp; ... root = context.connection.root ()
& Nbsp; ... vastauksia = root [vastaukset ']
& Nbsp; ... jos sukupolvi == 1:
& Nbsp; ... sillä kysymys, vastaus answers.items ():
& Nbsp; ... vastauksia [kysymys] = cgi.escape (vastaus)
& Nbsp; ... elif sukupolvi == 2:
& Nbsp; ... sillä kysymys, vastaus answers.items ():
& Nbsp; ... del vastauksia [kysymys]
& Nbsp; ... vastauksia [cgi.escape (kysymys)] = vastaus
& Nbsp; ... muuta:
& Nbsp; ... nostaa ValueError ("Bummer")
& Nbsp; ... root [vastauksista '] = vastausten # ping pysyvyys
& Nbsp; ... transaction.commit ()
& Nbsp; >>> manager = MySchemaManager ()
& Nbsp; >>> zope.component.provideUtility (johtaja, ISchemaManager, nimi = 'some.app')
Nyt avulla avata uusi tietokanta:
& Nbsp; >>> db.close ()
& Nbsp; >>> db = DB ()
& Nbsp; >>> yht = db.open ()
& Nbsp; >>> vastaukset "in conn.root ()
& Nbsp; False
& Nbsp; >>> tapahtuma = DatabaseOpenedEventStub (db)
& Nbsp; >>> evolveMinimumSubscriber (tapahtuma)
& Nbsp; >>> conn.sync ()
& Nbsp; >>> root = conn.root ()
& Nbsp; >>> pprint (root [vastauksista '])
& Nbsp; {"Hei": "Hei ja miten teet?",
& Nbsp; "elämän tarkoitus?": "42",
& Nbsp; "neljä ": "Neljä
& Nbsp; 2
ZODB tapahtumaloki toteaa, että asentaa skripti teloitettiin
& Nbsp; >>> [it.description sille conn.db (). Storage.iterator ()] [- 2]
& Nbsp; u'some.app: käynnissä asentaa sukupolven "
(Minor huomautus: se ei ole viimeinen levy, koska on olemassa kaksi arkistotoimituksiin: MySchemaManager suorittaa yhden, ja evolveMinimumSubscriber suorittaa toinen. MySchemaManager ei todellakaan tarvitse sitoutua.)
Mitä uutta tässä julkaisussa:
- Lisätty tuki Python 3.3.
- Vaihdettu vanhentunut zope.interface.implements käyttö vastaavia zope.interface.implementer sisustajalle.
- Pudonnut Python 2.4 ja 2.5.
Mitä uutta strong> versiossa 3.7.1:
- Poistettu verkon rakentaminen osa, jota käytettiin kehityksen aikana, mutta ei ei koota Windows.
- Generation skriptit lisätä tapahtuman huomautus.
Vaatimukset :
- Python
Kommentteja ei löytynyt