sqlalchemy association_proxy分页

时间:2014-03-07 21:48:47

标签: python-2.7 pagination sqlalchemy

我有下面的数据模型。我如何按日期降序对评论顺序进行分页

user.comments.order_by(Comment.date.desc())[0:100];

我是否可以提出,但association_proxy没有order_by?我要做的是返回用户的评论列表,并按最新评论排序。我的代码中有很多区域会使用类似的模式。

我的数据模型示例:

from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.orm import relationship, backref

from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class User(Base):
    __tablename__ = 'user'
    id = Column(Integer, primary_key=True)
    name = Column(String(64))

    # association proxy of "user_comments" collection
    # to "comment" attribute
    comments = association_proxy('user_comments', 'comment')

    def __init__(self, name):
        self.name = name

class UserComment(Base):
    __tablename__ = 'user_comment'
    user_id = Column(Integer, ForeignKey('user.id'), primary_key=True)
    comment_id = Column(Integer, ForeignKey('comment.id'), primary_key=True)

    # bidirectional attribute/collection of "user"/"user_comments"
    user = relationship(User,
                backref=backref("user_comments",
                                cascade="all, delete-orphan")
            )

    # reference to the "Comment" object
    comment = relationship("Comment")

    def __init__(self, comment=None, user=None):
        self.user = user
        self.comment = comment

class Comment(Base):
    __tablename__ = 'comment'
    id = Column(Integer, primary_key=True)
    comment = Column('comment', String(64))
    date = db.Column(db.DateTime)

    def __init__(self, comment):
        self.comment = comment

    def __repr__(self):
        return 'Comment(%s)' % repr(self.comment)

1 个答案:

答案 0 :(得分:3)

在SQLAlchemy中,关系绑定属性通常没有您所描述的“order_by()”方法。在SQLAlchemy中,“order_by()”是一种产生SELECT语句的方法,如session.query()和select()。像“user.comments.order_by()”之类的东西有意义的一种情况是,如果你正在使用所谓的“动态”关系,这是一种特殊策略,其中附加到实例的集合实际上是一个查询()对象。在上面,我没有看到任何“动态”的使用,因此不适用。

在上面的示例中,如果您已经加载了“用户”对象,并且您说“user.comments”,那么最好只加载一次评论然后将它们保存在内存中。所以你需要在这里的关系上使用ORDER BY,但是你正在使用关联对象模式,这使得执行它变得更加困难。我上面没有看到您需要使用关联对象模式,因为您没有任何其他属性,所以如果是这样的话我会丢失关联映射并将order_by放在关系上,也就是说,替换UserComment类如下:

class User(Base):
    __tablename__ = 'user'
    id = Column(Integer, primary_key=True)
    name = Column(String(64))

    comments = relationship("Comment",
                        secondary=Table('user_comment', Base.metadata,
                            Column('user_id', ForeignKey('user.id'), primary_key=True),
                            Column('comment_id', ForeignKey('comment.id'), primary_key=True)
                        ),
                        order_by="Comment.date.desc()"
                )

    def __init__(self, name):
        self.name = name

现在,如果你真的有理由明确地映射UserComment,你仍然可以获得你想要的效果,如果你建立一个跳过UserComment映射的关系,如果你把“动态”放在它上面你想要的确切语法工作:

from sqlalchemy import *
from sqlalchemy.orm import *

from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class User(Base):
    __tablename__ = 'user'
    id = Column(Integer, primary_key=True)
    name = Column(String(64))

    comments = relationship("Comment",
                        secondary="user_comment",
                        lazy="dynamic", viewonly=True)

    def __init__(self, name, **kw):
        super(User, self).__init__(**kw)
        self.name = name

class UserComment(Base):
    __tablename__ = 'user_comment'
    user_id = Column(Integer, ForeignKey('user.id'), primary_key=True)
    comment_id = Column(Integer, ForeignKey('comment.id'), primary_key=True)

    user = relationship(User,
                backref=backref("user_comments",
                                cascade="all, delete-orphan")
            )

    comment = relationship("Comment")

    def __init__(self, comment=None, user=None):
        self.user = user
        self.comment = comment

class Comment(Base):
    __tablename__ = 'comment'
    id = Column(Integer, primary_key=True)
    comment = Column('comment', String(64))
    date = Column(DateTime)

    def __init__(self, comment):
        self.comment = comment

    def __repr__(self):
        return 'Comment(%s)' % repr(self.comment)

e = create_engine("sqlite://", echo=True)
Base.metadata.create_all(e)

s = Session(e)

s.add_all([
    User(name='u1', user_comments=[
        UserComment(comment=Comment(comment='c1')),
        UserComment(comment=Comment(comment='c2')),
        UserComment(comment=Comment(comment='c3')),
    ])
])
s.commit()

u1 = s.query(User).first()
print u1.comments.order_by(Comment.date.desc()).all()

(旁注,为什么User->评论多对多?评论是否可以由多个用户拥有?这看起来很奇怪?)