【发布时间】:2011-04-26 13:44:56
【问题描述】:
我是一名 Web 应用程序开发人员,在使用 SQLAlchemy 时,当我想要来自(例如)users 表的特定 行 时,我发现在我的许多控制器中执行此操作很笨拙:
from model import dbsession # SQLAlchemy SessionMaker instance
from model import User
user = dbsession().query(User).filter_by(some_kw_args).first()
或者说我想向表中添加一个用户(假设另一个控制器):
from model import dbsession # SQLAlchemy SessionMaker instance
from model import User
user = User("someval", "anotherval", "yanv")
dbsession().add(user)
因此,由于这种笨拙(我不会介绍我的其他一些个人习语),我不喜欢仅仅为了向表中添加一条记录或从表中获取一条记录而进行所有这些操作.所以我决定(在对 SQLAlchemy 进行了很多讨厌的黑客攻击并决定我做了太多“神奇”的事情之后)这适合代理模式。
我(起初)在model 模块中做了类似的事情:
def proxy_user(delete=False, *args, **kwargs):
session = DBSession()
# Keyword args? Let's instantiate it...
if (len(kwargs) > 0) and delete:
obj = session.query(User).filter_by(**kwargs).first()
session.delete(obj)
return True
elif len(kwargs) > 0:
kwargs.update({'removed' : False})
return session.query(User).filter_by(**kwargs).first()
else:
# Otherwise, let's create an empty one and add it to the session...
obj = User()
session.add(obj)
return obj
我为我的所有模型都做了这个(我知道代码重复很糟糕),而且效果很好。我可以将关键字参数传递给代理函数,它会为我处理所有会话查询(甚至为删除的标志提供默认过滤关键字)。我可以初始化一个空模型对象,然后通过更新对象属性向其中添加数据,并且所有这些更改都被跟踪(并提交/刷新),因为该对象已添加到 SQLAlchemy 会话中。
所以,为了减少重复,我将大部分逻辑放在装饰器函数中,现在正在这样做:
def proxy_model(proxy):
"""Decorator for the proxy_model pattern."""
def wrapper(delete=False, *args, **kwargs):
model = proxy()
session = DBSession()
# Keyword args? Let's instantiate it...
if (len(kwargs) > 0) and delete:
obj = session.query(model).filter_by(**kwargs).first()
session.delete(obj)
return True
elif len(kwargs) > 0:
kwargs.update({'removed' : False})
return session.query(model).filter_by(**kwargs).first()
else:
# Otherwise, let's create an empty one and add it to the session...
obj = model()
session.add(obj)
return obj
return wrapper
# The proxy_model decorator is then used like so:
@proxy_model
def proxy_user(): return User
所以现在,在我的控制器中我可以这样做:
from model import proxy_user
# Fetch a user
user = proxy_user(email="someemail@ex.net") # Returns a user model filtered by that email
# Creating a new user, ZopeTransaction will handle the commit so I don't do it manually
new_user = proxy_user()
new_user.email = 'anotheremail@ex.net'
new_user.password = 'just an example'
如果我需要做其他更复杂的查询,如果我经常使用它,我通常会编写处理它的函数。如果这是一次性的事情,我将只导入 dbsession 实例,然后执行“标准”SQLAlchemy orm 查询......
这更干净,效果也很好,但我仍然觉得它并没有完全“锁定”。其他任何人(或更有经验的 python 程序员)能否提供一个更好的习语,以实现与我所寻求的类似数量的清晰性,同时作为一个更清晰的抽象?
【问题讨论】:
标签: python sqlalchemy abstraction idioms