Acc-South
Django od verze 1.7 bude mít vlastní nástroje na migrace. South už bude zbytečný.
Django South
Úvodní prohlášení: South užívám občas, takže vždy stačím zapomenout, jak se to vlastně dělalo. Toto jsou poznámky pro moje rychlejší rozpomenutí. Snažil jsem se to ale napsat tak, aby tomu rozumněl i někdo jiný. Snad se mi to povedlo :)
Obsah stránky (hide)
South je rozšíření frameworku Django o možnosti dělat změny v popisu modelů dat (i samotných dat) a promítnout je do databázového schématu. Django samotné umí pouze databázi z modelů vytvořit (syncdb), neumí je ale měnit ani mazat.
Migrace se ukládají vždy ke konkrétní aplikaci (není jedna pro celý project). Není-li v aplikaci migrace definovaná (nemá podadresář migrations), South jí jednoduše ignoruje.
South umožňuje i zpětné změny - odvolání migrací (pokročilé).
Dobrá rada: Změny v modelech provádějte atomickým způsobem - jedna konktrétní migrace by měla odpovídat jediné konkrétní změně v modelu. Při "hromadných" změnách si to roz...(nebo jak to říci slušně). Samozřejmě může být vhodné připravit si několik dílčích schemamigration a pak to vše spustit naráz migrate.
1. Instalace
- nainstalovat python-django-south (Debian), nebo přes pip a pod (nejnovější verze).
- settings.py - INSTALLED_APPS, přidat 'south',
- spustit manage.py syncdb - vytvoří se potřebné pomocné tabulky v databázi
V manage.py přibudou možnosti pro South.
2. Základní schéma migrace
Jednotilvé migrace budou zapisovány v podadresáři migrations příslušné aplikace, a to do souborů, jejichž název začíná pořadovým číslem migrace (00013_...) a pokračuje názvem, který zpravidla popisuje, co se v migraci dělo..
Migrace probíhá ve dvou fázích:
$ ./manage.py schemamigration app_name --auto $ ./manage.py migrate app_name
V první fázi se připraví zmíněný soubor pro migraci, ve druhé se migrace provede.
Následují popisy pro výjimečné situace, kterých je ale většina ;-)
3. Úvodní migrace
Před rutinním použitím South, je potřeba připravit prostředí. Úvodní migrace vytvoří podadresář migrations v adresáři aplikace app_name a udělá v něm úvodní nastavení. Jsou dvě varianty:
Pro zcela novou aplikaci:
Zcela nová aplikace nemá ještě žádné tabulky v databázi - jsou definovány modely, ale nedělali jsme nad nimi dosud manage.py syncdb.
$ manage.py schemamigration app_name --initial
Pro již existující aplikaci:
To bude obvyklejší varianta - máme už databázi i s nějakými cvičnými daty a nyní narazíme na problém, jak měnit modely a následně schéma databáze. Tak nainstalujeme South a... tohle je náš první příkaz:
$ manage.py convert_to_south app_name
Pozor: tento příkaz spouštět ve stavu, kdy modely odpovídají tomu, co je v databázi. Teprve po tomto příkazu se můžeme pustit do vytoužených změn. Je-li model jiný, než tabulka v databázi, South to pozná, zahlásí chybu a schválně zhavaruje.
3.1 Spuštění vlastní migrace
Po úvodním příkaze, zaznamenáme tuto úvodní migraci do databáze:
$ ./manage.py migrate app_name
4. Migrace po změně modelu (schématu)
Všechy migrace v této kapitole se týkají změn v popisu modelu, který nemá vliv na stav dat. Datové migrace jsou popsány v další kapitole.
$ manage.py schemamigration app_name --auto
4.1 Přidání / Odbrání sloupce
Přidání, nebo odebrání sloupce v modelu vyžaduje buď nastavené default=, nebo null=True. Ano, i při odebrání sloupce - South umí i vracet změny, takže vrácení smazaného sloupce je vlastně vytvoření sloupce:). Není-li default hodnota, pak bude South požadovat její doplnění do modelu, nebo nám umožní zadat ji jednorázově:
? 1. Quit now, and add a default to the field in models.py ? 2. Specify a one-off value to use for existing columns now ? Please select a choice:
Dobře připravenou migraci pak spustíme obvyklým způsobem:
$ ./manage.py migrate app_name
4.2 Přejmenování sloupce
Tohle v jádru nejde, ale neboj.
- Přejmenuj si sloupec v definici modelu (př. ulice -> street v modelu Person) a udělej normální schemamigration --auto.
- Vzniklý soubbor migrace si otevři a u forward a backward najdeš něco o odstranění a přidání sloupců, to smaž a místo toho tam dej:
def forwards(self, orm): # Renaming field 'Person.ulice' db.rename_column(u'myapp_person', 'ulice', 'street') def backwards(self, orm): db.rename_column(u'myapp_person', 'street', 'ulice')
- Pod těmito řádky je takový nějaký maglajs vytvořený Southem, který je v pořádku, ale můžeš si tam zkontrolovat v tvém modelu, že tam je nové jméno sloupce.
- Ulož to a pro pořádek soubor s migrací přejmenuj, aby název nemluvil o mazání a přídávání sloupce, ale o přejmenovávání (nepovinné, ale skvělé).
- A teď už normálně migrate appname.
Poznámka: Někde na netu jsem našel návod, který obsahoval jen ty for- a back- ward, ale ne to pod tím, co tam South dá sám (vynachala se tedy fáze schemamigration --auto). Migrace proběhla, ale pokus do další migraci se schemamigration --auto South odmítal udělat s tím, že aplikace není "freeze" - to je předpokládám ten maglajs pod popisem migrace v souboru migrace. Takže --auto, --auto, --auto.
Zajímavé může být využít parametr --empty příkazu schemamigration. To vytvoří nový "prázdný" soubor pro migraci. Prázdný v tom smyslu, že obsahuje všechno, ale forwards a backwards obsahují pouze příkaz "pass". Tento soubor pak upravíme výše uvedeným způosobem:
python manage.py schemamigration appname mgrationname --empty
4.3 Oprava poslední migrace (případ "překlep";)
Stane se, že po provedení migrace objevíme chybu (překlep v názvu pole, typ pole...). Pak není nutné připravovat novou migraci, ale tu poslední můžeme update:
$ manage.py schemamigration app_name --auto --update
South nejdříve rollback odvolá tu posledně provedenou migraci, opraví její soubor a tuto migraci (již opravenou) udělá znovu. (Zakončíme samozřjemě manage.py migrate app_name).
4.4 Problém s Unique
Přidáme-li k existujícímu sloupci parametr unique=True, pak při migraci může být objevena ne-unikátnost a migrace zhavaruje. Databázi "zunifikovat" předem. Týká se i Meta... unique_together.
4.5 ManyToMany - zprostředkující tabulka
Přidáme-li omezení ManyToMany, South je objeví a automaticky vytvoří potřebnou tabulku pro zprostředkování vztahu. Při odebrání omezení z modelu, tuto tabulku zase smaže.
Výjimkou je omezení s parametrem through=tablename - tato tabulka funguje jako samostatný model, takže je řešena nezávilse na tomto omezení (není s ním vytvářena/mazána).
4.6 Námi vytvořená nestandardní pole
South je neumí obsloužit a vyžaduje to trochu práce navíc. Viz orig. dokumentace.
5. Vypsání provedených migrací
$ ./manage.py migrate [app_name] --list
6. Odvolání migrace
$ ./manage.py migrate app_name number
Jednoduše nakonec napíšeme číslo migrace z počátku názvu (nebo můžeme zadat název celý). Příkaz migrate vlastně automaticky udělá migraci, která má nejvyšší číslo. Zadáme-li nižší, udělá se vytoužený rollback.
7. Migrace dat
Není možné změnit typ sloupce a doufat, že se vše stane samo. (čínský mudrc)
Poznámka: Pokud sloupec neobsahuje žádná data (třeba na počátku vývoje), můžete ho klidně přejmenovat.
Zazálohujte si všechna data. (marná rada)
Obvyklý postup bude:
- vytvořit nový sloupec se žádoucí definicí (migrace schématu)
- provést konverzi dat ze starého sloupce do nového (migrace dat)
- odstranit starý sloupec (migrace schématu)
Body 1 a 3 umíme. Přesto vše souhrnně:
7.1 1. vytvoříme nový sloupec v modelu a
$ ./manage.py schemamigration app_name --auto
7.2 2. přpravíme datovou migraci
$ ./manage.py datamigration app_name migration_name
South vytvoří soubor pro migraci nnnnn_migration_name.py. Ten si upravíme. Jsou tu dvě funkce "forwards" pro žádané změny a "backwards" pro případné vrácení změn. Například:
def forwards(self, orm): for wife in orm.Wife.objects.all(): wife.ears_size = wife.ears wife.save() def backwards(self, orm): for wife in orm.Wife.objects.all(): wife.ears = 2 wife.save()
Zkrátka pro všechny řádky v tabulce uděláme dopřednou konverzi a pak ještě zpětnou. V tomto případě řešíme převod počtu uší na velikost uší u manželek. Dopředu nastavíme velikost ucha podle jejich počtu. Při zpětné konverzi nastavíme natvrdo dvě uši.
Jako název pro migration_name dáváme obvykle jméno přidávaného sloupce.
7.3 3. smázneme nepotřebný sloupec z modelu
7.4 a všechno to necháme proběhnout
$ ./manage.py migrate app_name
7.5 závěrem
Do třídy Migration souboru pro datovou migraci můžeme přidat jakýkoliv kód - metody. South je bude ignorovat, my je můžeme použít při migraci.
8. Další dokumentace
South toho umí více. Zde jsem zapsal jen nejpoužívanější základy. Originální dokumentace je na adrese: