Reusable Python Code Modules, Part 11 - Pagination
Handling Large Data Sets: Creating Reusable Pagination Modules
Pagination is essential for managing large datasets by splitting them into manageable chunks. It improves performance and enhances user experience by preventing overload of data on a single page. This guide covers how to structure reusable pagination modules in Python using Flask, manage paginated data efficiently, and integrate common libraries.
Common Libraries and Tools
1. Flask-SQLAlchemy
Flask-SQLAlchemy is an extension for Flask that adds support for SQLAlchemy, the popular SQL toolkit and Object-Relational Mapping (ORM) library.
Key Features
ORM Integration: Simplifies database operations with an ORM
Pagination Support: Provides built-in support for paginated queries
Declarative Model: Uses a declarative model for defining tables and relationships
Integration with Flask: Seamlessly integrates with Flask applications
2. Flask-Paginate
Flask-Paginate is a simple extension for adding pagination support to Flask applications.
Key Features
Simple Integration: Easy to integrate with Flask applications
Flexible Pagination: Supports various pagination styles and configurations
Template Integration: Provides template support for rendering pagination controls
Customizable: Allows customization of pagination parameters and appearance
3. Marshmallow-Pagination
Marshmallow-Pagination is an extension that provides pagination support for Flask applications using Marshmallow for serialization
Key Features
Marshmallow Integration: Integrates with Marshmallow for data serialization
Flexible Pagination: Supports different pagination strategies
Schema-Based: Uses Marshmallow schemas for defining data structures
Easy to Use: Simple API for adding pagination to endpoints
4. Flask-RESTful
Flask-RESTful is an extension for Flask that adds support for quickly building REST APIs, including pagination support.
Key Features
REST API Support: Provides tools for building RESTful APIs
Pagination Integration: Supports paginated responses for API endpoints
Resource-Based Routing: Simplifies API development with resource-based routing
Customizable: Allows customization of pagination parameters
Comparison
Flask-SQLAlchemy: Best for applications using SQLAlchemy ORM with built-in pagination support
Flask-Paginate: Ideal for simple and flexible pagination with template integration
Marshmallow-Pagination: Suitable for applications using Marshmallow for serialization with schema-based pagination
Flask-RESTful: Best for RESTful APIs needing integrated pagination and resource-based routing
Examples
Example 1: Flask-SQLAlchemy
Setup:
$ pip install flask-sqlalchemy
Configuration:
from flask import Flask, request, jsonify
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///example.db'
db = SQLAlchemy(app)
class Item(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(80))
db.create_all()
Usage:
@app.route('/items')
def get_items():
page = request.args.get('page', 1, type=int)
per_page = request.args.get('per_page', 10, type=int)
items = Item.query.paginate(page, per_page, error_out=False)
return jsonify({
'items': [item.name for item in items.items],
'total': items.total,
'pages': items.pages,
'current_page': items.page
})
if __name__ == '__main__':
app.run(debug=True)
Example 2: Flask-Paginate
Setup:
$ pip install flask-paginate
Configuration:
from flask import Flask, request, render_template
from flask_paginate import Pagination, get_page_parameter
app = Flask(__name__)
items = list(range(100)) # Example data
Usage:
@app.route('/items')
def get_items():
page = request.args.get(get_page_parameter(), type=int, default=1)
per_page = 10
offset = (page - 1) * per_page
total = len(items)
pagination_items = items[offset: offset + per_page]
pagination = Pagination(page=page, total=total, per_page=per_page, css_framework='bootstrap4')
return render_template('items.html', items=pagination_items, page=page, per_page=per_page, pagination=pagination)
if __name__ == '__main__':
app.run(debug=True)
Template (items.html):
<!doctype html>
<html>
<head>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<ul>
{% for item in items %}
<li>{{ item }}</li>
{% endfor %}
</ul>
{{ pagination.links }}
</div>
</body>
</html>
Example 3: Marshmallow-Pagination
Setup:
$ pip install marshmallow marshmallow-sqlalchemy
Configuration:
from flask import Flask, request, jsonify
from flask_sqlalchemy import SQLAlchemy
from marshmallow import Schema, fields
from marshmallow_sqlalchemy import SQLAlchemySchema, auto_field
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///example.db'
db = SQLAlchemy(app)
class Item(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(80))
class ItemSchema(SQLAlchemySchema):
class Meta:
model = Item
id = auto_field()
name = auto_field()
item_schema = ItemSchema(many=True)
db.create_all()
Usage:
@app.route('/items')
def get_items():
page = request.args.get('page', 1, type=int)
per_page = request.args.get('per_page', 10, type=int)
items = Item.query.paginate(page, per_page, error_out=False)
result = item_schema.dump(items.items)
return jsonify({
'items': result,
'total': items.total,
'pages': items.pages,
'current_page': items.page
})
if __name__ == '__main__':
app.run(debug=True)
Example 4: Flask-RESTful
Setup:
$ pip install flask-restful
Configuration:
from flask import Flask, request
from flask_restful import Resource, Api
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///example.db'
db = SQLAlchemy(app)
api = Api(app)
class Item(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(80))
db.create_all()
Usage:
class ItemResource(Resource):
def get(self):
page = request.args.get('page', 1, type=int)
per_page = request.args.get('per_page', 10, type=int)
items = Item.query.paginate(page, per_page, error_out=False)
return {
'items': [item.name for item in items.items],
'total': items.total,
'pages': items.pages,
'current_page': items.page
}
api.add_resource(ItemResource, '/items')
if __name__ == '__main__':
app.run(debug=True)