Reputation: 1468
I'm trying to convert an SQL query into an SQLAlchemy query to user inside get API. The problem is that I cannot query anything from the association table. (I'm sure I don't know the method).
ORM:
roles_users = db.Table(
'roles_users',
db.Column('user_id', db.Integer(), db.ForeignKey('user.id')),
db.Column('role_id', db.Integer(), db.ForeignKey('role.id'))
)
class Role(db.Model, RoleMixin):
id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.String(50), unique=True)
description = db.Column(db.String(255))
def __str__(self):
return self.name
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
first_name = db.Column(db.String(50))
last_name = db.Column(db.String(50))
email = db.Column(db.String(50), unique=True)
password = db.Column(db.String(255))
.
.
.
roles = db.relationship('Role', secondary=roles_users,
backref=db.backref('users', lazy='dynamic'))
def __str__(self):
return self.email
Working SQL query:
select first_name, last_name, role.name from user
join roles_users
join role on user.id = roles_users.user_id
and role.id = roles_users.role_id;
SQLAlchemy query that I'm having trouble with:
roles_users.query.join(Role).join(User)
.filter(roles_users.user_id == User.id and
roles_users.role_id == Role.id).all()
Error that I'm getting using above SQLAlchemy query:
AttributeError: 'Table' object has no attribute 'query'
How do I perform the equivalent of my SQL query using SQLAlchemy?
Upvotes: 26
Views: 29299
Reputation: 101
It's also possible to use a select_from
statement.
This is for when you have declared your association table as an object and are using flask_user:
from flask_user import UserMixin
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class User(db.Model, UserMixin):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100, collation='NOCASE'),
nullable=False, server_default='')
password = db.Column(db.String(255), nullable=False, server_default='')
roles = db.relationship('Role', secondary='user_roles')
class Role(db.Model):
__tablename__ = 'roles'
id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.String(50), unique=True)
# Associatin Table:
class UserRoles(db.Model):
__tablename__ = 'user_roles'
id = db.Column(db.Integer(), primary_key=True)
user_id = db.Column(db.Integer(), db.ForeignKey('users.id',
ondelete='CASCADE'))
role_id = db.Column(db.Integer(), db.ForeignKey('roles.id',
ondelete='CASCADE'))
You can then query the user roles like this:
from app.db_model import db, Broker, UserRoles
from flask_user import current_user
user_id = current_user.id
all_user_roles =\
(db.session.query(Role.name)
.select_from(UserRoles, Role)
.join(UserRoles)
.filter(UserRoles.user_id == user_id)
.all())
EDIT: Ok, it's even simpler with current_user
# a list of all Role objects in roles
current_user.roles
# print out all names
print([role.name for role in current_user.roles])
Upvotes: 2
Reputation: 388
Very similar to the selected answer, but maybe helpful for some people with some more examples:
result = session.query(User.first_name, User.last_name, Role.name, roles_users).filter(
roles_users.c.user_id == User.id).filter(roles_users.c.role_id == Role.id).all()
Upvotes: 9
Reputation: 1440
I think if your DAO codebase is ORM oriented then maybe you should try to rethink your scenario and take advantage of the sqlalchemy relationship you had defined given it will take care of necessary joins for you in order to query users' roles. According to your example, something like:
users = db.session.query(User).all()
for user in users:
for role in user.roles:
print((user.first_name, user.last_name, role.name))
Upvotes: 5
Reputation: 1468
Ok, so the key to querying association object in Flask-Sql alchemy is to make an external join to roles_users. Try to join all tables first and then filter afterwards. I'm posting the answer below.
query_user_role = User.query.join(roles_users).join(Role).
filter((roles_users.c.user_id == User.id) & (roles_users.c.role_id == Role.id)).all()
Do not forget to put 'c' when querying association table object. Without it, it won't work.
One more thing, do not forget to set backref lazy = 'joined'
Upvotes: 41