web-dev-qa-db-fra.com

Alembic: IntegrityError: "la colonne contient des valeurs null" lors de l'ajout d'une colonne non nullable

J'ajoute une colonne à une table existante. Cette nouvelle colonne est nullable=False.

op.add_column('mytable', sa.Column('mycolumn', sa.String(), nullable=False))

Lorsque je lance la migration, il se plaint:

sqlalchemy.exc.IntegrityError: column "mycolumn" contains null values
30
Ron

C’est parce que vos données existantes n’ont aucune valeur pour cette nouvelle colonne, c’est-à-dire null. Causant ainsi ladite erreur. Lorsque vous ajoutez une colonne non Nullable, vous devez décider quelle valeur attribuer aux données existantes.


Bon, les données existantes devraient alors avoir "lorem ipsum" pour cette nouvelle colonne. Mais comment je le fais? Je ne peux pas mettre à jour parce que la colonne n'est pas encore là.

Utilisez le server_default arg:

op.add_column('mytable', sa.Column(
    'mycolumn', 
    sa.String(), 
    nullable=False, 
    server_default='lorem ipsum', #  <---  add this
))

Mais, mais je ne veux pas qu'il ait la valeur par défaut

Déposez-le ensuite en utilisant op.alter_column('mytable', 'mycolumn', server_default=None)

Par exemple. Votre fonction upgrade() serait:

def upgrade():
    op.add_column('mytable', sa.Column('mycolumn', sa.String(), nullable=False, server_default='lorem ipsum'))
    op.alter_column('mytable', 'mycolumn', server_default=None)
53
Ron

Une alternative à la réponse de @ Ron est de faire le contraire et de modifier les données avant ajouter la contrainte:

def upgrade():
    op.add_column('my_table', sa.Column('my_column', sa.String()))
    op.execute('UPDATE my_table SET my_column=my_other_column')
    op.alter_column('my_table', 'my_column', nullable=False)

Cela semble plus propre et plus puissant pour moi, mais vous écrivez SQL :-).

22
Antoine Lizée

Cela vous indique - à juste titre - qu'il existe (ou existera) des valeurs NULL existantes dans la base de données pour cette colonne. La réponse consiste à modifier le fichier de migration pour mettre à jour la colonne avant de modifier la définition de la colonne:

from sqlalchemy.sql import table, column

def upgrade():
    op.add_column('role', sa.Column('role_name', sa.String(length=30), nullable=True))
    role = table('role', column('role_name'))       
    op.execute(role.update().values(role_name=''))       
    op.alter_column('role', 'role_name', nullable=False)       
0
Arjunsingh