Миграционные операции ¶
Файлы миграции состоят из одного или нескольких Operation
объектов, которые декларативно записывают, что миграция должна делать с вашей базой данных.
Django также использует эти Operation
объекты, чтобы определить, как ваши модели выглядели исторически, и вычислить, какие изменения вы внесли в свои модели с момента последней миграции, чтобы он мог автоматически записывать ваши миграции; вот почему они декларативны, поскольку это означает, что Django может легко загрузить их все в память и просмотреть их, не касаясь базы данных, чтобы определить, как должен выглядеть ваш проект.
Существуют также более специализированные Operation
объекты, предназначенные для таких вещей, как
миграция данных и расширенное ручное управление базой данных. Вы также можете написать свои собственные Operation
классы, если хотите инкапсулировать пользовательское изменение, которое вы обычно делаете.
Если вам нужен пустой файл миграции для записи ваших собственных Operation
объектов, используйте , но имейте в виду, что добавление операций изменения схемы вручную может сбить с толку автодетектор миграции и привести к получению выходных запусков неправильного кода.python manage.py makemigrations --empty yourappname
makemigrations
Все основные операции Django доступны из
django.db.migrations.operations
модуля.
Вводный материал см. В руководстве по миграции .
Схема Операции ¶
CreateModel
¶
-
класс
CreateModel
( имя , поля , параметры = Нет , базы = Нет , менеджеры = Нет ) ¶
Создает новую модель в истории проекта и соответствующую таблицу в базе данных.
name
- название модели, как будет написано в models.py
файле.
fields
представляет собой список из двух кортежей . Экземпляр поля должен быть несвязанным полем (так просто
, а не полем, взятым из другой модели).(field_name, field_instance)
models.CharField(...)
options
- необязательный словарь значений из Meta
класса модели .
bases
- необязательный список других классов, от которых наследуется эта модель; он может содержать как объекты класса, так и строки в формате,
"appname.ModelName"
если вы хотите зависеть от другой модели (чтобы вы унаследовали от исторической версии). Если он не указан, по умолчанию он наследует от стандарта models.Model
.
managers
принимает список из двух кортежей . Первый менеджер в списке будет менеджером по умолчанию для этой модели во время миграции.(manager_name, manager_instance)
DeleteModel
¶
-
класс
DeleteModel
( имя ) ¶
Удаляет модель из истории проекта и ее таблицу из базы данных.
RenameModel
¶
-
класс
RenameModel
( old_name , new_name ) ¶
Переименовывает модель со старого имени на новое.
Возможно, вам придется добавить это вручную, если вы измените название модели и сразу несколько ее полей; для автодетектора это будет выглядеть так, как будто вы удалили модель со старым именем и добавили новую с другим именем, а при миграции, которую он создает, будут потеряны все данные в старой таблице.
AlterModelTable
¶
-
класс
AlterModelTable
( название , таблица ) ¶
Изменяет имя таблицы модели ( db_table
опция в Meta
подклассе).
AlterUniqueTogether
¶
-
класс
AlterUniqueTogether
( имя , уникальное_всего ) ¶
Изменяет набор уникальных ограничений модели (
unique_together
параметр в Meta
подклассе).
AlterIndexTogether
¶
-
класс
AlterIndexTogether
( имя , индекс_всего ) ¶
Изменяет набор пользовательских индексов модели (
index_together
параметр в Meta
подклассе).
AlterOrderWithRespectTo
¶
-
class
AlterOrderWithRespectTo
( name , order_with_respect_to ) ¶
Создает или удаляет _order
столбец, необходимый для
order_with_respect_to
параметра Meta
подкласса.
AlterModelOptions
¶
-
класс
AlterModelOptions
( имя , параметры ) ¶
Сохраняет изменения в различных параметрах модели (настройках модели Meta
), таких как permissions
и verbose_name
. Не влияет на базу данных, но сохраняет эти изменения для RunPython
использования экземплярами. options
должны быть имена параметров сопоставления словаря значениям.
AlterModelManagers
¶
-
класс
AlterModelManagers
( имя , менеджеры ) ¶
Изменяет менеджеров, доступных во время миграций.
AddField
¶
-
класс
AddField
( имя_модели , имя , поле , preserve_default = True ) ¶
Добавляет поле в модель. model_name
- это имя модели, это имя name
поля и field
это несвязанный экземпляр поля (то, что вы поместили бы в объявление поля, models.py
например
models.IntegerField(null=True)
,.
preserve_default
Аргумент указывает , является ли значение поля по умолчанию постоянными и должны быть запеченный в состояние проекта ( True
), или , если это временно и только для этой миграции ( False
) - как правило , потому , что миграция является добавление ненулевых поля к столу и потребностей значение по умолчанию для добавления в существующие строки. Это не влияет на поведение установки значений по умолчанию в базе данных напрямую - Django никогда не устанавливает значения по умолчанию для базы данных и всегда применяет их в коде Django ORM.
Предупреждение
В старых базах данных добавление поля со значением по умолчанию может привести к полной перезаписи таблицы. Это происходит даже для полей, допускающих значение NULL, и может отрицательно сказаться на производительности. Чтобы этого избежать, следует предпринять следующие шаги.
- Добавьте поле, допускающее значение NULL, без значения по умолчанию и выполните
makemigrations
команду. Это должно вызвать миграцию сAddField
операцией. - Добавьте в свое поле значение по умолчанию и запустите
makemigrations
команду. Это должно вызвать миграцию сAlterField
операцией.
RemoveField
¶
-
class
RemoveField
( имя_модели , имя ) ¶
Удаляет поле из модели.
Имейте в виду, что при инвертировании это фактически добавление поля в модель. Операция обратима (за исключением любой потери данных, которая необратима), если поле допускает значение NULL или имеет значение по умолчанию, которое можно использовать для заполнения воссозданного столбца. Если поле не допускает значения NULL и не имеет значения по умолчанию, операция необратима.
AlterField
¶
-
класс
AlterField
( имя_модели , имя , поле , preserve_default = True ) ¶
Alters определению поля, в том числе изменения в его типа,
null
, unique
,
db_column
и другие атрибуты поля.
preserve_default
Аргумент указует , является ли значение поля по умолчанию постоянное и должно быть запеченным в состояние проекта ( True
), или , если это временно и только для этой миграции ( False
) - как правило , потому , что миграция изменяет обнуляемое поле к Ненулевому один и требуется значение по умолчанию для помещения в существующие строки. Это не влияет на поведение установки значений по умолчанию в базе данных напрямую - Django никогда не устанавливает значения по умолчанию для базы данных и всегда применяет их в коде Django ORM.
Обратите внимание, что не все изменения возможны во всех базах данных - например, вы не можете изменить поле текстового типа, как models.TextField()
в поле числового типа, как models.IntegerField()
в большинстве баз данных.
RenameField
¶
-
класс
RenameField
( model_name , old_name , new_name ) ¶
Изменяет имя поля (и, если db_column
не установлено, имя столбца).
AddIndex
¶
-
class
AddIndex
( имя_модели , индекс ) ¶
Создает индекс в таблице базы данных для модели с model_name
.
index
является экземпляром Index
класса.
RemoveIndex
¶
-
class
RemoveIndex
( имя_модели , имя ) ¶
Удаляет индекс, названный name
из модели с model_name
.
AddConstraint
¶
-
class
AddConstraint
( имя_модели , ограничение ) ¶
Создает ограничение в таблице базы данных для модели с model_name
.
Специальные операции ¶
RunSQL
¶
-
класс
RunSQL
( SQL , reverse_sql = None , state_operations = None , намеки = нет , elidable = False ) ¶
Позволяет запускать произвольный SQL в базе данных - полезно для более продвинутых функций серверной части базы данных, которые Django не поддерживает напрямую.
sql
, и, reverse_sql
если он предоставлен, должны быть строками SQL для запуска в базе данных. В большинстве бэкэндов баз данных (всех, кроме PostgreSQL) Django разбивает SQL на отдельные операторы перед их выполнением.
Предупреждение
В PostgreSQL и SQLite используйте только BEGIN
или COMMIT
в своем SQL в
неатомарных миграциях , чтобы избежать нарушения состояния транзакции Django.
Вы также можете передать список строк или двух кортежей. Последний используется для передачи запросов и параметров так же, как cursor.execute () . Эти три операции эквивалентны:
migrations.RunSQL("INSERT INTO musician (name) VALUES ('Reinhardt');")
migrations.RunSQL([("INSERT INTO musician (name) VALUES ('Reinhardt');", None)])
migrations.RunSQL([("INSERT INTO musician (name) VALUES (%s);", ['Reinhardt'])])
Если вы хотите включить в запрос буквальные знаки процента, вы должны удвоить их, если вы передаете параметры.
Эти reverse_sql
запросы выполняются , когда миграция Непримененная. Они должны отменить то, что делают sql
запросы. Например, чтобы отменить указанную выше вставку с удалением:
migrations.RunSQL(
sql=[("INSERT INTO musician (name) VALUES (%s);", ['Reinhardt'])],
reverse_sql=[("DELETE FROM musician where name=%s;", ['Reinhardt'])],
)
Если reverse_sql
есть None
(по умолчанию), RunSQL
операция необратима.
state_operations
Аргумент позволяет снабженческих операций, которые эквивалентны SQL в терминах состояния проекта. Например, если вы вручную создаете столбец, вы должны передать здесь список, содержащий AddField
операцию, чтобы автодетектор по-прежнему имел актуальное состояние модели. Если вы этого не сделаете, при следующем запуске makemigrations
он не увидит никаких операций, добавляющих это поле, и попытается запустить его снова. Например:
migrations.RunSQL(
"ALTER TABLE musician ADD COLUMN name varchar(255) NOT NULL;",
state_operations=[
migrations.AddField(
'musician',
'name',
models.CharField(max_length=255),
),
],
)
Необязательный hints
аргумент будет передан в **hints
отношении
allow_migrate()
метода маршрутизаторов баз данных, чтобы помочь им в принятии решений о маршрутизации. См. Подсказки для получения более подробной информации о подсказках базы данных.
Необязательный elidable
аргумент определяет, будет ли операция удалена (исключена) при сжатии миграций .
-
RunSQL.
noop
¶ Передайте
RunSQL.noop
атрибут вsql
или,reverse_sql
если вы хотите, чтобы операция ничего не делала в заданном направлении. Это особенно полезно для того, чтобы сделать операцию обратимой.
RunPython
¶
-
Класс
RunPython
( код , reverse_code = None , атомные = None , намеки = нет , elidable = False ) ¶
Выполняет собственный код Python в историческом контексте. code
(и reverse_code
если предоставлено) должны быть вызываемыми объектами, которые принимают два аргумента; первый - это экземпляр, django.apps.registry.Apps
содержащий исторические модели, соответствующие месту операции в истории проекта, а второй - экземпляр SchemaEditor
.
reverse_code
Аргумент называется , когда unapplying миграции. Этот вызываемый объект должен отменить то, что сделано в code
вызываемом файле, чтобы миграция была обратимой. Если reverse_code
есть None
(по умолчанию),
RunPython
операция необратима.
Необязательный hints
аргумент будет передан в **hints
отношении
allow_migrate()
метода маршрутизаторов баз данных, чтобы помочь им в принятии решения о маршрутизации. См. Подсказки для получения более подробной информации о подсказках базы данных.
Необязательный elidable
аргумент определяет, будет ли операция удалена (исключена) при сжатии миграций .
Рекомендуется написать код как отдельную функцию над Migration
классом в файле миграции и передать его в RunPython
. Вот пример использования RunPython
для создания некоторых начальных объектов на Country
модели:
from django.db import migrations
def forwards_func(apps, schema_editor):
# We get the model from the versioned app registry;
# if we directly import it, it'll be the wrong version
Country = apps.get_model("myapp", "Country")
db_alias = schema_editor.connection.alias
Country.objects.using(db_alias).bulk_create([
Country(name="USA", code="us"),
Country(name="France", code="fr"),
])
def reverse_func(apps, schema_editor):
# forwards_func() creates two Country instances,
# so reverse_func() should delete them.
Country = apps.get_model("myapp", "Country")
db_alias = schema_editor.connection.alias
Country.objects.using(db_alias).filter(name="USA", code="us").delete()
Country.objects.using(db_alias).filter(name="France", code="fr").delete()
class Migration(migrations.Migration):
dependencies = []
operations = [
migrations.RunPython(forwards_func, reverse_func),
]
Обычно это операция, которую вы использовали бы для создания миграции данных , запуска пользовательских обновлений и изменений данных и всего остального, для чего вам нужен доступ к ORM и / или коду Python.
Точно так же RunSQL
убедитесь, что если вы меняете схему внутри здесь, вы либо делаете это за пределами системы модели Django (например, триггеры), либо используете SeparateDatabaseAndState
для добавления операций, которые будут отражать ваши изменения в состоянии модели - в противном случае версионный ORM, и автодетектор перестанет работать правильно.
По умолчанию RunPython
его содержимое будет запускаться внутри транзакции в базах данных, которые не поддерживают транзакции DDL (например, MySQL и Oracle). Это должно быть безопасно, но может вызвать сбой, если вы попытаетесь использовать schema_editor
предоставленное на этих серверных ВМ; в этом случае переходите
atomic=False
к RunPython
операции.
В базах данных, которые поддерживают транзакции DDL (SQLite и PostgreSQL), к
RunPython
операциям не добавляются автоматически какие-либо транзакции, кроме транзакций, созданных для каждой миграции. Таким образом, в PostgreSQL, например, вам следует избегать объединения изменений схемы и RunPython
операций в одной миграции, иначе вы можете столкнуться с такими ошибками, как .OperationalError: cannot
ALTER TABLE "mytable" because it has pending trigger events
Если у вас другая база данных и вы не уверены, поддерживает ли она транзакции DDL, проверьте django.db.connection.features.can_rollback_ddl
атрибут.
Если RunPython
операция является частью неатомарной миграции , операция будет выполняться в транзакции только в том случае, если atomic=True
она передана в RunPython
операцию.
Предупреждение
RunPython
не меняет волшебным образом подключение моделей за вас; любые методы модели, которые вы вызываете, перейдут в базу данных по умолчанию, если вы не дадите им текущий псевдоним базы данных (доступен из
schema_editor.connection.alias
, где schema_editor
- второй аргумент вашей функции).
-
static
RunPython.
noop
() ¶ Передайте
RunPython.noop
методcode
или,reverse_code
если вы хотите, чтобы операция не выполняла никаких действий в заданном направлении. Это особенно полезно для того, чтобы сделать операцию обратимой.
SeparateDatabaseAndState
¶
-
class
SeparateDatabaseAndState
( database_operations = None , state_operations = None ) ¶
Узкоспециализированная операция, которая позволяет смешивать и сопоставлять аспекты операций с базой данных (изменение схемы) и состояния (включение автодетектора).
Он принимает два списка операций. Когда его попросили применить состояние, он будет использовать
state_operations
список (это обобщенная версия RunSQL
«S
state_operations
аргумента). Когда вас попросят применить изменения к базе данных, он будет использовать database_operations
список.
Если фактическое состояние базы данных и представление состояния Django не синхронизируются, это может нарушить структуру миграции и даже привести к потере данных. Стоит проявлять осторожность и тщательно проверять свою базу данных и операции состояния. Вы можете использовать sqlmigrate
и dbshell
для проверки операций вашей базы данных. Вы можете использовать makemigrations
, особенно с --dry-run
, для проверки операций состояния.
Пример использования SeparateDatabaseAndState
см. В разделе «
Изменение ManyToManyField для использования сквозной модели» .
Написание собственного ¶
Операции имеют относительно простой API, и они разработаны таким образом, чтобы вы могли легко написать свой собственный в дополнение к встроенным в Django. Базовая структура объекта Operation
выглядит так:
from django.db.migrations.operations.base import Operation
class MyCustomOperation(Operation):
# If this is False, it means that this operation will be ignored by
# sqlmigrate; if true, it will be run and the SQL collected for its output.
reduces_to_sql = False
# If this is False, Django will refuse to reverse past this operation.
reversible = False
def __init__(self, arg1, arg2):
# Operations are usually instantiated with arguments in migration
# files. Store the values of them on self for later use.
pass
def state_forwards(self, app_label, state):
# The Operation should take the 'state' parameter (an instance of
# django.db.migrations.state.ProjectState) and mutate it to match
# any schema changes that have occurred.
pass
def database_forwards(self, app_label, schema_editor, from_state, to_state):
# The Operation should use schema_editor to apply any changes it
# wants to make to the database.
pass
def database_backwards(self, app_label, schema_editor, from_state, to_state):
# If reversible is True, this is called when the operation is reversed.
pass
def describe(self):
# This is used to describe what the operation does in console output.
return "Custom Operation"
@property
def migration_name_fragment(self):
# Optional. A filename part suitable for automatically naming a
# migration containing this operation, or None if not applicable.
return "custom_operation_%s_%s" % (self.arg1, self.arg2)
migration_name_fragment
Имущество было добавлено.
Вы можете взять этот шаблон и работать с ним, хотя мы предлагаем взглянуть на встроенные операции Django django.db.migrations.operations
- они охватывают множество примеров использования полувнутренних аспектов инфраструктуры миграции, таких ProjectState
как шаблоны, используемые для получения исторических моделей, а также ModelState
шаблоны, используемые для мутации исторических моделей в
state_forwards()
.
Несколько замечаний:
Вам не нужно слишком много разбираться
ProjectState
в написании миграций; просто знайте, что у него естьapps
свойство, которое дает доступ к реестру приложений (который вы затем можете вызватьget_model
).database_forwards
иdatabase_backwards
оба получают два состояния, переданные им; они представляют разницу, которуюstate_forwards
мог бы применить метод, но даны вам по соображениям удобства и скорости.Если вы хотите работать с классами модели или экземплярами модели из
from_state
аргумента вdatabase_forwards()
илиdatabase_backwards()
, вы должны визуализировать состояния модели, используяclear_delayed_apps_cache()
метод, чтобы сделать связанные модели доступными:def database_forwards(self, app_label, schema_editor, from_state, to_state): # This operation should have access to all models. Ensure that all models are # reloaded in case any are delayed. from_state.clear_delayed_apps_cache() ...
to_state
в методе database_backwards - более старое состояние; то есть тот, который будет текущим состоянием после завершения реверсирования миграции.Вы можете увидеть реализации
references_model
встроенных операций; это часть кода автоопределения и не имеет значения для пользовательских операций.
Предупреждение
По соображениям производительности Field
экземпляры в
ModelState.fields
повторно используются во время миграции. Вы никогда не должны изменять атрибуты этих экземпляров. Если вам нужно изменить поле
state_forwards()
, вы должны удалить старый экземпляр
ModelState.fields
и добавить на его место новый. То же верно и для Manager
экземпляров в
ModelState.managers
.
В качестве примера давайте выполним операцию, которая загружает расширения PostgreSQL (которые содержат некоторые из наиболее интересных функций PostgreSQL). Поскольку нет никаких изменений состояния модели, все, что она делает, - это запускает одну команду:
from django.db.migrations.operations.base import Operation
class LoadExtension(Operation):
reversible = True
def __init__(self, name):
self.name = name
def state_forwards(self, app_label, state):
pass
def database_forwards(self, app_label, schema_editor, from_state, to_state):
schema_editor.execute("CREATE EXTENSION IF NOT EXISTS %s" % self.name)
def database_backwards(self, app_label, schema_editor, from_state, to_state):
schema_editor.execute("DROP EXTENSION %s" % self.name)
def describe(self):
return "Creates extension %s" % self.name
@property
def migration_name_fragment(self):
return "create_extension_%s" % self.name