Python “新建”是检索SQLAlchemy对象的好方法吗
我正在使用SQLAlchemy,我刚刚读到了Python “新建”是检索SQLAlchemy对象的好方法吗,python,sqlalchemy,python-2.x,Python,Sqlalchemy,Python 2.x,我正在使用SQLAlchemy,我刚刚读到了\uuuu new\uuu函数。我还阅读了其他关于\uuuuuu new\uuuuuu的帖子,因此我意识到了\uuuuuu init\uuuuu的不同之处,它们被调用的顺序以及它们的目的和主要信息是:使用\uuu new\uuuuu来控制新实例的创建 因此,考虑到这一点,当我使用SQLAlchemy并希望检索实例(如果实例不存在,则创建一个实例,例如检索用户对象,我通常会这样做: user = DBSession.query(User).filter(
\uuuu new\uuu
函数。我还阅读了其他关于\uuuuuu new\uuuuuu
的帖子,因此我意识到了\uuuuuu init\uuuuu
的不同之处,它们被调用的顺序以及它们的目的和主要信息是:使用\uuu new\uuuuu
来控制新实例的创建
因此,考虑到这一点,当我使用SQLAlchemy并希望检索实例(如果实例不存在,则创建一个实例,例如检索用户对象,我通常会这样做:
user = DBSession.query(User).filter(User.id==user_id).first()
if not user:
user = User()
这将返回当前用户或给我一个新用户。现在我对魔术有了新的认识,我认为这样做可能是个好主意:
user = User(id=user_id)
在我的数据库类中,我会调用:
def __new__(cls, id=0):
if id:
user = DBSession.query(User).filter(User.id==id).first()
if not id or not user:
user = super(User, cls).__new__(cls, id=id)
return user
现在,这段代码只是一个快速的草稿(例如,缺少对super的调用),但它应该清楚地指出这个想法
现在我的问题是:这是一种好的做法还是应该避免这种做法?如果应该避免:为什么?从我的观察和理解来看,没有理由不将代码放入
\uuuu init\uuuuu
而不是\uu new\uuuuuu
中。对于\uu new\uuuuu>和您应该真正知道自己在做什么。因此,除非您有很好的理由,否则请坚持使用\uuu init\uu
第一个示例(检查返回值)和第二个示例(立即使用构造函数)之间存在非常明显的差异;而这种差异就是自由变量:DBSession
在某些情况下,这种差异并不有趣;如果您只使用sqlalchemy映射的对象进行数据库持久化;然后仅在允许使用sqlalchemy.orm.scopedsession
的上下文中(每个线程正好有一个会话),那么这种差异就不是很有趣了
我发现这两种情况都成立是不寻常的,而且通常两种情况都不成立
通过这样做,您可以防止对象在数据库持久性上下文之外有用。通过断开模型与数据库的连接,您的应用程序可以回答诸如“如果此对象具有此属性怎么办?”以及诸如“此对象是否具有此属性”之类的问题这就是为什么我们将数据库值映射为python对象的关键所在,这样它们就可以有有趣的行为,而不是像dict
s那样仅仅是一袋袋属性
例如,除了使用常规的数据库持久登录外,您还可以允许用户使用类似OAuth的东西登录您的站点。虽然您不需要将用户名和密码持久保存到数据库中,但您仍然需要创建User
对象,以便应用程序的其余部分正常工作(以便用户的gravatar显示在模板中)
默认情况下隐式访问特定数据库上下文的另一个问题通常不是一个好主意。随着应用程序的增长,管理数据库方式的需要变得更加复杂。对象可能在多个数据库主机上进行分区;您可能在同一线程中管理多个并发事务;您可能希望重用pa用于缓存性能原因的特定会话。sqlalchemysession
类的存在是为了解决所有这些特性;显式管理它们,即使您只是使用最常见的模式;使处理偶尔的变化变得更容易
在web应用程序中,一个非常常见的例子是启动代码;有时,在应用程序准备好服务任何请求之前,需要从数据库中提取一些关键数据位;但是,既然没有需要服务的请求,那么数据库连接从何而来?一旦启动完毕,如何摆脱它?这些问题对于显式管理的会话,问题通常没有问题。根据您的问题和评论,我建议您不要这样做,因为您似乎没有任何理由这样做,而且您似乎不明白自己在做什么
你说你会把某些代码放到什么的\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
中?如果你有这个:
class User(Base):
def __new__(cls, id=0):
if id:
user = DBSession.query(User).filter(User.id==id).first()
if not user:
user = User()
return user
…然后,当您尝试创建一个用户
实例时,它的\uuuu new\uuuu
将尝试创建另一个实例,依此类推,从而导致无限递归
使用user=user.\uuuu init\uuuu()
无法解决任何问题。\uuuuu init\uuuu
始终返回None,因此您将尝试创建None对象
\uuuuu new\uuuuu
的适当用例是,当您通过执行SomeClass()实例化类时,希望更改返回的对象类型
。很少需要这样做。最常见的情况是当您想要创建一个模仿内置类型(如dict
)的用户定义类时,但即使这样,您也可能不需要这样做
如果您的代码在没有覆盖\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
的情况下工作,请不要覆盖?如果按照您的建议执行,实例化类实际上将返回User
的实例,而不是该类的实例。为什么要这样做?为什么不使用一个工厂函数来返回User
实例呢?User
类是我的数据库类,例如class User(Base)
使用Base=declarative_Base()
。是的,我可以实现工厂函数(即工厂类或静态方法/类方法)要检索它,但似乎这就是构建\uuuuuu new\uuuuuu
的目的。这只是一个观点,但我不会将数据库查询放在构造函数中。有时,您可能只想用值实例化对象,比如酸洗或反序列化。您应该显式地