I've recently used sqlacodegen
When I try and run against the generated code it get this message that I've been unable to fix:
Could not determine join condition between parent/child tables on relationship Workgrp.usrmst - there are multiple foreign key paths linking the tables. Specify the 'foreign_keys' argument, providing a list of those columns which should be counted as containing a foreign key reference to the parent table.
I'm wondering if someone can shed some light:
Here is the generated code for the relevant tables causing the issue:
class Workgrp(Owner):
__tablename__ = 'workgrp'
workgrp_id = Column(ForeignKey('owner.owner_id'), primary_key=True)
workgrp_prntid = Column(Numeric(scale=0, asdecimal=False))
workgrp_name = Column(String(256))
workgrp_desc = Column(String(4000))
workgrp_owner = Column(ForeignKey('usrmst.usrmst_id'))
workgrp_lstchgtm = Column(DateTime, index=True)
workgrp_externid = Column(String(20))
workgrp_profile = Column(Text)
workgrp_usrmodtm = Column(DateTime)
usrmst = relationship('Usrmst')
class Usrmst(Owner):
__tablename__ = 'usrmst'
__table_args__ = (
Index('usrmst_ak1', 'usrmst_domain', 'usrmst_name'),
)
usrmst_id = Column(ForeignKey('owner.owner_id'), primary_key=True)
usrmst_domain = Column(String(256))
usrmst_name = Column(String(256), nullable=False)
usrmst_fullname = Column(String(1024))
usrmst_desc = Column(String(4000))
usrmst_phoneno = Column(String(40))
usrmst_pagerno = Column(String(40))
usrmst_email = Column(String(1024))
usrmst_emailtype = Column(Numeric(scale=0, asdecimal=False))
secmst_id = Column(ForeignKey('secmst.secmst_id'))
lngmst_id = Column(ForeignKey('lngmst.lngmst_id'))
usrmst_password = Column(String(1024))
usrmst_externid = Column(String(20))
usrmst_suser = Column(String(1))
usrmst_lstchgtm = Column(DateTime, index=True)
usrmst_orapassword = Column(String(144))
usrmst_wingroup = Column(String(1))
usrmst_tmpacct = Column(String(1))
usrmst_profile = Column(Text)
usrmst_usrmodtm = Column(DateTime)
usrmst_principal = Column(String(256))
usrmst_keytab = Column(String(4000))
lngmst = relationship('Lngmst')
secmst = relationship('Secmst')
I've looked at the SQLAlchemy docs, and tried things with
But ended up with messages like:
Here are some screenshots relevant raw Tables in DBeaver, the Eclipse based SQL Explorer type plugin:
I don't think it should make much difference but I'm developing on:
There is a snippet I've added after the generated code, with the relevant imports..
engine = create_engine("oracle://<dbuser>:<dbpwd>@<host>:<port>/<db>")
Session = sessionmaker(bind=engine)
session = Session()
firstjm = session.query(Jobmst).first()
print(firstjm)
Other annoying things about the sqlacodegen generated code:
Didn't generate string implementations, of __repr__
and __str__
, so printing out a table didn't generically list, table name, followed by key, value pair list for columns and their values.
Purports to be PEP compliant code, lines often blew the character limit, and so you'd have to go and reformat long comparison strings 'x x' into 'x' ' x' etc ,
I finally tracked down the syntactic sugar doing a Google advanced search on the exact term:
usrmst = relationship('Usrmst', foreign_keys=[workgrp_owner])
I also overrode the default implementation of __repr__
for the Base class defined by:
Base = declarative_base()
to this:
import json
def tablerepr(self):
return "<{}: ({})>".format(self.__table__,
json.dumps(
dict(
list(
self.__dict__.items()
)[1:]
), default=str)
)
Base.__repr__ = tablerepr
Useful links I found when getting to grips with the objects SQLAlchemy spits out:
__repr__
implementationSo I end up adding the tablerepr method to my main generated code..
Then in a separate python script I import the generated code with my tweaks, and have code like this:
engine = create_engine("oracle://<user>:<password>@<host>:<port>/<db>")
inspector = inspect(engine)
Session = sessionmaker(bind=engine)
session = Session()
print(session.query(Jobmst).first())
Jobmst is a class representing a table I've imported. This represents kind of content that print then generates, with the customer data replaced by .... The table name, then a tuple containing each column name and it's data as key/value pairs:
<jobmst: ({"jobmst_id": 1590.0, "jobmst_alias": "1590", "jobmst_owner": 67.0, "jobmst_type": 1.0, "jobmst_dirty": "0", "jobmst_desc": null, "jobmst_vars": null, "jobmst_prntid": 1589.0, "jobmst_crttm": "2001-06-18 10:38:19", "jobmst_active": "N", "jobmst_usrmodtm": "2001-06-29 20:27:06", "jobdtl_id": 1591.0, "evntmst_id": null, "bizunit_id": null, "jobmst_lstchgtm": "2001-06-29 20:27:06", "jobmst_evntoffset": null, "jobmst_desc_type": null, "jobmst_runbook": null, "jobmst_name": "....", "jobmst_runbook_type": null, "jobcls_id": 32.0, "jobmst_mode": null, "jobmst_prntname": "...."})>