2017-11-19 12 views
0

다음 코드 샘플에서 Country.nameunique=True이므로 같은 이름의 두 국가가 만들어 졌기 때문에 session.commit()이 실패 할 것으로 예상됩니다.SQLAlchemy에서 고유 제한 위반 발견

from sqlalchemy import Column, Integer, String 
from sqlalchemy.ext.declarative import declarative_base 
from sqlalchemy import create_engine 
from sqlalchemy.orm import sessionmaker 


Base = declarative_base() 


class Country(Base): 
    __tablename__ = 'countries' 
    id = Column(Integer, primary_key=True, autoincrement=True) 
    name = Column(String(64), unique=True, nullable=False, index=True) 


engine = create_engine('sqlite:///countries_example.db') 
Base.metadata.create_all(engine) 
Base.metadata.bind = engine 
DBSession = sessionmaker(bind=engine) 
session = DBSession() 

malta1 = Country(name='Malta') 
malta2 = Country(name='Malta') 
session.add(malta1) 
session.add(malta2) 
session.commit() 

하지만 커밋이 잘 진행됩니다. 고유 제한 조건이 위반되었다는 것을 어떻게 발견합니까? 작성된 난 당신의 코드를 실행하면

+2

모델에'unique = True'를 추가하기 전에 DB를 만들었습니까? 그렇다면 DB 스키마를 다른 방법으로 마이그레이션해야합니다. –

답변

0

, 그것은 실패 않습니다

Traceback (most recent call last): 
    File "so4.py", line 26, in <module> 
    session.commit() 
    File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/sqlalchemy/orm/session.py", line 906, in commit 
    self.transaction.commit() 
    File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/sqlalchemy/orm/session.py", line 461, in commit 
    self._prepare_impl() 
    File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/sqlalchemy/orm/session.py", line 441, in _prepare_impl 
    self.session.flush() 
    File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/sqlalchemy/orm/session.py", line 2177, in flush 
    self._flush(objects) 
    File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/sqlalchemy/orm/session.py", line 2297, in _flush 
    transaction.rollback(_capture_exception=True) 
    File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/sqlalchemy/util/langhelpers.py", line 66, in __exit__ 
    compat.reraise(exc_type, exc_value, exc_tb) 
    File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/sqlalchemy/util/compat.py", line 187, in reraise 
    raise value 
    File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/sqlalchemy/orm/session.py", line 2261, in _flush 
    flush_context.execute() 
    File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/sqlalchemy/orm/unitofwork.py", line 389, in execute 
    rec.execute(self) 
    File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/sqlalchemy/orm/unitofwork.py", line 548, in execute 
    uow 
    File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/sqlalchemy/orm/persistence.py", line 181, in save_obj 
    mapper, table, insert) 
    File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/sqlalchemy/orm/persistence.py", line 835, in _emit_insert_statements 
    execute(statement, params) 
    File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/sqlalchemy/engine/base.py", line 945, in execute 
    return meth(self, multiparams, params) 
    File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/sqlalchemy/sql/elements.py", line 263, in _execute_on_connection 
    return connection._execute_clauseelement(self, multiparams, params) 
    File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/sqlalchemy/engine/base.py", line 1053, in _execute_clauseelement 
    compiled_sql, distilled_params 
    File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/sqlalchemy/engine/base.py", line 1189, in _execute_context 
    context) 
    File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/sqlalchemy/engine/base.py", line 1402, in _handle_dbapi_exception 
    exc_info 
    File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/sqlalchemy/util/compat.py", line 203, in raise_from_cause 
    reraise(type(exception), exception, tb=exc_tb, cause=cause) 
    File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/sqlalchemy/util/compat.py", line 186, in reraise 
    raise value.with_traceback(tb) 
    File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/sqlalchemy/engine/base.py", line 1182, in _execute_context 
    context) 
    File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/sqlalchemy/engine/default.py", line 470, in do_execute 
    cursor.execute(statement, parameters) 
sqlalchemy.exc.IntegrityError: (sqlite3.IntegrityError) UNIQUE constraint failed: countries.name [SQL: 'INSERT INTO countries (name) VALUES (?)'] [parameters: ('Malta',)] 

고유 제한 조건은 테이블, 반드시 모델의 일부입니다. 먼저 데이터베이스 생성을 실행하지 않고 코드를 실행하면 문제가 없습니다.

좀 더 복잡한 테이블의 경우, alembic과 같은 마이그레이션 도구를 사용하고 싶지만,이 작업을 수행 할 수 있습니다 (하나의 스크립트에서 수행 할 수 있지만 두 가지 작업 만 수행하면됩니다.) 즉하지 파이썬의 경우 간단한 미안 :.

from sqlalchemy import Column, Integer, String 
from sqlalchemy.ext.declarative import declarative_base 
from sqlalchemy import create_engine 
from sqlalchemy.orm import sessionmaker 


Base = declarative_base() 


class Country(Base): 
    __tablename__ = 'countries' 
    id = Column(Integer, primary_key=True, autoincrement=True) 
    name = Column(String(64), unique=True, nullable=False, index=True) 

class TempCountry(Base): 
    __tablename__ = 'temp_countries' 
    id = Column(Integer, primary_key=True, autoincrement=True) 
    name = Column(String(64), nullable=False, index=True) 

engine = create_engine('sqlite:///countries_example.db') 
Base.metadata.create_all(engine) 
Base.metadata.bind = engine 
DBSession = sessionmaker(bind=engine) 
session = DBSession() 

foreach country in session.query(Country).all(): 
    if len(session.query(TempCountry).filter_by(name=country.name).all()) == 0: 
     temp_country = TempCountry(id=country.id, name=country.name) 
     session.add(temp_country) 
     session.commit() 

Country.__table__.drop(engine) 
session.commit() 

당신은 ID를 전달할 필요가 없습니다

from sqlalchemy import Column, Integer, String 
from sqlalchemy.ext.declarative import declarative_base 
from sqlalchemy import create_engine 
from sqlalchemy.orm import sessionmaker 


Base = declarative_base() 


class Country(Base): 
    __tablename__ = 'countries' 
    id = Column(Integer, primary_key=True, autoincrement=True) 
    name = Column(String(64), unique=True, nullable=False, index=True) 

class TempCountry(Base): 
    __tablename__ = 'temp_countries' 
    id = Column(Integer, primary_key=True, autoincrement=True) 
    name = Column(String(64), nullable=False, index=True) 

engine = create_engine('sqlite:///countries_example.db') 
Base.metadata.create_all(engine) 
Base.metadata.bind = engine 
DBSession = sessionmaker(bind=engine) 
session = DBSession() 

foreach temp_country in session.query(TempCountry).all(): 
    country = Country(id=country.id, name=country.name) 
    session.add(country) 

session.commit() 

TempCountry.__table__.drop(engine) 
session.commit() 

다음,하지만 당신은 당신이 어떤 이유를 계속해야 할 경우에도, 기억 테이블을 떨어 뜨리기 전에 커밋하거나 제대로 작동하지 않습니다.