我有以下SQLAlchemy模型:
from datetime import date
from app import Base
from sqlalchemy import Column, Integer, String, ForeignKey, Date
from sqlalchemy.orm import relationship
class Article(Base):
__tablename__ = 'article'
id = Column(Integer, primary_key=True)
title = Column(String)
posts = relationship('Post', back_populates='article')
class Post(Base):
__tablename__ = 'post'
id = Column(Integer, primary_key=True)
article_id = Column(Integer, ForeignKey('article.id'))
date = Column(Date)
article = relationship('Article', back_populates='posts')
我希望能够快速灵活地将文章article
的帖子从日期start_date
和日期end_date
之间发布。
我知道我能做到:
`session.query(Post).filter(Post.article == article, Post.date >= start_date, Post.date < end_date).all()`
但是我觉得它太长了而且不够“面向对象”。
经过一些研究,我发现我可以使用lazy
的{{1}}参数:
relationship
之后,“posts”属性不再是一个列表,而是一个Query Object,它允许我们这样做:
posts = relationship('Post', back_populates='article', lazy='dynamic')
但我想做的是:
article.posts.filter(Post.date >= start_date, Post.date < end_date).all()
我想我必须使用article.posts[start_date:end_date]
属性,例如:
collection_class
但我不知道在class DatedList(list):
def __getitem__(self, item):
if isinstance(item, slice):
# What to do here ?
else:
super(DatedList, self).__getitem__(item)
posts = relationship('Post', back_populates='article', lazy='dynamic', collection_class=DatedList)
函数内写什么,因为我们无法访问__getitem__
对象给出的查询!
有人有想法可以帮助我吗?
答案 0 :(得分:3)
我通过发布在SQLAlchemy Google Group上找到了解决方案。
正如Mike Baker所说,collection_class
不能使用lazy
设置的dynamic
参数,所以我不得不使用query_class
参数:
from sqlalchemy.orm import Query
class PostClassQuery(Query):
def __getitem__(self, item):
if isinstance(item, slice) and (isinstance(item.start, date) or isinstance(item.stop, date)):
query = self
if isinstance(item.start, date):
query = query.filter(Post.date >= item.start)
if isinstance(item.stop, date):
query = query.filter(Post.date < item.stop)
return query.all()
else:
super(PostClassQuery, self).__getitem__(item)
在文章实体之后:
posts = relationship('Post', back_populates='article', lazy='dynamic', query_class=PostClassQuery)
如果您愿意,您甚至可以通过移除.all()
中的return.query.all()
来返回查询而不是结果,这样您就可以执行article.posts[date(2015, 1, 1):date(2015, 6, 1)][10:20]
之类的操作。