sirven que para migrations migraciones manage las borrar app django django-migrations

que - Migraciones de Django usando RunPython para confirmar cambios



para que sirven las migraciones en django (2)

Quiero modificar una clave foránea en uno de mis modelos que actualmente puede tener valores NULL para que no puedan ser nulos

makemigrations el null=True de mi campo y corrí makemigrations

Debido a que estoy alterando una tabla que ya tiene filas que contienen valores NULL en ese campo, se me pide que proporcione un valor único de inmediato o edite el archivo de migración y agregue una operación RunPython .

Mi operación RunPython aparece ANTES de la operación AlterField y realiza la actualización necesaria para este campo, por lo que no contiene valores NULL (solo las filas que ya contienen un valor NULL).

Pero, la migración aún falla con este error: django.db.utils.OperationalError: cannot ALTER TABLE "my_app_site" because it has pending trigger events

Aquí está mi código:

# -*- coding: utf-8 -*- from __future__ import unicode_literals from django.db import models, migrations def add_default_template(apps, schema_editor): Template = apps.get_model("my_app", "Template") Site = apps.get_model("my_app", "Site") accept_reject_template = Template.objects.get(name="Accept/Reject") Site.objects.filter(template=None).update(template=accept_reject_template) class Migration(migrations.Migration): dependencies = [ (''my_app'', ''0021_auto_20150210_1008''), ] operations = [ migrations.RunPython(add_default_template), migrations.AlterField( model_name=''site'', name=''template'', field=models.ForeignKey(to=''my_app.Template''), preserve_default=False, ), ]

Si entiendo correctamente, este error puede ocurrir cuando se modifica un campo para que no sea anulable, pero el campo contiene valores nulos. En ese caso, la única razón por la que puedo pensar por qué sucede esto es porque la transacción de la operación RunPython no " RunPython " los cambios en la base de datos antes de ejecutar AlterField .

Si esta es la razón, ¿cómo puedo asegurarme de que los cambios se reflejen en la base de datos? Si no, ¿cuál puede ser la razón del error?

¡Gracias!


Esto sucede porque Django crea restricciones como DEFERRABLE INITIALLY DEFERRED :

ALTER TABLE my_app_site ADD CONSTRAINT "[constraint_name]" FOREIGN KEY (template_id) REFERENCES my_app_template(id) DEFERRABLE INITIALLY DEFERRED;

Esto le dice a PostgreSQL que la clave foránea no necesita ser verificada justo después de cada comando, pero puede ser diferida hasta el final de las transacciones.

Entonces, cuando una transacción modifica el contenido y la estructura, las restricciones se verifican en paralelo con los cambios en la estructura, o las verificaciones se programan para que se realicen después de modificar la estructura. Ambos estados son malos y la base de datos abortará la transacción en lugar de hacer suposiciones.

Puede instruir a PostgreSQL para que compruebe las restricciones inmediatamente en la transacción actual llamando a SET CONSTRAINTS ALL IMMEDIATE , por lo que los cambios en la estructura no serán un problema (consulte la documentación de SET CONSTRAINTS ). Tu migración debe verse así:

operations = [ migrations.RunSQL(''SET CONSTRAINTS ALL IMMEDIATE'', reverse_sql=migrations.RunSQL.noop), # ... the actual migration operations here ... migrations.RunSQL(migrations.RunSQL.noop, reverse_sql=''SET CONSTRAINTS ALL IMMEDIATE''), ]

La primera operación es para aplicar migraciones (hacia adelante) y la última para migraciones no aplicadas (hacia atrás).

EDITAR: el aplazamiento de restricciones es útil para evitar la ordenación por inserción, especialmente para tablas de auto-referenciación y tablas con dependencias cíclicas. Así que ten cuidado al doblar Django.

LATE EDIT: en Django 1.7 y versiones más recientes hay una operación especial SeparateDatabaseAndState que permite cambios de datos y cambios de estructura en la misma migración. Intente usar esta operación antes de recurrir al método anterior "establecer restricciones todo inmediato". Ejemplo:

operations = [ migrations.SeparateDatabaseAndState(database_operations=[ # put your sql, python, whatever data migrations here ], state_operations=[ # field/model changes goes here ]), ]


Sí, diría que son los límites de la transacción los que impiden que se confirme el cambio de datos en su migración antes de ejecutar ALTER.

Haría lo que @danielcorreia dice y lo implemento como dos migraciones, ya que parece que incluso el SchemaEditor está vinculado por las transacciones, a través del administrador de contexto que estaría obligado a usar.