Here is a trimmed down version of my problem:
Consider that I have two tables: 'procedure' and 'role'.
role has fields: (role_uid, role_name)
procedure has fields: (procedure_uid, procedure_name, inform_role_uid, consult_role_uid)
So 'role' has two one-to-many relationships with 'procedure'.
Some code:
class Role(Base):
__tablename__ = "role"
__table_args__ = ({'autoload':True, 'useexisting': True})
class Procedure(Base):
__tablename__ = "procedure"
__table_args__ = (sqlalchemy.ForeignKeyConstraint(['consult_role_uid','inform_role_uid'],['role.role_uid', 'role.role_uid']),
{'autoload':True, 'useexisting': True})
Procedure.consult_role = sqlalchemy.orm.relationship(Role,
primaryjoin="Procedure.consult_role_uid==Role.role_uid", foreign_keys=Role.role_uid)
Procedure.inform_role = sqlalchemy.orm.relationship(Role,
primaryjoin="Procedure.inform_role_uid==Role.role_uid", foreign_keys=Role.role_uid)
consult_role = sqlalchemy.orm.aliased(Role, name="consult_role")
inform_role = sqlalchemy.orm.aliased(Role, name="inform_role")
query = session.query(
Procedure.procedure_name,
consult_role.role_name.label("consult_role_name"),
inform_role.role_name.label("inform_role_name")).join(consult_role, inform_role)
This produces the following SQL:
SELECT
`procedure`.procedure_name AS procedure_procedure_name,
consult_role.role_name AS consult_role_name,
inform_role.role_name AS inform_role_name
FROM
`procedure`
INNER JOIN role AS consult_role
ON consult_role.role_uid = `procedure`.consult_role_uid
AND consult_role.role_uid = `procedure`.inform_role_uid
INNER JOIN role AS inform_role
ON inform_role.role_uid = `procedure`.consult_role_uid
AND inform_role.role_uid = `procedure`.inform_role_uid
As you can see, I had no intention of EACH of the inner joins to join on both the fields. Why does it seem to be ignoring my 'primaryjoin' argument?
This:
sqlalchemy.ForeignKeyConstraint(['consult_role_uid','inform_role_uid'],['role.role_uid', 'role.role_uid'])
Is roughly how you say that the relationship between two tables is through both attributes, as if the referant has a composite primary key. You need to specify ForeignKey
twice if you want to have two foreign key references.
class Procedure(Base):
__tablename__ = "procedure"
__table_args__ = (
sqlalchemy.ForeignKeyConstraint(['consult_role_uid'],['role.role_uid']),
sqlalchemy.ForeignKeyConstraint(['inform_role_uid'],['role.role_uid']),
{'autoload':True, 'useexisting': True})
So for completeness, here is the fixed code to the problem above. I added two ForeignKeyContstaints and I also had to specify which relationship to use in the join.
class Role(Base):
__tablename__ = "role"
__table_args__ = ({'autoload':True, 'useexisting': True})
class Procedure(Base):
__tablename__ = "procedure"
__table_args__ = (
sqlalchemy.ForeignKeyConstraint(['consult_role_uid'], ['role.role_uid']),
sqlalchemy.ForeignKeyConstraint(['inform_role_uid'], ['role.role_uid']),
{'autoload':True, 'useexisting': True})
Procedure.consult_role = sqlalchemy.orm.relationship(Role,
primaryjoin="Procedure.consult_role_uid==Role.role_uid", foreign_keys=Role.role_uid)
Procedure.inform_role = sqlalchemy.orm.relationship(Role,
primaryjoin="Procedure.inform_role_uid==Role.role_uid", foreign_keys=Role.role_uid)
consult_role = sqlalchemy.orm.aliased(Role, name="consult_role")
inform_role = sqlalchemy.orm.aliased(Role, name="inform_role")
query = session.query(
Procedure.procedure_name,
consult_role.role_name.label("consult_role_name"),
inform_role.role_name.label("inform_role_name")).join((consult_role, Procedure.consult_role), (inform_role, Procedure.inform_role))
This produced the following correct SQL:
SELECT
`procedure`.procedure_name AS procedure_procedure_name,
consult_role.role_name AS consult_role_name,
inform_role.role_name AS inform_role_name
FROM
`procedure`
INNER JOIN role AS consult_role ON `procedure`.consult_role_uid = consult_role.role_uid
INNER JOIN role AS inform_role ON `procedure`.inform_role_uid = inform_role.role_uid
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.