Los archivos de migración están compuestos por uno o más Operations, objetos que declaran lo que la migración debe hacer con tu base de datos.
Django utiliza también estos objetos Operation para determinar cómo se veían tus modelos históricamente y calcular los cambios realizados en tus modelos desde la última migración, por lo que puede escribir automáticamente las migraciones; eso es por qué son declarativos, ya que significa que Django puede cargarlos fácilmente en memoria y ejecutarlos sin tocar la base de datos para determinar cómo debería verse tu proyecto.
También hay operaciones Operation más especializadas para cosas como las migraciones de datos y para manipulaciones avanzadas de la base de datos. Puedes escribir también tus propias clases Operation si quieres encapsular un cambio personalizado que realizas comúnmente.
Si necesitas un archivo de migración vacío para escribir tus propios objetos Operation, utiliza python manage.py makemigrations --empty yourappname, pero ten en cuenta que agregar operaciones que alteran la estructura de la base de datos manualmente puede confundir al autodetector de migraciones y hacer que los resultados de makemigrations generen código incorrecto.
Todas las operaciones de Django están disponibles en el módulo django.db.migrations.operations.
Para material introductorio, consulta la guía de temas sobre migraciones: migraciones.
CreateModel¶Crea un nuevo modelo en la historia del proyecto y una tabla correspondiente en la base de datos para que coincida con ella.
name es el nombre del modelo, tal como se escribiría en el archivo models.py.
fields es una lista de tuplas de 2 elementos de la forma (nombre_de_campo, instancia_de_campo). La instancia del campo debe ser un campo no vinculado (por lo tanto solo models.CharField(…), en lugar de un campo tomado de otro modelo).
opciones es un diccionario opcional de valores de la clase Meta del modelo.
bases es una lista opcional de otras clases que a esta modelo le permiten heredar; puede contener tanto objetos de clase como cadenas en el formato "appname.ModelName" si deseas depender de otra modelo (de modo que heredes de la versión histórica). Si no se proporciona, por defecto hereda de la estándar models.Model.
manejadores toma una lista de tuplas de 2 elementos de (nombre_del_manejador, instancia_del_manejador). El primer manejador en la lista será el manejador predeterminado para este modelo durante las migraciones.
Elimina el modelo del historial del proyecto y su tabla de la base de datos.
Renombra el modelo desde un antiguo nombre a uno nuevo.
You pueden tener que agregar esto manualmente si cambias el nombre del modelo y varios de sus campos a la vez; para el autodetector, esto parecerá que eliminaste un modelo con el antiguo nombre y agregaste uno nuevo con un nombre diferente, y la migración que crea perderá cualquier dato en la tabla antigua.
AlterModelTable¶Cambia el nombre de la tabla del modelo (la opción db_table en la subclase Meta).
AlterModelTableComment¶Cambia el comentario de la tabla del modelo (la opción db_table_comment en la subclase Meta).
AlterUniqueTogether¶Cambia el conjunto de restricciones únicas del modelo (la opción unique_together en la subclase Meta).
AlterIndexTogether¶Cambia el conjunto de índices personalizados del modelo (la opción index_together en la subclase Meta).
Advertencia
AlterIndexTogether solo está oficialmente soportado para archivos de migración pre-Django 4.2. Por razones de compatibilidad hacia atrás, sigue siendo parte de la API pública y no hay planes para deprecarlo o eliminarlo, pero no debe usarse en nuevas migraciones. Utiliza las operaciones AddIndex y RemoveIndex en su lugar.
AlterOrderWithRespectTo¶Crea o elimina la columna _order necesaria para la opción order_with_respect_to en la subclase Meta.
AlterModelOptions¶Almacena cambios en opciones de modelo misceláneas (configuraciones en la subclase Meta del modelo) como permissions y verbose_name. No afecta la base de datos, pero persiste estos cambios para que los instancias de RunPython puedan utilizarlos. options debe ser un diccionario que mapee nombres de opciones a valores.
AlterModelManagers¶Modifica los administradores disponibles durante las migraciones.
AddField¶Agrega un campo a un modelo. model_name es el nombre del modelo, name es el nombre del campo y field es una instancia no vinculada de Campo (la cosa que pondrías en la declaración de campos en models.py - por ejemplo, models.IntegerField(null=True)).
La argumento preserve_default indica si el valor predeterminado del campo es permanente y debe ser incluido en el estado del proyecto (True), o si es temporal y solo para esta migración (False) - generalmente porque la migración está agregando un campo no nulo a una tabla y necesita un valor por defecto para ponerlo en las filas existentes. No afecta el comportamiento de establecer valores predeterminados directamente en la base de datos - Django nunca establece valores predeterminados y siempre los aplica en el código ORM de Django.
Advertencia
En bases de datos antiguas, agregar un campo con un valor por defecto puede causar una reescritura completa de la tabla. Esto sucede incluso para campos nulos y puede tener un impacto negativo en el rendimiento. Para evitar eso, se deben seguir los siguientes pasos.
Añade el campo nulo sin valor por defecto y ejecuta el comando makemigrations. Esto debería generar una migración con una operación AddField.
Añada el valor por defecto a su campo y ejecute el comando makemigrations. Esto debería generar una migración con una operación AlterField.
RemoveField¶Elimina un campo de un modelo.
Ten en cuenta que cuando se invierte, esto es en realidad agregar un campo a un modelo. La operación es reversible (a excepción de cualquier pérdida de datos, que es irreversible) si el campo es nulo o si tiene un valor por defecto que puede usarse para poblar la columna recreada. Si el campo no es nulo y no tiene un valor por defecto, la operación es irreversible.
PostgreSQL
RemoveField también eliminará cualquier objeto de base de datos adicional relacionado con el campo eliminado (como vistas, por ejemplo). Esto se debe a que la sentencia DROP COLUMN resultante incluirá la cláusula CASCADE para asegurar que los objetos dependientes fuera de la tabla también sean eliminados.
AlterField¶Modifica la definición de un campo, incluyendo cambios en su tipo, null, unique, db_column y otras atributos del campo.
El argumento preserve_default indica si el valor por defecto del campo es permanente y debe incluirse en el estado del proyecto (True), o si es temporal y solo para esta migración (False) - generalmente porque la migración está alterando un campo nulo a uno no nulo y necesita un valor por defecto para ponerlo en las filas existentes. No afecta el comportamiento de establecer valores por defecto directamente en la base de datos - Django nunca establece valores por defecto en la base de datos y siempre los aplica en el código ORM de Django.
Ten en cuenta que no todas las modificaciones son posibles en todas las bases de datos - por ejemplo, no se puede cambiar un campo de tipo texto como models.TextField() a un campo de tipo número como models.IntegerField() en la mayoría de las bases de datos.
RenameField¶Cambia el nombre del campo (y, a menos que se haya establecido db_column, su nombre de columna).
AddIndex¶Crea un índice en la tabla de base de datos para el modelo con model_name. index es una instancia de la clase Index.
RemoveIndex¶Elimina el índice llamado name del modelo con model_name.
RenameIndex¶Renombra un índice en la tabla de base de datos para el modelo con model_name. Exactamente uno de old_name y old_fields se puede proporcionar. old_fields es una iterable de las cadenas, a menudo correspondientes a campos de index_together (opción pre-Django 5.1).
En bases de datos que no admiten un statement de renombrado de índice (SQLite y MariaDB < 10.5.2), la operación eliminará e insertará el índice, lo que puede ser costoso.
AddConstraint¶Creates a restricción en la tabla de la base de datos para el modelo con model_name.
RemoveConstraint¶Elimina la restricción llamada name del modelo con model_name.
AlterConstraint¶Modifica la restricción llamada name del modelo con model_name con el nuevo constraint sin afectar la base de datos.
RunSQL¶Permite ejecutar SQL arbitrario en la base de datos - útil para características avanzadas de backends de bases de datos que Django no soporta directamente.
Los valores sql y reverse_sql, si se proporcionan, deben ser cadenas de SQL para ejecutar en la base de datos. En la mayoría de los backends de bases de datos (todos excepto PostgreSQL), Django dividirá el SQL en declaraciones individuales antes de ejecutarlas.
Advertencia
En PostgreSQL y SQLite, solo utilice BEGIN o COMMIT en su SQL en migraciones no atómicas, para evitar romper el estado de transacción de Django.
You también puedes pasar una lista de cadenas o 2-tuplas. El último es utilizado para pasar consultas y parámetros de la misma manera que :ref:`cursor.execute() <executing-custom-sql> `. Estos tres operaciones son equivalentes:
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"])])
Si deseas incluir signos porcentuales literales en la consulta, debes duplicarlos si estás pasando parámetros.
Las consultas reverse_sql se ejecutan cuando la migración es desaplicada. Deben deshacer lo que hace las consultas sql. Por ejemplo, para deshacer la inserción anterior con una eliminación:
migrations.RunSQL(
sql=[("INSERT INTO musician (name) VALUES (%s);", ["Reinhardt"])],
reverse_sql=[("DELETE FROM musician where name=%s;", ["Reinhardt"])],
)
Si reverse_sql es None (el valor por defecto), la operación RunSQL no es reversible.
El argumento state_operations permite suministrar operaciones equivalentes a las consultas SQL en términos de estado del proyecto. Por ejemplo, si estás creando manualmente una columna, debes pasar una lista conteniendo una operación AddField aquí para que el autodetector tenga un estado actualizado del modelo. Si no lo haces, cuando ejecutes makemigrations nuevamente, no verá ninguna operación que agregue esa columna y así tratará de volver a ejecutarla. Por ejemplo:
migrations.RunSQL(
"ALTER TABLE musician ADD COLUMN name varchar(255) NOT NULL;",
state_operations=[
migrations.AddField(
"musician",
"name",
models.CharField(max_length=255),
),
],
)
El argumento opcional hints se pasará como **hints al método allow_migrate() de los routers de bases de datos para ayudarlos en la toma de decisiones de routing. Consulta Indicaciones para obtener más detalles sobre las pista de base de datos.
El argumento opcional elidable determina si la operación se eliminará (se «elimina») cuando squashing migrations .
Pasa el atributo RunSQL.noop a sql o reverse_sql cuando desees que la operación no haga nada en la dirección dada. Esto es especialmente útil para hacer la operación reversible.
RunPython¶Ejecuta código Python personalizado en un contexto histórico. code (y reverse_code si se proporciona) deben ser objetos llamables que acepten dos argumentos; el primero es una instancia de django.apps.registry.Apps conteniendo modelos históricos que coincidan con la posición del operador en la historia del proyecto, y el segundo es una instancia de SchemaEditor.
La traducción de los textos es la siguiente:
El argumento opcional hints se pasará como **hints al método allow_migrate() de los routers de bases de datos para ayudarles a tomar una decisión de enrutamiento. Consulte Indicaciones para obtener más detalles sobre las pautas de base de datos.
El argumento opcional elidable determina si la operación se eliminará (se «elimina») cuando squashing migrations .
Se le recomienda escribir el código como una función separada encima de la clase Migration en el archivo de migración, y pasarla a RunPython''. Aquí tienes un ejemplo de cómo utilizar ``RunPython para crear algunos objetos iniciales en un modelo Country:
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),
]
Esto es generalmente la operación que usarías para crear migraciones de datos, ejecutar actualizaciones y alteraciones de datos personalizadas, y cualquier otra cosa a la que necesites acceso a un ORM y/o código Python.
Al igual que RunSQL, asegúrate de que si cambias el esquema aquí estás haciendolo fuera del alcance del sistema de modelos Django (por ejemplo, triggers) o que usas SeparateDatabaseAndState para agregar operaciones que reflejarán tus cambios en el estado del modelo - de lo contrario, la versión del ORM y el autodetector dejarán de funcionar correctamente.
Por defecto, RunPython ejecutará su contenido dentro de una transacción en bases de datos que no admiten transacciones DDL (por ejemplo, MySQL y Oracle). Esto debería ser seguro, pero puede causar un error si intentas usar el schema_editor proporcionado en estos backends; en este caso, pasa atomic=False a la operación RunPython.
En bases de datos que admiten transacciones DDL (SQLite y PostgreSQL), las operaciones RunPython no tienen ninguna transacción automáticamente agregada además de las transacciones creadas para cada migración. Por lo tanto, en PostgreSQL, por ejemplo, debes evitar combinar cambios de esquema y operaciones RunPython en la misma migración o podrías encontrar errores como OperationalError: cannot ALTER TABLE "mytable" because it has pending trigger events.
Si tienes una base de datos diferente y no estás seguro si admite transacciones DDL, verifica el atributo django.db.connection.features.can_rollback_ddl.
Si la operación RunPython es parte de una migración no-atómica, la operación solo se ejecutará en una transacción si se pasa atomic=True a la operación RunPython.
Advertencia
RunPython no altera mágicamente la conexión de los modelos para ti; cualquier método de modelo que llames irá a la base de datos por defecto a menos que les des el alias de base de datos actual (disponible desde schema_editor.connection.alias, donde schema_editor es el segundo argumento de tu función).
Una operación altamente especializada que te permite mezclar y combinar los aspectos de base de datos (cambios de esquema) y estado (autodetector) de las operaciones.
Acepta dos listas de operaciones. Cuando se le pide aplicar el estado, utilizará la lista state_operations (esta es una versión generalizada del argumento state_operations de RunSQL). Cuando se le pida aplicar cambios a la base de datos, utilizará la lista database_operations.
Si el estado real de la base de datos y la vista de Django del estado se desincronizan, esto puede romper el marco de migración, incluso provocando pérdidas de datos. Es recomendable ejercer precaución y revisar cuidadosamente las operaciones de base de datos y estado. Puedes utilizar sqlmigrate y dbshell para revisar las operaciones de base de datos. Puedes utilizar makemigrations, especialmente con la opción --dry-run , para revisar las operaciones de estado.
Para un ejemplo que utiliza SeparateDatabaseAndState, ver Cambiar un campo ManyToManyField para utilizar un modelo through.
Las operaciones tienen una API relativamente simple, y están diseñadas para que puedas escribir tus propias fácilmente para complementar las incorporadas en Django. La estructura básica de una Operation se parece a esto:
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
# This categorizes the operation. The corresponding symbol will be
# displayed by the makemigrations command.
category = OperationCategory.ADDITION
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.
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)
Puedes tomar este template y trabajar desde él, aunque sugerimos mirar las operaciones incorporadas en Django en django.db.migrations.operations - cubren un gran parte del uso de ejemplo de aspectos semi-internos del marco de migración como ProjectState y los patrones utilizados para obtener modelos históricos, así como ModelState y los patrones utilizados para mutar modelos históricos en state_forwards().
Algunas cosas a tener en cuenta:
No necesitas aprender demasiado sobre ProjectState para escribir migraciones; solo conoce que tiene una propiedad apps que te da acceso a un registro de aplicaciones (que puedes llamar luego get_model).
database_forwards y database_backwards reciben ambos dos estados pasados a ellos; estos representan la diferencia que el método state_forwards habría aplicado, pero se les da a ti por conveniencia y razones de velocidad.
Si deseas trabajar con clases de modelos o instancias de modelos desde el argumento from_state en database_forwards() o database_backwards(), debes renderizar los estados de modelo utilizando el método clear_delayed_apps_cache() para hacer disponibles los modelos relacionados:
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()
...
El parámetro to_state en el método database_backwards es el estado más antiguo; es decir, el que será el estado actual una vez que la migración haya terminado de revertirse.
Puede ver implementaciones de references_model en las operaciones incorporadas; esto forma parte del código de detección automática y no importa para las operaciones personalizadas.
Advertencia
Por razones de rendimiento, los instancias de Field en ModelState.fields se reutilizan entre migraciones. Nunca debes cambiar los atributos en estas instancias. Si necesitas mutar un campo en state_forwards(), debes eliminar la instancia antigua de ModelState.fields y agregar una nueva instancia en su lugar. Lo mismo es cierto para las instancias de Manager en ModelState.managers.
Como ejemplo, vamos a crear una operación que carga extensiones de PostgreSQL (que contienen algunas de las características más emocionantes de PostgreSQL). Dado que no hay cambios en los estados de modelo, solo ejecuta un comando:
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
may 31, 2026