2013-08-01 2 views
0

나는 포인트와 개체의 개념을 가진 데이터베이스를 가지고 있습니다. 객체는 일대일 관계에서 단일 지점과 연관됩니다. 고유성 제약 조건을 적용한 개체는 한 번에 하나의 개체에만 연결할 수 있습니다.존재하지 않는 레코드에 대한 참조를 허용하는 SQLAlchemey의 복합 외래 키

그러나 저는 항상 객체가 존재할 수있는 점에만 연관 될 수 있다고 말하고 싶지만 그 목표를 달성하는 방법을보기 위해 고심하고 있습니다.

내가 더 설명하기 전에

, 여기에 내가 가진 몇 가지 테스트 코드 :
import sqlalchemy as sql 
import sqlalchemy.orm as sqlorm 
import sqlalchemy.ext.declarative 
import os 

debug = True 
db_file = "/".join([os.getcwd() if __name__ == "__main__" else os.path.dirname(__file__), 'sqlite.db']) 

engine_opts = { 
    'echo': debug 
} 

engine = sql.create_engine('sqlite:///{}'.format(db_file), **engine_opts) 
Session = sqlorm.sessionmaker(bind=engine) 

Base = sqlalchemy.ext.declarative.declarative_base() 


class Point(Base): 
    __tablename__ = 'point' 
    x = sql.Column(sql.Integer, primary_key=True, nullable=False) 
    y = sql.Column(sql.Integer, primary_key=True, nullable=False) 

    def __repr__(self): 
     return self.__str__() 

    def __str__(self): 
     return "({x},{y})".format(x=self.x, y=self.y) 

    def __unicode__(self): 
     return self.__str__() 


class Obj(Base): 
    __tablename__ = 'obj' 
    id = sql.Column(sql.Integer, primary_key=True) 
    x = sql.Column(sql.Integer) 
    y = sql.Column(sql.Integer) 

    __table_args__ = (
     sql.ForeignKeyConstraint([x, y], [Point.x, Point.y]), 
     sql.UniqueConstraint(x, y, name='obj_coords'), 
    ) 
    point = sqlorm.relationship("Point", backref=sqlorm.backref('obj', uselist=False)) 


def init_db(): 
    Base.metadata.create_all(engine) 
    session = Session() 

    min_val = 0 
    max_val = 20 

    for x in range(min_val, max_val): 
     for y in range(min_val, max_val): 
      session.add(Point(x=x, y=y)) 
    session.commit() 

    session.add(Obj(x=0, y=0)) 
    session.add(Obj(x=10, y= 10)) 
    session.add(Obj(x=-1, y=-1)) 

    session.commit() 
    session.close() 


def reinit_db(): 
    Base.metadata.drop_all(engine) 
    init_db() 


if __name__ == "__main__": 
    reinit_db() 

내가 Point을위한 복합 기본 키가를, 나는 외래 키로 Objxy을 사용하고 싶습니다 .

backref 작품과 고유성 제약 조건에는 2 OBJS가 같은 지점을 차지할 수 있다는 것을 의미합니다,하지만 내 테스트 코드는 제가 원하는 때 존재하지 않는 Point (-1, -1)이 될하기에 Obj을 만들 수 있습니다 예방.

달성이 가능합니까? 어떻게해야합니까?

답변

1

데모 목적으로 만 SQLite를 실제로 사용하는 경우 문제는 현재 기본적으로 외래 키 제약 조건을 적용하지 않는 것입니다 (그리고 3.6.19 이전에는 외래 키 제약 조건을 적용하지 않았습니다). 거래를 시작하기 전에 PRAGMA foreign_keys=ON을 실행해야합니다. 필요에 따라, 그런 다음 프로그램을 실행

import sqlalchemy.event as sqlevent 

# ... 

engine = sql.create_engine('sqlite:///{0}'.format(db_file), **engine_opts) 
sqlevent.listen(engine, 'connect', 
    lambda conn, rec: conn.execute('PRAGMA foreign_keys=ON;')) 

무결성 오류가 발생합니다 : SQLAlchemy의에서이 이벤트 시스템을 사용하여 구현 될 수있다이 오류 만 높이에서 발생

sqlalchemy.exc.IntegrityError: (IntegrityError) 
foreign key constraint failed u'INSERT INTO obj (x, y) VALUES (?, ?)' (-1, -1) 

하는 것으로/커밋 시간 : 그것을 SQLAlchemy는 데이터베이스 엔진에 의해보고되고, SQLAlchemy는 당신이 잘못된 객체를 생성했다는 것을 알 수 없다. 파이썬 측에서 FK를 추적하지 않는다.

+0

그걸 정리하면 완벽 해! 그리고 네, 편의상 SQLite를 개발 중입니다. 비록이게 딱 맞으면 편리 할까? – chrisbunney