SQLAlchemy:具有复合主键的关系表 [英] SQLAlchemy: Relation table with composite primary key
问题描述
我有一组看起来像这样的表格:
I have a set of tables that look like:
workflows = Table('workflows', Base.metadata,
Column('id', Integer, primary_key=True),
)
actions = Table('actions', Base.metadata,
Column('name', String, primary_key=True),
Column('workflow_id', Integer, ForeignKey(workflows.c.id), primary_key=True),
)
action_dependencies = Table('action_dependencies', Base.metadata,
Column('workflow_id', Integer, ForeignKey(workflows.c.id), primary_key=True),
Column('parent_action', String, ForeignKey(actions.c.name), primary_key=True),
Column('child_action', String, ForeignKey(actions.c.name), primary_key=True),
)
我的 ORM 类看起来像:
My ORM classes look like:
class Workflow(Base):
__table__ = workflows
actions = relationship("Action", order_by="Action.name", backref="workflow")
class Action(Base):
__table__ = actions
children = relationship("Action",
secondary=action_dependencies,
primaryjoin=actions.c.name == action_dependencies.c.parent_action,
secondaryjoin=actions.c.name == action_dependencies.c.child_action,
backref="parents"
)
因此,在我的系统中,每个操作都由工作流 ID 及其名称的组合唯一标识.我希望每个动作都有 parents
和 children
属性来引用它的父和子动作.每个动作可以有多个父级和子级.
So in my system, each action is uniquely identified by a combination of a workflow id and its name. I'd like each action to have parents
and children
attribute that refers its parent and child actions. Each action can have multiple parents and children.
当我有一个函数时会出现这个问题:
The problem occurs when I have a function such as :
def set_parents(session, workflow_id, action_name, parents):
action = session.query(db.Action).filter(db.Action.workflow_id == workflow.id).filter(db.Action.name == action_name).one()
for parent_name in parents:
parent = session.query(db.Action).filter(db.Action.workflow_id == workflow.id).filter(db.Action.name == parent_name).one()
action.parents.append(parent)
session.commit()
我收到如下错误:
IntegrityError: (IntegrityError) action_dependencies.workflow_id may not be NULL u'INSERT INTO action_dependencies (parent_action, child_action) VALUES (?, ?)' (u'directory_creator', u'packing')
如何获得正确设置工作流 ID 的关系?
How do I get the relationship to set the workflow_id correctly?
推荐答案
见下面的工作代码.关键点是我在评论中提到的:
See below working code. The key points are those I mentioned in the comments:
- 适当的复合
ForeignKey
s - 使用 FK 正确的
relationship
配置
代码:
workflows = Table('workflows', Base.metadata,
Column('id', Integer, primary_key=True),
)
actions = Table('actions', Base.metadata,
Column('workflow_id', Integer, ForeignKey(workflows.c.id), primary_key=True),
Column('name', String, primary_key=True),
)
action_dependencies = Table('action_dependencies', Base.metadata,
Column('workflow_id', Integer, ForeignKey(workflows.c.id), primary_key=True),
Column('parent_action', String, ForeignKey(actions.c.name), primary_key=True),
Column('child_action', String, ForeignKey(actions.c.name), primary_key=True),
ForeignKeyConstraint(['workflow_id', 'parent_action'], ['actions.workflow_id', 'actions.name']),
ForeignKeyConstraint(['workflow_id', 'child_action'], ['actions.workflow_id', 'actions.name']),
)
class Workflow(Base):
__table__ = workflows
actions = relationship("Action", order_by="Action.name", backref="workflow")
class Action(Base):
__table__ = actions
children = relationship("Action",
secondary=action_dependencies,
primaryjoin=and_(actions.c.name == action_dependencies.c.parent_action,
actions.c.workflow_id == action_dependencies.c.workflow_id),
secondaryjoin=and_(actions.c.name == action_dependencies.c.child_action,
actions.c.workflow_id == action_dependencies.c.workflow_id),
backref="parents"
)
# create db schema
Base.metadata.create_all(engine)
# create entities
w_1 = Workflow()
w_2 = Workflow()
a_11 = Action(name="ac-11", workflow=w_1)
a_12 = Action(name="ac-12", workflow=w_1)
a_21 = Action(name="ac-21", workflow=w_2)
a_22 = Action(name="ac-22", workflow=w_2)
session.add(w_1)
session.add(w_2)
a_22.parents.append(a_21)
session.commit()
session.expunge_all()
print '-'*80
# helper functions
def get_workflow(id):
return session.query(Workflow).get(id)
def get_action(name):
return session.query(Action).filter_by(name=name).one()
# test another OK
a_11 = get_action("ac-11")
a_12 = get_action("ac-12")
a_11.children.append(a_12)
session.commit()
session.expunge_all()
print '-'*80
# test KO (THIS SHOULD FAIL VIOLATING FK-constraint)
a_11 = get_action("ac-11")
a_22 = get_action("ac-22")
a_11.children.append(a_22)
session.commit()
session.expunge_all()
print '-'*80
这篇关于SQLAlchemy:具有复合主键的关系表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!