db.migrations.operations.RunPython

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).

doc_Django
2016-10-09 18:35:10
Comments
Leave a Comment

Please login to continue.