class RunPython(code, reverse_code=None, atomic=None, hints=None, elidable=False)
[source]
Runs custom Python code in a historical context. code
(and reverse_code
if supplied) should be callable objects that accept two arguments; the first is an instance of django.apps.registry.Apps
containing historical models that match the operation’s place in the project history, and the second is an instance of 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.
The optional hints
argument will be passed as **hints
to the allow_migrate()
method of database routers to assist them in making a routing decision. See Hints for more details on database hints.
The optional elidable
argument determines whether or not the operation will be removed (elided) when squashing migrations.
You are advised to write the code as a separate function above the Migration
class in the migration file, and just pass it to RunPython
. Here’s an example of using RunPython
to create some initial objects on a Country
model:
# -*- 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), ]
This is generally the operation you would use to create data migrations, run custom data updates and alterations, and anything else you need access to an ORM and/or Python code for.
If you’re upgrading from South, this is basically the South pattern as an operation - one or two methods for forwards and backwards, with an ORM and schema operations available. Most of the time, you should be able to translate the orm.Model
or orm["appname", "Model"]
references from South directly into apps.get_model("appname", "Model")
references here and leave most of the rest of the code unchanged for data migrations. However, apps
will only have references to models in the current app unless migrations in other apps are added to the migration’s dependencies.
Much like RunSQL
, ensure that if you change schema inside here you’re either doing it outside the scope of the Django model system (e.g. triggers) or that you use SeparateDatabaseAndState
to add in operations that will reflect your changes to the model state - otherwise, the versioned ORM and the autodetector will stop working correctly.
By default, RunPython
will run its contents inside a transaction on databases that do not support DDL transactions (for example, MySQL and Oracle). This should be safe, but may cause a crash if you attempt to use the schema_editor
provided on these backends; in this case, pass atomic=False
to the RunPython
operation.
On databases that do support DDL transactions (SQLite and PostgreSQL), RunPython
operations do not have any transactions automatically added besides the transactions created for each migration. Thus, on PostgreSQL, for example, you should avoid combining schema changes and RunPython
operations in the same migration or you may hit errors like OperationalError: cannot
ALTER TABLE "mytable" because it has pending trigger events
.
If you have a different database and aren’t sure if it supports DDL transactions, check the django.db.connection.features.can_rollback_ddl
attribute.
If the RunPython
operation is part of a non-atomic migration, the operation will only be executed in a transaction if atomic=True
is passed to the RunPython
operation.
Warning
RunPython
does not magically alter the connection of the models for you; any model methods you call will go to the default database unless you give them the current database alias (available from schema_editor.connection.alias
, where schema_editor
is the second argument to your function).
Please login to continue.