Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python SQLAlchemy:修改查询对象的from子句_Python_Mysql_Sqlalchemy - Fatal编程技术网

Python SQLAlchemy:修改查询对象的from子句

Python SQLAlchemy:修改查询对象的from子句,python,mysql,sqlalchemy,Python,Mysql,Sqlalchemy,我有几个类具有相同的抽象基和相同的模式,引用数据库中类似的表。我的查询非常简单,没有连接,过滤条件简单直观。我在类层次结构中使用多态标识,以便无缝地执行联合 问题是,有时我需要对多个表重复相同的查询并执行联合。我在SQLAlchemy中找不到解决这个问题的方法,我正在尝试在我的自定义BaseQuery类上实现一个方法,通过克隆原始查询并更改用于from子句的类/映射器,我可以使用该方法自动完成这一切 例如,今天我必须做这样的事情: query1 = MyModel1.query.filter_b

我有几个类具有相同的抽象基和相同的模式,引用数据库中类似的表。我的查询非常简单,没有连接,过滤条件简单直观。我在类层次结构中使用多态标识,以便无缝地执行联合

问题是,有时我需要对多个表重复相同的查询并执行联合。我在SQLAlchemy中找不到解决这个问题的方法,我正在尝试在我的自定义BaseQuery类上实现一个方法,通过克隆原始查询并更改用于from子句的类/映射器,我可以使用该方法自动完成这一切

例如,今天我必须做这样的事情:

query1 = MyModel1.query.filter_by(foo=bar)
query2 = MyModel2.query.filter_by(foo=bar)
query3 = MyModel3.query.filter_by(foo=bar)

query = query1.union(query2).union(query3)
我希望能做一些类似的事情

query = MyModel1.query.filter_by(foo=bar).with_unions(MyModel2, MyModel3)
对于_联合,应该是这样的,其中replace_from_子句是我所追求的方法:

def with_unions(self, *others):
    query = self._clone()

    for other in others:
        query = query.union(replace_from_clause(query, other))

    return query
SQLAlchemy中是否有类似于replace_from_子句的方法,或者有什么方法可以实现它


不用说,如果有更好的方法,我洗耳恭听。

据我所知/根据我的经验/根据StackOveflow回答:你不能像这样与ORM结合

我设法实现了您或多或少想要的语法,并在返回时将所有内容加载回orm。关于相同列的联合等的一般注意事项都适用于more,这里需要使用相同的列名进行筛选。此外,我不认为我会在实践中使用这个

from functools import partial
import sqlalchemy
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import *
from sqlalchemy import orm
from sqlalchemy import sql

engine = sqlalchemy.create_engine('sqlite://')
connection = engine.connect()


Base = declarative_base()


class Student(Base):
    __tablename__ = "students"
    id = Column(Integer, primary_key=True)
    name = Column(String(767), unique=True)
    caretaker = Column(String(50))

    def __repr__(self):
        return 'Student(name={s.name}, caretaker={s.caretaker}'.format(s=self)


class Patient(Base):
    __tablename__ = "patients"
    id = Column(Integer, primary_key=True)
    name = Column(String(767), unique=True)
    caretaker = Column(String(50))

    def __repr__(self):
        return 'Patient(name={s.name}, caretaker={s.caretaker}'.format(s=self)

class StagedOperation(object):

    def __init__(self, attr):
        self.attr = attr

    def __call__(self, *args, **kwargs):
        self.args = args
        self.kwargs = kwargs


class StagedQuery(object):

    def __init__(self, model, session=None):
        self.session = session
        self.models = [model]
        self.columns = [e.name for e in model.__table__.columns]
        self.ops = []

    def __getattr__(self, attr):
        # __getattr__ fires only when an attribute is requested & not found
        # We will attempt to pass on any attribute call on to the resulting 
        # Query objects; do note this will only work, technically and logicaly, 
        # with method calls, not attribute access 
        if hasattr(orm.query.Query, attr):
            obj = StagedOperation(attr)
            self.ops.append(obj)

            # really getting hacky to enable "chaining"
            # Could also build this into the StagedOperation.__call__
            def _allow_chaining(desired_return, op, *args, **kwargs):
                op(*args, **kwargs)
                return desired_return

            return partial(_allow_chaining, self, obj)

    def with_unions(self, *models):
        self.models.extend(models)
        return self

    def with_session(self, session):
        self.session = session
        return self

    def query(self):
        q = None
        for model in self.models:
            id_col = sql.literal(model.__tablename__).label('tablename')
            columns = self.columns + [id_col]
            mq = orm.query.Query(columns).select_from(model)
            for op in self.ops:
                mq = getattr(mq, op.attr)(*op.args, **op.kwargs)
            q = q.union(mq) if q else mq
        return q

    def _deserialize_row(self, row):
        ref = {e.__tablename__: e for e in self.models}
        return ref[row.tablename](**{k: getattr(row, k) for k in self.columns})

    def one(self):
        return self._deserialize_row(
            self.query().with_session(self.session).one())

    def first(self):
        r = self.query().with_session(self.session).first()
        if r:
            return self._deserialize_row(r)

    def all(self):
        return [
            self._deserialize_row(e) for e in
            self.query().with_session(self.session).all()]


if __name__ == '__main__':
    engine = create_engine('sqlite://')
    Session = orm.sessionmaker()
    Session.configure(bind=engine)
    Base.metadata.bind = engine
    Base.metadata.create_all()

    session = Session()

    #
    # Insert some objects
    #

    stu = Student(id=1, name='John', caretaker='Mother')
    stu2 = Student(id=2, name='Sally', caretaker='Mother')
    stu3 = Student(id=3, name='Scott', caretaker='Father')

    pat = Patient(id=1, name='Susan', caretaker='Mother')
    pat2 = Patient(id=2, name='Sally', caretaker='Father')
    pat3 = Patient(id=3, name='Turnip', caretaker='Father')

    session.add_all([stu, stu2, stu3, pat, pat2, pat3])
    session.flush()

    # Some usage options
    print (
        StagedQuery(Student)
        .filter_by(caretaker='Mother')
        .with_unions(Patient)
        .with_session(session)
        .all())

    print (
        StagedQuery(Student, session=session)
        .filter_by(caretaker='Mother')
        .filter_by(name='Sally')
        .with_unions(Patient)
        .all())
印刷品

[Student(name=John, caretaker=Mother, Patient(name=Susan, caretaker=Mother, Student(name=Sally, caretaker=Mother]
[Student(name=Sally, caretaker=Mother]

不可怕,但仍远不能使用。它给了我一些想法,谢谢。顺便说一句,当您具有多态身份时,联合就起作用了。事实上,如果我使用基类进行查询,SQLAlchemy会自动执行联合,但他将where子句放在最终的联合查询中,而不是每个子查询中,MySQL太笨了,无法优化它;我想在你的问题上加上这个,它会改变我的答案。好主意。我就这么做了。