How to Implement Pagination with Offset and Limit in Python
A mock API pagination pattern that parses page and per_page query parameters, computes offset and limit, and slices a list of items for a specific page.
Python code
26 linesdef paginate(items, page, per_page):
offset = (page - 1) * per_page
return items[offset:offset + per_page]
def parse_query_params(query_string):
params = {}
if query_string:
for pair in query_string.split("&"):
key, value = pair.split("=")
params[key] = value
page = int(params.get("page", 1))
per_page = int(params.get("per_page", 10))
return page, per_page
if __name__ == "__main__":
mock_items = list(range(1, 101)) # 100 items
query = "page=3&per_page=20"
page, per_page = parse_query_params(query)
result = paginate(mock_items, page, per_page)
print(f"Page {page}, {per_page} items per page")
print(f"Items: {result}")
print(f"Count: {len(result)}")
Output
Page 3, 20 items per page
Items: [41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60]
Count: 20
How it works
The parse_query_params function splits the raw query string into key-value pairs and returns page and per_page with sensible defaults (1 and 10). The paginate function computes the offset as (page - 1) * per_page and then slices the list to return only that page's items. The parse_query_params function uses the int() cast so that the values can be used in arithmetic. The main block demonstrates the pattern with 100 items, showing exactly 20 results for page 3.
Common mistakes
- Forgetting to validate that `page` and `per_page` are positive integers, which can cause negative offsets or empty results
- Not handling query strings with malformed pairs that lack an `=` sign, which will raise a ValueError
- Using `page` and `per_page` directly as strings in arithmetic, causing a TypeError
- Off-by-one errors when computing the offset, especially for the first page
Variations
- Use `parse_qs` from `urllib.parse` to automatically handle duplicate keys and URL-decoded values
- Convert the mock list to a SQL query and use `OFFSET` and `LIMIT` clauses in a real database
Real-world use cases
- Building a REST API endpoint that returns lists of records with page navigation controls
- Implementing a frontend data table that loads a subset of rows on each user scroll
- Writing a batch processing script that iterates over a dataset in chunks to avoid memory overload
Sponsored
More from API design & gRPC
- Build a Bulk Array POST Mock Server in Python medium
- Build a Mock REST API with PUT and GET in Python medium
- Convert Protobuf to JSON and Dict in Python easy
- Create a Data Helper in Python for gRPC-style APIs easy
- Format data in Python using dataclasses like gRPC messages easy
- Generate an OpenAPI Spec from Mock Routes in Python easy
Keep learning
Related tutorials and quizzes for this topic.