Orm 实施";软删除";使用sqlalchemy的系统

Orm 实施";软删除";使用sqlalchemy的系统,orm,sqlalchemy,Orm,Sqlalchemy,我们正在使用tornado和sqlalchemy为应用程序创建服务。该应用程序是用django编写的,并使用“软删除机制”。这意味着底层mysql表中没有删除。要将一行标记为已删除,我们只需将属性化的“delete”设置为True。然而,在服务中,我们使用的是sqlalchemy。最初,我们开始在通过sqlalchemy本身进行的查询中添加check for delete,如下所示: customers = db.query(Customer).filter(not_(Customer.dele

我们正在使用tornado和sqlalchemy为应用程序创建服务。该应用程序是用django编写的,并使用“软删除机制”。这意味着底层mysql表中没有删除。要将一行标记为已删除,我们只需将属性化的“delete”设置为True。然而,在服务中,我们使用的是sqlalchemy。最初,我们开始在通过sqlalchemy本身进行的查询中添加check for delete,如下所示:

customers = db.query(Customer).filter(not_(Customer.deleted)).all()
然而,这会导致许多潜在的bug,因为开发人员往往会错过对已删除查询的检查。因此,我们决定使用执行“预筛选”的查询类覆盖默认查询:

这源于sqlalchemy文档的解决方案:

https://bitbucket.org/zzzeek/sqlalchemy/wiki/UsageRecipes/PreFilteredQuery
但是,我们仍然面临一些问题,比如我们一起进行过滤和更新,并且使用上面定义的查询类,在应用过滤器进行更新时,更新不遵守
delete=False
的标准

db = CustomSession(with_deleted=False)()
result = db.query(Customer).filter(Customer.id == customer_id).update({Customer.last_active_time: last_active_time })

如何在sqlalchemy中实现“软删除”功能我在这里做了类似的事情。我们做的有点不同,我们制作了一个服务层,所有数据库访问都要经过它,有点像一个控制器,但只针对db访问,我们称之为ResourceManager,它的灵感来源于“域驱动设计”(一本很棒的书,对于很好地使用SQLAlchemy非常有价值)。每个聚合根都有一个派生的ResourceManager,即您希望获得的每个资源类。(虽然有时对于真正简单的ResourceManager,派生的manager类本身是动态生成的)它有一个方法,可以给出基本查询,并且在发出该基本查询之前,该基本查询会被过滤以进行软删除。从那时起,您可以生成性地添加到该查询以进行筛选,最后使用query.one()或first()或all()或count()调用它。注意,对于这种生成式查询处理,我遇到了一个难题,如果您加入一个表的次数太多,您可能会挂起自己。在某些情况下,为了进行筛选,我们必须跟踪哪些表已经加入。如果您的删除筛选器不在主表中,只需先筛选该筛选器,然后您就可以随意无条件地加入

比如说:

class ResourceManager(object):
     # these will get filled in by the derived class
     # you could use ABC tools if you want, we don't bother
     model_class = None
     serializer_class = None

     # the resource manager gets instantiated once per request
     # and passed the current requests SQAlchemy session 
     def __init__(self, dbsession):
         self.dbs = dbsession 

     # hand out base query, assumes we have a boolean 'deleted' column
     @property
     def query(self):
         return self.dbs(self.model_class).filter(
            getattr(self.model_class, 'deleted')==False)

 class UserManager(ResourceManager):
     model_class = User

 # some client code might look this
 dbs = SomeSessionFactoryIHave()
 user_manager = UserManager(dbs)   
 users = user_manager.query.filter_by(name_last="Duncan").first()        
现在,只要我总是从ResourceManager开始,它还有其他好处(参见前面提到的书),我就知道我的查询是预过滤的。这对于我们当前的一个项目非常有效,该项目具有软删除和相当广泛且棘手的数据库模式


我在这里也做过类似的事情。我们做的有点不同,我们制作了一个服务层,所有数据库访问都要经过它,有点像一个控制器,但只针对db访问,我们称之为ResourceManager,它的灵感来源于“域驱动设计”(一本很棒的书,对于很好地使用SQLAlchemy非常有价值)。每个聚合根都有一个派生的ResourceManager,即您希望获得的每个资源类。(虽然有时对于真正简单的ResourceManager,派生的manager类本身是动态生成的)它有一个方法,可以给出基本查询,并且在发出该基本查询之前,该基本查询会被过滤以进行软删除。从那时起,您可以生成性地添加到该查询以进行筛选,最后使用query.one()或first()或all()或count()调用它。注意,对于这种生成式查询处理,我遇到了一个难题,如果您加入一个表的次数太多,您可能会挂起自己。在某些情况下,为了进行筛选,我们必须跟踪哪些表已经加入。如果您的删除筛选器不在主表中,只需先筛选该筛选器,然后您就可以随意无条件地加入

比如说:

class ResourceManager(object):
     # these will get filled in by the derived class
     # you could use ABC tools if you want, we don't bother
     model_class = None
     serializer_class = None

     # the resource manager gets instantiated once per request
     # and passed the current requests SQAlchemy session 
     def __init__(self, dbsession):
         self.dbs = dbsession 

     # hand out base query, assumes we have a boolean 'deleted' column
     @property
     def query(self):
         return self.dbs(self.model_class).filter(
            getattr(self.model_class, 'deleted')==False)

 class UserManager(ResourceManager):
     model_class = User

 # some client code might look this
 dbs = SomeSessionFactoryIHave()
 user_manager = UserManager(dbs)   
 users = user_manager.query.filter_by(name_last="Duncan").first()        
现在,只要我总是从ResourceManager开始,它还有其他好处(参见前面提到的书),我就知道我的查询是预过滤的。这对于我们当前的一个项目非常有效,该项目具有软删除和相当广泛且棘手的数据库模式


我将创建一个函数

def customer_query():
    return db.session.query(Customer).filter(Customer.deleted == False)

我使用查询函数来不忘记默认标志,根据用户权限设置标志,使用连接等进行过滤,这样这些东西就不会在不同的地方被复制粘贴和忘记。

我将创建一个函数

def customer_query():
    return db.session.query(Customer).filter(Customer.deleted == False)

我使用查询功能来不忘记默认标志,根据用户权限设置标志,使用连接等进行过滤,这样这些东西就不会在不同的地方被复制粘贴和忘记。

如果不删除,就不会停止查询,这一点至关重要。因为关键是要避免错误。
customer\u query().filter(something).update(something)2
应该将delete筛选器与
something
筛选器一起应用。如果没有deleted,则不会停止查询,这一点至关重要。因为关键在于避免错误。
customer\u query().filter(something.update(something.2)
应将删除筛选器与
something
筛选器一起应用。