从SQLAlchemy获取第一行

89

我有以下查询:

profiles = session.query(profile.name).filter(and_(profile.email == email, profile.password == password_hash))

我该如何检查是否存在一行数据,并且如何只返回第一行(如果有匹配的话,应该只有一行)?

4个回答

158

使用query.one()方法来获取一个且只能获取到一个结果。在所有其他情况下,它会引发一个异常,您可以处理:

from sqlalchemy.orm.exc import NoResultFound
from sqlalchemy.orm.exc import MultipleResultsFound

try:
    user = session.query(User).one()
except MultipleResultsFound, e:
    print e
    # Deal with it
except NoResultFound, e:
    print e
    # Deal with that as well

同时还有query.first(),它将仅给您第一个可能的结果,而不会引发那些异常。但是,由于您想处理没有结果或比您想象的更多的情况,因此query.one()正是您应该使用的。


谢谢!不过还有一个小问题。我添加了 profile.name,但它只给了我一个元组... - Asken
2
是的,当你使用query(Class.attr)明确请求映射类中的一列时,SQLAlchemy会返回一个sqlalchemy.util._collections.NamedTuple而不是数据库对象。 - Lukas Graf
请注意,first()函数会应用LIMIT限制,这可能会将您较大的查询的一部分转换为子查询,并将其与其他所有内容JOIN在一起。 - skyler
3
在给定 db = SQLAlchemy(app) 的情况下,是否可以导入 flask-sqlalchemy 的异常,或者我必须像你一样直接导入它? - Tjorriemorrie
2
@Tjorriemorrie,你需要从sqlalchemy中导入它们。flask-sqlalchemy模块只是Flask的一个集成包,它不会子类化或包装任何sqlalchemy的异常。 - Lukas Graf

65
您可以在查询对象上使用 first() 函数。它将返回第一个结果,如果没有结果,则返回 None。
result = session.query(profile.name).filter(...).first()

if not result:
    print 'No result found'

或者您可以使用one(),它将为您提供唯一的项目,但对于返回零个或多个结果的查询会引发异常。

from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
try:
    result = session.query(profile.name).filter(...).one()
    print result
except NoResultFound:
    print 'No result was found'
except MultipleResultsFound:
    print 'Multiple results were found'

刚刚注意到第二个except中有一个错别字 - MultipleResultsFound。能否更新一下? - Hussain
@Hussain:这个except是正确的,因为one()期望只有一个结果,并创建异常来覆盖两种情况(没有和多个)。根据下面的答案,one_or_none()将限制输出为一个(或没有),从而使此异常变得多余。 - CodeMantle

16

假设你有一个名为User的模型,你可以使用以下代码获取第一个结果:

User.query.first()

如果表为空,它将返回None。


9

使用 one_or_none()。返回最多一个结果或引发异常。

如果查询未选择任何行,则返回None。


1
值得一提的是,这是“版本1.0.9中的新功能:添加了Query.one_or_none()”。 - ezdazuzena

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接