如何将Mixins与SQLAlchemy一起使用以简化查询和过滤操作?

时间:2018-01-27 01:29:31

标签: python sqlalchemy mixins

假设以下设置:

from sqlalchemy import Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class MyClass(Base):
    id = Column(Integer, primary_key=True)
    name = Column(String)

使用SQLAlchemy查询数据库的正常范例是执行以下操作:

Session = sessionmaker()
engine = 'some_db_location_string'
session = Session(bind=engine)
session.query(MyClass).filter(MyClass.id == 1).first()

假设,我想将查询简化为以下内容:

MyClass(s).filter(MyClass.id == 1).first()

OR     MyClass(s​​).filter(id == 1).first()

我该怎么做?我第一次尝试使用模型Mixin类失败了。这就是我试过的:

class ModelMixins(object)
    def __init__(self, session):
        self.session = session

    def filter(self, *args):
        self.session.query(self).filter(*args)

# Redefine MyClass to use the above class
class MyClass(ModelMixins, Base):
    id = Column(Integer, primary_key=True)
    name = Column(String)

主要的失败似乎是我无法完全转移表达式' MyClass.id == 1'到作为会话对象一部分的实际过滤函数。

人们可能会问我为什么要这样做:

MyClass(s).filter(id == 1).first()

我已经看过类似之前使用的类似内容,并且认为语法变得如此清晰,我可以实现这一点。我想复制这个,但一直没能。能够做这样的事情:

def get_stuff(some_id):
    with session_scope() as s:
        rec = MyClass(s).filter(MyClass.id== some_id').first()
    if rec:
        return rec.name
    else:
        return None

......似乎是最干净的做事方式。首先,会话管理是分开的。其次,查询本身被简化了。拥有这样的Mixin类可以让我将过滤器功能添加到任意数量的类中......那么有人可以在这方面提供帮助吗?

2 个答案:

答案 0 :(得分:1)

Integer需要;你给它session.query,这是一个实例。将您的self方法替换为:

filter

并且至少有这么多:

def filter(self, *args):
    return session.query(self.__class__).filter(*args)

生成的SQL看起来也正确(为清晰起见添加了换行符):

In [45]: MyClass(session).filter(MyClass.id==1)
Out[45]: <sqlalchemy.orm.query.Query at 0x10e0bbe80>

不保证不会有奇怪之处;我以前从未尝试过这样的事情。

答案 1 :(得分:0)

我一直在使用此mixin获得成功。很可能不是世界上最有效的事情,我也不是专家。我为每个表定义一个date_created

class QueryBuilder:
"""
This class describes a query builer.
"""
q_debug = False
def query_from_dict(self, db_session: Session, **q_params: dict):
    """
    Creates a query.

    :param      db_session:  The database session
    :type       db_session:  Session
    :param      q_params:    The quarter parameters
    :type       q_params:    dictionary
    """
    q_base = db_session.query(type(self))
    for param, value in q_params.items():
        if param == 'start_date':
            q_base = q_base.filter(
                type(self).__dict__.get('date_created') >= value
            )
        elif param == 'end_date':
            q_base = q_base.filter(
                type(self).__dict__.get('date_created') <= value
            )
        elif 'like' in param:
            param = param.replace('_like', '')
            member = type(self).__dict__.get(param)
            if member:
                q_base = q_base.filter(member.ilike(f'%{value}%'))
        else:
            q_base = q_base.filter(
                type(self).__dict__.get(param) == value
            )
    if self.q_debug:
        print(q_base)
    return q_base