Как выполнить запрос в выражении sqlalchemy hybird? - PullRequest
0 голосов
/ 27 мая 2018

Имейте класс Run, который имеет отношение "имеет много" к тегу класса.Мне нужно иметь возможность фильтровать прогоны на основе функции тегов (tag_collection).

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

Base = automap_base()

class Run(Base):
    __tablename__ = 'runs'
    macro_id = Column(ForeignKey('macros.id'))  

    @hybrid_property
    def tag_count(self):
        return(len(self.tag_collection))

    @hybrid_property
    def default_region(self):
        return(reduce(lambda  memo, t: memo or t.name == "region" and t.value == "default", self.tag_collection, False))

    @default_region.expression
    def default_region(cls):
        # how do I do the query here?

class Tag(Base):
    __tablename__ = 'tags'
    run_id = Column(ForeignKey('runs.id'))    

Если я получу экземпляр Run, я могу использовать свойство default_region, нокогда я запускаю запрос и пытаюсь фильтровать, используя свойство default_region, я либо получаю класс Run, переданный (как self) в @hybird_property украшенный default_region метод, либо получаю @default_region.expression украшенный default_region метод, который также получает класс Run.

Пример запроса:

session.query(Run).filter(Run.default_region == True).all()

Я думаю, что мне нужно сделать запрос в @default_region.expression украшенном default_region методе, но яне вижу, как получить ручку на сессии.Я знаю о Session.object_session(someobject), но я думаю, что someobject должен быть экземпляром класса orm, а не самого класса.

Я думаю, что я либо совершенно ошибочен в моей методологии фильтрации, либо мне нужнокаким-то образом получить дескриптор объекта сеанса в этом @default_region.expression украшенном default_region методе.

Есть ли лучший способ выполнить эту фильтрацию?

Как получить сеанс в@default_region.expression оформленный default_region метод?

1 Ответ

0 голосов
/ 27 мая 2018

Мне кажется, что это коррелированный гибрид отношений подзапроса .Когда Run.default_region добавляется в качестве фильтра, вы хотите обновить запрос, добавив

WHERE EXISTS (
    SELECT 1 FROM tags
    WHERE run_id = runs.id
      AND name = "region"
      AND value = "default")

Возвращать его как выражение с помощью функции exists() :

from sqlalchemy.sql import exists, and_

@default_region.expression
def default_region(cls):
    return exists([1]).where(and_(
        Tag.run_id == cls.id,
        Tag.name == 'region',
        Tag.value == 'default'))

Обратите внимание, что вы хотите избегать , используя == True или == False здесь, в этом нет необходимости!Просто используйте свойство напрямую:

session.query(Run).filter(Run.default_region).all()

или используйте ~ для отрицания:

session.query(Run).filter(~Run.default_region).all()

Определяя метод .expression для свойства, вывелел SQLAlchemy использовать этот метод при доступе к свойству класса, поэтому контекст всегда там .Без определения .exists (или .comparator) Run.default_region вызовет метод получения default_region (метод, украшенный `@hybrid_property) как метод класса, поэтому только тогда этот метод будет иметьзатем работать с экземпляром или передаваемого класса. Для некоторых реализаций гибридного свойства это работает благодаря тому, как они используют атрибуты в контексте.

Что касаетсяреализация свойства default_region instance , я бы там не использовал reduce();используйте функцию any() :

@hybrid_property
def default_region(self):
    return any(
        t.name == "region" and t.value == "default"
        for t in self.tag_collection)

any() прекращает итерацию по предоставленному выражению генератора, когда совпадение найдено.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...