I got 3 tables
class Article_Comment(Base):
__tablename__ = 'article_comment'
article_id = Column(Integer, ForeignKey('article.id'), primary_key=True)
comment_id = Column(Integer, ForeignKey('comment.id'), primary_key=True)
child = relationship("Comment", lazy="joined", innerjoin=True)
class Article(Base):
__tablename__ = 'article'
id = Column(Integer, primary_key=True)
title = Column(String)
children = relationship("Article_Comment", lazy="joined", innerjoin=True)
class Comment(Base):
__tablename__ = 'comment'
id = Column(Integer, primary_key=True)
text = Column(String)
I need to get specific Article with Comments. I do this like this:
Session = sessionmaker(bind=engine)
session = Session()
result = session.query(Article, Comment).join(Article_Comment).join(Comment).filter(Article_Comment.article_id == Article.id).filter(Article_Comment.comment_id == Comment.id).filter(Article.title=='music').all()
for i, j in result:
print i.title, j.text
But I want to make this query without using .join.
Can someone help me?
May be, I need to remake relationships?
My thx to univerio
Here is the full answer
set up a relationship on Article, comments = relationship(Comment, secondary=Article_Comment.__table__, lazy="joined")
session.query(Article).filter(Article.title=='music').one().comments
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}")
I have a issue using SQLAlchemy.
Base = declarative_base()
node_to_node = Table("node_to_node", Base.metadata,
Column("left_node_id", Integer, ForeignKey("node.id"), primary_key=True),
Column("right_node_id", Integer, ForeignKey("node.id"), primary_key=True)
)
class Node(Base):
__tablename__ = 'node'
id = Column(Integer, primary_key=True)
label = Column(String)
right_nodes = relationship("Node",
secondary=node_to_node,
primaryjoin=id==node_to_node.c.left_node_id,
secondaryjoin=id==node_to_node.c.right_node_id,
backref="left_nodes"
)
metadata = Base.metadata
engine = create_engine("postgres+psycopg2://postgres:admin#localhost:5432/test")
Base.metadata.drop_all(engine)
Base.metadata.create_all(engine)
session = sessionmaker()
session.configure(bind=engine)
s = session()
node1 = Node(label="node1")
node2 = Node(label="node2")
node3 = Node(label="node3")
node1.right_nodes.append(node2)
node1.right_nodes.append(node3)
s.add_all([node1, node2, node3])
s.commit()
what I want is to have the IDs of all the right nodes of node 1 as an array, so here [2, 3]
Do you know a method that allows me to do that?
Thanks in advance for any help!
EDIT :
class NeedTag(Base):
__tablename__ = 'need_tags'
tag_id = Column(Integer, ForeignKey('tags.id'), primary_key=True)
text_id = Column(Integer, ForeignKey('texts.id'), primary_key=True)
class Text(Base) :
__tablename__ = 'texts'
id = Column(Integer, primary_key=True)
text = Column(Text, nullable=False)
need_tag = relationship("Tag",
secondary="need_tags")
class Tag(Base):
__tablename__ = 'tags'
id = Column(Integer, primary_key=True)
name = Column(String(), nullable=False)
I have a problem with the SQL Alchemy synthax.
For example, I defined the Text and Tags class and a many-to-many relationship between Text and Tags: To use a text, you need to have some tags that must be present.
An example of a condition is:
If tag1 or tag2 :
If tag3 or tag 4 :
Text1 can be used
I would like to do this:
text1.need_tags = [ [tag1, tag2],[tag3, tag4] ]
And therefore to use text1, you need at least 1 tag in the 1st list AND 1 tag in the 2nd list
But I tried so many techniques and they all failed
Do you know if it is possible to do that with SQLAlchemy ? Or something like that that accomplish the same thing
class BlogPost(SchemaBase):
id = Column(Integer, primary_key=True)
name = Column(String, unique=True)
authors = relationship('Authors', secondary='authors_to_blog_post')
__tablename__ = 'blogpost'
class Authors(SchemaBase):
id = Column(Integer, primary_key=True)
name = Column(String, unique=True)
__tablename__ = 'author'
authors_to_blog_post = Table('authors_to_blog_post', Base.metadata,
Column('author_id', Integer, ForeignKey('author.id')),
Column('blogpost_id', Integer, ForeignKey('blogpost.id'))
)
Now how to query for all blogposts without any author?
session.query(BlogPost).filter(BlogPost.authors == []) doesnt work
Found answer from here: https://groups.google.com/d/msg/sqlalchemy/Ow0bb6HvczU/VVQbtd7MnZkJ
So the solution is
session.query(BlogPost).filter(~BlogPost.authors.any())
I have the following tables configured:
class User(Base):
__tablename__ = "user"
id = Column(Integer, primary_key=True)
name = Column(String)
class Gadget(Base):
__tablename__ = "gadget"
id = Column(Integer, primary_key=True)
brand = Column(String)
class UserGadget(Base):
__tablename__ = "user_gadget"
user_id = Column(Integer, ForeignKey('user.id'), primary_key=True)
gadget_id = Column(Integer, ForeignKey('gadget.id'), primary_key=True)
user = relationship("User", backref=backref('userGadgets', order_by=user_id))
gadget = relationship("Gadget", backref=backref('userGadgets', order_by=gadget_id))
class GadgetComponent(Base):
__tablename__ = "gadget_component"
id = Column(String, primary_key=True)
gadget_id = Column(Integer,ForeignKey('gadget.id'))
component_maker = Column(String)
host = relationship("Gadget", backref=backref('components', order_by=id))
class ComponentUsingMetal(Base):
__tablename__ = "component_metal"
id = Column(Integer, primary_key=True)
component_id = Column(Integer, ForeignKey('GadgetComponent.id'))
metal = Column(String)
component = relationship("GadgetComponent", backref=backref('gadgetComponentMetals', order_by=id))
On doing the following query:
session.query(User).join("userGadgets", "gadget", "components","gadgetComponentMetals").filter(ComponentUsingMetal.metal == 'iron') , component_metal gets attached to the query twice giving an error 'table name component_metal specified more than once'.
Any idea what I am doing wrong?
I traced the problem down to the following line in selectable.py:
froms = [f for f in froms if f not in toremove] This line removes the tables which are already covered by joins so that FROM clause doesn't have the same table specified more than once. The line didn't remove component_metal even though toremove had it meaning that I had two different Table objects for the same db table. And then I noticed the import for component_metal's class, ComponentUsingMetal, looked different. The others imports looked like:
from myschema import GadgetComponent
from myschema import Gadget
from python.myschema ComponentUsingMetal
As soon as fixed the import the issue went away.
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