python - SQLAlchemy 一对一关系创建多行

标签 python sql postgresql sqlalchemy

我试图在我的数据库(postgresql)中的两个表之间建立一对一的关系。我在 python 中使用 SQLAlchemy。因此,我使用了文档本身中给出的示例。 one-to-one relationship

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:hello@localhost/fullstack')
Base.metadata.create_all(engine)

这将创建两个表 parent 和 child。 现在我在父表和子表中插入值

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

engine = create_engine('postgresql+psycopg2://testdb:hello@localhost/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对应的child。我不希望 child 有相同的 parent_id。

谢谢。

最佳答案

问题是您直接指定了字段parent_id。在这种情况下,sqlalchemy 没有机会验证关系是否为一对一。相反,使用关系:

# 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)

关于python - SQLAlchemy 一对一关系创建多行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34458521/

相关文章:

python - 切换 python 打印的最佳方法是什么?

mysql - 查找包含一个以上冒号字符的所有条目

ruby - rake 中止! PG::ConnectionBad: fe_sendauth: 没有提供密码 sinatra

SQL for public private records 这取决于所选择的项目

python - 使用 Pandas 打开 Excel 文件

python - 打印用户定义类的对象列表

MySql 查询列属性

postgresql - Gorm Jsonb 类型存储为 bytea

python - Python中的正则表达式在 ":"之后获取文本

MySQL 在子查询中插入自动生成的列