Kontrola nad schematem


4 września 2013


South - po co i jak go używać? Opis narzędzia oraz przykłady sprawią, że zaczniesz używać South jeszcze dzisiaj.

1. Opis

W jednym z poprzednich wpisów obiecałem, że napiszę kilka słów o South. Po urlopie należy wziąć się w końcu do roboty dlatego spełniam dane słowo. South to system migracji, który sprawi, że będziemy posiadali pełną kontrolę nad schematem bazy danych. Nie powtórzy się już sytuacja gdy wprowadzaliśmy zmiany w strukturze danych wykonując zapytania w oknie konsoli.

South tworzy, w oparciu o zmiany w aplikacji, pliki migracji, które po wykonaniu modyfikują schemat bazy danych. Migracje mogą być wycofywane dzięki czemu w razie błędu możemy powrócić do poprzedniej wersji schematu.

Ogromną zaletą South jest to, że jest niezależny od warstwy bazodanowej. 

2. Instalacja

Instalację South możemy przeprowadzić na kilka sposobów. Oto jeden z nich (w systemie Fedora):

yum install python-django-south

Obecnie instalujemy South jako niezależne narzędzie ale twórcy mają w planach integrację z Django (jako część frameworka) 

Po zainstalowaniu South w systemie musimy skonfigurować projekt w Django aby z niego korzystał. Aby to zrobić należy w pliku settings.py w sekcji "INSTALLED_APPS" dodać 'south'.
Aby instalacja była pełna musimy wywołać polecenie: 

./manage.py syncdb

W wyniku jego wywołania zostaną utworzone tabele związane z obsługą South.

3. Komendy

Opisuję działanie podstawowych komend. 

a)  schemamigration 

Polecenie tworzy szablon na podstawie, którego będzie przeprowadzana migracja. Przyjmuje kilka parametrów spośród których najczęściej używane są: initial oraz auto.
Załóżmy, że mamy aplikację 'kalendarz' a w niej prosty model składający się z jednego pola: nazwa

from django.db import models

class Dzien(models.Model):
    nazwa = models.CharField(max_length=100)

Jeżeli chcemy przeprowadzić pierwszą migrację musimy wykonać polecenia:

./manage.py schemamigration kalendarz --initial
./manage.py migrate kalendarz

Tabela w bazie danych zostanie utworzona. Jeżeli dokonamy zmiany w modelu np. dodamy nowe pole:

from django.db import models

class Dzien(models.Model):
    nazwa = models.CharField(max_length=100)
    skrot = models.CharField(max_length=10)

Po zmianie powinniśmy wykonać nową migrację. Pierwszą migrację wykonaliśmy z parametrem "initial". Jeżeli South ma automatycznie wyłapać zmiany w modelu musimy uruchomić go z parametrem "auto".

./manage.py schemamigration kalendarz --auto
./manage.py migrate kalendarz

Po wykonaniu migracji do tabeli zostanie dodane nowe pole.

b)  migrate 

Polecenie zostało użyte w przykładach i służy do uruchamiania migracji. Podając dodatkowe parametry możemy przeglądać traceback, przeglądać dokonane zmiany itp. Aby zobaczyć listę wszystkich migracji musimy wykonać polecenie:

./manage.py migrate --list

Dotychczasowy przykład prezentował prostą migrację. Jeżeli do modelu dodamy kolejne pole, które nie może być puste South podczas migracji zmusi nas do dokonania wyboru: 

from django.db import models

class Dzien(models.Model):
    nazwa = models.CharField(max_length=100)
    skrot = models.CharField(max_length=10)
    numer = models.IntegerField(null=False)
./manage.py schemamigration kalendarz --auto
 ? The field 'Knight.shrubberies' does not have a default specified, 
 ? yet is NOT NULL.
 ? Since you are adding or removing this field, you MUST specify a default
 ? value to use for existing rows. Would you like to:
 ?  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:

 

Możemy dodać wartość domyślną w modelu lub w konsoli.

Przejdźmy do kolejnego przykładu. Załóżmy, że zmieniliśmy typ pól modelu:

class Dzien(models.Model):
    nazwa = models.TextField()
    skrot = models.TextField()

W takiej sytuacji, musimy zaktualizować schemat:

./manage.py schemamigration kalendarz --auto --update
./manage.py migrate kalendarz

South usunie starą migracje i w zastąpi ją nową z poprawkami w schemacie bazy danych.

c)  datamigration 

South dokonuje zmian w schemacie bazy danych. Może służyć także jako narzędzie do modyfikowania danych zgromadzonych w bazie danych czyli przeprowadzać operację migracji danych. 

W naszym przykładzie, załóżmy, że mamy następujący model:

from django.db import models

class Pracownicy(models.Model):
    imie_nazwisko = models.CharField(max_length=255)
    data_urodzenia = models.DateField()

Po wykonaniu migracji dodajmy dwóch pracowników do nowo utworzonej tabeli. Wykonamy to w konsoli Django.

./manage.py shell
from kadry.models import Pracownicy
a = Pracownicy(1,'Jan Kowalski', "1990-01-01")
a.save()
b = Pracownicy(2, 'Anna Kowalska', "1991-01-01")
b.save()

Gdy już mamy tabelę oraz rekordy użyjemy migracji danych za pomocą South. Nasza zmiana będzie polegała na tym, że do modelu dodamy pola: "imie", "nazwisko" i zmigrujemy dane umieszczone w polu "imie_nazwisko" a następnie usuniemy pole "imie_nazwisko", ponieważ nie będzie już potrzebne. W pierwszym kroku musimy dodać do modelu dwa nowe pola i przeprowadzić zwykłą migrację (moja aplikacja to "kadry").

from django.db import models

class Pracownicy(models.Model):
    imie_nazwisko = models.CharField(max_length=255)
    data_urodzenia = models.DateField()
    imie = models.CharField(max_length=255, null=True)
    nazwisko = models.CharField(max_length=255, null=True)
./manage.py schemamigration kadry --auto
./manage.py migrate kadry

Migracja danych za pomocą South wymaga utworzenie szkieletu migracji. Utworzymy go wywołując polecenie (w katalogu aplikacja/migrations zostanie utworzony plik z nazwą, którą podajemy jako parametr  polecenia - nazwa szkieletu rozpoczyna się od numeru migracji np. 0004_zmiana_danych.py ):

./manage.py datamigration kadry zmiana_danych

Plik (szkielet migracji) zawiera dwie metody: forwards oraz backwards. Odpowiednio pierwsza dotyczy migracji, którą chcemy wykonać a druga odpowiada za operację wsteczną w przypadku gdybyśmy musieli cofnąć wprowadzone zmiany.

Zmiana rekordów (rozbicie wartości w polu "imie_nazwisko" i migracja danych do nowych pól) będzie możliwa gdy oprogramujemy to w metodzie: forwards. Nasza metoda po wprowadzonych zmianach będzie wyglądała następująco:

def forwards(self, orm):
        "Write your forwards methods here."
        # Note: Don't use "from appname.models import ModelName".
        # Use orm.ModelName to refer to models in this application,
        # and orm['appname.ModelName'] for models in other applications.
        for pracownik in orm.Pracownicy.objects.all():
            imie, nazwisko = pracownik.imie_nazwisko.split(' ')
            pracownik.imie = imie
            pracownik.nazwisko = nazwisko
            pracownik.imie_nazwisko = ' '
            pracownik.save()

Po wykonaniu migracji dane zostaną zmienione. Pozostaje nam tylko usunąć niepotrzebne pole "imie_nazwisko" odpowiednio modyfikując model oraz poraz kolejny przeprowadzić operację migracji. 

Zainteresowanych South odsyłam do dokumentacji: http://south.readthedocs.org/en/latest/ 

Co zawiera blog?

Na blogu umieszczam wpisy dotyczące mojej pracy, zainteresowań. Głowna tematyka to programowanie oraz recenzje płyt oraz książek.

Inteligentne techno?


Fotografia: © Sony Music Entertainment (UK) Ltd.
Recenzja albumu "Leftism" ...

A Tribe Called Quest - Midnight Marauders


Recenzja jednego z najlepszych albumów rap/hip-hop. Poznaj hip-hop wysokich lotów.

Django-filter i "Generic View"


Przykład użycia Django-filter w widokach generycznych opartych na klasach

Twórzmy aplikacje wspólnie!


Grzegorz Tatara "Koma Software" - Tworzymy nowoczesne, bezpieczne oraz użyteczne ...

Coś innego, coś lepszego?


Python to język programowania coraz częściej wybierany przez programistów aplikacji ...

Potrzeba udokumentowania ...


Sphinx - przykłady wykorzystania generatora dokumentacji. Tworzenie dokumentacji już nigdy ...

© Grzegorz Tatara
Przeglądając stronę grzegorztatara.pl zgadzasz się na użycie plików cookies
Ikona avatara pobrana z internetu (na licencji do użytku komercyjnego).