SQLAlchemy:具有跨多个关系的类表达式的混合属性

时间:2016-09-21 21:17:09

标签: python postgresql sqlalchemy

我有兴趣弄清楚如何为下面的@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。

任何想法或见解都会受到赞赏!

0 个答案:

没有答案
相关问题