Confused with multiple Join in single query, Sqlalchemy - mysql

I am trying to join three tables in a single query in SQLAlchemy specifically but unable to do so.
I have done this so far :-
Test.query.join(Test.sections).join(QuestionSection.section).all()
I know it is wrong but I am trying to do it in a single query.
Here are my tables :-
Question section Model :-
class QuestionSection(Dictifiable, db.Model):
__tablename__ = 'question_section'
section_id = Column(Integer, ForeignKey('section.id'), primary_key=True)
question_id = Column(Integer, ForeignKey('question.id'), primary_key=True)
question = db.relationship('Question', backref='question_section')
section = db.relationship('Section', backref='question_section')
Section Table :-
class Section(Dictifiable, db.Model):
__tablename__ = 'section'
id = Column(Integer, Sequence('section_id_seq'), primary_key=True)
test_id = Column(Integer, ForeignKey('test.id'))
name = Column(String(50))
test = relationship("Test", back_populates="sections")
questions = db.relationship('Question',
secondary='question_section')
And Test table :-
id = Column(Integer, Sequence('test_id_seq'), primary_key=True)
name = Column(String(50))
sections = relationship("Section", back_populates="test")
tests = relationship("Corporate", secondary='corporate_test',
back_populates='tests')

I understood what I was doing wrong, I should join like this :-
Test.query.join(Test.sections).join(QuestionSection, QuestionSection.section_id == Section.id).all()

Related

how to fetch data from multiple tables without doing join in sqlalchemy (Using fastApi)

class Actions(Base):
__tablename__ = "actions"
id = Column(Integer, primary_key=True, index=True)
resource_id = Column(Integer, ForeignKey('resources.id'))
action_short_name = Column(String(20),nullable=True)
description = Column(String(250),nullable=True)
status = Column(String(1),nullable=True)
action_resource = relation(Resource, backref = "actions")
detailsQ = session.query(Actions).join(Resource).filter(Actions.resource_id == Resource.id).all()
I don't want to use join so how I am able to fetch data though I have made relations ?

SQLAlchemy get parent object when using group_by and join

I'm learning SQLAlchemy on a new project and I'm struggling how to get "parent" object when using group_by on a join table.
class Address(Base):
__tablename__ = "addresses"
id_address = Column(Integer, primary_key=True)
country = Column(String)
[...]
class Order(Base):
__tablename__ = "orders"
id_order = Column(Integer, primary_key=True)
id_billing = Column(Integer, ForeignKey("addresses.id_address"))
id_shipping = Column(Integer, ForeignKey("addresses.id_address"))
billing = relationship(Address, foreign_keys=id_billing)
shipping = relationship(Address, foreign_keys=id_shipping)
[...]
billing = aliased(models.Address, name="billing")
shipping = aliased(models.Address, name="shipping")
db.query(shipping.country) \
.join(billing, models.Order.billing) \
.join(shipping, models.Order.shipping) \
.group_by(shipping.country)
Returns a list, like:
[('DE',), ('ES',), ('GR',), ('HU',), ('LT',), ('LV',), ('RO',)]
What I would like is a list of models.Order objects containing only "models.Order.shipping.country".
Any hints or working examples are very appreciated!

SqlAlchemy error: Foreign key could not find table

So I'm building an app and I'm trying to save new changes to my database but when I try to commit the changes in the flask using db.session.commit() it returns me the following error:
sqlalchemy.exc.NoReferencedTableError: Foreign key associated with column 'products.country_id' could not find table 'countries' with which to generate a foreign key to target column 'id'
In my models.py I have the following:
from app import db
from . import db
from datetime import datetime
def now():
return datetime.now()
class Countries(db.Model):
__tablename__ = 'countries'
__table_args__ = {'schema': 'products_data'}
id = db.Column(db.Integer, primary_key=True, unique=True, autoincrement=True)
name = db.Column(db.String(255))
code = db.Column(db.String(45))
def __repr__(self):
return f'Id {self.id}'
class Categories(db.Model):
__tablename__ = 'categories'
__table_args__ = {'schema': 'products_data'}
id = db.Column(db.Integer, primary_key=True, unique=True, autoincrement=True)
name = db.Column(db.String(255))
def __repr__(self):
return f'Id {self.id}'
class Brands(db.Model):
__tablename__ = 'brands'
__table_args__ = {'schema': 'products_data'}
id = db.Column(db.Integer, primary_key=True, unique=True, autoincrement=True)
name = db.Column(db.String(255))
logo = db.Column(db.String(5000))
feed = db.Column(db.String(5000))
feed_type = db.Column(db.String(45))
category_id = db.Column(db.Integer, db.ForeignKey('categories.id'))
country_id = db.Column(db.Integer, db.ForeignKey('countries.id'))
awinmid = db.Column(db.Integer)
def __repr__(self):
return f'Id {self.id}'
class Products(db.Model):
__tablename__ = 'products'
__table_args__ = {'schema': 'products_data'}
id = db.Column(db.Integer, primary_key=True, unique=True, autoincrement=True)
name = db.Column(db.String(255))
url = db.Column(db.Text)
category_id = db.Column(db.Integer, db.ForeignKey('categories.id'))
country_id = db.Column(db.Integer, db.ForeignKey('countries.id'))
price = db.Column(db.Float)
currency = db.Column(db.String(45))
discount_price = db.Column(db.Float)
shipping = db.Column(db.Float)
brand_id = db.Column(db.Integer, db.ForeignKey('brands.id'))
Am I doing anything wrong when associating a column in products with a foreign key? This is the first time I encounter this error so I'm really lost on what to do right now.
To fix I just added the schema to the db.ForeignKey and it worked
Example:
db.ForeignKey('products_data.countries.id')
PS:
Not my idea. Just wanted to post the answer in case someone visits the post later with the same problem.
Gord Thompson thanks for the help!
First of all, I don t see any table Categories. Secondly, you copy pasted your schema from the Products table into your Countries one.
PS: By default sqlalchemy gives the tables the name of the class (lower cased). So your __tablename__='products' does nothing actually.
EDIT:
The problem with your code lies in how you set the __table_args__ attribute. You assign an object to it, which by their specifications is wrong.
Take a look at the following example and modify your code accordingly
__table_args__ = ({'schema': 'products_data'})
Also for further reference, take a look at this https://docs.sqlalchemy.org/en/13/orm/extensions/declarative/table_config.html

Count related items in a sqlalchemy model

I'm trying to count the number of items in their respective categories and end up with a collection that I can iterate through in a jinja template. My final output is something like:
category1, 5
category2, 10
category3, 0
The zero items case is important.
My model is:
class Category(Base):
__tablename__ = 'category'
id = Column(Integer, primary_key=True)
name = Column(String(80), unique=True)
user_id = Column(Integer, ForeignKey('user.id'))
user = relationship(User)
class Item(Base):
__tablename__ = 'item'
id = Column(Integer, primary_key=True)
name = Column(String(80))
description = Column(String(500))
category_id = Column(Integer, ForeignKey('category.id'))
category = relationship(Category)
user_id = Column(Integer, ForeignKey('user.id'))
user = relationship(User)
date_added = Column(DateTime, default=datetime.datetime.now)
I have been kindly pointed in the direction of Stackoverflow: Counting relationships in SQLAlchemy, which led me to the query
count_categories = db_session.query(Category.name, func.count(Item.id)).join(Item.category).group_by(Category.id).all()
Which is almost correct, but it does not handle the zero case. When a category has zero items, I still need the category returned by the query.
Any help, much appreciated.
Actually, I've figured it out:
count_categories = db_session.query(
Category.name, func.count(Item.id)).outerjoin(
Item).group_by(Category.id).all()
See SQLAlchemy documentation on Joins

How to insert the 'answer' model?

The title may be not exactly, but I don't know how to express it.
I have 3 class: User, Question, Answer. The simple code is:
Session = scoped_session(sessionmaker())
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
questions = relationship('Question', backref="user")
answers = relationship('Answer', backref="user")
class Question(Base):
__tablename__ = 'questions'
id = Column(Integer, primary_key=True)
user_id = Column(Integer, ForeignKey('users.id'))
answers = relationship('Answer', backref="user")
class Answer(Base):
__tablename__ = 'answers'
user_id = Column(Integer, ForeignKey('users.id'))
question_id = Column(Integer, ForeignKey('questions.id'))
id = Column(Integer, primary_key=True)
Now, A user asked a question, so there will be an answer created:
user = get_user_from_session()
question = get_question(question_id)
# create answer
answer = Answer()
answer.user = user
answer.question = question
Session.add(answer) # !!!
Session.commit()
I hope the answer will be inserted to database, but unfortunately, there is an error reported:
AttributeError: 'module' object has no attribute '_sa_instance_state'
Is there something I've missed? How to fix it?
UPDATE
Thanks for #dhaffey, I've fixed the typos. I recreate a test file to test this, found no error happened again, but answer.user_id and answer.question_id are null in database after commit.
This is my code, you can run it directly.
from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import *
engine = create_engine('sqlite:///test.sqlite', echo=True)
Session = scoped_session(sessionmaker())
Base = declarative_base()
Base.metadata.bind=engine
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String)
questions = relationship('Question')
answers = relationship('Answer')
class Question(Base):
__tablename__ = 'questions'
id = Column(Integer, primary_key=True)
user_id = Column(Integer, ForeignKey('users.id'))
title = Column(String)
answers = relationship('Answer')
class Answer(Base):
__tablename__ = 'answers'
user_id = Column(Integer, ForeignKey('users.id'))
question_id = Column(Integer, ForeignKey('questions.id'))
id = Column(Integer, primary_key=True)
Base.metadata.create_all()
user = User()
user.name = 'aaa'
Session.add(user)
Session.flush()
question = Question()
question.title = 'ttt'
question.user = user
Session.add(question)
Session.flush()
answer = Answer()
answer.user = user
answer.question = question
Session.add(answer)
Session.commit()
print answer.id # not None
found = Session.query(Answer).filter_by(id=answer.id).one()
print found.user.name # not None
print found.question.title # not None
# !!! It seems all models are saved correctly,
# but please open the test.sqlite database, (not querying by sqlahchemy)
# the question.user_id and answer.user_id and answer.question_id are null
Your class declarations don't "compile" for me, so I'm wondering if you've run this code, and which SQLAlchemy version you're using if so. The line
user_id = Column(Integer, ForeignKey='users.id')
raises
sqlalchemy.exc.ArgumentError: Unknown arguments passed to Column: ['ForeignKey']
with SQLAlchemy 0.6.4. You're trying to declare the foreign key with a keyword argument, but the correct usage is to construct a ForeignKey object and pass it positionally, like this:
user_id = Column(Integer, ForeignKey('users.id'))
With the foreign keys fixed, your example works as expected for me.
Note that you don't need to explicitly provide the primaryjoin argument on these relationships when the corresponding foreign keys are appropriately declared - SQLAlchemy infers the correct join.