Как элегантно проверить существование объекта/экземпляра/переменной и одновременно присвоить его переменной, если он существует в python?

Я использую SQLAlchemy для заполнения базы данных, и часто мне нужно проверить, существует ли объект формы в базе данных перед обработкой. Это может быть нестандартный вопрос, но я часто сталкивался с этим шаблоном:

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

Я мечтаю о чем-то вроде:

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, но и каждого эквивалентного сценария.

закрываю глаза, нажимаю "Оставить свой вопрос" и жду, пока умные люди и питонисты наизусть выследят меня за то, что я задал что-то, возможно, неуместное ;-)


person Aufwind    schedule 05.07.2011    source источник
comment
Явное всегда лучше неявного, говорит Python... и мы это понимаем. Меня это тоже поначалу смущало. Так неэлегантно. Ну что ж.   -  person arkigos    schedule 08.07.2011
comment
Согласно PEP 572, в Python 3.8 это будет form if my_object := session.query(...):, что в значительной степени соответствует тому, что запрашивает OP.   -  person Sam Rockett    schedule 14.01.2019


Ответы (9)


Вы хотите выполнить запрос Exist, чтобы быть эффективным

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

Майк Байер объясняет это в своем блоге:
http://techspot.zzzeek.org/2008/09/09/selecting-booleans/

Вы можете использовать скаляр, если не хотите, чтобы в результате был кортеж:

ret = Session.query(exists().where(SomeObject.field==value)).scalar()
person Rach    schedule 14.04.2013
comment
Не забудьте импортировать exists(): from sqlalchemy import exists - person ChaimG; 30.06.2016
comment
Как я могу проверить более одного поля? то есть в «где» вызовите что-то вроде «Someobject.field1 == value1 и Someobject.field2 == value2» - person user3731622; 20.01.2017
comment
Я нашел это. ret = Session.query(exists().where(and_(Someobject.field1 == value1, Someobject.field2 == value2))) - person user3731622; 20.01.2017
comment
Есть ли способ получить данные с помощью динамического поля? Например. field_name = 'id' или field_name = 'email' ret = Session.query(exists().where(SomeObject[field_name]==value)).scalar() - person wolfsbane; 02.12.2017
comment
Чтобы сделать его более общим и не указывать тип, его можно изменить на: session.query(exists().where(type(my_object).id == my_object.id)).scalar() - person johnbt; 27.06.2019

Это было задано давно, но для будущих посетителей более краткий способ проверить это

 if session.query(model).filter(some_filter).count():
     # do stuff
person elbear    schedule 24.10.2012
comment
Похоже, это именно то, о чем он просил. - person num1; 27.11.2012
comment
count() может быть кратким, но также и неэффективным - дороже проверить, сколько вещей соответствует фильтру X, чем проверить, соответствует ли какая-нибудь вещь фильтру X; для проверки существования можно объявить об успехе, когда будет найдено первое совпадение, вместо того, чтобы продолжать искать другие. - person Charles Duffy; 19.09.2015
comment
что такое модель и что такое some_filter? - person Steinfeld; 11.05.2016
comment
Модель — это любая модель, которую вы запрашиваете, а фильтр — это любой фильтр, по которому вы хотите отфильтровать запрос. - person Craicerjack; 10.12.2018

оберните его в функцию (бессовестно украденный из 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 на простой аргумент (например, некоторые_фильтры), если хотите

попытайтесь обернуть то, что вы часто используете (оберните их в функции или классы)

это всего лишь псевдокод, может быть синтаксическая ошибка.

РЕДАКТИРОВАТЬ: подчеркнуть

person kusut    schedule 05.07.2011
comment
Бонусный балл: попробуйте сделать так, чтобы ваша функция сообщала вам, является ли объект, который она вам дает, из базы данных или вновь созданным (подсказка уже есть: см. get_or_create django) - person kusut; 06.07.2011

Я знаю, что это не один шаг, но приемлемо ли это?

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

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() при необходимости.

person Metalstorm    schedule 30.10.2014

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

Это эффективный однострочный способ проверки существования записи. Он эффективен, потому что захватывает только первый объект и может находиться в одной строке, поскольку first() возвращает None при отсутствии соответствующих записей. Надеюсь, это поможет!

person jmercouris    schedule 06.12.2015
comment
Я согласен. это очень чисто и эффективно без использования дополнительных ресурсов в блоке try/exception. - person michael g; 09.01.2017

Вы можете использовать это:

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

Я протестировал его. Он работает хорошо.

person bass chuck    schedule 30.08.2017

Несколько хороших предложений здесь. Как насчет использования исключения NoResultFound?

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

Вот функция для проверки существования объекта с помощью 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
person Umar Hayat    schedule 25.02.2020