Spec-Zone.ru › Django 1.9

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

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

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

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

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

Аргумент managers был добавлен.

DeleteModel

class DeleteModel(name) [source]

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

RenameModel

class RenameModel(old_name, new_name) [source]

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

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

AlterModelTable

class AlterModelTable(name, table) [source]

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

AlterUniqueTogether

class AlterUniqueTogether(name, unique_together) [source]

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

AlterIndexTogether

class AlterIndexTogether(name, index_together) [source]

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

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.

RemoveField

class RemoveField(model_name, name) [source]

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

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

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, имя столбца).

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

RunSQL

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

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

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

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

migrations.RunSQL(
    [("INSERT INTO musician (name) VALUES (%s);", ['Reinhardt'])],
    [("DELETE FROM musician where name=%s;", ['Reinhardt'])],
)

Аргумент 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() роутеров баз данных для помощи им в принятии решений о маршрутизации. Подробнее см. Подсказки.

Добавлена возможность передачи параметров в sql и reverse_sql запросы.

Добавлен аргумент hints.

RunSQL.noop

Передайте атрибут RunSQL.noop в sql или reverse_sql, если вы хотите, чтобы операция ничего не делала в заданном направлении. Это особенно полезно для обратимости операции.

RunPython

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

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

Аргумент reverse_code вызывается при отмене миграций. Этот вызываемый объект должен отменить то, что делается в вызываемом объекте code, чтобы миграция была обратимой.

Необязательный аргумент hints будет передан как **hints методу allow_migrate() роутеров баз данных для помощи им в принятии решения о маршрутизации. Подробнее см. Подсказки.

Добавлен аргумент hints.

Рекомендуется писать код в виде отдельной функции над классом Migration в файле миграции и просто передавать его в RunPython. Вот пример использования RunPython для создания начальных объектов модели Country.

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import migrations, models

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-коду.

Если вы переходите с South, эта операция в основном соответствует паттерну South — один или два метода для прямых и обратных действий с доступным ORM и операциями над схемой. В большинстве случаев вы сможете напрямую перевести orm.Model или orm["appname", "Model"] из South в apps.get_model("appname", "Model") и оставить большую часть остального кода для миграций данных без изменений. Однако apps будет содержать ссылки только на модели текущего приложения, если к зависимости миграции не добавлены миграции других приложений.

Подобно RunSQL, убедитесь, что если вы изменяете схему внутри неё, то делаете это вне сферы системы моделей Django (например, триггеры) или используете SeparateDatabaseAndState для добавления операций, которые отражают ваши изменения в состоянии модели — иначе версионированная ORM и автодетектора перестанут работать правильно.

По умолчанию, RunPython будет запускать содержимое внутри транзакции в базах данных, которые не поддерживают транзакции DDL (например, MySQL и Oracle). Это должно быть безопасно, но может вызвать сбой, если вы попытаетесь использовать предоставленный schema_editor на этих бэкендах; в этом случае передайте atomic=False в операцию RunPython.

В базах данных, поддерживающих транзакции DDL (SQLite и PostgreSQL), операции RunPython не имеют автоматически добавляемых транзакций помимо транзакций, созданных для каждой миграции (параметр atomic не влияет на эти базы данных). Таким образом, например, в PostgreSQL следует избегать объединения изменений схемы и операций RunPython в одной миграции, чтобы не столкнуться с ошибками типа OperationalError: cannot ALTER TABLE "mytable" because it has pending trigger events.

Если у вас другая база данных и вы не уверены, поддерживает ли она транзакции DDL, проверьте атрибут django.db.connection.features.can_rollback_ddl.

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

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]

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

Она принимает два списка операций, и при запросе состояния будет использовать список состояния, а при запросе изменений в базе данных будет использовать список базы данных. Не используйте эту операцию, если вы не уверены в том, что делаете.

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

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

Вы можете взять эту шаблон и работать от него, хотя мы рекомендуем посмотреть на встроенные операции Django в django.db.migrations.operations — они легко читаются и охватывают множество примеров использования полувнутренних аспектов фреймворка миграций, таких как ProjectState и паттернов для получения исторических моделей, а также ModelState и паттернов для изменения исторических моделей в state_forwards().

Некоторые замечания:

  • Вам не нужно углубляться в ProjectState для написания простых миграций; просто знайте, что у него есть свойство apps, которое предоставляет доступ к реестру приложений (на котором можно вызвать get_model).
  • database_forwards и database_backwards оба получают два состояния, переданные им; они просто представляют разницу, которую метод state_forwards применил бы, но предоставляются для удобства и скорости.
  • 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

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

Spec-Zone.ru

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