我有兴趣弄清楚如何为下面的@expression
写@hybrid_property
。
架构有点复杂,因为这是一个更大的项目的一小部分,我没有完全控制,所以请不要挂在类和表定义的奇怪排列和使用关系和映射器。我还必须更改所有的班级名称,以便在此发布,所以请原谅任何小错字。以下是相关部分:
tables.py
course_table = Table('course', metadata,
id = Column(Integer, primary_key=True),
name = Column(String(80)),
)
book_table = Table('book', metadata,
booknum = Column(Integer, primary_key=True),
title = Column(String(80)),
)
librarybook = Table('librarybook', metadata,
dewey_num = Column(Integer, primary_key=True),
booknum = Column(Integer, ForeignKey('book.booknum')),
shelf_location = Column(String(80)),
)
author = Table('author', metadata,
id = Column(Integer, primary_key=True),
name = Column(String(80)),
)
course_book_view_table = view('course_book_view', metadata,
Column('course_id', Integer,
ForeignKey(course_table.c.id),
primary_key=True, autoincrement=False),
Column('booknum', Text,
ForeignKey(book_table.c.booknum),
primary_key=True),
)
)
model.py
import tables as t
class Course(Base):
course_books=relation(Book,
secondary=t.course_book_view_table,
backref='courses',
order_by=Book.dewey,
),
@hybrid_property
def course_book_author_names(self):
if self.course_books:
return list(set([lb.author.name
for b in self.course_books
for lb in b.library_books]))
else:
return None
@course_book_author_names.expression
def course_book_author_names(cls):
join_tbl = t.course_book_view_table.join(
t.librarybook,
t.librarybook.c.booknum == t.course_book_view_table.c.booknum) \
.join(
t.author,
t.author.c.booknum == t.librarybook.c.booknum
)
q = select([func.array_agg(t.author.c.name)])
q = q.select_from(join_tbl)
q = q.where(t.course_book_view_table.c.course_id == cls.id)
q = q.distinct()
return q.label('course_book_author_names')
class Book(Base):
pass
class Librarybook(Base):
pass
class Author(Base):
pass
mapper(Librarybook, t.librarybook, properties=dict(
book = relationship(
Book,
primaryjoin=t.librarybook.c.booknum == t.book_table.c.booknum,
foreign_keys=[t.librarybook.c.booknum],
backref='library_books',
),
author=relationship(Author, backref='books'),
))
mapper(Author, t.author)
我最终可以通过两种方式使用@hybrid_property
:
作为python属性:
>>>course = session.query(Course).get(1234)
>>>course.course_book_author_names
['Bjarne Stroustrup', 'Brian Kernighan', 'Dennis Ritchie', 'Guido van Rossum', 'James Gosling']
作为与SA一起使用的类级别表达式,类似于:
>>>session.query(Course).filter(Course.course_book_author_names \
.any(Author.name == 'Bjarne Stroustrup')).first()
1234
相反,我收到一个错误:
session.query(Course).filter(Course.course_book_author_names \
.any(Author.name == 'Bjarne Stroustrup')).first()
...
AttributeError: Neither 'Label' object nor 'Comparator' object has an attribute 'any'
我不是百分之百确定这是调用它的正确方法,而且我愿意接受能够产生正确过滤效果的更好语法(in_而不是任何?)的建议。
另一方面,也许我只是需要一种更直接将课程与作者联系起来的自定义关系?
对于它的价值,底层数据库是postgres。
任何想法或见解都会受到赞赏!