2014-12-13 4 views
6

나는 영약 SQLAlchemy도, 증류기과 래퍼 플라스크에 (플라스크-SQLAlchemy의와 플라스 크 - 마이그레이션)와 프로젝트에서 일하고 있어요. 나는 네 마이그레이션이 : 나는 새로운 깨끗한 데이터베이스를 시작하고 내가 오류를 얻을 마이그레이션을 실행하려고Flask-Migrate가 2 단계 마이그레이션을 수행하는 이유는 무엇입니까?

1c5f54d4aa34 -> 4250dfa822a4 (head), Feed: Countries 
312c1d408043 -> 1c5f54d4aa34, Feed: Continents 
41984a51dbb2 -> 312c1d408043, Basic Structure 
<base> -> 41984a51dbb2, Init Alembic 

:

[email protected]:/vagrant$ python manage.py db upgrade 
... 
sqlalchemy.exc.ProgrammingError: (ProgrammingError) relation "continent" does not exist 
... 

내가 플라스크-마이그레이션은 모든 마이그레이션을 실행하도록 요구하는 경우에 있지만, 마지막으로 작동합니다. 그 후 나는 다시 업그레이드 명령을 실행하면 작동 - 즉, 완전히 코드에서 하나의 변화없이 내 데이터베이스를 업그레이드 :

[email protected]:/vagrant$ python manage.py db upgrade 312c1d408043 
INFO [alembic.migration] Context impl PostgresqlImpl. 
INFO [alembic.migration] Will assume transactional DDL. 
INFO [alembic.migration] Running upgrade -> 41984a51dbb2, Init Alembic 
INFO [alembic.migration] Running upgrade 41984a51dbb2 -> 312c1d408043, Basic Structure 

[email protected]:/vagrant$ python manage.py db upgrade 
INFO [alembic.migration] Context impl PostgresqlImpl. 
INFO [alembic.migration] Will assume transactional DDL. 
INFO [alembic.migration] Running upgrade 312c1d408043 -> 1c5f54d4aa34, Feed: Continents 
INFO [alembic.migration] Running upgrade 1c5f54d4aa34 -> 4250dfa822a4, Feed: Countries 

TL; DR

마지막으로 마이그레이션 (피드 : 국가)는 이전 피드 (Feed : Continents)가 제공 한 테이블에서 쿼리를 실행합니다. 대륙 테이블을 만들고 먹이면 스크립트가 작동해야합니다. 그러나 그렇지 않습니다. 다른 명령으로 다시 시작하려면 그 사이에 마이그레이션 프로세스를 중지해야하는 이유는 무엇입니까? 나는 정말로 이것을 얻지 못한다. Alembic이 일련의 이주 후에 실행하는 명령인가? 어떤 아이디어?

내 모델로 정의됩니다 이런 경우에

은 다음과 같습니다

class Country(db.Model): 

    __tablename__ = 'country' 
    id = db.Column(db.Integer, primary_key=True) 
    alpha2 = db.Column(db.String(2), index=True, unique=True) 
    title = db.Column(db.String(140)) 
    continent_id = db.Column(db.Integer, db.ForeignKey('continent.id')) 
    continent = db.relationship('Continent', backref='countries') 

    def __repr__(self): 
     return '<Country #{}: {}>'.format(self.id, self.title) 

class Continent(db.Model): 

    __tablename__ = 'continent' 
    id = db.Column(db.Integer, primary_key=True) 
    alpha2 = db.Column(db.String(2), index=True, unique=True) 
    title = db.Column(db.String(140)) 

    def __repr__(self): 
     return '<Continent #{}: {}>'.format(self.id, self.title) 

많은 감사,

UPDATE 1 : 마지막 두 마이그레이션의 업그레이드 방법을

@Miguel이 의견에서 묻는대로, 여기에 업그레이드가 있습니다. 마지막 두 마이그레이션 ethods :

피드 : 대륙

def upgrade(): 
    csv_path = app.config['BASEDIR'].child('migrations', 'csv', 'en') 
    csv_file = csv_path.child('continents.csv') 
    with open(csv_file) as file_handler: 
     csv = list(reader(file_handler)) 
     csv.pop(0) 
     data = [{'alpha2': c[0].lower(), 'title': c[1]} for c in csv] 
     op.bulk_insert(Continent.__table__, data) 

피드 :

def upgrade(): 

    # load countries iso3166.csv and build a dictionary 
    csv_path = app.config['BASEDIR'].child('migrations', 'csv', 'en') 
    csv_file = csv_path.child('iso3166.csv') 
    countries = dict() 
    with open(csv_file) as file_handler: 
     csv = list(reader(file_handler)) 
     for c in csv: 
      countries[c[0]] = c[1] 

    # load countries-continents from country_continent.csv 
    csv_file = csv_path.child('country_continent.csv') 
    with open(csv_file) as file_handler: 
     csv = list(reader(file_handler)) 
     country_continent = [{'country': c[0], 'continent': c[1]} for c in csv] 

    # loop 
    data = list() 
    for item in country_continent: 

     # get continent id 
     continent_guess = item['continent'].lower() 
     continent = Continent.query.filter_by(alpha2=continent_guess).first() 

     # include country 
     if continent is not None: 
      country_name = countries.get(item['country'], False) 
      if country_name: 
       data.append({'alpha2': item['country'].lower(), 
          'title': country_name, 
          'continent_id': continent.id}) 

csv로 I (마지막 마이그레이션에 공급 된 테이블에 따라 다름) 나라 기본적으로이 패턴을 따르고 있습니다 :

con tinents.csv

... 
AS, "Asia" 
EU, "Europe" 
NA, "North America" 
... 

iso3166.csv

... 
CL,"Chile" 
CM,"Cameroon" 
CN,"China" 
... 

_country_continent.csv_

... 
US,NA 
UY,SA 
UZ,AS 
... 

그래서 피드 : 대륙 대륙 테이블을 공급하고, 피드 : 국가 국가 표를 먹인다. 그러나 그것은 대륙 테이블을 쿼리하여 대륙과의 적절한 연결 고리를 만들어야합니다.

UPDATE 2 : 레딧의 일부 사람은 이미 설명과

내가 the same question on Reddit 물었다 해결 방법을 제공하고, themathemagician는 말했다 : 레딧에 @themathemagician에 의해 표시된 바와 같이

I've run into this before, and the issue is that the migrations don't execute individually, but instead alembic batches all of them (or all of them that need to be run) and then executes the SQL. This means that by the time the last migration is trying to run, the tables don't actually exist yet so you can't actually make queries. Doing

from alembic import op 

def upgrade(): 
    #migration stuff 
    op.execute('COMMIT') 
    #run queries 

This isn't the most elegant solution (and that was for Postgres, the command may be different for other dbs), but it worked for me. Also, this isn't actually an issue with Flask-Migrate as much as an issue with alembic, so if you want to Google for more info, search for alembic. Flask-Migrate is just a wrapper around alembic that works with Flask-Script easily.

+1

마지막 두 번의 마이그레이션 중'upgrade()'메소드를 추가 할 수 있습니까? – Miguel

+0

@Miguel, 감사합니다. 방금 게시물을 편집하고 메소드를 추가했습니다. BTW, [다른 곳] (https://github.com/cuducos/whiskyton#thanks) 나는 당신에게 "고맙다"고 말했지만 어쩌면 당신은 그것을 보지 못했을 것입니다 - 그래서, 다시 한 번 더 공유하겠습니다 ... – cuducos

답변

8

, 증류기 기본적으로 단일 트랜잭션에서 모든 마이그레이션을 실행하므로 데이터베이스 엔진 및 마이그레이션 스크립트에서 수행하는 작업에 따라 이전 마이그레이션에서 추가 된 작업에 따라 일부 작업이 실패 할 수 있습니다.

나는 이것을 직접 사용해 보지 않았지만, Alembic 0.6.5는 이것을 설명 할 수있는 transaction_per_migration 옵션을 선보였다. 이 옵션은 configure() 전화에서 env.py으로 전화를 거는 옵션입니다.

def run_migrations_online(): 
    """Run migrations in 'online' mode. 

    # ... 
    context.configure(
       connection=connection, 
       target_metadata=target_metadata, 
       transaction_per_migration=True  # <-- add this 
       ) 
    # ... 

은 또한 당신이 오프라인 마이그레이션을 실행하려는 경우가 configure() 전화를 고칠 필요가 있습니다 : 플라스크-마이그레이션이 그들을 생성으로 기본 설정 파일을 사용하는 경우 migrations/env.py에서이 문제를 해결할 경우, 다음이있다 run_migrations_offline()에서도 마찬가지입니다.

문제를 해결하려면 알려주세요.

+0

Yay ! 그게 효과가있어, 미구엘! 많은 감사합니다, – cuducos