table name specified more than once - python

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.

Related

Many to many relationship in flask SQLAlchemy

I'm learning flask and i'm looking to implement a many to many realtionship. I searched on internet but there are different ways,
this is what i have tried so far
class Group(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String)
class Course(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String)
class Group_Course(db.Model):
id = db.Column(db.Integer, primary_key=True)
group_id = db.Column(db.Integer, db.ForeignKey(Group.id))
theory_id = db.Column(db.Integer, db.ForeignKey(Course.id))
I'm not sure this is the right way to do it. I'm having issues with delete endpoint. I think that i should add on delete cascade but i don't know how to do it.
there are some sites that add relationships to the table association, so the association table looks like that.
class Group_Course(db.Model):
id = db.Column(db.Integer, primary_key=True)
group_id = db.Column(db.Integer, db.ForeignKey(Group.id))
course_id = db.Column(db.Integer, db.ForeignKey(Course.id))
course = db.relationship(Course, backref="course",cascade='all,
delete')
group = db.relationship(Group, backref="group", cascade='all,
delete`)
there are another examples where they are including a relationship field in both tables like that:
class Group(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String)
courses = db.relationship("Course", secondary=course_groups,
back_populates="courses")
class Course(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String)
groups = db.relationship("Group", secondary=course_groups,
back_populates="groups")
So i'm confused, which one is the most correct ?

How to use relationships in SQLAlchemy

I am new to SQLAlchemy and I am having troubles implementing the concept of relationships into my logic.
I have two tables: Offices and Departments where departments include the office it exists in.
I tried to apply the information present in the documentation https://www.tutorialspoint.com/sqlalchemy/sqlalchemy_orm_building_relationship.htm but I am having struggles understanding where should I insert the Relationship and if back_populates attribute is actually useful in this case.
class Offices(Base):
__tablename__: 'offices'
id = Column(Integer, primary_key=True)
name = Column(String)
code = Column(String)
reader = Column(Integer)
class Departments(Base):
__tablename__ = 'departments'
id = Column(Integer, primary_key=True)
name = Column(String)
office_id = Column(Integer, ForeignKey('offices.id'))
office = relationship("Offices", back_populates="departments")
def __init__(self, name):
self.name = name
Also, will I have to define anything related to the office in the department's __init__ in order to save it when I try inserting new rows into the table?
You can specify them relationship in both models
class Offices(Base):
__tablename__: 'offices'
id = Column(Integer, primary_key=True)
name = Column(String)
code = Column(String)
reader = Column(Integer)
departments = relationship("Departments", back_populates='office')
class Departments(Base):
__tablename__ = 'departments'
id = Column(Integer, primary_key=True)
name = Column(String)
office_id = Column(Integer, ForeignKey('offices.id'))
office = relationship("Offices", back_populates="departments")
After that you can achieve this (assume department and office are objects)
department.offices # this will refer to office
office.departments # this will refer to departments set (department is one of them)
The alternative is backref. It will create reverse relationship by itself, so
class Offices(Base):
__tablename__: 'offices'
id = Column(Integer, primary_key=True)
name = Column(String)
code = Column(String)
reader = Column(Integer)
class Departments(Base):
__tablename__ = 'departments'
id = Column(Integer, primary_key=True)
name = Column(String)
office_id = Column(Integer, ForeignKey('offices.id'))
office = relationship("Offices", backref="departments")
will do the same the first does

SqlAlchemy, how to make automatic join

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

Generated queries contain redundant products?

I have rather simple models like these:
TableA2TableB = Table('TableA2TableB', Base.metadata,
Column('tablea_id', BigInteger, ForeignKey('TableA.id')),
Column('tableb_id', Integer, ForeignKey('TableB.id')))
class TableA(Base):
__tablename__ = 'TableA'
id = Column(BigInteger, primary_key=True)
infohash = Column(String, unique=True)
url = Column(String)
tablebs = relationship('TableB', secondary=TableA2TableB, backref='tableas')
class TableB(Base):
__tablename__ = 'TableB'
id = Column(Integer, primary_key=True)
url = Column(String, unique=True)
However, sqla generates queries like
SELECT "TableB".id, "TableB".url AS "TableB_url" FROM "TableB", "TableA2TableB"
WHERE "TableA2TableB".tableb_id = "TableB".id AND "TableA2TableB".tablea_id = 408997;
But why is there a cartesian product in the query when the attributes selected are those in TableB? TableA2TableB shouldn't be needed.
Thanks
As it is right now, there is a backref relationship in TableB (tableas) and it's loaded because the default loading mode is set to select.
You may want to change the TableA.tablebs to
tablebs = relationship('TableB', secondary=TableA2TableB, backref='tableas', lazy="dynamic")

NoForeignKeysError: Could not determine join condition ... there are no foreign keys linking these tables

Im using sqlalchemy to design a forum style website. I started knocking out the design but everytime I try to test it with a few inserts, it dumps a brick;
NoForeignKeysError: Could not determine join condition between parent/child
tables on relationship Thread.replies - there are no foreign keys linking
these tables. Ensure that referencing columns are associated with a
ForeignKey or ForeignKeyConstraint, or specify a 'primaryjoin' expression.
Here are my "models"
from sqlalchemy import Integer, Column, String, create_engine, ForeignKey
from sqlalchemy.orm import relationship, sessionmaker, backref
from .database import Base # declarative base instance
class User(Base):
__tablename__ = "user"
id = Column(Integer, primary_key=True)
username = Column(String, unique=True)
email = Column(String, unique=True)
threads = relationship("Thread", backref="user")
posts = relationship("Post", backref="user")
class Post(Base):
__tablename__ = "post"
id = Column(Integer, primary_key=True)
name = Column(String)
body = Column(String)
author = Column(Integer, ForeignKey("user.id"))
class Thread(Base):
__tablename__ = "thread"
id = Column(Integer, primary_key=True)
name = Column(String)
desc = Column(String)
replies = relationship("Post", backref="thread")
author_id = Column(Integer, ForeignKey("user.id"))
board_id = Column(Integer, ForeignKey("board.id"))
class Board(Base):
__tablename__ = "board"
id = Column(Integer, primary_key=True)
name = Column(String)
desc = Column(String)
threads = relationship("Thread", backref="board")
category_id = Column(Integer, ForeignKey("category.id"))
class Category(Base):
__tablename__ = "category"
id = Column(Integer, primary_key=True)
name = Column(String)
desc = Column(String)
threads = relationship("Board", backref="category")
engine = create_engine('sqlite:///:memory:', echo=True)
Base.metadata.create_all(engine)
session_factory = sessionmaker(bind=engine)
session = session_factory()
Your Post model has no thread reference. Add a column to Post referencing the Thread a post belongs to:
class Post(Base):
__tablename__ = "post"
id = Column(Integer, primary_key=True)
name = Column(String)
body = Column(String)
author = Column(Integer, ForeignKey("user.id"))
thread_id = Column(Integer, ForeignKey('thread.id'))
We can't use the name thread because that's what the Post.replies relationship will add to retrieved Thread instances.
This is a One to Many relationship as documented in the SQLAlchemy Relationship Configuration documentation.
You should add a field in the Post model that reads:
thread_id = Column(Integer, ForeignKey("thread.id"), nullable=True, default=None)
How is SQLAlchemy supposed to know how this relationship you defined supposed to link a thhread to a post? That's why you should have a foreign key from a post to its thread. You can allow it to be null, if it does not belong to a thread, it depends on your use case.

Categories

Resources