Эквивалент моделей. Менеджер по SqlAlchemy - PullRequest
6 голосов
/ 07 июля 2011

Я использую SQLAlchemy, и мне в Django ORM мне понравился диспетчер, который я мог реализовать для переопределения исходного запроса объекта.

Существует ли что-то подобное в SQLAlchemy?Я хотел бы всегда исключать элементы, которые имеют «visible = False», когда я делаю что-то вроде:

session.query(BlogPost).all()

Возможно ли это?

Спасибо!

Ответы [ 2 ]

7 голосов
/ 07 июля 2011

РЕДАКТИРОВАТЬ: оригинальная версия почти работала.Следующая версия на самом деле работает.

Похоже, что вы пытаетесь сделать так, чтобы объект запроса был чем-то отличным от SELECT table.* FROM table.В sqlalchemy вы можете сопоставить любой "выбираемый" с классом;Есть некоторые предостережения, хотя;если выбираемый не таблица, вставка данных может быть сложной.Нечто подобное приближается к работоспособному решению.Вы, вероятно, do хотите, чтобы обычная таблица отображалась для разрешения вставок, поэтому первая часть - это полностью обычная таблица, класс и сопоставитель.

blog_post_table = Table("blog_posts", metadata,
    Column('id', Integer, primary_key=True),
    Column('visible', Boolean, default=True),
    ...
)

class BlogPost(object):
    pass

blog_post_mapper = mapper(BlogPost, blog_post_table)

Или, если вы использовалидекларативное расширение, все это будет один

class BlogPost(Base):
    __tablename__ = 'blog_posts'
    id = Column(Integer, primary_key=True)
    visible = Column(Boolean, default=True)

Теперь нам нужно выражение select для представления видимых сообщений.

visible_blog_posts_expr = sqlalchemy.sql.select(
        [BlogPost.id,
         BlogPost.visible]) \
    .where(BlogPost.visible == True) \
    .alias()

Или, так как присвоены имена всем столбцамжелаемого запроса утомительно (не говоря уже о нарушении DRY), вы можете использовать ту же конструкцию, что и session.query(BlogPost), и извлечь «оператор».Однако на самом деле вы не хотите, чтобы он был привязан к сеансу, поэтому вызывайте класс напрямую.

visible_blog_posts_expr = \
    sqlalchemy.orm.Query(BlogPost) \
    .filter(BlogPost.visible == True) \
    .statement \
    .alias()

И мы тоже это отображаем.

visible_blog_posts = mapper(BlogPost, visible_blog_posts_expr, non_primary=True)

Затем можно использовать visible_blog_posts маппер вместо BlogPost s с Session.query, и вы все равно получите BlogPost, который можно обновлять и сохранять как обычно.

posts = session.query(visible_blog_posts).all()
assert all(post.visible for post in posts)

Для этого конкретного примера естьнет большой разницы между явным mapper использованием и декларативным расширением, вы все равно должны вызвать mapper для неосновных отображений.В лучшем случае он позволяет вам набирать SomeClass.colname вместо some_table.c.colname (или SomeClass.__table__.colname, или BlogPost.metadata.tables[BlogPost.__tablename__], или ... и т. Д.).

Ошибки, которые я допустил в исходном примере,которые сейчас исправлены.Я пропустил некоторые пропущенные [] в вызове sqlalchemy.sql.select, который ожидает, что столбцы будут в последовательности.при использовании оператора select для mapper sqlalchemy настаивает на том, чтобы оператор был псевдонимом, чтобы его можно было назвать (SELECT .... ) AS some_subselect_alias_5

0 голосов
/ 07 июля 2011

Вы можете сделать, например,

session.query(BlogPost).filter_by(visible=True)

, который должен дать вам только те сообщения, которые вам нужны.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...