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