最新消息:20210816 当前crifan.com域名已被污染,为防止失联,请关注(页面右下角的)公众号

【已解决】Flask-Restful中如何设计分页的API

Flask crifan 7031浏览 0评论

Flask中,用Flask-Restful去设计api

现在遇到一个,需要实现分页的接口

想要搞清楚,一般设计这种接口的逻辑是啥

直接从数据库query后,然后根据当前的page数,返回结果即可?

Flask-restful 分页 api

RESTful API 编写指南 – 掘金

可以借鉴这个:

{

  “page”: 1,            # 当前是第几页

  “pages”: 3,           # 总共多少页

  “per_page”: 10,       # 每页多少数据

  “has_next”: true,     # 是否有下一页数据

  “has_prev”: false,    # 是否有前一页数据

  “total”: 27           # 总共多少数据

}

RESTful 架构风格概述

使用 Flask-RESTful 设计 RESTful API — Designing a RESTful API with Python and Flask 1.0 documentation

RESTful API 设计最佳实践 – 文章 – 伯乐在线

flask restful pagination

Customizing the ReSTful interface — Flask-Restless 0.17.0 documentation

flask-restful/paging.py at master · flask-restful/flask-restful

HATEOAS support for pagination on server side · Issue #60 · flask-restful/flask-restful

web services – RESTful Design: Paging Collections – Stack Overflow

Flask REST api resource URLs suggestions – Stack Overflow

flask restful paging

The Flask Mega-Tutorial, Part IX: Pagination – miguelgrinberg.com

flask_restful.paging.retrieve_next_page – Nullege Python Samples

Is there any way to do the pagination in SQLAlchemy using Query object instead of BaseQuery object from Flask-SQLAlchemy package? – Quora

The Flask Mega-Tutorial, Part IX: Pagination – miguelgrinberg.com

-》

    posts = g.user.followed_posts().paginate(1, 3, False).items

-》

看来是:

Flask-SQLAlchemy支持的paginate,所以去搜:

Flask-SQLAlchemy page

Flask-SQLAlchemy paging

在flask-sqlalchemy中使用分页 – ranvane的个人空间 – 开源中国社区

API — Flask-SQLAlchemy Documentation (2.1)

http://flask-sqlalchemy.pocoo.org/2.1/api/

paginate(page=None, per_page=None, error_out=True)
Returns per_page items from page page. By default it will abort with 404 if no items were found and the page was larger than 1. This behavor can be disabled by setting error_out to False.
If page or per_page are None, they will be retrieved from the request query. If the values are not ints and error_out is true, it will abort with 404. If there is no request or they aren’t in the query, they default to page 1 and 20 respectively.
Returns an Pagination object.
Utilities
class flask.ext.sqlalchemy.Pagination(query, page, per_page, total, items)
Internal helper class returned by BaseQuery.paginate(). You can also construct it from any other SQLAlchemy query object if you are working with other libraries. Additionally it is possible to pass None as query object in which case the prev() and next() will no longer work.
has_next
True if a next page exists.
has_prev
True if a previous page exists
items = None
the items for the current page
iter_pages(left_edge=2, left_current=2, right_current=5, right_edge=2)
Iterates over the page numbers in the pagination. The four parameters control the thresholds how many numbers should be produced from the sides. Skipped page numbers are represented as None. This is how you could render such a pagination in the templates:
{% macro render_pagination(pagination, endpoint) %}
  <div class=pagination>
  {%- for page in pagination.iter_pages() %}
    {% if page %}
      {% if page != pagination.page %}
        <a href=”{{ url_for(endpoint, page=page) }}”>{{ page }}</a>
      {% else %}
        <strong>{{ page }}</strong>
      {% endif %}
    {% else %}
      <span class=ellipsis>…</span>
    {% endif %}
  {%- endfor %}
  </div>
{% endmacro %}
next(error_out=False)
Returns a Pagination object for the next page.
next_num
Number of the next page
page = None
the current page number (1 indexed)
pages
The total number of pages
per_page = None
the number of items to be displayed on a page.
prev(error_out=False)
Returns a Pagination object for the previous page.
prev_num
Number of the previous page.
query = None
the unlimited query object that was used to create this pagination object.
total = None
the total number of items matching the query

[AF][Flask-SQLAlchemy] Pagination:flask

【总结】

然后此处,参考了:

API — Flask-SQLAlchemy Documentation (2.1)

最后写成:

<code>
        curPageTaskList = None

        # for debug
        taskPagination = None

        if curRole == UserRole.Initiator:
            taskPagination = Task.query.filter_by(initiatorId=userId).paginate(
                page=curPageNum,
                per_page=numPerPage,
                error_out=False)
        elif curRole == UserRole.Errandor:
            taskPagination = Task.query.filter_by(errandorId=userId).paginate(
                page=curPageNum,
                per_page=numPerPage,
                error_out=False)

        gLog.debug("type(taskPagination)=%s"
                   ",taskPagination=%s"
                   ",has_next=%s"
                   ",has_prev=%s"
                   # ",items=%s"
                   # ",next()=%s"
                   # ",next_num=%s"
                   ",page=%s"
                   ",pages=%s"
                   ",per_page=%s"
                   # ",prev_num=%s"
                   # ",query=%s"
                   ",total=%s",
                   type(taskPagination),
                   taskPagination,
                   taskPagination.has_next,
                   taskPagination.has_prev,
                   # taskPagination.items,
                   # taskPagination.next(error_out=False),
                   # taskPagination.next_num,
                   taskPagination.page,
                   taskPagination.pages,
                   taskPagination.per_page,
                   # taskPagination.prev_num,
                   # taskPagination.query,
                   taskPagination.total
                   )

        # gLog.debug("type(taskPagination)=%s,taskPagination=%s", type(taskPagination), taskPagination)
        # type(taskPagination)=&lt;class 'flask_sqlalchemy.Pagination'&gt;, taskPagination=&lt;flask_sqlalchemy.Pagination object at 0x7f07b83c7950&gt;

        paginatedTaskList = taskPagination.items
        # gLog.debug("type(paginatedTaskList)=%s, paginatedTaskList=%s", type(paginatedTaskList), paginatedTaskList)

        paginatedTaskDict = {}
        for curIdx, eachTask in enumerate(paginatedTaskList):
            # gLog.debug("[%s] eachTask=%s", curIdx, eachTask)
            gLog.debug("[%s] eachTask.id=%s", curIdx, eachTask.id)
            paginatedTaskDict[eachTask.id] = marshal(eachTask, task_fields)

        respPaginatedTaskInfoDict = {
            "curPageNum"    : taskPagination.page,
            "totalPageNum"  : taskPagination.pages,
            "numPerPage"    : taskPagination.per_page,
            "hasPrev"       : taskPagination.has_prev,
            "hasNext"       : taskPagination.has_next,
            "totalTaskNum"  : taskPagination.total,
            'tasks'         : paginatedTaskDict
        }

        gLog.debug("respPaginatedTaskInfoDict=%s", respPaginatedTaskInfoDict)
</code>

某次的输出的效果是:

[2016-11-09 14:33:14,533 DEBUG User.py:541 get] type(taskPagination)=<class ‘flask_sqlalchemy.Pagination’>,taskPagination=<flask_sqlalchemy.Pagination object at 0x7f78b6847890>,has_next=False,has_prev=True,page=2,pages=2,per_page=10,total=14
[2016-11-09 14:33:14,533 DEBUG User.py:553 get] [0] eachTask.id=task-10b01105-ec53-41bb-810e-720ab468bdf7
[2016-11-09 14:33:14,560 DEBUG User.py:553 get] [1] eachTask.id=task-f3c0c660-e7f5-4583-bab2-23c7006dadc4
[2016-11-09 14:33:14,582 DEBUG User.py:553 get] [2] eachTask.id=task-f7a4d0df-3142-444b-a962-83660acd447f
[2016-11-09 14:33:14,599 DEBUG User.py:553 get] [3] eachTask.id=task-da013992-e7aa-4ae9-8b6f-bdf621b9fbaa
[2016-11-09 14:33:14,615 DEBUG User.py:566 get] respPaginatedTaskInfoDict={‘tasks’: {u’task-da013992-e7aa-4ae9-8b6f-bdf621b9fbaa’: OrderedDict([(‘hasEnded’, True), (‘itemType’, ‘Small’), (‘initiatorEndLocation’, OrderedDict([(‘fullStr’,。。。。。
。。。。
, (‘password’, None), (‘id’, None), (‘createdAt’, None), (‘errandorIsAuthenticated’, None)]))])}, ‘hasNext’: False, ‘totalPageNum’: 2, ‘hasPrev’: True, ‘numPerPage’: 10, ‘curPageNum’: 2, ‘totalNum’: 14L}

返回的json是:

{

    “code”: 200,

    “data”: {

        “curPageNum”: 2,

        “hasNext”: false,

        “hasPrev”: true,

        “numPerPage”: 10,

        “tasks”: {

            “task-10b01105-ec53-41bb-810e-720ab468bdf7”: {。。。},

            “task-da013992-e7aa-4ae9-8b6f-bdf621b9fbaa”: {。。。},

            “task-f3c0c660-e7f5-4583-bab2-23c7006dadc4”: {。。。},

            “task-f7a4d0df-3142-444b-a962-83660acd447f”: {。。。}

        },

        “totalNum”: 14,

        “totalPageNum”: 2

    },

    “message”: “get task/orders ok”

}

注:

此处的prev()有个bug,需要注意去规避:

【无需解决】Flask中SQLAlchemy中使用Pagination的prev出错:_mysql_exceptions ProgrammingError 1064 You have an error in your SQL syntax

对于上述的核心代码:

<code>taskPagination = Task.query.filter_by(errandorId=userId).paginate(
                page=curPageNum,
                per_page=numPerPage,
                error_out=False)
</code>

的具体解释:

1.query对象,可以去通过paginate得到一个Pagination的对象

比如:

<code>Task.query.filter_by(errandorId=userId)
</code>

得到的就是query对象

然后通过调用paginate,即可得到对应的Pagination对象

<code>type(taskPagination)=&lt;class 'flask_sqlalchemy.Pagination'&gt;,taskPagination=&lt;flask_sqlalchemy.Pagination object at 0x7f78b6847890&gt;
</code>

2.Pagination的对象中,最常用到的属性就是:

  • items:具体有多少个对象,是个列表

    • 然后就可以通过items去获取每个对象的详细信息了。

其他还有一些常用属性:

  • page:当前的页数

  • pages:总的页数

  • per_page:每一页的个数

  • has_prev:是否有前一页

  • has_next:是否有后一页

  • total:(符合当前分页查询的)总(的项目的)个数

转载请注明:在路上 » 【已解决】Flask-Restful中如何设计分页的API

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
82 queries in 0.165 seconds, using 22.22MB memory