代码之家  ›  专栏  ›  技术社区  ›  nPn

如何在sqlAlchemy hybird表达式中运行查询?

  •  0
  • nPn  · 技术社区  · 6 年前

    使类运行与类标记具有“多”关系。 我需要能够根据标签(tag_collection)的函数筛选运行。

    下面是我的代码片段。在这种情况下,我正在使用automapper,但我不认为这太重要。

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

    如果我得到一个运行实例,我可以利用 default_region 属性,但当我运行查询并尝试使用 默认区域 属性,我或者让运行类在 @hybird_property 装饰 默认区域 方法或我最终在 @default_region.expression 装饰 默认区域 方法,它还接收运行类。

    示例查询:

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

    我想我需要在 @默认_region.expression 装饰 默认区域 方法,但我不知道如何获取会话的句柄。我知道 Session.object_session(someobject) 但是我想 someobject 需要是ORM类的实例,而不是类本身。

    我认为我对过滤方法完全错误,或者我需要以某种方式处理会话对象。 @默认_region.expression 装饰 默认区域 方法。

    有没有更好的方法来完成这个过滤?

    A如何在 @默认_region.expression 默认区域 方法?

    1 回复  |  直到 6 年前
        1
  •  1
  •   Martijn Pieters    6 年前

    在我看来这是一个 Correlated Subquery Relationship Hybrid . 什么时候? Run.default_region 作为筛选器添加,您要更新要添加的查询

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

    将其作为表达式返回,并使用 exists() function :

    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 method 对于该属性,您已经告诉sqlAlchemy在访问类上的属性时使用该方法,因此上下文是 总是在课堂上 在那里。没有定义 .exists (或) .comparator ), run.default_区域 会打电话给 default_region getter(用`@hybrid_属性修饰的方法)作为类方法,因此只有这样,该方法才能与任何一个实例一起使用 正在传入的类。对于一些混合属性实现,这恰好是由于它们如何在上下文中使用属性而起作用的。

    关于实施 默认区域 实例 属性,我不使用 reduce() 在那里;使用 any() function :

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

    任意() 找到匹配项后停止迭代提供的生成器表达式。