Boccetta di errore di migrazione Alembic
-
21-12-2019 - |
Domanda
Sto facendo un blog di prova usando la guida trovata qui . È abbastanza completo. Tuttavia, sto avendo problemi con le migrazioni Alembic. Posso cancellare tutte le versioni e fai girare un nuovo database con tutte le colonne bene. Ma quando aggiungo una nuova colonna ho problemi. Ecco il codice nel mio models.py
:
models.py
....
class Person(db.Model):
__tablename__ = 'person'
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(100), unique=True)
pwdhash = db.Column(db.String(100))
name = db.Column(db.String(100), unique=True)
def __init__(self, email, name, password):
self.email = email
self.name = name.title()
self.set_password(password)
def __repr__(self):
return '<User %r>' % (self.name)
def set_password(self, password):
self.pwdhash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.pwdhash, password)
@classmethod
def all(cls):
return Person.query.all()
class Category(db.Model):
__tablename__ = 'category'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), unique=True)
description = db.Column(db.Text)
def __unicode__(self):
return self.name
class Article(db.Model):
__tablename__ = 'articles'
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(100))
body = db.Column(db.Text)
created = db.Column(db.DateTime, default=datetime.datetime.now)
category_name = db.Column(db.String(10), db.ForeignKey(Category.name))
category = db.relationship(Category)
person_name = db.Column(db.String(100), db.ForeignKey(Person.name, onupdate="CASCADE", ondelete="CASCADE"))
person = db.relationship(Person)
@property
def slug(self):
return urlify(self.title)
@classmethod
def all(cls):
return Article.query.order_by(desc(Article.created)).all()
@classmethod
def find_by_category(cls, category):
return Article.query.filter(Article.category_name == category).all()
.
È tutto grazioso. Tuttavia, se dovessi aggiungere una colonna casuale alla mia tabella di persone, come questa:
class Person(db.Model):
....
random_column = db.Column(db.Integer())
.
Quindi eseguire un python manage.py db migrate
(che funziona bene), quindi eseguire un python manage.py db upgrade
, quindi ottengo il seguente errore:
Traceback (most recent call last):
File "manage.py", line 7, in <module>
manager.run()
File "/Library/Python/2.7/site-packages/flask_script/__init__.py", line 397, in run
result = self.handle(sys.argv[0], sys.argv[1:])
File "/Library/Python/2.7/site-packages/flask_script/__init__.py", line 376, in handle
return handle(app, *positional_args, **kwargs)
File "/Library/Python/2.7/site-packages/flask_script/commands.py", line 145, in handle
return self.run(*args, **kwargs)
File "/Library/Python/2.7/site-packages/flask_migrate/__init__.py", line 82, in upgrade
command.upgrade(config, revision, sql = sql, tag = tag)
File "/Library/Python/2.7/site-packages/alembic/command.py", line 124, in upgrade
script.run_env()
File "/Library/Python/2.7/site-packages/alembic/script.py", line 199, in run_env
util.load_python_file(self.dir, 'env.py')
File "/Library/Python/2.7/site-packages/alembic/util.py", line 198, in load_python_file
module = load_module(module_id, path)
File "/Library/Python/2.7/site-packages/alembic/compat.py", line 55, in load_module
mod = imp.load_source(module_id, path, fp)
File "migrations/env.py", line 72, in <module>
run_migrations_online()
File "migrations/env.py", line 65, in run_migrations_online
context.run_migrations()
File "<string>", line 7, in run_migrations
File "/Library/Python/2.7/site-packages/alembic/environment.py", line 652, in run_migrations
self.get_context().run_migrations(**kw)
File "/Library/Python/2.7/site-packages/alembic/migration.py", line 225, in run_migrations
change(**kw)
File "migrations/versions/4171a9f6ed2a_.py", line 19, in upgrade
op.drop_index('category_name_key', 'category')
File "<string>", line 7, in drop_index
File "<string>", line 1, in <lambda>
File "/Library/Python/2.7/site-packages/alembic/util.py", line 293, in go
return fn(*arg, **kw)
File "/Library/Python/2.7/site-packages/alembic/operations.py", line 716, in drop_index
self._index(name, table_name, ['x'], schema=schema)
File "/Library/Python/2.7/site-packages/alembic/ddl/impl.py", line 164, in drop_index
self._exec(schema.DropIndex(index))
File "/Library/Python/2.7/site-packages/alembic/ddl/impl.py", line 76, in _exec
conn.execute(construct, *multiparams, **params)
File "/Library/Python/2.7/site-packages/sqlalchemy/engine/base.py", line 662, in execute
params)
File "/Library/Python/2.7/site-packages/sqlalchemy/engine/base.py", line 720, in _execute_ddl
compiled
File "/Library/Python/2.7/site-packages/sqlalchemy/engine/base.py", line 874, in _execute_context
context)
File "/Library/Python/2.7/site-packages/sqlalchemy/engine/base.py", line 1024, in _handle_dbapi_exception
exc_info
File "/Library/Python/2.7/site-packages/sqlalchemy/util/compat.py", line 196, in raise_from_cause
reraise(type(exception), exception, tb=exc_tb)
File "/Library/Python/2.7/site-packages/sqlalchemy/engine/base.py", line 867, in _execute_context
context)
File "/Library/Python/2.7/site-packages/sqlalchemy/engine/default.py", line 324, in do_execute
cursor.execute(statement, parameters)
sqlalchemy.exc.InternalError: (InternalError) cannot drop index category_name_key because constraint category_name_key on table category requires it
HINT: You can drop constraint category_name_key on table category instead.
'\nDROP INDEX category_name_key' {}
.
Non menziona nemmeno il nome della colonna che ho creato nello stacktrace, in modo che mi porta a credere che qualcosa non va con gli altri tavoli. Cita la caduta di un indice, ma non sto facendo nulla del genere nella migrazione, aggiungendo una colonna alla tabella People
. È qualcosa in Alembic, che non capisco?
Come ho detto che funziona perfettamente a trovare quando spingo un database nuovo di zecca e carichi nella configurazione. È solo quando faccio un cambiamento e cerco di migrare che Alembic mi lanta questi errori. Qualcuno ha idea del perché questo sta accadendo?
Modifica
Nel caso in cui le persone hanno bisogno di vedere il mio file config.py
:
config.py
import os
basedir = os.path.abspath(os.path.dirname(__file__))
#-----Config the app
SECRET_KEY = 'my_key'
CSRF_ENABLED = True
#-----Config Database
SQLALCHEMY_DATABASE_URI = 'postgresql://username:changeme@localhost/test'
SQLALCHEMY_COMMIT_ON_TEARDOWN = True
SQLALCHEMY_MIGRATE_REPO = os.path.join(basedir, 'db_repository')
#-----Config Upload folder
UPLOAD_FOLDER = os.path.realpath('./snb/static') + '/uploads'
. Soluzione
ho seguito il link al documento < / a> sul pallone-migrazione per vedere come sta usando Alembic, e dice:
.Il comando Migrat aggiunge un nuovo script di migrazione. Dovresti rivederlo e modificalo per essere accurato, poiché Alembic non può rilevare tutte le modifiche Fai dei tuoi modelli. In particolare non rileva gli indici, quindi Quelli devono essere aggiunti manualmente allo script.
La migrazione del pallone utilizza una funzionalità di Alembic denominata "autogenerato", in cui tenta di confrontare lo stato del database con i tuoi modelli e creare automaticamente un diff.
Usiamo direttamente Alembic, e ho trovato autogenerato davvero conveniente, ma devo modificarlo a mano molto, specialmente quando hai a che fare con indici e vincoli.
Quindi la mia soluzione sarebbe quella di fare ciò che dice e modifica il file di migrazione a mano e rimuovi le linee che non si desidera o sono spurie.