我有一组看起来像这样的表:
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课程如下:
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
属性来引用其父级和子级操作。每个动作都可以有多个父母和孩子。
当我有如下函数时会出现问题:
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')
如何获得正确设置workflow_id的关系?
答案 0 :(得分:11)
见下面的工作代码。关键点是我在评论中提到的那些:
ForeignKey
s 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
答案 1 :(得分:0)
我认为将主键设为外键是不正确的。这是如何运作的?
但是要创建复合约束,一个“一起唯一”的键,请在表定义中使用它:
UniqueConstraint(u"name", u"workflow_id"),
但如果你真的希望它成为主键,你也可以使用它:
PrimaryKeyConstraint(*columns, **kw)
http://docs.sqlalchemy.org/en/latest/core/schema.html#sqlalchemy.schema.PrimaryKeyConstraint