Database
 sql >> база данни >  >> RDS >> Database

Django Migrations:A Primer

Гледайте сега Този урок има свързан видео курс, създаден от екипа на Real Python. Гледайте го заедно с писмения урок, за да задълбочите разбирането си:Django Migrations 101

От версия 1.7 Django се предлага с вградена поддръжка за миграции на бази данни. В Django миграциите на бази данни обикновено вървят ръка за ръка с модели:всеки път, когато кодирате нов модел, вие също генерирате миграция, за да създадете необходимата таблица в базата данни. Въпреки това, миграциите могат да направят много повече.

Ще научите как работят Django Migrations и как можете да извлечете максимума от тях в хода на четири статии и един видеоклип:

  • Част 1:Django Migrations:A Primer (текуща статия)
  • Част 2:Копаене по-дълбоко в миграциите
  • Част 3:Миграции на данни
  • Видео:Миграции на Django 1.7 – начален курс

В тази статия ще се запознаете с миграциите на Django и ще научите следното:

  • Как да създадете таблици на база данни, без да пишете SQL
  • Как автоматично да променяте вашата база данни, след като сте променили моделите си
  • Как да върнете промените, направени във вашата база данни

Безплатен бонус: Щракнете тук, за да получите достъп до безплатно ръководство за учебни ресурси на Django (PDF), което ви показва съвети и трикове, както и често срещани клопки, които трябва да избягвате, когато създавате уеб приложения на Python + Django.


Проблемите, които миграцията решава

Ако сте нов в Django или уеб разработката като цяло, може да не сте запознати с концепцията за миграции на бази данни и може да не изглежда очевидно защо те са добра идея.

Първо, нека бързо да дефинираме няколко термина, за да сме сигурни, че всички са на една и съща страница. Django е проектиран да работи с релационна база данни, съхранявана в система за управление на релационна база данни като PostgreSQL, MySQL или SQLite.

В релационна база данни данните са организирани в таблици. Таблицата на база данни има определен брой колони, но може да има произволен брой редове. Всяка колона има специфичен тип данни, като низ с определена максимална дължина или положително цяло число. Описанието на всички таблици с техните колони и съответните им типове данни се нарича схема на база данни.

Всички системи за бази данни, поддържани от Django, използват езика SQL за създаване, четене, актуализиране и изтриване на данни в релационна база данни. SQL се използва също за създаване, промяна и изтриване на самите таблици на базата данни.

Работата директно със SQL може да бъде доста тромава, така че, за да улесни живота ви, Django идва с обектно-релационен картограф или накратко ORM. ORM картографира релационната база данни в света на обектно ориентираното програмиране. Вместо да дефинирате таблици на база данни в SQL, вие пишете Django модели в Python. Вашите модели дефинират полета на база данни, които съответстват на колоните в техните таблици на база данни.

Ето пример за това как клас на модел на Django се съпоставя с таблица на база данни:

Но само дефинирането на модел на клас във файл на Python не кара таблицата на базата данни да се появи магически от нищото. Създаването на таблици на база данни за съхраняване на вашите Django модели е работа на миграция на база данни. Освен това, когато правите промяна във вашите модели, като добавяне на поле, трябва да се промени и базата данни. Миграциите също се справят с това.

Ето няколко начина, по които миграциите на Django правят живота ви по-лесен.


Извършване на промени в базата данни без SQL

Без миграции ще трябва да се свържете с вашата база данни и да въведете куп SQL команди или да използвате графичен инструмент като PHPMyAdmin, за да промените схемата на базата данни всеки път, когато искате да промените дефиницията на вашия модел.

В Django миграциите са написани предимно на Python, така че не е нужно да знаете SQL, освен ако нямате наистина напреднали случаи на употреба.



Избягване на повторения

Създаването на модел и след това писането на SQL за създаване на таблиците на базата данни за него би било повтарящо се.

Миграциите се генерират от вашите модели, като се уверите, че не се повтаряте.



Осигуряване на синхронизиране на дефинициите на модела и схемата на базата данни

Обикновено имате множество копия на вашата база данни, например една база данни за всеки разработчик във вашия екип, база данни за тестване и база данни с данни в реално време.

Без миграции ще трябва да извършите каквито и да е промени в схемата във всяка една от вашите бази данни и ще трябва да следите кои промени вече са направени в коя база данни.

С Django Migrations можете лесно да поддържате множество бази данни в синхрон с вашите модели.



Проследяване на промяната на схемата на базата данни в контрола на версиите

Система за контрол на версиите, като Git, е отлична за код, но не толкова за схеми на база данни.

Тъй като миграциите са обикновен Python в Django, можете да ги поставите в система за контрол на версиите, както всеки друг код.

Досега се надяваме, че сте убедени, че миграциите са полезен и мощен инструмент. Нека започнем да се учим как да разгърнем тази сила.




Настройване на Django проект

В този урок ще работите върху просто приложение за проследяване на биткойн като примерен проект.

Първата стъпка е да инсталирате Django. Ето как да направите това в Linux или macOS X, като използвате виртуална среда:

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

Сега сте създали нова виртуална среда и сте я активирали, както и инсталирали Django в тази виртуална среда.

Имайте предвид, че в Windows ще стартирате env/bin/activate.bat вместо source env/bin/activate за да активирате вашата виртуална среда.

За по-лесна четливост, конзолните примери няма да включват (env) част от подканата от сега нататък.

С инсталиран Django можете да създадете проекта, като използвате следните команди:

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

Това ви дава прост проект и приложение, наречено historical_data . Вече трябва да имате следната структура на директорията:

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

В рамките на bitcoin_tracker директория, има две поддиректории:bitcoin_tracker за файлове за целия проект и historical_data съдържащи файлове за създаденото от вас приложение.

Сега, за да създадете модел, добавете този клас в 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()

Това е основният модел за проследяване на цените на биткойн.

Също така, не забравяйте да добавите новосъздаденото приложение към settings.INSTALLED_APPS . Отворете bitcoin_tracker/settings.py и добавете historical_data към списъка INSTALLED_APPS , като това:

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

Другите настройки са подходящи за този проект. Този урок предполага, че вашият проект е конфигуриран да използва SQLite база данни, което е по подразбиране.



Създаване на миграции

С създадения модел, първото нещо, което трябва да направите, е да създадете миграция за него. Можете да направите това със следната команда:

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

Забележка: Указване на името на приложението, historical_data , е по избор. Ако го оставите изключено, ще създадете миграции за всички приложения.

Това създава файла за миграции, който инструктира Django как да създаде таблиците на базата данни за моделите, дефинирани във вашето приложение. Нека да разгледаме още веднъж дървото на директориите:

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

Както можете да видите, migrations директорията вече съдържа нов файл:0001_initial.py .

Забележка: Може да забележите, че изпълнявате makemigrations команда също създаде файла db.sqlite3 , който съдържа вашата база данни SQLite.

Когато се опитате да получите достъп до несъществуващ файл на база данни SQLite3, той ще бъде създаден автоматично.

Това поведение е уникално за SQLite3. Ако използвате друга база данни като PostgreSQL или MySQL, трябва сами да създадете базата данни преди изпълнява makemigrations .

Можете да надникнете в базата данни с dbshell команда за управление. В SQLite командата за изброяване на всички таблици е просто .tables :

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

Базата данни все още е празна. Това ще се промени, когато приложите миграцията. Въведете .quit за да излезете от обвивката на SQLite.



Прилагане на миграции

Вече създадохте миграцията, но за да направите каквито и да е промени в базата данни, трябва да я приложите с командата за управление 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

Тук има много неща! Според изхода вашата миграция е приложена успешно. Но откъде идват всички други миграции?

Запомнете настройката INSTALLED_APPS ? Някои от другите приложения, изброени там, също идват с миграции и migrate командата за управление прилага миграциите за всички инсталирани приложения по подразбиране.

Погледнете отново базата данни:

$ 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>

Сега има множество маси. Имената им дават представа за предназначението им. Миграцията, която генерирахте в предишната стъпка, създаде historical_data_pricehistory маса. Нека го проверим с помощта на .schema команда:

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 командата разпечатва CREATE оператор, който бихте изпълнили, за да създадете таблицата. Параметърът --indent го форматира добре. Дори и да не сте запознати със синтаксиса на SQL, можете да видите, че схемата на historical_data_pricehistory таблицата отразява полетата на PriceHistory модел.

Има колона за всяко поле и допълнителна колона id за първичния ключ, който Django създава автоматично, освен ако не посочите изрично първичен ключ във вашия модел.

Ето какво се случва, ако стартирате migrate команда отново:

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

Нищо! Django помни кои миграции вече са приложени и не се опитва да ги изпълни отново.

Струва си да се отбележи, че можете също да ограничите migrate команда за управление към едно приложение:

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

Както можете да видите, Django вече прилага миграции само за historical_data приложение.

Когато изпълнявате миграциите за първи път, е добра идея да приложите всички миграции, за да сте сигурни, че вашата база данни съдържа необходимите таблици за функциите, които може да приемете за даденост, като удостоверяване на потребителя и сесии.



Промяна на модели

Вашите модели не са вложени в камък. Вашите модели ще се променят, когато вашият Django проект придобие повече функции. Можете да добавяте или премахвате полета или да променяте техните типове и опции.

Когато промените дефиницията на модел, таблиците на базата данни, използвани за съхраняване на тези модели, също трябва да бъдат променени. Ако дефинициите на модела ви не съвпадат с текущата ви схема на база данни, най-вероятно ще се сблъскате с django.db.utils.OperationalError .

И така, как да промените таблиците на базата данни? Чрез създаване и прилагане на миграция.

Докато тествате своя биткойн тракер, разбирате, че сте направили грешка. Хората продават части от биткойн, така че полето volume трябва да бъде от типа DecimalField вместо PositiveIntegerField .

Нека променим модела, за да изглежда така:

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)

Без миграции ще трябва да разберете синтаксиса на SQL, за да превърнете PositiveIntegerField в DecimalField . За щастие Django ще се справи с това вместо вас. Просто му кажете да направи миграции:

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

Забележка: Името на файла за мигриране (0002_auto_20181112_1950.py ) се основава на текущото време и ще бъде различно, ако следвате в системата си.

Сега прилагате тази миграция към вашата база данни:

$ 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

Миграцията е приложена успешно, така че можете да използвате dbshell за да проверите дали промените са имали ефект:

$ 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
);

Ако сравните новата схема със схемата, която видяхте по-рано, ще забележите, че типът на volume колоната е променена от integer към decimal за да отрази промяната на volume поле в модела от PositiveIntegerField към DecimalField .



Изписване на миграции

Ако искате да знаете какви миграции съществуват в проект на Django, не е нужно да ровите в migrations директории на инсталираните ви приложения. Можете да използвате showmigrations команда:

$ ./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

Това изброява всички приложения в проекта и миграциите, свързани с всяко приложение. Освен това ще постави голям X до вече приложените миграции.

За нашия малък пример, showmigrations командата не е особено вълнуваща, но е полезна, когато започнете да работите върху съществуваща кодова база или работите в екип, в който не сте единственият човек, който добавя миграции.



Неприлагане на миграции

Сега знаете как да правите промени в схемата на базата данни чрез създаване и прилагане на миграции. В даден момент може да искате да отмените промените и да се върнете към по-ранна схема на база данни, защото:

  • Искам да тествам миграция, написа от колега
  • Осъзнайте, че промяната, която сте направили, е лоша идея
  • Работа с множество функции с различни промени в базата данни паралелно
  • Искате да възстановите резервно копие, създадено, когато базата данни все още имаше по-стара схема

За щастие миграциите не трябва да бъдат еднопосочна улица. В много случаи ефектите от миграцията могат да бъдат отменени чрез прекратяване на прилагането на миграция. За да отмените прилагането на миграция, трябва да извикате migrate с името на приложението и името на миграцията преди миграцията, която искате да отмените.

Ако искате да върнете миграцията 0002_auto_20181112_1950 във вашите historical_data приложение, трябва да преминете 0001_initial като аргумент за migrate команда:

$ 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

Миграцията не е приложена, което означава, че промените в базата данни са отменени.

Прекратяването на прилагането на миграция не премахва нейния файл за миграция. Следващия път, когато стартирате migrate команда, миграцията ще бъде приложена отново.

Внимание: Не бъркайте неприлагането на миграции с операцията за отмяна, с която сте свикнали от любимия си текстов редактор.

Не всички операции с база данни могат да бъдат напълно върнати. Ако премахнете поле от модел, създадете миграция и го приложите, Django ще премахне съответната колона от базата данни.

Прекратяването на прилагането на тази миграция ще създаде отново колоната, но няма да върне данните, които са били съхранени в тази колона!

Когато се занимавате с имена на миграция, Django ви спестява няколко натискания на клавиши, като не ви принуждава да изписвате цялото име на миграцията. Има нужда само от достатъчно име, за да го идентифицира уникално.

В предишния пример би било достатъчно да стартирате python manage.py migrate historical_data 0001 .



Миграции на именуване

В горния пример Django измисли име за миграцията въз основа на времевата марка – нещо като *0002_auto_20181112_1950 . Ако не сте доволни от това, тогава можете да използвате --name параметър за предоставяне на персонализирано име (без .py разширение).

За да изпробвате това, първо трябва да премахнете старата миграция. Вече сте го отменили, така че можете безопасно да изтриете файла:

$ rm historical_data/migrations/0002_auto_20181112_1950.py

Сега можете да го пресъздадете с по-описателно име:

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

Това ще създаде същата миграция, както преди, освен с новото име на 0002_switch_to_decimals .



Заключение

Обхванахте доста полета в този урок и научихте основите на миграцията на Django.

За да обобщим, основните стъпки за използване на Django миграции изглеждат така:

  1. Създайте или актуализирайте модел
  2. Изпълнете ./manage.py makemigrations <app_name>
  3. Изпълнете ./manage.py migrate за да мигрирате всичко или ./manage.py migrate <app_name> за да мигрирате отделно приложение
  4. Повторете, ако е необходимо

Това е! Този работен процес ще работи през по-голямата част от времето, но ако нещата не вървят според очакванията, вие също знаете как да изброите и да отмените миграциите.

Ако по-рано сте създавали и модифицирали таблиците си в базата данни с ръчно написан SQL, сега сте станали много по-ефективни, като делегирате тази работа на Django миграции.

В следващия урок от тази серия ще се задълбочите в темата и ще научите как Django Migration работят под капака.

Безплатен бонус: Щракнете тук, за да получите достъп до безплатно ръководство за учебни ресурси на Django (PDF), което ви показва съвети и трикове, както и често срещани клопки, които трябва да избягвате, когато създавате уеб приложения на Python + Django.

Наздраве!



Видео



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Всичко, което трябва да знаете за LIKE оператора в SQL

  2. Какво представлява Greenplum Database? Въведение в базата данни Big Data

  3. Десет често срещани заплахи за качеството на плана за изпълнение

  4. Разбиране на Pivot оператора в SQL

  5. Изчисляване на медиана с динамичен курсор