如何优雅地检查对象/实例/变量的存在,并同时将其分配给python中存在的变量?


73

我正在使用SQLAlchemy填充数据库,并且经常需要在处理之前检查数据库中是否存在orm对象。这可能是一个非常规的问题,但是我发现自己经常遇到这种模式:

my_object = session.query(SomeObject).filter(some_fiter).first()
if my_object: # Mostly in databases...
    # Juchee it exists
    # process
else:
    # It does not exist. :-(
    my_object = SomeObject()
    # process

我在做梦of的是:

if my_object = session.query(someObject).blabla.first():
    # if my_object is None this scope is left alone
    # if my_object is not None I can work with my_object here...

我知道这种语法是错误的,但我想解释一下此示例的含义。任何等效的方式都会让我高兴。

这种模式是否有优雅的python方法?这个问题不仅针对SQLAlchemy,而且针对每个等效方案。

闭上眼睛打“发表您的问题”,并真诚地等待聪明的人和pythonistas追捕我,询问可能不适当的问题;-)


1
Python表示,显式总是比隐式好。起初我也感到沮丧。太优雅了 那好吧。
arkigos 2011年

2
根据PEP 572,我们将在Python 3.8中以与if my_object := session.query(...):OP要求完全相同的形式提供此功能。
山姆·洛克特

Answers:


108

您想要执行一个现有查询以提高效率

(ret, ), = Session.query(exists().where(SomeObject.field==value))

Mike Bayer在他的博客文章中对此进行了解释:http :
//techspot.zzzeek.org/2008/09/09/selecting-booleans/

如果不希望使用元组,则可以使用标量:

ret = Session.query(exists().where(SomeObject.field==value)).scalar()

21
别忘了导入from sqlalchemy import exists
exist

2
如何检查多个字段?即在“哪里”中调用类似“ Someobject.field1 == value1和Someobject.field2 == value2”的用户
user3731622

5
我找到了。ret = Session.query(exists().where(and_(Someobject.field1 == value1, Someobject.field2 == value2)))
user3731622

有没有一种方法可以使用动态字段获取数据?例如。field_name ='id'或field_name ='email'ret = Session.query(exists()。where(SomeObject [field_name] == value))。scalar()
wolfsbane

为了使其更通用而不指定类型,可以将其修改为:session.query(exists().where(type(my_object).id == my_object.id)).scalar()
johnb

26

这是很久以前问过的,但对以后的访客来说,一种更简洁的检查方法是

 if session.query(model).filter(some_filter).count():
     # do stuff

2
这看起来完全符合他的要求。
num1 2012年

23
count()可能很简洁,但效率也很低-检查多少个与过滤器X相匹配的检查要比检查是否与过滤器X相匹配的检查要昂贵得多;对于“存在”检查,可以在找到第一个匹配项时声明成功,而不是继续寻找更多匹配项。
Charles Duffy 2015年

3
什么是模型,什么是some_filter?
斯坦菲尔德

Model是您要查询的模型,filter是您要用来过滤查询的任何过滤器。
Craicerjack

14

将其包装在一个函数上(从django get_or_create中被无耻地窃取,尽管这样不会返回元组)

get_or_create(model, **kwargs):
    try:
        # basically check the obj from the db, this syntax might be wrong
        object = session.query(model).filter(**kwargs).first()
        return object
    except DoesNotExistException: # or whatever error/exception it is on SQLA
        object = model()
        # do it here if you want to save the obj to the db
        return object

而已。使用它:

obj = get_or_create(SomeObject, filters)

改变**kwargs一个简单的参数(如some_filters),如果你想

尝试包装您经常使用的东西(将它们包装到函数或类中)

多数民众赞成只有伪代码,可能有语法错误。

编辑:强调


2
重点:尝试让您的函数告诉您,它给您的对象是来自数据库还是新创建的(提示已经存在:请参见django的get_or_create)
Kusut 2011年

5

我知道这不是全部步骤,但是可以接受吗?

my_object = session.query(SomeObject).filter(some_filter).first()
if my_object is None:
    my_object = SomeObject()
#process

4
from sqlalchemy.orm.util import has_identity

my_object = session.query(SomeObject).get(id) or SomeObject()
# Processing...

# Check if the object exists in the database
if not has_identity(my_object):
    session.add(my_object)

session.commit()

如果需要,可以将.get()替换为filter()+ first()


2
if DBSession.query(ObjectType).filter(ObjectType.some_parametter == "This").first() is None:

这是检查记录是否存在的一种有效的单行方式。它之所以有效是因为它仅捕获第一个对象,并且可以在一行上,因为在没有匹配记录时,first()返回None。希望有帮助!


我同意。这是超级干净和高效的,而不必在try / exception块上使用额外的资源。
michael g

2

您可以使用此:

sth = session.query.filter_by().first()
if sth is None:
    ....
else:
    ....

我已经测试过了,效果很好。


1

这里有一些不错的建议。如何使用NoResultFound异常?

try:
    existing = dbsession.query(SomeObject).filter_by(value=value).one()
    return existing
except sqlalchemy.orm.exc.NoResultFound:
    obj = SomeObject()

0

这是使用SQLalchemy检查对象是否存在的函数。

def exists(obj, **kwargs):
    """" if obj filtered by kwargs exist return it otherwise return None
        obj : is the sql alchemy model object which existence is being checked here.
        **kwargs : (username = user_name, email=user_email)
    """
    db_obj = obj.query.filter_by(**kwargs).first()
    if db_obj is not None:
        return True
    else:
        return False
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.