.. _pagination: .. currentmodule:: flask_smorest Pagination ========== When returning a list of objects, it is generally good practice to paginate the resource. This is where :meth:`Blueprint.paginate ` steps in. Pagination is more or less transparent to view function depending on the source of the data that is returned. Two modes are supported: pagination in view function and post-pagination. Pagination in View Function --------------------------- In this mode, :meth:`Blueprint.paginate ` injects the pagination parameters into the view function as a :class:`PaginationParameters ` object passed as ``pagination_parameters`` keyword argument. It is the responsability of the view function to return only selected elements. The view function must also specify the total number of elements by setting it as ``item_count`` attribute of the `PaginationParameters` object. .. code-block:: python :emphasize-lines: 4,5,6,8,9 @blp.route("/") class Pets(MethodView): @blp.response(200, PetSchema(many=True)) @blp.paginate() def get(self, pagination_parameters): pagination_parameters.item_count = Pet.size return Pet.get_elements( first_item=pagination_parameters.first_item, last_item=pagination_parameters.last_item, ) Post-Pagination --------------- This is the mode to use when the data is returned as a lazy database cursor. The view function does not need to know the pagination parameters. It just returns the cursor. This mode is also used if the view function returns the complete list at no extra cost and there is no interest in specifying the pagination parameters to avoid fetching unneeded data. For instance, if the whole list is already in memory. This mode makes the view look nicer because everything happens in the decorator and the lazy cursor. Cursor Pager ^^^^^^^^^^^^ In this case, :meth:`Blueprint.paginate ` must be passed a pager class to take care of the pagination. `flask-smorest` provides a pager for `list`-like objects: :class:`Page `. For other types, a custom pager may have to be defined. For instance, the following custom pager works with cursor classes that support slicing and provide a ``count`` method returning the total number of elements, such as SQLAlchemy's :class:`Query `. .. code-block:: python :emphasize-lines: 13 from flask_smorest import Page class CursorPage(Page): @property def item_count(self): return self.collection.count() @blp.route("/") class Pets(MethodView): @blp.response(200, PetSchema(many=True)) @blp.paginate(CursorPage) def get(self): return db.session.query(Pet) Pagination Parameters --------------------- Once a view function is decorated with :meth:`Blueprint.paginate `, the client can request a specific range of data by passing query arguments: ``GET /pets/?page=2&page_size=10`` The view function gets default values for the pagination parameters, as well as a maximum value for ``page_size``. Those default values are defined as .. code-block:: python DEFAULT_PAGINATION_PARAMETERS = {"page": 1, "page_size": 10, "max_page_size": 100} They can be modified globally by overriding ``DEFAULT_PAGINATION_PARAMETERS`` class attribute of the :class:`Blueprint ` class or overridden in a specific view function by passing them as keyword arguments to :meth:`Blueprint.paginate `. Pagination Header ----------------- When pagination is used, a ``'X-Pagination'`` header is added to the response. It contains the pagination information. .. code-block:: python print(headers["X-Pagination"]) # { # 'total': 1000, 'total_pages': 200, # 'page': 2, 'first_page': 1, 'last_page': 200, # 'previous_page': 1, 'next_page': 3, # } The name of the header can be changed by overriding ``PAGINATION_HEADER_NAME`` class attribute of the :class:`Blueprint ` class. When setting this attribute to ``None``, no pagination header is added to the response.