Spec-Zone.ru › Django 5.2

Операции миграций

Файлы миграций состоят из одной или нескольких Operation, объектов, которые декларативно записывают, что миграция должна сделать с вашей базой данных.

Django также использует эти Operation объекты, чтобы понять, как выглядели ваши модели в прошлом, и рассчитать изменения, внесенные в ваши модели с последней миграцией, чтобы автоматически создавать ваши миграции; именно поэтому они декларативные, так как это означает, что Django может легко загрузить их все в память и пройтись по ним, не затрагивая базу данных, чтобы понять, как должен выглядеть ваш проект.

Также существуют более специализированные Operation объекты, предназначенные для таких задач, как миграции данных и для продвинутого ручного управления базой данных. Вы также можете написать свои собственные Operation классы, если хотите инкапсулировать пользовательское изменение, которое вы часто вносите.

Если вам нужен пустой файл миграции, чтобы записать в него свои собственные Operation объекты, используйте python manage.py makemigrations --empty yourappname, но имейте в виду, что ручное добавление операций изменения схемы может сбить с толку автоматический детектор миграций и привести к неправильному коду при последующих выполнении makemigrations.

Все основные операции Django доступны из модуля django.db.migrations.operations.

Для вводного материала см. руководство по теме миграций.

Операции со схемой

CreateModel

class CreateModel(name, fields, options=None, bases=None, managers=None) [source]

Создает новую модель в истории проекта и соответствующую таблицу в базе данных.

name — это имя модели, как оно записано в файле models.py.

fields — это список пар кортежей из (field_name, field_instance). Экземпляр поля должен быть несвязанным полем (т.е. просто models.CharField(...), а не полем, взятым из другой модели).

options — это необязательный словарь значений из класса Meta модели.

bases — это необязательный список других классов, от которых должна наследоваться эта модель; он может содержать как объекты классов, так и строки в формате "appname.ModelName", если вы хотите зависеть от другой модели (то есть наследовать от исторической версии). Если он не указан, по умолчанию происходит наследование от стандартного класса models.Model.

managers принимает список пар кортежей из (manager_name, manager_instance). Первый менеджер в списке будет менеджером по умолчанию для этой модели во время миграций.

DeleteModel

class DeleteModel(name) [source]

Удаляет модель из истории проекта и её таблицу из базы данных.

RenameModel

class RenameModel(old_name, new_name) [source]

Переименовывает модель со старого имени на новое.

Возможно, вам придется вручную добавить эту операцию, если вы измените имя модели и довольно много её полей сразу; для автообнаруживателя это будет выглядеть как удаление модели со старым именем и добавление новой с другим именем, и создаваемая им миграция потеряет любые данные в старой таблице.

AlterModelTable

class AlterModelTable(name, table) [source]

Изменяет имя таблицы модели (опция db_table подкласса Meta).

AlterModelTableComment

class AlterModelTableComment(name, table_comment) [source]

Изменяет комментарий к таблице модели (опция db_table_comment подкласса Meta).

AlterUniqueTogether

class AlterUniqueTogether(name, unique_together) [source]

Изменяет набор уникальных ограничений модели (опция unique_together подкласса Meta).

AlterIndexTogether

class AlterIndexTogether(name, index_together) [source]

Изменяет набор пользовательских индексов модели (опция index_together подкласса Meta).

Предупреждение

AlterIndexTogether официально поддерживается только для файлов миграций Django до 4.2. По соображениям обратной совместимости он по-прежнему входит в общедоступный API, и нет планов по его устареванию или удалению, но его не следует использовать для новых миграций. Используйте операции AddIndex и RemoveIndex вместо него.

AlterOrderWithRespectTo

class AlterOrderWithRespectTo(name, order_with_respect_to) [source]

Создает или удаляет столбец _order, необходимый для опции order_with_respect_to подкласса Meta.

AlterModelOptions

class AlterModelOptions(name, options) [source]

Хранит изменения в различных параметрах модели (настройки подкласса Meta), таких как permissions и verbose_name. Не влияет на базу данных, но сохраняет эти изменения для использования экземплярами RunPython. options должен быть словарем, сопоставляющим имена параметров значениям.

AlterModelManagers

class AlterModelManagers(name, managers) [source]

Изменяет менеджеры, доступные во время миграций.

AddField

class AddField(model_name, name, field, preserve_default=True) [source]

Добавляет поле в модель. model_name — имя модели, name — имя поля, а field — экземпляр поля без привязки (то, что вы бы поместили в объявление поля в models.py — например, models.IntegerField(null=True)).

Аргумент preserve_default указывает, является ли значение по умолчанию поля постоянным и должно быть включено в состояние проекта (True), или оно временное и только для этой миграции (False) — обычно потому, что миграция добавляет поле без значения NULL в таблицу и ей требуется значение по умолчанию для заполнения существующих строк. Это не влияет на поведение установки значений по умолчанию непосредственно в базе данных — Django никогда не устанавливает значения по умолчанию в базе данных и всегда применяет их в коде Django ORM.

Предупреждение

В старых базах данных добавление поля со значением по умолчанию может привести к полной пересборке таблицы. Это происходит даже для полей с NULL и может отрицательно сказаться на производительности. Чтобы этого избежать, следует выполнить следующие шаги.

  • Добавьте поле с NULL без значения по умолчанию и выполните команду makemigrations. Это должно сгенерировать миграцию с операцией AddField.
  • Добавьте значение по умолчанию к вашему полю и выполните команду makemigrations. Это должно сгенерировать миграцию с операцией AlterField.

RemoveField

class RemoveField(model_name, name) [source]

Удаляет поле из модели.

Помните, что при обратном выполнении эта операция фактически добавляет поле в модель. Операция обратима (кроме любой потери данных, которая необратима), если поле имеет значение NULL или если оно имеет значение по умолчанию, которое может использоваться для заполнения вновь созданного столбца. Если поле не допускает NULL и не имеет значения по умолчанию, операция необратима.

PostgreSQL

RemoveField также удалит все дополнительные объекты базы данных, связанные с удаленным полем (например, представления). Это связано с тем, что результирующее утверждение DROP COLUMN будет включать предложение CASCADE, чтобы гарантировать удаление зависимых объектов за пределами таблицы.

AlterField

class AlterField(model_name, name, field, preserve_default=True) [source]

Изменяет определение поля, включая изменения его типа, null, unique, db_column и другие атрибуты поля.

Аргумент preserve_default указывает, является ли значение по умолчанию поля постоянным и должно быть включено в состояние проекта (True), или оно временное и только для этой миграции (False) — обычно потому, что миграция изменяет необязательное поле на обязательное и требует значения по умолчанию для существующих строк. Это не влияет на поведение установки значений по умолчанию непосредственно в базе данных — Django никогда не устанавливает значения по умолчанию в базе данных и всегда применяет их в коде Django ORM.

Обратите внимание, что не все изменения возможны во всех базах данных — например, вы не можете изменить текстовое поле, такое как models.TextField(), на числовое поле, такое как models.IntegerField(), в большинстве баз данных.

RenameField

class RenameField(model_name, old_name, new_name) [source]

Изменяет имя поля (и, если db_column не задано, его имя столбца).

AddIndex

class AddIndex(model_name, index) [source]

Создает индекс в таблице базы данных для модели с model_name. index — это экземпляр класса Index.

RemoveIndex

class RemoveIndex(model_name, name) [source]

Удаляет индекс с именем name из модели с model_name.

RenameIndex

class RenameIndex(model_name, new_name, old_name=None, old_fields=None) [source]

Переименовывает индекс в таблице базы данных для модели с model_name. Должен быть предоставлен только один из old_name и old_fields. old_fields — это итерируемый список строк, часто соответствующий полям index_together (вариант до Django 5.1).

В базах данных, не поддерживающих операцию переименования индексов (SQLite и MariaDB < 10.5.2), операция будет удалять и воссоздавать индекс, что может быть дорогостоящим.

AddConstraint

class AddConstraint(model_name, constraint) [source]

Создает ограничение в таблице базы данных для модели с model_name.

RemoveConstraint

class RemoveConstraint(model_name, name) [source]

Удаляет ограничение с именем name из модели с model_name.

AlterConstraint

Новое в Django 5.2.
class AlterConstraint(model_name, name, constraint) [source]

Изменяет ограничение с именем name модели с model_name с новым constraint без изменения базы данных.

Специальные операции

RunSQL

class RunSQL(sql, reverse_sql=None, state_operations=None, hints=None, elidable=False) [source]

Позволяет выполнять произвольный SQL-код на базе данных — полезно для более сложных функций баз данных, которые Django не поддерживает напрямую.

sql, и reverse_sql, если предоставлены, должны быть строками SQL-кода для выполнения на базе данных. В большинстве баз данных (кроме PostgreSQL), Django разделит SQL-код на отдельные инструкции перед выполнением.

Предупреждение

В PostgreSQL и SQLite используйте только BEGIN или COMMIT в вашем SQL-коде в неатомарных миграциях, чтобы избежать нарушения состояния транзакций Django.

Также можно передать список строк или 2-кортежей. Последние используются для передачи запросов и параметров так же, как в 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

class RunPython(code, reverse_code=None, atomic=None, hints=None, elidable=False) [source]

Выполняет пользовательский Python-код в историческом контексте. code (и reverse_code, если предоставлены) должны быть вызываемыми объектами, принимающими два аргумента; первый — экземпляр django.apps.registry.Apps, содержащий исторические модели, соответствующие месту операции в истории проекта, а второй — экземпляр SchemaEditor.

Аргумент reverse_code вызывается при отмене миграций. Эта функция должна отменять то, что сделано в функции 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() [source]

Передайте метод RunPython.noop к code или reverse_code, если вы хотите, чтобы операция ничего не делала в данном направлении. Это особенно полезно для обеспечения обратимости операции.

SeparateDatabaseAndState

class SeparateDatabaseAndState(database_operations=None, state_operations=None) [source]

Высокоспециализированная операция, позволяющая комбинировать операции базы данных (изменение схемы) и состояния (питание автодетектора).

Она принимает два списка операций. При запросе применения состояния она будет использовать список state_operations (это обобщённая версия аргумента state_operations RunSQL). При запросе изменения базы данных она будет использовать список database_operations.

Если фактическое состояние базы данных и представление состояния Django расходятся, это может нарушить работу механизма миграций, вплоть до потери данных. Стоит проявить осторожность и внимательно проверить операции с базой данных и состоянием. Для проверки операций с базой данных можно использовать sqlmigrate и dbshell. Для проверки операций со состоянием можно использовать makemigrations, особенно с --dry-run.

Пример использования SeparateDatabaseAndState см. в Изменение поля ManyToManyField на использование модели через.

Категория операции

Новая в Django 5.1.
class OperationCategory [source]

Категории операций миграции, используемые командой makemigrations для отображения осмысленных символов.

ADDITION

Символ: +

REMOVAL

Символ: -

ALTERATION

Символ: ~

PYTHON

Символ: p

SQL

Символ: s

MIXED

Символ: ?

Написание собственных операций

Операции имеют относительно простой 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

    # This categorizes the operation. The corresponding symbol will be
    # displayed by the makemigrations command.
    category = OperationCategory.ADDITION

    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.
        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)

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

© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/5.2/ref/migration-operations/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API