#python #sqlalchemy
#python #sqlalchemy
Вопрос:
Исторически я избегал ORM в пользу рукописного SQL. Тем не менее, я обнаружил, что сейчас пытаюсь использовать SQLAlchemy для проекта, потому что это, казалось, имело смысл для этого проекта. Тем не менее, я изо всех сил пытаюсь понять, как перенести некоторые из немного более сложных SQL в SQLAlchemy.
У меня есть что-то вроде связанного списка, реализованного следующим образом:
class TransactionModel(Base):
__tablename__ = 'transactionlog'
chain = Column(String(36), primary_key = True)
id = Column(String(36), primary_key = True)
overwrite_id = Column(String(36))
user_id = Column(Integer, ForeignKey('users.id'))
timestamp = Column(DateTime, nullable=False, server_default=func.now())
user = relationship(UserModel, foreign_keys=[user_id])
__table_args__ = (
ForeignKeyConstraint(
['chain', 'overwrite_id'],
['transactionlog.chain', 'transactionlog.id']
),
)
Большинство вещей кажутся довольно простыми:
# Prev Item in list
TransactionModel.query.filter((TransactionModel.chain == current.chain) amp; (TransactionModel.id == current.overwrite_id)).one()
# Next item in list
TransactionModel.query.filter((TransactionModel.chain == current.chain) amp; (TransactionModel.overwrite_id == current.id)).one()
Но я не могу понять, как получить последний элемент в списке. Если бы я писал SQL вручную, я бы сделал это:
SELECT *
FROM transactionlog AS t
WHERE chain = "somevalue"
AND NOT EXISTS (
SELECT *
FROM transactionlog AS other
WHERE other.chain = t.chain
AND other.overwrite_id = t.id
)
Однако я не могу понять, как перевести это в SQLAlchemy. Может кто-нибудь указать мне правильное направление?
Ответ №1:
Если бы я должен был написать это в SQLAlchemy, я бы использовал sqlalchemy.exists()
and sqlalchemy.orm.aliased
. Последнее позволяет вам иметь по существу именованную копию модели, чтобы вы могли различать одну и ту же таблицу:
from sqlalchemy import exists
from sqlalchemy.orm import aliased
other = aliased(TransactionModel)
TransactionModel.query.filter(
TransactionModel.chain == "somevalue",
~exists().where(
(other.overwrite_id == TransactionModel.id) amp;
(other.chain == TransactionModel.chain)
)
)
или эквивалентно (используя and_
вместо amp;
)
from sqlalchemy import and_, exists
from sqlalchemy.orm import aliased
other = aliased(TransactionModel)
TransactionModel.query.filter(
TransactionModel.chain == "somevalue",
~exists().where(and_(
other.overwrite_id == TransactionModel.id,
other.chain == TransactionModel.chain
))
)
Комментарии:
1. Мне пришлось заменить
other.c
часть на simplyother
. После этого он отлично работал. Мне также нравится, что это выглядит довольно близко к тому, что я написал бы в обычном SQL. Спасибо!