Python 3.x 烧瓶SQLAlchemy:自动过滤';删除';条目

Python 3.x 烧瓶SQLAlchemy:自动过滤';删除';条目,python-3.x,flask,sqlalchemy,flask-sqlalchemy,Python 3.x,Flask,Sqlalchemy,Flask Sqlalchemy,我正在开发一个庞大的代码库,它可以完成以下所有数据库交互: ExampleClass.query.all() class BaseEntity(object): deleted = db.Column(db.DateTime, default=None, nullable=True) ... # more columns AttributeError: 'Mapper' object has no attribute 'deleted' 其中,ExampleClass继承了

我正在开发一个庞大的代码库,它可以完成以下所有数据库交互:

ExampleClass.query.all()
class BaseEntity(object):
    deleted = db.Column(db.DateTime, default=None, nullable=True)
    ... # more columns
AttributeError: 'Mapper' object has no attribute 'deleted'
其中,
ExampleClass
继承了
db.Model
和我们的
BaseEntity
的属性,定义如下:

ExampleClass.query.all()
class BaseEntity(object):
    deleted = db.Column(db.DateTime, default=None, nullable=True)
    ... # more columns
AttributeError: 'Mapper' object has no attribute 'deleted'
现在,当我查询所有条目的
ExampleClass
时,
ExampleClass.query.all()
,我希望将删除字段设置为日期的条目(即从系统中删除的条目)排除在外。如果我不必用一个简单的
.filter(deleted!=None)
更新整个代码库,这将是理想的选择。我的解决方案是添加SQLAlchemy事件筛选器:。文档为我提供了搜索的确切内容:

@event.listens_for(Query, "before_compile", retval=True)
def no_deleted(query):
    for desc in query.column_descriptions:
        if desc['type'] is ExampleClass:
            entity = desc['expr']
            query = query.filter(entity.deleted == False)
    return query
但是,我无法使其工作,我遇到的最后一个错误如下:

ExampleClass.query.all()
class BaseEntity(object):
    deleted = db.Column(db.DateTime, default=None, nullable=True)
    ... # more columns
AttributeError: 'Mapper' object has no attribute 'deleted'

我使用的库的版本是:Flask==0.10.1,Flask SQLAlchemy==1.0,SQLAlchemy==1.0.6

class BaseEntity(db.Model):
    deleted = db.Column(db.DateTime, default=None, nullable=True)

BaseEntity.query = BaseEntity.query.filter(BaseEntity.deleted == None)

这样说,其他开发人员可能会期望 BaseTrave.QueQue/Cult>从一个干净的查询对象开始,因此您可以考虑使用不同的类属性而不是<代码>查询< /> >:

class BaseEntity(db.Model):
    deleted = db.Column(db.DateTime, default=None, nullable=True)

BaseEntity.non_deleted = BaseEntity.query.filter(BaseQuery.deleted == None)

# and then use it like …
BaseEntity.non_deleted.all()

我知道这是一个老问题,但最近我通过此函数使其工作:

@event.listens_for(Query, "before_compile", retval=True) 
def no_deleted(query):
    for desc in query.column_descriptions:
        if desc['type'] is ExampleClass:
           entity = desc['entity']

           limit, offset = query._limit, query._offset
           query._limit, query._offset = None, None

           query = query.filter(entity.deleted == False)

           query._limit, query._offset = limit, offset

    return query
您需要对实体而不是类型进行筛选。临时取消限额和抵销

烧瓶==1.0.2,烧瓶SQLAlchemy==2.3.2,SQLAlchemy==1.2.12

升级版本: 如果希望不排除已删除的项目,则有以下选项:

创建QueryMixin:

class ShowDeleted:
    def show_deleted(self):
        q = self._clone()
        q.__dict__['__show_deleted'] = True
        return q
编辑无删除功能

def no_deleted(query):
    for desc in query.column_descriptions:
        show_deleted = query.__dict__.get('__show_deleted', False)
        if not show_deleted and desc['type'] is ExampleClass:
            entity = desc['entity']

            limit, offset = query._limit, query._offset
            query._limit, query._offset = None, None

            query = query.filter(entity.deleted == False)

            query._limit, query._offset = limit, offset

    return query
如果您使用的是FlaskSQLAlchemy,请按以下方式设置数据库:

from flask_sqlalchemy import SQLAlchemy, BaseQuery

db = SQLAlchemy(query_class= type('Query', (ShowDeleted, BaseQuery), {}))
对于原始sqlalchemy,请使用以下代码段:

from sqlalchemy.orm import Query
db = scoped_session(sessionmaker(query_cls=type('Query', (ShowDeleted, Query), {})))
现在您可以输入代码调用

db.session.query(ExampleClass).show_deleted().all()