В этом решении используется обычная SQLAlchemy, но запуск его на Flask-SQLAlchemy происходит всего за пару изменений синтаксиса.
Идея состоит в том, что мы запрашиваем как нужный код страны, так и резервный, убедитесь, чторезультаты всегда сначала сортируются по нужному коду страны, а затем ограничиваются 1. Например:
result = (
s.query(Bar)
.filter(
Bar.foo == foo_filter,
Bar.country_code.in_([country_code_filter, "RoW"]),
)
.order_by(func.FIELD(Bar.country_code, country_code_filter, "RoW"))
.limit(1)
.first()
)
Функция FIELD
в MySQL позволяет вам указать пользовательский порядок сортировки, в данном случае этогарантирует, что при наличии результата с нужным кодом страны он всегда будет возвращаться первым. Вы можете прочитать больше о FIELD
здесь .
Вот полный тестовый код:
from sqlalchemy_app import Base, Session, engine # you need to create these
from sqlalchemy import Column, Integer, String, func
class Bar(Base):
id = Column(Integer, primary_key=True)
foo = Column(String(32))
country_code = Column(String(32))
if __name__ == "__main__":
Base.metadata.create_all(engine)
s = Session()
s.add_all(
[
Bar(foo="hello", country_code="ES"),
Bar(foo="hello", country_code="ZIM"),
Bar(foo="hello", country_code="RoW"),
]
)
s.commit()
for foo_filter, country_code_filter, exp_res in (
("hello", "ES", "ES"),
("hello", "ZIM", "ZIM"),
("hello", "AUS", "RoW"),
("goodbye", "GBR", None),
):
result = (
s.query(Bar)
.filter(
Bar.foo == foo_filter,
Bar.country_code.in_([country_code_filter, "RoW"]),
)
.order_by(func.FIELD(Bar.country_code, country_code_filter, "RoW"))
.limit(1)
.first()
)
assert getattr(result, "country_code", None) == exp_res
Поскольку вы говорите, что хотите вызвать исключение в случаечто запрос возвращает None
, вы можете поменять метод доступа .first()
на .one()
, так как запрос ограничивает набор результатов до 1 результата на стороне сервера, вы никогда не получите исключение для возврата более 1 результата ивызвать исключение NoResultFound
, если ни одна строка не соответствует запросу.