SQLAlchemy添加分页-paginate

来源:互联网 发布:数据库隔离的四个级别 编辑:程序博客网 时间:2024/06/06 07:33

项目使用了flask作为web框架,当然数据库操作框架会选择flask-sqlalchemy,这使用的过程中真的很方便,简直是痛快,并且sqlalchemy提供了分页函数(paginate),与datatables结合简直是完美,但是在后来随着功能的增加,需要在项目中添加线程(threading),添加线程是没问题的,但是在线程中进行数据库操作就会出现问题,这是因为线程脱离了flask的上下文,不能访问和flask绑定的数据库对象,刚开始是要再创建一个数据库对象去解决,这样就要维护两份表与对象的映射关系,最后还是放弃了flask-sqlalchemy,使用了sqlalchemy,真心感觉flask-sqlalchemy对sqlalchemy封装的很好,并且是线程安全的,换成sqlalchemy后所有的table分页都出了问题,sqlalchemy既然没有paginate方法,考虑到自己封装一个paginate,以查询对象作为参数,但是这样会改好多代码,代价太大,经过分析flask-sqalchemy源码发现,可以将flask-sqlalchemy中的paginate方法绑定到sqlalchemy的Query对象上。
操作如下:

from sqlalchemy.orm import  Queryclass Pagination(object):    """    分页对象    """    def __init__(self, query, page, per_page, total, items):        self.query = query        self.page = page        self.per_page = per_page        self.total = total        self.items = items    @property    def pages(self):        if self.per_page == 0:            pages = 0        else:            pages = int(ceil(self.total / float(self.per_page)))        return pages    def prev(self, error_out=False):        assert self.query is not None, 'a query object is required ' \                                       'for this method to work'        return self.query.paginate(self.page - 1, self.per_page, error_out)    @property    def prev_num(self):        if not self.has_prev:            return None        return self.page - 1    @property    def has_prev(self):        return self.page > 1    def next(self, error_out=False):        assert self.query is not None, 'a query object is required ' \                                       'for this method to work'        return self.query.paginate(self.page + 1, self.per_page, error_out)    @property    def has_next(self):        return self.page < self.pages    @property    def next_num(self):        if not self.has_next:            return None        return self.page + 1    def iter_pages(self, left_edge=2, left_current=2,                   right_current=5, right_edge=2):        last = 0        for num in xrange(1, self.pages + 1):            if num <= left_edge or \               (num > self.page - left_current - 1 and \                num < self.page + right_current) or \               num > self.pages - right_edge:                if last + 1 != num:                    yield None                yield num                last = numdef paginate(self, page=None, per_page=None, error_out=True):    """    分页函数    :param self:    :param page:    :param per_page:    :param error_out:    :return:    """    if request:        if page is None:            try:                page = int(request.args.get('page', 1))            except (TypeError, ValueError):                if error_out:                    abort(404)                page = 1        if per_page is None:            try:                per_page = int(request.args.get('per_page', 20))            except (TypeError, ValueError):                if error_out:                    abort(404)                per_page = 20    else:        if page is None:            page = 1        if per_page is None:            per_page = 20    if error_out and page < 1:        abort(404)    items = self.limit(per_page).offset((page - 1) * per_page).all()    if not items and page != 1 and error_out:        abort(404)    if page == 1 and len(items) < per_page:        total = len(items)    else:        total = self.order_by(None).count()    return Pagination(self, page, per_page, total, items)Query.paginate = paginate#在原查询类上加上分页方法

这样就搞定了,上面的paginate方法和Pagination类是从flask-sqlalchemy中复制的,当然也可以通过这个方法为sqlalchemy定制其他的方法。

原创粉丝点击