如何在SQLAlchemy中查询关联表?

时间:2016-12-21 19:16:16

标签: python sql sqlalchemy flask-sqlalchemy

我正在尝试将SQL查询转换为SQLAlchemy查询到get API内的用户。问题是我无法从关联表中查询任何内容。 (我确定我不知道这个方法。)

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

使用SQL查询:

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查询我遇到问题:

roles_users.query.join(Role).join(User)
   .filter(roles_users.user_id == User.id and 
       roles_users.role_id == Role.id).all()

我在SQLAlchemy查询上面使用的错误:

AttributeError: 'Table' object has no attribute 'query'

如何使用SQLAlchemy执行SQL查询的等效操作?

4 个答案:

答案 0 :(得分:8)

好的,所以在Flask-Sql炼金术中查询关联对象的关键是对roles_users进行外部连接。尝试先加入所有表,然后再过滤。我在下面发布了答案。

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()

不要忘记放置' c'查询关联表对象时。没有它,它就不会起作用。

还有一点,不要忘记设置backref lazy ='加入'

答案 1 :(得分:1)

与选择的答案非常相似,但对于更多示例而言,可能对某些人有用:

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()

答案 2 :(得分:0)

我认为,如果您的DAO代码库是面向ORM的,那么也许您应该尝试重新考虑您的情况,并利用您定义的sqlalchemy关系,因为它会为您查询用户角色,从而为您处理必要的联接。 根据您的示例,类似:

users = db.session.query(User).all()
for user in users:
  for role in user.roles:
    print((user.first_name, user.last_name, role.name))

答案 3 :(得分:0)

也可以使用select_from语句。

这是用于将关联表声明为对象并使用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'))

然后您可以像这样查询用户角色:

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())

编辑:好的,使用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])