マイグレーションファイルは一つ以上の オペレーション
、データベースに対してマイグレーションが行うべき操作を宣言的に保持するオブジェクト、から構成されます。
加えて Django はモデルが過去からどのように変遷したかを解明するため、またマイグレーションを自動的に記述できるように最後のマイグレーション以降モデルに対して行われた変更を導出するために、これらの オペレーション
オブジェクトを利用します;マイグレーションの定義が宣言的であるのはそのためで、これは Django がプロジェクトの全容がどういった物であるかを解析する際、データベースを直接操作することなく、容易にマイグレーション定義を全てメモリ上にロードして処理できる事を意味します。
データのマイグレーション や高度なデータベースへの手動操作のような特別な オペレーション
も存在します。もし頻繁に行われる独自の変更をカプセル化したければ独自に オペレーション
を記述する事もできます。
If you need an empty migration file to write your own Operation
objects
into, use python manage.py makemigrations --empty yourappname
, but be aware
that manually adding schema-altering operations can confuse the migration
autodetector and make resulting runs of makemigrations
output
incorrect code.
Django が提供するコア機能は全て django.db.migrations.operations
モジュールから利用できます。
より入門的な内容に関しては、 トピックスのマイグレーション を参照ください。
CreateModel
¶CreateModel
(name, fields, options=None, bases=None, managers=None)¶プロジェクトの履歴に新たなモデル、そしてデータベース上に対応するテーブルを作成します。
name
は models.py
ファイルに定義されているであろうモデルの名称です。
fields
は (フィールド名, フィールドのインスタンス)
という 2 値のタプルのリストです。フィールドのインスタンスは束縛されないフィールド(他のモデルから取得した物でなく、単に models.CharField(...)
等と記述する物)でなければいけません。
options
は定義されるモデルの Meta
クラスの値からなるオプションの辞書オブジェクトです。
bases
is an optional list of other classes to have this model inherit from;
it can contain both class objects as well as strings in the format
"appname.ModelName"
if you want to depend on another model (so you inherit
from the historical version). If it's not supplied, it defaults to inheriting
from the standard models.Model
.
managers
は (マネージャ名, マネージャのインスタンス)
という 2 値のタプルのリストを受け取ります。マイグレーションの間はリスト内で最初に定義されたマネージャがこのモデルの標準マネージャとして利用されます。
RenameModel
¶RenameModel
(old_name, new_name)¶モデルの名称を今までの名称から新しい名称に変更します。
一度に定義しているモデルの名前とかなり多くのフィールドの名前を変更した場合は手動でこの処理を追加する必要があるかもしれません;マイグレーションの自動検知機構が古い名称を持ったモデルを削除して異なった名称のモデルを追加したと認識してしまうため、そのマイグレーション処理は古いテーブルの全てのデータを消去してしまいます。
AlterModelTable
¶AlterModelTable
(name, table)¶定義しているモデルのテーブル名を変更します(Meta
サブクラスの db_table
オプションを参照します)。
AlterUniqueTogether
¶AlterUniqueTogether
(name, unique_together)¶Changes the model's set of unique constraints (the
unique_together
option on the Meta
subclass).
AlterIndexTogether
¶AlterIndexTogether
(name, index_together)¶Changes the model's set of custom indexes (the
index_together
option on the Meta
subclass).
AlterOrderWithRespectTo
¶AlterOrderWithRespectTo
(name, order_with_respect_to)¶Makes or deletes the _order
column needed for the
order_with_respect_to
option on the Meta
subclass.
AlterModelOptions
¶AlterModelOptions
(name, options)¶Stores changes to miscellaneous model options (settings on a model's Meta
)
like permissions
and verbose_name
. Does not affect the database, but
persists these changes for RunPython
instances to use. options
should be a dictionary mapping option names to values.
AlterModelManagers
¶AlterModelManagers
(name, managers)¶Alters the managers that are available during migrations.
AddField
¶AddField
(model_name, name, field, preserve_default=True)¶Adds a field to a model. model_name
is the model's name, name
is
the field's name, and field
is an unbound Field instance (the thing
you would put in the field declaration in models.py
- for example,
models.IntegerField(null=True)
.
The preserve_default
argument indicates whether the field's default
value is permanent and should be baked into the project state (True
),
or if it is temporary and just for this migration (False
) - usually
because the migration is adding a non-nullable field to a table and needs
a default value to put into existing rows. It does not affect the behavior
of setting defaults in the database directly - Django never sets database
defaults and always applies them in the Django ORM code.
警告
On older databases, adding a field with a default value may cause a full rewrite of the table. This happens even for nullable fields and may have a negative performance impact. To avoid that, the following steps should be taken.
makemigrations
command. This should generate a migration with
an AddField
operation.makemigrations
command. This should generate a migration with an AlterField
operation.RemoveField
¶RemoveField
(model_name, name)¶Removes a field from a model.
Bear in mind that when reversed, this is actually adding a field to a model. The operation is reversible (apart from any data loss, which is irreversible) if the field is nullable or if it has a default value that can be used to populate the recreated column. If the field is not nullable and does not have a default value, the operation is irreversible.
AlterField
¶AlterField
(model_name, name, field, preserve_default=True)¶Alters a field's definition, including changes to its type,
null
, unique
,
db_column
and other field attributes.
The preserve_default
argument indicates whether the field's default
value is permanent and should be baked into the project state (True
),
or if it is temporary and just for this migration (False
) - usually
because the migration is altering a nullable field to a non-nullable one and
needs a default value to put into existing rows. It does not affect the
behavior of setting defaults in the database directly - Django never sets
database defaults and always applies them in the Django ORM code.
Note that not all changes are possible on all databases - for example, you
cannot change a text-type field like models.TextField()
into a number-type
field like models.IntegerField()
on most databases.
RenameField
¶RenameField
(model_name, old_name, new_name)¶Changes a field's name (and, unless db_column
is set, its column name).
AddIndex
¶AddIndex
(model_name, index)¶Creates an index in the database table for the model with model_name
.
index
is an instance of the Index
class.
RemoveIndex
¶RemoveIndex
(model_name, name)¶Removes the index named name
from the model with model_name
.
AddConstraint
¶AddConstraint
(model_name, constraint)¶Creates a constraint in the database table for
the model with model_name
.
RunSQL
¶RunSQL
(sql, reverse_sql=None, state_operations=None, hints=None, elidable=False)¶Allows running of arbitrary SQL on the database - useful for more advanced features of database backends that Django doesn't support directly.
sql
, and reverse_sql
if provided, should be strings of SQL to run on
the database. On most database backends (all but PostgreSQL), Django will
split the SQL into individual statements prior to executing them.
警告
On PostgreSQL and SQLite, only use BEGIN
or COMMIT
in your SQL in
non-atomic migrations, to avoid breaking
Django's transaction state.
文字列もしくは 2 値のタプルのリストを渡すことができます。その内後者はクエリとパラメータを cursor.execute() において行うのと同じ形式で渡すために用いられます。以下の 3 つの処理は互いに等価です:
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'])])
クエリにパーセント文字リテラルを含ませたい場合、パラメータを渡していればパーセント文字を二重に記述する必要が有ります。
The reverse_sql
queries are executed when the migration is unapplied. They
should undo what is done by the sql
queries. For example, to undo the above
insertion with a deletion:
migrations.RunSQL(
sql=[("INSERT INTO musician (name) VALUES (%s);", ['Reinhardt'])],
reverse_sql=[("DELETE FROM musician where name=%s;", ['Reinhardt'])],
)
If reverse_sql
is None
(the default), the RunSQL
operation is
irreversible.
The state_operations
argument allows you to supply operations that are
equivalent to the SQL in terms of project state. For example, if you are
manually creating a column, you should pass in a list containing an AddField
operation here so that the autodetector still has an up-to-date state of the
model. If you don't, when you next run makemigrations
, it won't see any
operation that adds that field and so will try to run it again. For example:
migrations.RunSQL(
"ALTER TABLE musician ADD COLUMN name varchar(255) NOT NULL;",
state_operations=[
migrations.AddField(
'musician',
'name',
models.CharField(max_length=255),
),
],
)
オプションの hints
引数はデータベースルータオブジェクトの allow_migrate()
メソッドに **hints
として渡されてルーティングの決定を補助します。データベースのヒントに関しての詳細は Hints を参照ください。
オプションの elidable
引数はこの処理を マイグレーションの統合 を行った際に消去する(省略する)か否かを決定します。
RunSQL.
noop
¶指定された順序での処理を行わない場合、sql
もしくは reverse_sql
に対して RunSQL.noop
要素を渡します。これは特に処理を逆の順序で行いたい場合に有用です。
RunPython
¶RunPython
(code, reverse_code=None, atomic=None, hints=None, elidable=False)¶マイグレーション履歴を反映して独自の Python コードを実行します。code
(与えられれば加えて reverse_code
)は二つの引数を受け取る呼び出し可能オブジェクトでなければなりません;第一引数はプロジェクトの履歴において処理の場所が一致している履歴を反映したモデルを含んだ django.apps.registry.Apps
のインスタンスであり、第二引数は SchemaEditor
のインスタンスです。
The reverse_code
argument is called when unapplying migrations. This
callable should undo what is done in the code
callable so that the
migration is reversible. If reverse_code
is None
(the default), the
RunPython
operation is irreversible.
オプションの hints
引数はルーティングの決定を補助するためにデータベースルータの allow_migrate()
メソッドに **hints
として渡されます。データベースのヒントに関しての詳細は Hints を参照してください。
オプションの elidable
引数はこの処理を マイグレーションの統合 を行った際に消去する(省略する)か否かを決定します。
You are advised to write the code as a separate function above the Migration
class in the migration file, and pass it to RunPython
. Here's an example of
using RunPython
to create some initial objects on a Country
model:
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 のモデル機構のスコープ範囲外(例えば triggers 等)で行うか、もしくはモデルの状態に変更を反映する処理に SeparateDatabaseAndState
を追加する事を心がけてください - そうでなければ、バージョン管理された ORM およびマイグレーションの自動検出機構が正常に動作しなくなります。
標準では RunPython
は DDL トランザクションをサポートしないデータベース(例えば MySQL と Oracle 等)上では通常のトランザクション内で記述された内容の処理を行います。この仕組みは安全ではありますが、これらのデータベースバックエンドを利用中に schema_editor
を利用しようとするとクラッシュを引き起こす場合が有ります;このような場合は、RunPython
に対して atomic=False
を渡してください。
トランザクション中の 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
操作が 非アトミックなマイグレーション の一部である場合、その操作は RunPython
操作に対して atomic=True
が渡されて生成されたトランザクション中においてのみ実行されます。
警告
RunPython
はモデルのデータベース接続を魔法のように切り替える事はしません;データベースのエイリアス(作成した関数の第二引数 schema_editor
内、 schema_editor.connection.alias
から利用可能)を指定していないモデルのメソッドはすべてデフォルトのデータベースを利用します。
RunPython.
noop
()¶指定された順序で処理を行いたくない場合は code
もしくは reverse_code
に RunPython.noop
メソッドを渡してください。この指定は処理を逆順で行いたい場合に特に有用です。
SeparateDatabaseAndState
¶SeparateDatabaseAndState
(database_operations=None, state_operations=None)¶データベース(スキーマ変更)と状態(自動検出機能)という2つの側面を混在させてマッチさせることができる、高度に専門化された操作です。
これは2つの操作のリストを受け入れます。状態への適用を求められたときは、 state_operations
リストを使用します(これは RunSQL
の state_operations
引数の一般化されたバージョンです)。データベースへの変更の適用を求められたときは、 database_operations
リストを使用します。
データベースの実際の状態と Django の状態のビューが同期しなくなると、マイグレーションフレームワークが壊れてしまい、データが失われることさえあります。じっくりと、データベースと状態の操作を慎重にチェックすべきです。データベースの操作をチェックするために、 sqlmigrate
と dbshell
を使うことができます。状態の操作をチェックするために makemigrations
、特に --dry-run
を使うことができます。
For an example using SeparateDatabaseAndState
, see
Changing a ManyToManyField to use a through model.
オペレーションは比較的シンプルな 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)
The migration_name_fragment
property was added.
You can take this template and work from it, though we suggest looking at the
built-in Django operations in django.db.migrations.operations
- they cover
a lot of the example usage of semi-internal aspects of the migration framework
like ProjectState
and the patterns used to get historical models, as well
as ModelState
and the patterns used to mutate historical models in
state_forwards()
.
いくつかの注意すべき点
You don't need to learn too much about ProjectState
to write migrations;
just know that it has an apps
property that gives access to an app
registry (which you can then call get_model
on).
database_forwards
and database_backwards
both get two states passed
to them; these represent the difference the state_forwards
method would
have applied, but are given to you for convenience and speed reasons.
If you want to work with model classes or model instances from the
from_state
argument in database_forwards()
or
database_backwards()
, you must render model states using the
clear_delayed_apps_cache()
method to make related models available:
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()
...
database_backwards メソッドにおける to_state
は 古い 状態を示します;そのため、その値はマイグレーションが状態を戻した場合は現在の状態となります。
内蔵されたオペレーションにおいて references_model
が実装されているのを見つけるかもしれません;これは独自のオペレーションのためでなく自動検知機構のコードの一部として存在しています。
警告
パフォーマンス上の理由から、ModelState.fields
内の Field
のインスタンスはマイグレーション間で再利用されます。これらのインスタンスの属性を決して変更してはいけません。state_forwards()
内のフィールドを変更したい場合は、ModelState.fields
から古いインスタンスを削除して新たなインスタンスと置き換える必要が有ります。ModelState.managers
内の Manager
のインスタンスについても同様です。
As an example, let's make an operation that loads PostgreSQL extensions (which contain some of PostgreSQL's more exciting features). Since there's no model state changes, all it does is run one command:
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
2022年6月01日