SQLAlchemy:返回现有对象,而不是在调用构造函数时创建一个新的对象



我想以这样的方式使用sqlalchemy:

email1 = EmailModel(email="user@domain.com", account=AccountModel(name="username"))
email2 = EmailModel(email="otheruser@domain.com", account=AccountModel(name="username"))

通常,sqlalchemy 会为该帐户创建两个条目,并将每个电子邮件地址链接到此条目。如果我将帐户名设置为唯一 sqlalchemy 会抛出一个异常,告诉我已经存在具有相同值的条目。这很有意义,并且按预期工作。

现在我想出了一种自己的方法,它允许上述代码,并且只需通过覆盖 AccountModel 类的新构造函数来创建一次帐户:

def __new__(*cls, **kw):
    if len(kw) and "name" in kw:
        x = session.query(cls.__class__).filter(cls[0].name==kw["name"]).first()
        if x: return x
    return object.__new__(*cls, **kw)

这对我来说非常有效。但问题是:

  • 这是正确的方法吗?
  • 有没有一种方法可以达到同样的目的?

我正在使用最新的 0.8.x SQLAlchemy 版本和 Python 2.7.x

感谢您的任何帮助:)

在 http://www.sqlalchemy.org/trac/wiki/UsageRecipes/UniqueObject 的 wiki 上正好有这个例子。

不过,最近我更喜欢为此使用 @classmethod 而不是重新定义构造函数,因为显式比隐式更好,也更简单:

user.email = Email.as_unique('foo@bar.com')

(我现在实际上要更新 wiki 以更全面地表示这里的使用选项。

我认为这不是

实现此目的的最佳方法,因为它创建了构造函数对全局变量session的依赖关系,并且还以意想不到的方式修改了构造函数的行为(毕竟new应该返回一个新对象)。例如,如果有人将你的类与两个会话并行使用,代码将失败,他将不得不深入研究代码以查找错误。

我不知道有任何"sqlalchemy"方法可以实现这一点,但我建议创建一个createOrGetAccountModel这样的函数

def createOrGetAccountModel(**kw):
    if len(kw) and "name" in kw:
      x = session.query(AccountModel).filter_by(name=kw["name"]).first()
      if x: return x
    return AccountModel(**kw)

最新更新