SQLAlchemy ленивый = динамический с отношением m2m с использованием шаблона объекта ассоциации

У меня есть простая связь m2m между таблицами users и roles:

users_roles = db.Table('users_roles',
    db.Column('user_id', db.Integer, db.ForeignKey('users.id')),
    db.Column('role_id', db.Integer, db.ForeignKey('roles.id')),
    db.Column('is_primary', db.Boolean)
)

class User(db.Model):
    __tablename__ = 'users'
    id = db.Column('id', db.Integer, primary_key=True)
    roles = db.relationship('Role', secondary=users_roles, lazy='dynamic', backref=db.backref('users', lazy='dynamic'))

class Role(db.Model):
    __tablename__ = 'roles'
    id = db.Column('id', db.Integer, primary_key=True)
    users = db.relationship('User', secondary=users_roles, lazy='dynamic', backref=db.backref('roles', lazy='dynamic'))

Чтобы добавить запись в таблицу users_roles, мне нужно сделать что-то вроде этого:

role = Role.get(1)
user = User()
user.roles.append(role)
db.session.add(user)
db.session.commit()

Это нормально, но у меня есть столбец с именем is_primary в таблице users_roles, который также должен быть заполнен.

Я изменил свой код, чтобы использовать шаблон объекта ассоциации как описано в документации SQLAlchemy.

Теперь мой код выглядит так:

class User(db.Model):
    __tablename__ = 'users'
    id = db.Column('id', db.Integer, primary_key=True)

class Role(db.Model):
    __tablename__ = 'roles'
    id = db.Column('id', db.Integer, primary_key=True)

class UserRole(db.Model):
    __tablename__ = 'users_roles'
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'), primary_key=True)
    role_id = db.Column(db.Integer, db.ForeignKey('roles.id'), primary_key=True)
    is_primary = db.Column(db.Boolean)

    user = db.relationship(User, backref="users_roles")
    role = db.relationship(Role, backref="users_roles")

User.roles = association_proxy("users_roles", "role")
Role.users = association_proxy("users_roles", "user")

Это работает хорошо, но у меня все еще есть проблема. Возможно ли, что User.roles (добавленный с прокси-сервером ассоциации) возвращает AppenderBaseQuery, что я могу добавить дополнительные фильтры, например. User.query.get(1).roles.filter_by(...)? Я привык делать это с помощью простого отношения «многие ко многим», используя lazy=dynamic в объявлении отношения, но после указания сопоставления классов с таблицей ассоциаций кажется, что я больше не могу этого делать. Есть ли способ добиться этого?

@IfLoop Я последовал вашей рекомендации в этом сообщении. Ваша помощь будет высоко оценена.


person stefanobaldo    schedule 31.01.2015    source источник


Ответы (1)


Что ж, в итоге я отфильтровал roles, используя следующий код:

roles = Role.query.filter_by(...).join(UserRole).join(User).filter_by(id=1)

Я все еще хочу иметь возможность сделать что-то вроде этого:

roles = User.query.get(1).roles.filter_by(...).all()

В любом случае, если я не получу ответов через несколько дней, я приму это как ответ.

person stefanobaldo    schedule 01.02.2015