如何用动态关系映射SQLAlchemy中的层次结构?

2024-05-18 23:40:49 发布

您现在位置:Python中文网/ 问答频道 /正文

我定义了如下SQLAlchemy模型:

class SubProject(Base):
  active = Column(Boolean)

class Project(Base):
  active = Column(Boolean)
  subprojects = relationship(SubProject, backref=backref('project'))

class Customer(Base):
  active = Column(Boolean)
  projects = relationship(Project, backref=backref('customer'))

我需要得到这两个州之一的客户名单:

  1. 所有客户,包括所有项目和所有子项目
  2. 只有活动客户,只有活动项目和活动子项目

    编辑值得注意的是,所有没有项目的活跃客户都应包括在内, 所有未进行调查的活动项目都应包括在这一部分中。

这在SQL中使用join是微不足道的,但是我不知道如何使用sqlalchemyorm来完成它。解决办法是什么?在


Tags: 项目模型projectbase客户定义sqlalchemycolumn
2条回答

如果我理解正确,您需要所有非活动对象对查询不可见。以下类将筛选出active属性设置为False的所有模型对象,包括通过关系访问的对象:

from sqlalchemy.orm import Query
from sqlalchemy.orm.util import _class_to_mapper


class QueryActive(Query):

    def __init__(self, entities, *args, **kwargs):
        Query.__init__(self, entities, *args, **kwargs)
        query = self
        for entity in entities:
            if hasattr(entity, 'parententity'):
                entity = entity.parententity
            cls = _class_to_mapper(entity).class_
            if hasattr(cls, 'active'):
                query = query.filter(cls.active==True)
        self._criterion = query._criterion

    def get(self, ident):
        # Use default implementation when there is no condition
        if not self._criterion:
            return Query.get(self, ident)
        # Copied from Query implementation with some changes.
        if hasattr(ident, '__composite_values__'):
            ident = ident.__composite_values__()
        mapper = self._only_mapper_zero(
                    "get() can only be used against a single mapped class.")
        key = mapper.identity_key_from_primary_key(ident)
        if ident is None:
            if key is not None:
                ident = key[1]
        else:
            from sqlalchemy import util
            ident = util.to_list(ident)
        if ident is not None:
            columns = list(mapper.primary_key)
            if len(columns)!=len(ident):
                raise TypeError("Number of values doesn't match number "
                                'of columns in primary key')
            params = {}
            for column, value in zip(columns, ident):
                params[column.key] = value
            return self.filter_by(**params).first()

要使用它,您必须创建一个单独的会话对象:

^{pr2}$

这种方法有局限性,对于一些复杂的查询来说不适用,但对于大多数项目来说是可以的。在

为了补充丹尼斯的回答,您可以使用enable\u断言(False)。据我所知,这是对SQLAlchemy为正常操作添加的查询的额外检查。对于更复杂的情况,您可以禁用它。在

相关问题 更多 >

    热门问题