Spec-Zone.ru › Django 5.1

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

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

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

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

Если вам нужен пустой файл миграции, чтобы записать в него свои собственные 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 — это список пар 2-х элементов, представляющих (field_name, field_instance). Объект поля должен быть свободным полем (т.е. просто models.CharField(...), а не поле, взятое из другой модели).

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

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

managers принимает список пар 2-х элементов, представляющих (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) — обычно потому, что миграция добавляет непустое поле в таблицу и ей нужно значение по умолчанию для существующих строк. Это не влияет на поведение установки значений по умолчанию непосредственно в базе данных — Django никогда не устанавливает значения по умолчанию в базе данных и всегда применяет их в коде Django ORM.

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

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

  • Добавьте необязательное поле без значения по умолчанию и запустите команду 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) — обычно потому, что миграция изменяет поле, допускающее значения NULL, на поле, не допускающее значений NULL, и ей нужно значение по умолчанию для существующих строк. Это не влияет на поведение установки значений по умолчанию непосредственно в базе данных — 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.

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

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.1/ref/migration-operations/

Spec-Zone.ru

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