通过非主键属性查询的惯用方法是什么?

时间:2015-06-03 11:38:06

标签: python sqlalchemy

我的User模型的主键位于user_id,唯一username。如果我知道user_id,我会使用session.query(User).get(user_id)。当属性不是主键时,等效查询是什么,如session.query(User).get(username=username)

如果没有找到行,

session.query(User).filter_by(username=username).first()也会返回None,但它没有明确表示该查询永远不会有多行。

我写了以下内容,但这是否是任何人在其代码中常规实现的帮助?

try:
  user = session.query(User).filter_by(username=username).one()
except (NoResultFound, MultipleResultsFound):
  user = None

1 个答案:

答案 0 :(得分:1)

"惯用"查询一件事的方法是使用filterfirstoneget基本上只是主键的快捷方式。如果您要问的是"这个尝试/接受块是否可以使用"然后是的,它会正常工作,没有人会觉得难以理解。

有点令人困惑的是,如果有多个结果,则会返回None,但如果这就是你需要的那么可行。鉴于username列已经具有唯一约束,无论如何这种方法都是无用的,因为用户名永远不会有多个结果。

更强大的可重用解决方案是使用自定义Query子类并添加行为与one类似的one_or_none方法。创建会话时,通过传递query_cls使其使用此类。

from sqlalchemy.orm import Query

class MyQuery(Query):
    def one_or_none(self):
        """Return one result, or None if there are zero or >1 results."""
        ret = self.limit(2).all()

        if len(ret) == 1:
            return ret[0]
        else:
            return None

session = Session(query_cls=MyQuery)
session.query(User).filter(username="example").one_or_none()

同样,当有多个结果时返回None并不是典型的行为,并且当它有一个独特的约束时,它并没有真正做任何事情。

如果这是一项常见操作,您还可以添加一个特定的方法来按用户名进行查询。来自this gistuser Adam Smith修改:

from sqlalchemy.orm import Query
from sqlalchemy.orm.exc import MultipleResultsFound

class MyQuery(Query):
    def get_by_username(self, username):
        ret = self.filter(username=username).limit(2).all()

        if len(ret) == 1:
            return ret[0]
        else:
            return None

session = Session(query_cls=MyQuery)
session.query(User).get_by_username("example")