Spec-Zone.ru › Django 1.11

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

Файлы миграции состоят из одного или нескольких 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).

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]

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

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

AlterField

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

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

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

END_OF_DOCUMENT_MARKER

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

RenameField

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

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

AddIndex

class AddIndex(model_name, index) [source]
Новое в Django 1.11.

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

RemoveIndex

class RemoveIndex(model_name, name) [source]
Новое в Django 1.11.

Удаляет индекс с именем 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-код на отдельные операторы перед выполнением. Для этого необходимо установить библиотеку Python sqlparse.

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

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

Необязательный аргумент elidable определяет, будет ли операция удалена (исключена) при сжатии миграций.

RunSQL.noop

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

Новое в Django 1.10:

Был добавлен аргумент elidable.

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, чтобы миграция была обратимой.

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

Необязательный аргумент elidable определяет, будет ли операция удалена (исключена) при сжатии миграций.

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

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

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

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

Новое в Django 1.10:

Был добавлен аргумент elidable.

Изменено в Django 1.10:

Значение по умолчанию аргумента atomic было изменено на None, указывая, что атомарность контролируется атрибутом atomic миграции.

SeparateDatabaseAndState

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

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

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

Создание собственной операции

Операции имеют относительно простой API, и они разработаны таким образом, что вы можете легко создавать свои собственные, чтобы дополнить встроенные операции Django. Базовая структура собственной операции выглядит так:

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 применил бы, но предоставляются вам для удобства и повышения скорости.
  • Если вы хотите работать с классами моделей или экземплярами моделей из аргумента 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()
        ...
    
    Введено в Django 1.11:

    Это требование и метод 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

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

Spec-Zone.ru

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