Django
Миграции
Поиск…
параметры
Команда django-admin | подробности |
---|---|
makemigrations <my_app> | Создание миграции для my_app |
makemigrations | Создание миграций для всех приложений |
makemigrations --merge | Устранение конфликтов миграции для всех приложений |
makemigrations --merge <my_app> | my_app конфликтов миграции для my_app |
makemigrations --name <migration_name> <my_app> | Сформировать миграции для my_app с именем migration_name |
migrate <my_app> | Применить ожидающие миграции my_app в базу данных |
migrate | Применить все ожидающие миграции в базу данных |
migrate <my_app> <migration_name> | Применить или исключить до migration_name |
migrate <my_app> zero | Не использовать все миграции в my_app |
sqlmigrate <my_app> <migration_name> | Распечатывает SQL для указанной миграции |
showmigrations | Показывает все миграции для всех приложений |
showmigrations <my_app> | Показывает все миграции в my_app |
Работа с миграциями
Django использует миграции для распространения изменений, которые вы делаете на свои модели, в свою базу данных. В большинстве случаев django может генерировать их для вас.
Чтобы создать миграцию, выполните:
$ django-admin makemigrations <app_name>
Это создаст файл migration
подмодуле migration
app_name
. Первая миграция будет называться 0001_initial.py
, другая начнется с 0002_
, затем 0003
, ...
Если вы опустите <app_name>
это создаст миграцию для всех ваших INSTALLED_APPS
.
Чтобы распространять миграцию в вашу базу данных, запустите:
$ django-admin migrate <app_name>
Чтобы показать все ваши миграции, запустите:
$ django-admin showmigrations app_name
app_name
[X] 0001_initial
[X] 0002_auto_20160115_1027
[X] 0003_somemodel
[ ] 0004_auto_20160323_1826
-
[X]
означает, что миграция была передана в вашу базу данных -
[ ]
означает, что миграция не была распространена в вашей базе данных. Используйтеdjango-admin migrate
для распространения
Вы также вызываете и возвращаете миграцию, это можно сделать, передав имя migrate command
. Учитывая приведенный выше список миграций (показано с помощью django-admin showmigrations
):
$ django-admin migrate app_name 0002 # Roll back to migration 0002
$ django-admin showmigrations app_name
app_name
[X] 0001_initial
[X] 0002_auto_20160115_1027
[ ] 0003_somemodel
[ ] 0004_auto_20160323_1826
Ручная миграция
Иногда миграций, создаваемых Django, недостаточно. Это особенно актуально, если вы хотите выполнить миграцию данных .
Например, давайте иметь такую модель:
class Article(models.Model):
title = models.CharField(max_length=70)
У этой модели уже есть существующие данные, и теперь вы хотите добавить SlugField
:
class Article(models.Model):
title = models.CharField(max_length=70)
slug = models.SlugField(max_length=70)
Вы создали миграцию для добавления поля, но теперь вы хотите установить пул для всей существующей статьи в соответствии с их title
.
Конечно, вы можете просто сделать что-то подобное в терминале:
$ django-admin shell
>>> from my_app.models import Article
>>> from django.utils.text import slugify
>>> for article in Article.objects.all():
... article.slug = slugify(article.title)
... article.save()
...
>>>
Но вам придется делать это во всех своих средах (например, на рабочем столе вашего офиса, на вашем ноутбуке ...), всем вашим коллегам также придется это делать, и вам придется подумать об этом при постановке и при нажатии жить.
Чтобы сделать это раз и навсегда, мы сделаем это в процессе миграции. Сначала создайте пустую миграцию:
$ django-admin makemigrations --empty app_name
Это создаст пустой файл миграции. Откройте его, он содержит базовый скелет. Предположим, что ваша предыдущая миграция была названа 0023_article_slug
и она называется 0024_auto_20160719_1734
. Вот что мы напишем в нашем файле миграции:
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-07-19 15:34
from __future__ import unicode_literals
from django.db import migrations
from django.utils.text import slugify
def gen_slug(apps, schema_editor):
# We can't import the Article model directly as it may be a newer
# version than this migration expects. We use the historical version.
Article = apps.get_model('app_name', 'Article')
for row in Article.objects.all():
row.slug = slugify(row.name)
row.save()
class Migration(migrations.Migration):
dependencies = [
('hosting', '0023_article_slug'),
]
operations = [
migrations.RunPython(gen_slug, reverse_code=migrations.RunPython.noop),
# We set `reverse_code` to `noop` because we cannot revert the migration
# to get it back in the previous state.
# If `reverse_code` is not given, the migration will not be reversible,
# which is not the behaviour we expect here.
]
Поддельные миграции
Когда миграция выполняется, Django сохраняет имя миграции в таблице django_migrations.
Создание и подделка начальных миграций для существующей схемы
Если ваше приложение уже имеет модели и таблицы базы данных и не имеет миграций. Сначала создайте начальные миграции для своего приложения.
python manage.py makemigrations your_app_label
Теперь поддельные начальные миграции применимы
python manage.py migrate --fake-initial
Поддельные все миграции во всех приложениях
python manage.py migrate --fake
Поддельные миграции приложений
python manage.py migrate --fake core
Поддельный файл с одной миграцией
python manage.py migrate myapp migration_name
Пользовательские имена для файлов миграции
Используйте параметр makemigrations --name <your_migration_name>
чтобы разрешить именовать миграцию (-и) вместо использования сгенерированного имени.
python manage.py makemigrations --name <your_migration_name> <app_name>
Устранение конфликтов миграции
Вступление
Иногда конфликты конфликтуют, в результате чего миграция не выполняется. Это может произойти во множестве scenerio, однако это может происходить на регулярной основе при разработке одного приложения с командой.
Общие конфликты миграции происходят при использовании контроля источника, особенно когда используется метод «функция-ветвь». Для этого сценария мы будем использовать модель Reporter
с name
и address
атрибутов.
Два разработчика на этом этапе собираются разработать функцию, поэтому они оба получат эту исходную копию модели Reporter
. Разработчик A добавляет age
который приводит к файлу 0002_reporter_age.py
. Разработчик B добавляет поле bank_account
которое 0002_reporter_bank_account
в 0002_reporter_bank_account
. Как только эти разработчики объединит свой код и попытаются перенести миграции, возник конфликт миграции.
Этот конфликт возникает, потому что эти миграции изменяют одну и ту же модель, Reporter
. Кроме того, новые файлы начинаются с 0002.
Слияние миграций
Есть несколько способов сделать это. В рекомендуемом порядке:
Самое простое решение для этого - запустить команду makemigrations с флагом -merge.
python manage.py makemigrations --merge <my_app>
Это создаст новую миграцию, разрешающую предыдущий конфликт.
Когда этот дополнительный файл не приветствуется в среде разработки по личным причинам, опция заключается в удалении конфликтующих миграций. Затем новая миграция может быть выполнена с помощью обычной команды
makemigrations
. Когда пользовательские миграции записываются, напримерmigrations.RunPython
, необходимо учитывать этот метод.
Измените CharField на ForeignKey
Прежде всего, давайте предположим, что это ваша первоначальная модель внутри приложения, называемого discography
:
from django.db import models
class Album(models.Model):
name = models.CharField(max_length=255)
artist = models.CharField(max_length=255)
Теперь вы понимаете, что вместо этого вы хотите использовать ForeignKey для исполнителя. Это несколько сложный процесс, который необходимо выполнить в несколько этапов.
Шаг 1, добавьте новое поле для ForeignKey, убедившись, что он отмечен как null (обратите внимание, что теперь мы подключаем модель):
from django.db import models
class Album(models.Model):
name = models.CharField(max_length=255)
artist = models.CharField(max_length=255)
artist_link = models.ForeignKey('Artist', null=True)
class Artist(models.Model):
name = models.CharField(max_length=255)
... и создать миграцию для этого изменения.
./manage.py makemigrations discography
Шаг 2, заполните новое поле. Для этого вам нужно создать пустую миграцию.
./manage.py makemigrations --empty --name transfer_artists discography
Когда у вас будет эта пустая миграция, вы хотите добавить к ней одну операцию RunPython
, чтобы связать ваши записи. В этом случае он может выглядеть примерно так:
def link_artists(apps, schema_editor):
Album = apps.get_model('discography', 'Album')
Artist = apps.get_model('discography', 'Artist')
for album in Album.objects.all():
artist, created = Artist.objects.get_or_create(name=album.artist)
album.artist_link = artist
album.save()
Теперь, когда ваши данные будут перенесены в новое поле, вы действительно можете сделать и оставить все как есть, используя новое поле artist_link
для всего. Или, если вы хотите немного очистить, вы хотите создать еще две миграции.
Для первой миграции вы хотите удалить свое исходное поле, artist
. Для вашей второй миграции переименуйте новое поле artist_link
в artist
.
Это делается несколькими шагами, чтобы гарантировать, что Django правильно распознает операции.