Using the example from the SQLAlchemy documentation for inheritance, how would I query the Employee class for only the id and engineer_info columns of all derived classes, including ones which don't have the engineer_info column?
class Employee(Base):
__tablename__ = 'employee'
id = Column(Integer, primary_key=True)
name = Column(String(50))
type = Column(String(50))
__mapper_args__ = {
'polymorphic_identity':'employee',
'polymorphic_on':type,
}
class Engineer(Employee):
__tablename__ = 'engineer'
id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
engineer_info = Column(String(50))
__mapper_args__ = {
'polymorphic_identity':'engineer',
}
class Manager(Employee):
__tablename__ = 'manager'
id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
manager_data = Column(String(50))
__mapper_args__ = {
'polymorphic_identity':'manager',
}
It looks like you can do this if you explicitly join the employee table to engineer table in a left/outer join, like:
session.query(Employee.id, Engineer.engineer_info).join(Engineer, isouter=True).all()
or:
session.query(Employee.id, Engineer.engineer_info).outerjoin(Engineer).all()
For future searchability: See also SQLAlchemy inheritance filter on all columns which I found by googling "sqlalchemy left join subclass"
Related
I have 3 classes;
'Company' top class its subclass 'Department' its subclass 'DepartmentalUnit'
I can access the values of all classes from the 'DepartmentalUnit' class to the top class 'Company'
What I could not do and understand despite reading the document is that;;
I cannot access other subclasses from the 'company' class
class Company(Base):
__tablename__ = 'company'
id = Column(Integer, primary_key=True)
name = Column(String)
departments = relationship('Department',backref='company')
class Department(Base):
__tablename__ = 'department'
id = Column(Integer, primary_key=True)
department_name = Column(String)
company_id = Column(Integer, ForeignKey('company.id'))
departmentalunits = relationship('DepartmentalUnit', backref='department')
class DepartmentalUnit(Base):
__tablename__ = 'departmentalunit'
id = Column(Integer, primary_key=True,nullable=False)
departmental_unit_name = Column(String)
departments_id = Column(Integer, ForeignKey('department.id'))
The code from which I access the upper classes from the subclasses:
query = session.query(DepartmentalUnit)
instance = query.all()
for i in instance:
print(i.department.company.name)
print(i.department.department_name)
print(i.departmental_unit_name)
The code I can't access other subclasses from the company class:
query = session.query(Company)
instance = query.all()
for i in instance:
print(i.department.department_name)
Your last query should be used differently:
there is a typo in the name of the relationship: should be departments instead of department
given that the relationship is 1-N, the result is a list, so you should iterate over children.
This should work:
query = session.query(Company)
for company in query.all():
print(company.name)
for dep in company.departments:
print(" ", dep.department_name)
for dep_unit in dep.departmentalunits:
print(" ", dep_unit.departmental_unit_name)
I solved the problem. I added a backref to relationships and now I can access all of them from the company. Not sure if it's a correct method? However, I am currently getting the return I want. I have no unanswered request yet.
Example solved:
class Company(Base):
__tablename__ = 'company'
id = Column(Integer, primary_key=True)
name = Column(String)
departments = relationship('Department',backref='company',uselist=False)
class Department(Base):
__tablename__ = 'department'
id = Column(Integer, primary_key=True)
department_name = Column(String)
company_id = Column(Integer, ForeignKey('company.id'))
departmentalunits = relationship('DepartmentalUnit', backref='department',uselist=False)
class DepartmentalUnit(Base):
__tablename__ = 'departmentalunit'
id = Column(Integer, primary_key=True,nullable=False)
departmental_unit_name = Column(String)
departments_id = Column(Integer, ForeignKey('department.id'))
query = session.query(Company)
instance = query.all()
for i in instance:
print(f"Company: {i.name}")
print(f"Department: {i.departments.department_name}")
print(f"Department Unit: {i.departments.departmentalunits.departmental_unit_name}")
print( f"Report Category : {i.departments.departmentalunits.reportcategoryoftheunit.report_category_name}")
Maybe an easy one for others.
I want to write the name of a child object into the parent table AND into the child table:
class Object(db.Model):
__tablename__ = 'object'
id = Column(db.Integer, primary_key=True)
name = Column(db.String(50))
class ChildObject(Objekt):
__tablename__ = 'child_object'
id = db.Column(db.Integer, db.ForeignKey('object.id'), primary_key=True)
name = Object.name
__mapper_args__ = {
'polymorphic_identity':'ChildObject'
}
How can I do this?
First, I used Sqlalchemy's polymorphic architecture.
ChildA and ChildB extends Child.
ChildA has name column.
ChildB has age column.
class Parent(Base):
__tablename__ = 'parent'
id = Column(Integer, primary_key=True)
class Child(Base):
__tablename__ = 'child'
id = Column(Integer, primary_key=True)
parent_id = Column(Integer, ForeignKey('parent.id'))
parent = relationship(Parent, backref='children')
class ChildA(Child):
__tablename__ = 'child_a'
id = Column(Integer, primary_key=True)
name = Column(String(50))
class ChildB(Child):
__tablename__ = 'child_b'
id = Column(Integer, primary_key=True)
age = Column(Integer)
parent = DBSession.query(Parent).first()
subquery = parent.children.join(ChildA).subquery()
So I want to access ChildA.name column from subquery.
Something like subquery.c.ChildA.name == 'Tom'
If I understood properly what you are trying to do, you don't really need a subquery, it could be simply something like
In [13]:
f = session.query(Parent, ChildA).join(ChildA).first()
print(f.ChildA.name)
Pedro
For the use of subqueries, I would recommend you take a look to sqlalchemy tutorial.
On the other hand, I wasn't able to use the classes as you've defined them, I had to add a ForeignKey like this
class ChildA(Child):
__tablename__ = 'child_a'
id = Column(Integer, ForeignKey('child.id'), primary_key=True)
name = Column(String(50))
class ChildB(Child):
__tablename__ = 'child_b'
id = Column(Integer, ForeignKey('child.id'), primary_key=True)
age = Column(Integer)
I have no doubt that it works for you, this probably depends on the setup.
And finally, I would like to recommend you to use a column for the type of child. With this, it will be easier to recognize the children you are using. Something like this,
class Child(Base):
__tablename__ = 'child'
id = Column(Integer, primary_key=True)
parent_id = Column(Integer, ForeignKey('parent.id'))
parent = relationship(Parent, backref='children')
type = Column(String(20))
__mapper_args__ = {
'polymorphic_identity':'child',
'polymorphic_on':type
}
class ChildA(Child):
__tablename__ = 'child_a'
id = Column(Integer, ForeignKey('child.id'), primary_key=True)
name = Column(String(50))
__mapper_args__ = {
'polymorphic_identity':'child_a',
}
class ChildB(Child):
__tablename__ = 'child_b'
id = Column(Integer, ForeignKey('child.id'), primary_key=True)
age = Column(Integer)
__mapper_args__ = {
'polymorphic_identity':'child_b',
}
Please take a look to sqlalchemy docs for details.
Hope it helps.
I'm working with SQLAlchemy and I try to achieve one-to-one and one-to-many relationships on the same parent class.
This is for the simplicity of keeping track of the main child entity.
Unfortunately I'm getting an error:
AmbiguousForeignKeysError: Could not determine join condition between
parent/child tables on relationship Customer.contact - 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.
Am I doing something wrong or it is not possible?
Here is a code example:
class Customer(Base):
__tablename__ = 'customer'
id = Column(Integer, primary_key=True)
contact_id = Column(Integer, ForeignKey('contact.id'))
address_id = Column(Integer, ForeignKey('address.id'))
contact = relationship('Contact', backref=backref("contact", uselist=False))
address = relationship('Address', backref=backref("address", uselist=False))
contact_list = relationship('Contact')
address_list = relationship('Address')
class Contact(Base):
__tablename__ = 'contact'
id = Column(Integer, primary_key=True)
customer_id = Column(Integer, ForeignKey(
'customer.id',
use_alter=True, name='fk_contact_customer_id_customer',
onupdate='CASCADE', ondelete='SET NULL'
))
first_name = Column(String(32))
last_name = Column(String(32))
class Address(Base):
__tablename__ = 'address'
id = Column(Integer, primary_key=True)
customer_id = Column(Integer, ForeignKey(
'customer.id',
use_alter=True, name='fk_address_customer_id_customer',
onupdate='CASCADE', ondelete='SET NULL'
))
label = Column(String(32))
Thanks
Apparently the solution was later in the documentation:
SQLAlchemy does not know which foreign key to use, so you have to specify those as Column objects in relationship(foreign_keys=[]) like so:
class Contact(Base):
# ...
customer_id = Column(Integer, ForeignKey(
'customer.id',
use_alter=True, name='fk_contact_customer_id_customer',
onupdate='CASCADE', ondelete='SET NULL'
))
# ...
class Customer(Base):
# ...
contact_id = Column(Integer, ForeignKey('contact.id'))
#...
contact = relationship('Contact', uselist=False, foreign_keys=[contact_id])
contact_list = relationship('Contact', foreign_keys=[Contact.customer_id])
#...
I am using sqlalchemy to create a structure that resembles a graph, so that there are several types of nodes and links joining them. The nodes are defined like this:
class Node(Base):
__tablename__ = 'node'
id = Column(Integer, primary_key=True)
type = Column(Unicode)
__mapper_args__ = {'polymorphic_on': type}
class InputNode(Node):
__tablename__ = 'inputnode'
id = Column(Integer, ForeignKey('node.id'), primary_key=True)
__mapper_args__ = {'polymorphic_identity': 'input'}
class ThruNode(Node):
__tablename__ = 'thrunode'
id = Column(Integer, ForeignKey('node.id'), primary_key=True)
__mapper_args__ = {'polymorphic_identity': 'thru'}
class OutputNode(Node):
__tablename__ = 'outputnode'
id = Column(Integer, ForeignKey('node.id'), primary_key=True)
__mapper_args__ = {'polymorphic_identity': 'output'}
Now I want to create a Link table which would looks something like this:
class Link(Base):
__tablename__ = 'link'
input = Column(Integer, ForeignKey('node.id', where='type IN ("input", "thru")'))
output = Column(Integer, ForeignKey('node.id', where='type IN ("thru", "output")'))
The bit I'm struggling with is how to do the where part of it, since as I've written it is not valid in sqlalchemy. I had though of using a CheckConstraint or a ForeignKeyConstraint, but I can't see how either of them could actually be used to do this.
I haven't tryed it nor am I an expert of this, but shouldn't this work?
class Link(Base):
__tablename__ = 'link'
input = Column(Integer, ForeignKey('thrunode.id'))
output = Column(Integer, ForeignKey('outputnode.id'))
First I had another idea that maybe you could have used different names for the ids and than use those, kind of like:
instead of:
class InputNode(Node):
__tablename__ = 'inputnode'
id = Column(Integer, ForeignKey('node.id'), primary_key=True)
__mapper_args__ = {'polymorphic_identity': 'input'}
this:
class ThruNode(Node):
[...]
thrunode_id = Column(Integer, ForeignKey('node.id'), primary_key=True)
[...]
and then:
class Link(Base):
__tablename__ = 'link'
input = Column(Integer, ForeignKey('node.thrunode_id'))
output = Column(Integer, ForeignKey('node.outputnode_id'))
I got the idea from here sqlalchemy docs: declarative.html#joined-table-inheritance