SQLAlchemy запрос с использованием списка элементов

Я создал базу данных SQLAlchemy, которая выглядит примерно так:

class ChangelogEntry(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    apps = db.relationship('App', secondary=app_changelogEntry)
    appGroups = db.relationship('AppGroup', secondary=appGroup_changelogEntry)

class App(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(32), unique=True, index=True)
    appGroups = db.relationship('AppGroup', secondary=app_appGroup)

class AppGroup(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(32), unique=True, index=True)
    apps = db.relationship('App', secondary=app_appGroup)

ОБНОВИТЬ:

app_changelogEntry = db.Table('App_ChangelogEntry',
    db.Column('app_id', db.Integer, db.ForeignKey('app.id')),
    db.Column('changelog_id', db.Integer, db.ForeignKey('changelog_entry.id'))
)

appGroup_changelogEntry = db.Table('AppGroup_ChangelogEntry',
    db.Column('appGroup_id', db.Integer, db.ForeignKey('app_group.id')),
    db.Column('changelogEntry_id', db.Integer, db.ForeignKey('changelog_entry.id'))
)

app_appGroup = db.Table('App_AppGroup',
    db.Column('app_id', db.Integer, db.ForeignKey('app.id')),
    db.Column('appGroup_id', db.Integer, db.ForeignKey('app_group.id'))
)

Приложение может входить в состав нескольких групп приложений, а пользователи могут создавать ChangelogEntries и могут выбирать, к каким приложениям / приложениям и / или группам приложений принадлежит эта ChangelogEntry.

Это выглядит так:

Хорошо. Я просто хочу получить все ChangelogEntries, которые принадлежат, например, App3 (App3 является частью AppGroups Group1 и Group2) и в этом случае Group1 и Group2.

Я надеюсь, что вы можете помочь мне с этим!

1 ответ

Решение

Объединение может хорошо соответствовать поставленной задаче: найти объединение записей журнала изменений с прямыми отношениями приложения и через группы. Использование внутренних объединений:

direct = db.session.query(ChangelogEntry).\
    join("apps").\
    filter(App.name == "App3")

groups = db.session.query(ChangelogEntry).\
    join("appGroups", "apps").\
    filter(App.name == "App3")

direct.union(groups).all()

Из-за отношений "многие ко многим" объединения групп могут создать несколько строк для записи в журнале изменений, но об этом позаботится использование UNION вместо UNION ALL. Чтобы избежать дублирования строк, для начала вы можете использовать semijoins/EXISTS:

direct = db.session.query(ChangelogEntry).\
    filter(ChangelogEntry.apps.any(App.name == "App3"))

groups = db.session.query(ChangelogEntry).\
    filter(ChangelogEntry.appGroups.any(
        AppGroup.apps.any(App.name == "App3")))

direct.union(groups).all()
Другие вопросы по тегам