Database
 sql >> Baza danych >  >> RDS >> Database

Migracje Django:Elementarz

Obejrzyj teraz Ten samouczek zawiera powiązany kurs wideo stworzony przez zespół Real Python. Obejrzyj go razem z pisemnym samouczkiem, aby pogłębić swoją wiedzę:Django Migrations 101

Od wersji 1.7 Django ma wbudowaną obsługę migracji baz danych. W Django migracje baz danych zwykle idą w parze z modelami:za każdym razem, gdy kodujesz nowy model, generujesz również migrację, aby utworzyć niezbędną tabelę w bazie danych. Jednak migracje mogą zrobić znacznie więcej.

Dowiesz się, jak działają Django Migrations i jak możesz je jak najlepiej wykorzystać w trakcie czterech artykułów i jednego filmu:

  • Część 1:Migracje Django:elementarz (aktualny artykuł)
  • Część 2:Zagłębianie się w migracje
  • Część 3:Migracje danych
  • Wideo:Migracje Django 1.7 – wprowadzenie

W tym artykule zapoznasz się z migracjami Django i nauczysz się następujących rzeczy:

  • Jak tworzyć tabele bazy danych bez pisania SQL
  • Jak automatycznie modyfikować bazę danych po zmianie modeli
  • Jak przywrócić zmiany wprowadzone w bazie danych

Bezpłatny bonus: Kliknij tutaj, aby uzyskać dostęp do bezpłatnego przewodnika po zasobach edukacyjnych Django (PDF), który zawiera wskazówki i triki, a także typowe pułapki, których należy unikać podczas tworzenia aplikacji internetowych Python + Django.


Problemy, które rozwiązują migracje

Jeśli jesteś nowy w Django lub ogólnie w tworzeniu stron internetowych, możesz nie znać koncepcji migracji baz danych i może nie wydawać się oczywiste, dlaczego są one dobrym pomysłem.

Najpierw zdefiniujmy szybko kilka terminów, aby upewnić się, że wszyscy są na tej samej stronie. Django zaprojektowano do pracy z relacyjną bazą danych, przechowywaną w systemie zarządzania relacyjnymi bazami danych, takim jak PostgreSQL, MySQL lub SQLite.

W relacyjnej bazie danych dane są zorganizowane w tabelach. Tabela bazy danych ma określoną liczbę kolumn, ale może mieć dowolną liczbę wierszy. Każda kolumna ma określony typ danych, na przykład ciąg znaków o określonej maksymalnej długości lub dodatnią liczbę całkowitą. Opis wszystkich tabel wraz z ich kolumnami i odpowiednimi typami danych jest nazywany schematem bazy danych.

Wszystkie systemy baz danych obsługiwane przez Django używają języka SQL do tworzenia, odczytu, aktualizacji i usuwania danych w relacyjnej bazie danych. SQL jest również używany do tworzenia, zmieniania i usuwania samych tabel bazy danych.

Bezpośrednia praca z SQL może być dość uciążliwa, więc aby ułatwić Ci życie, Django zawiera mapper obiektowo-relacyjny, w skrócie ORM. ORM mapuje relacyjną bazę danych do świata programowania obiektowego. Zamiast definiować tabele bazy danych w SQL, piszesz modele Django w Pythonie. Twoje modele definiują pola bazy danych, które odpowiadają kolumnom w ich tabelach bazy danych.

Oto przykład odwzorowania klasy modelu Django na tabelę bazy danych:

Ale samo zdefiniowanie klasy modelu w pliku Pythona nie sprawi, że tabela bazy danych pojawi się w magiczny sposób znikąd. Tworzenie tabel bazy danych do przechowywania modeli Django to zadanie związane z migracją bazy danych. Dodatkowo, za każdym razem, gdy wprowadzasz zmiany w swoich modelach, takie jak dodanie pola, baza danych również musi zostać zmieniona. Migracje również to obsługują.

Oto kilka sposobów, w jakie migracje Django ułatwiają życie.


Wprowadzanie zmian w bazie danych bez SQL

Bez migracji musiałbyś połączyć się z bazą danych i wpisać kilka poleceń SQL lub użyć narzędzia graficznego, takiego jak PHPMyAdmin, aby zmodyfikować schemat bazy danych za każdym razem, gdy chcesz zmienić definicję modelu.

W Django migracje są głównie napisane w Pythonie, więc nie musisz znać żadnego SQL, chyba że masz naprawdę zaawansowane przypadki użycia.



Unikanie powtórzeń

Tworzenie modelu, a następnie pisanie SQL w celu utworzenia dla niego tabel bazy danych byłoby powtarzalne.

Migracje są generowane z Twoich modeli, dzięki czemu nie będziesz się powtarzał.



Zapewnianie synchronizacji definicji modeli i schematu bazy danych

Zwykle masz wiele instancji swojej bazy danych, na przykład jedną bazę danych dla każdego programisty w zespole, bazę danych do testowania i bazę danych z danymi na żywo.

Bez migracji będziesz musiał wykonać wszelkie zmiany schematu w każdej bazie danych i będziesz musiał śledzić, które zmiany zostały już wprowadzone w której bazie danych.

Dzięki Django Migrations możesz łatwo zsynchronizować wiele baz danych ze swoimi modelami.



Śledzenie zmiany schematu bazy danych w kontroli wersji

System kontroli wersji, taki jak Git, jest doskonały dla kodu, ale nie dla schematów baz danych.

Ponieważ migracje są zwykłym Pythonem w Django, możesz umieścić je w systemie kontroli wersji, tak jak każdy inny fragment kodu.

Do tej pory masz nadzieję, że jesteś przekonany, że migracje są użytecznym i potężnym narzędziem. Zacznijmy uczyć się, jak uwolnić tę moc.




Konfigurowanie projektu Django

W tym samouczku będziesz pracować nad prostą aplikacją do śledzenia bitcoinów jako przykładowym projektem.

Pierwszym krokiem jest zainstalowanie Django. Oto, jak to zrobić w systemie Linux lub macOS X przy użyciu środowiska wirtualnego:

$ python3 -m venv env
$ source env/bin/activate
(env) $ pip install "Django==2.1.*"
...
Successfully installed Django-2.1.3

Teraz utworzyłeś nowe środowisko wirtualne i aktywowałeś je, a także zainstalowałeś Django w tym środowisku wirtualnym.

Zwróć uwagę, że w systemie Windows możesz uruchomić env/bin/activate.bat zamiast source env/bin/activate aby aktywować środowisko wirtualne.

Dla łatwiejszej czytelności przykłady konsoli nie zawierają (env) część monitu od teraz.

Po zainstalowaniu Django możesz utworzyć projekt za pomocą następujących poleceń:

$ django-admin.py startproject bitcoin_tracker
$ cd bitcoin_tracker
$ python manage.py startapp historical_data

To daje prosty projekt i aplikację o nazwie historical_data . Powinieneś mieć teraz następującą strukturę katalogów:

bitcoin_tracker/
|
├── bitcoin_tracker/
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
|
├── historical_data/
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── migrations/
│   │   └── __init__.py
|   |
│   ├── models.py
│   ├── tests.py
│   └── views.py
|
└── manage.py

W bitcoin_tracker katalogu, istnieją dwa podkatalogi:bitcoin_tracker dla plików całego projektu i historical_data zawierające pliki utworzonej aplikacji.

Teraz, aby utworzyć model, dodaj tę klasę w historical_data/models.py :

class PriceHistory(models.Model):
    date = models.DateTimeField(auto_now_add=True)
    price = models.DecimalField(max_digits=7, decimal_places=2)
    volume = models.PositiveIntegerField()

Jest to podstawowy model do śledzenia cen bitcoinów.

Nie zapomnij też dodać nowo utworzonej aplikacji do settings.INSTALLED_APPS . Otwórz bitcoin_tracker/settings.py i dołącz historical_data do listy INSTALLED_APPS , tak:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'historical_data',
]

Pozostałe ustawienia są w porządku dla tego projektu. Ten samouczek zakłada, że ​​projekt jest skonfigurowany do korzystania z bazy danych SQLite, co jest ustawieniem domyślnym.



Tworzenie migracji

Po utworzeniu modelu pierwszą rzeczą, którą musisz zrobić, to utworzyć dla niego migrację. Możesz to zrobić za pomocą następującego polecenia:

$ python manage.py makemigrations historical_data
Migrations for 'historical_data':
  historical_data/migrations/0001_initial.py
    - Create model PriceHistory

Uwaga: Określanie nazwy aplikacji, historical_data , jest opcjonalne. Pozostawienie go powoduje migracje dla wszystkich aplikacji.

Spowoduje to utworzenie pliku migracji, który instruuje Django, jak tworzyć tabele bazy danych dla modeli zdefiniowanych w aplikacji. Przyjrzyjmy się jeszcze raz drzewu katalogów:

bitcoin_tracker/
|
├── bitcoin_tracker/
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
|
├── historical_data/
│   ├── migrations/
│   │   ├── 0001_initial.py
│   │   └── __init__.py
|   |
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── models.py
│   ├── tests.py
│   └── views.py
|
├── db.sqlite3
└── manage.py

Jak widać, migrations katalog zawiera teraz nowy plik:0001_initial.py .

Uwaga: Możesz zauważyć, że uruchomienie makemigrations polecenie utworzyło również plik db.sqlite3 , który zawiera bazę danych SQLite.

Gdy spróbujesz uzyskać dostęp do nieistniejącego pliku bazy danych SQLite3, zostanie on automatycznie utworzony.

To zachowanie jest unikalne dla SQLite3. Jeśli używasz innego zaplecza bazy danych, takiego jak PostgreSQL lub MySQL, musisz utworzyć bazę danych samodzielnie przed uruchamianie makemigrations .

Możesz rzucić okiem na bazę danych za pomocą dbshell polecenie zarządzania. W SQLite poleceniem do wyświetlenia wszystkich tabel jest po prostu .tables :

$ python manage.py dbshell
SQLite version 3.19.3 2017-06-27 16:48:08
Enter ".help" for usage hints.
sqlite> .tables
sqlite>

Baza danych jest nadal pusta. To się zmieni po zastosowaniu migracji. Wpisz .quit aby wyjść z powłoki SQLite.



Stosowanie migracji

Właśnie utworzyłeś migrację, ale aby faktycznie wprowadzić jakiekolwiek zmiany w bazie danych, musisz zastosować ją za pomocą polecenia zarządzania migrate :

$ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, historical_data, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying historical_data.0001_initial... OK
  Applying sessions.0001_initial... OK

Dużo się tu dzieje! Zgodnie z danymi wyjściowymi Twoja migracja została pomyślnie zastosowana. Ale skąd pochodzą wszystkie inne migracje?

Zapamiętaj ustawienie INSTALLED_APPS ? Niektóre inne wymienione tam aplikacje również są dostarczane z migracjami, a funkcja migrate polecenie zarządzania domyślnie stosuje migracje dla wszystkich zainstalowanych aplikacji.

Jeszcze raz spójrz na bazę danych:

$ python manage.py dbshell
SQLite version 3.19.3 2017-06-27 16:48:08
Enter ".help" for usage hints.
sqlite> .tables
auth_group                    django_admin_log
auth_group_permissions        django_content_type
auth_permission               django_migrations
auth_user                     django_session
auth_user_groups              historical_data_pricehistory
auth_user_user_permissions
sqlite>

Teraz jest wiele stołów. Ich imiona dają wyobrażenie o ich celu. Migracja wygenerowana w poprzednim kroku utworzyła historical_data_pricehistory stół. Sprawdźmy to za pomocą .schema polecenie:

sqlite> .schema --indent historical_data_pricehistory
CREATE TABLE IF NOT EXISTS "historical_data_pricehistory"(
  "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
  "date" datetime NOT NULL,
  "price" decimal NOT NULL,
  "volume" integer unsigned NOT NULL
);

.schema polecenie wyświetla CREATE instrukcja, którą wykonałbyś, aby utworzyć tabelę. Parametr --indent ładnie to formatuje. Nawet jeśli nie znasz składni SQL, możesz zobaczyć, że schemat historical_data_pricehistory tabela odzwierciedla pola PriceHistory model.

Dla każdego pola jest kolumna i dodatkowa kolumna id dla klucza podstawowego, który Django tworzy automatycznie, chyba że wyraźnie określisz klucz podstawowy w swoim modelu.

Oto, co się stanie, jeśli uruchomisz migrate polecenie ponownie:

$ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, historical_data, sessions
Running migrations:
  No migrations to apply.

Nic! Django pamięta, które migracje zostały już zastosowane i nie próbuje ich ponownie uruchomić.

Warto zauważyć, że możesz również ograniczyć migrate polecenie zarządzania do jednej aplikacji:

$ python manage.py migrate historical_data
Operations to perform:
 Apply all migrations: historical_data
Running migrations:
 No migrations to apply.

Jak widać, Django stosuje teraz migracje tylko dla historical_data aplikacja.

Kiedy uruchamiasz migracje po raz pierwszy, dobrym pomysłem jest zastosowanie wszystkich migracji, aby upewnić się, że Twoja baza danych zawiera niezbędne tabele dla funkcji, które możesz uznać za oczywiste, takich jak uwierzytelnianie użytkowników i sesje.



Zmiana modeli

Wasze modele nie są osadzone w kamieniu. Twoje modele będą się zmieniać, gdy Twój projekt Django zyska więcej funkcji. Możesz dodawać lub usuwać pola lub zmieniać ich typy i opcje.

Kiedy zmieniasz definicję modelu, tabele bazy danych używane do przechowywania tych modeli również muszą zostać zmienione. Jeśli definicje Twojego modelu nie pasują do bieżącego schematu bazy danych, najprawdopodobniej napotkasz django.db.utils.OperationalError .

Jak więc zmienić tabele bazy danych? Tworząc i stosując migrację.

Testując swój tracker Bitcoin, zdajesz sobie sprawę, że popełniłeś błąd. Ludzie sprzedają ułamki Bitcoina, więc pole volume powinien być typu DecimalField zamiast PositiveIntegerField .

Zmieńmy model, aby wyglądał tak:

class PriceHistory(models.Model):
    date = models.DateTimeField(auto_now_add=True)
    price = models.DecimalField(max_digits=7, decimal_places=2)
    volume = models.DecimalField(max_digits=7, decimal_places=3)

Bez migracji musiałbyś wymyślić składnię SQL, aby włączyć PositiveIntegerField w DecimalField . Na szczęście Django zajmie się tym za Ciebie. Po prostu powiedz mu, aby wykonał migracje:

$ python manage.py makemigrations
Migrations for 'historical_data':
  historical_data/migrations/0002_auto_20181112_1950.py
    - Alter field volume on pricehistory

Uwaga: Nazwa pliku migracji (0002_auto_20181112_1950.py ) opiera się na aktualnym czasie i będzie się różnić, jeśli będziesz podążać za nim w swoim systemie.

Teraz zastosuj tę migrację do swojej bazy danych:

$ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, historical_data, sessions
Running migrations:
  Applying historical_data.0002_auto_20181112_1950... OK

Migracja została pomyślnie zastosowana, więc możesz użyć dbshell aby sprawdzić, czy zmiany odniosły skutek:

$ python manage.py dbshell
SQLite version 3.19.3 2017-06-27 16:48:08
Enter ".help" for usage hints.
sqlite> .schema --indent historical_data_pricehistory
CREATE TABLE IF NOT EXISTS "historical_data_pricehistory" (
  "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
  "date" datetime NOT NULL,
  "price" decimal NOT NULL,
  "volume" decimal NOT NULL
);

Jeśli porównasz nowy schemat ze schematem, który widziałeś wcześniej, zauważysz, że typ volume kolumna zmieniła się z integer na decimal aby odzwierciedlić zmianę volume pole w modelu z PositiveIntegerField do DecimalField .



Wyświetlanie migracji

Jeśli chcesz wiedzieć, jakie migracje istnieją w projekcie Django, nie musisz przekopywać się przez migrations katalogi zainstalowanych aplikacji. Możesz użyć showmigrations polecenie:

$ ./manage.py showmigrations
admin
 [X] 0001_initial
 [X] 0002_logentry_remove_auto_add
 [X] 0003_logentry_add_action_flag_choices
auth
 [X] 0001_initial
 [X] 0002_alter_permission_name_max_length
 [X] 0003_alter_user_email_max_length
 [X] 0004_alter_user_username_opts
 [X] 0005_alter_user_last_login_null
 [X] 0006_require_contenttypes_0002
 [X] 0007_alter_validators_add_error_messages
 [X] 0008_alter_user_username_max_length
 [X] 0009_alter_user_last_name_max_length
contenttypes
 [X] 0001_initial
 [X] 0002_remove_content_type_name
historical_data
 [X] 0001_initial
 [X] 0002_auto_20181112_1950
sessions
 [X] 0001_initial

Zawiera listę wszystkich aplikacji w projekcie i migracji skojarzonych z każdą aplikacją. Ponadto wstawi duży X obok migracji, które już zostały zastosowane.

W naszym małym przykładzie showmigrations polecenie nie jest szczególnie ekscytujące, ale przydaje się, gdy zaczynasz pracę nad istniejącą bazą kodu lub pracujesz w zespole, w którym nie jesteś jedyną osobą dodającą migracje.



Anulowanie stosowania migracji

Teraz wiesz, jak wprowadzać zmiany w schemacie bazy danych, tworząc i stosując migracje. W pewnym momencie możesz chcieć cofnąć zmiany i wrócić do wcześniejszego schematu bazy danych, ponieważ:

  • Chcesz przetestować migrację, którą napisał kolega
  • Uświadom sobie, że wprowadzona przez Ciebie zmiana była złym pomysłem
  • Pracuj równolegle nad wieloma funkcjami z różnymi zmianami bazy danych
  • Chcesz przywrócić kopię zapasową, która została utworzona, gdy baza danych miała jeszcze starszy schemat

Na szczęście migracje nie muszą być ulicą jednokierunkową. W wielu przypadkach skutki migracji można cofnąć, cofając zastosowanie migracji. Aby anulować migrację, musisz zadzwonić do migrate z nazwą aplikacji i nazwą migracji przed migrację, którą chcesz anulować.

Jeśli chcesz cofnąć migrację 0002_auto_20181112_1950 w Twoich historical_data aplikacji, musisz przekazać 0001_initial jako argument do migrate polecenie:

$ python manage.py migrate historical_data 0001_initial
Operations to perform:
  Target specific migration: 0001_initial, from historical_data
Running migrations:
  Rendering model states... DONE
  Unapplying historical_data.0002_auto_20181112_1950... OK

Migracja nie została zastosowana, co oznacza, że ​​zmiany w bazie danych zostały cofnięte.

Cofnięcie zastosowania migracji nie powoduje usunięcia jej pliku migracji. Następnym razem, gdy uruchomisz migrate polecenie, migracja zostanie zastosowana ponownie.

Uwaga: Nie myl niestosowania migracji z operacją cofania, do której jesteś przyzwyczajony w swoim ulubionym edytorze tekstu.

Nie wszystkie operacje na bazie danych można całkowicie cofnąć. Jeśli usuniesz pole z modelu, utworzysz migrację i zastosujesz ją, Django usunie odpowiednią kolumnę z bazy danych.

Anulowanie tej migracji spowoduje ponowne utworzenie kolumny, ale nie przywróci danych przechowywanych w tej kolumnie!

Kiedy masz do czynienia z nazwami migracji, Django oszczędza ci kilku naciśnięć klawiszy, nie zmuszając cię do przeliterowania całej nazwy migracji. Potrzebuje tylko tyle nazwy, aby jednoznacznie ją zidentyfikować.

W poprzednim przykładzie wystarczyłoby uruchomić python manage.py migrate historical_data 0001 .



Migracje nazewnictwa

W powyższym przykładzie Django wymyśliło nazwę migracji na podstawie znacznika czasu — coś w rodzaju *0002_auto_20181112_1950 . Jeśli nie jesteś z tego zadowolony, możesz użyć --name parametr, aby podać niestandardową nazwę (bez .py rozszerzenie).

Aby to wypróbować, musisz najpierw usunąć starą migrację. Już go anulowałeś, więc możesz bezpiecznie usunąć plik:

$ rm historical_data/migrations/0002_auto_20181112_1950.py

Teraz możesz go odtworzyć z bardziej opisową nazwą:

$ ./manage.py makemigrations historical_data --name switch_to_decimals

Spowoduje to utworzenie tej samej migracji co poprzednio, z wyjątkiem nowej nazwy 0002_switch_to_decimals .



Wniosek

W tym samouczku omówiłeś sporo wiedzy i poznałeś podstawy migracji Django.

Podsumowując, podstawowe kroki do korzystania z migracji Django wyglądają tak:

  1. Utwórz lub zaktualizuj model
  2. Uruchom ./manage.py makemigrations <app_name>
  3. Uruchom ./manage.py migrate migrować wszystko lub ./manage.py migrate <app_name> przenieść pojedynczą aplikację
  4. Powtórz w razie potrzeby

Otóż ​​to! Ten przepływ pracy będzie działał przez większość czasu, ale jeśli coś nie pójdzie zgodnie z oczekiwaniami, wiesz również, jak wyświetlić listę i cofnąć migracje.

Jeśli wcześniej tworzyłeś i modyfikowałeś tabele bazy danych za pomocą odręcznie napisanego SQL, teraz jesteś znacznie bardziej wydajny, delegując tę ​​pracę na migracje Django.

W następnym samouczku z tej serii zagłębisz się w temat i dowiesz się, jak Django Migrations działa pod maską.

Bezpłatny bonus: Kliknij tutaj, aby uzyskać dostęp do bezpłatnego przewodnika po zasobach edukacyjnych Django (PDF), który zawiera wskazówki i triki, a także typowe pułapki, których należy unikać podczas tworzenia aplikacji internetowych Python + Django.

Pozdrawiam!



Wideo



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Zrozumienie utraty zdarzeń z rozszerzonymi zdarzeniami

  2. Co to jest baza danych? A DBMS?

  3. Operator SQL NOT

  4. Optymalizacja bazy danych:indeksy

  5. Jak znaleźć maksymalne wartości w wierszach