2015-12-24 35 views
1

我想在我的數據庫(postgresql)中的兩個表之間建立一對一的關係。我在Python中使用SQLAlchemy。所以,我使用了文檔中給出的示例。 one-to-one relationshipSQLAlchemy一對一的關係創建多行

from sqlalchemy import Column, ForeignKey, Integer, String, Date, Float 
from sqlalchemy import create_engine 
from sqlalchemy.ext.declarative import declarative_base 
from sqlalchemy.orm import relationship 

Base = declarative_base() 

class Parent(Base): 
    __tablename__ = 'parent' 
    id = Column(Integer, primary_key=True) 
    child = relationship("Child", uselist=False, back_populates="parent") 

class Child(Base): 
    __tablename__ = 'child' 
    id = Column(Integer, primary_key=True) 
    parent_id = Column(Integer, ForeignKey('parent.id')) 
    parent = relationship("Parent", back_populates="child" 

engine = create_engine('postgresql+psycopg2://testdb:[email protected]/fullstack') 
Base.metadata.create_all(engine) 

這創建了兩個表父和子。 現在我插入值父表和子表

from sqlalchemy import create_engine 
from sqlalchemy.orm import sessionmaker 
from test_databasesetup import Base, Parent, Child 

engine = create_engine('postgresql+psycopg2://testdb:[email protected]/fullstack') 
Base.metadata.bind = engine 
DBSession = sessionmaker(bind=engine) 
session = DBSession() 

parent = Parent() 
session.add(parent) 
session.commit() // insert in 'parent' table with id=1 
// insert into child 
child = Child(parent_id=1) 
session.add(child) 
session.commit() 

child = Child(parent_id=1) 
session.add(child) 
session.commit() 

與同PARENT_ID再次插入孩子應該扔了一個錯誤,但記錄得到插入。

id | parent_id 
----+----------- 
    1 |   1 
    2 |   1 

這裏應該做些什麼,以便我只能插入一個對應於父ID的子對象。我不想讓孩子擁有相同的parent_id。

謝謝。

回答

1

問題是你直接指定字段parent_id。在這種情況下,sqlalchemy沒有機會驗證關係爲one-to-one。相反,請使用以下關係:

# add new parent to the database 
parent = Parent() 
session.add(parent) 
session.commit() 

# insert new child for this parent 
child = Child(parent=parent) # @note: this is the code change. \ 
# Here we refer to parent, not parent_id field 
session.add(child) 
session.commit() 

# insert another child for the same parent: 
# this will assign this new child to the parent, and will 
# *remove* previous child from this parent 
child = Child(parent=parent) 
session.add(child) 
session.commit() 

另一個副作用是更乾淨的代碼。然而,另外一個是,sqlalchemy可以找出外鍵本身,你不需要知道對象的id

parent = Parent() 
child = Child(parent=parent) 
# it is enough to add only one related object, and the other (Child) will be added to session automatically 
session.add(parent) 
# we can commit only now, when we finished working on all the objects in the current session/transaction 
session.commit() 

此外,您可以添加一個唯一約束Child.parent_id字段作爲額外的數據庫級別檢查,這將在您的案例中引發錯誤:

parent_id = Column(Integer, ForeignKey('parent.id'), unique=True)