Skip to content

Filtering Pagination

DodaTech 2 min read

title: "Filtering with Pagination — Applying Filters Across Pages" description: "Filtering with pagination applies consistent server-side filters across all pages, using query parameters that persist through pagination navigation." date: 2026-06-28 lastmod: 2026-06-28 weight: 18 tags: [apis, pagination] }

Filtering with pagination applies server-side filter criteria consistently across all pages, with filter parameters persisted in pagination links for stable navigation.

What You'll Learn

  • Combining filters with pagination
  • Filter parameter design
  • Preserving filters in pagination links

Why It Matters

Filters must persist across paginated requests. If the filter changes between page 1 and page 2, the results are inconsistent.

Code Examples

# Filtering with pagination
@app.route('/users')
def list_users():
    # Filters
    status = request.args.get('status')
    role = request.args.get('role')
    search = request.args.get('q')

    # Pagination
    page = request.args.get('page', 1, type=int)
    limit = min(request.args.get('limit', 20, type=int), 100)

    # Build query
    query = "SELECT * FROM users WHERE 1=1"
    params = []
    if status:
        query += " AND status = ?"
        params.append(status)
    if role:
        query += " AND role = ?"
        params.append(role)
    if search:
        query += " AND (name LIKE ? OR email LIKE ?)"
        params.extend([f"%{search}%", f"%{search}%"])

    # Count
    count = db.execute(f"SELECT COUNT(*) FROM ({query})", params)[0][0]

    # Paginate
    query += " ORDER BY id LIMIT ? OFFSET ?"
    params.extend([limit, (page - 1) * limit])
    users = db.execute(query, params)

    # Build pagination links with preserved filters
    def pagination_url(p):
        qs = request.args.copy()
        qs['page'] = p
        return f"/users?{urlencode(qs)}"

    return jsonify({
        "data": users,
        "pagination": {
            "page": page,
            "total": count,
            "pages": (count + limit - 1) // limit,
            "links": {
                "first": pagination_url(1),
                "next": pagination_url(page + 1) if page * limit < count else None,
                "prev": pagination_url(page - 1) if page > 1 else None
            }
        }
    })

Common Mistakes

1. Filters Not Applied to Count

Always apply the same filters to the count query and the data query.

2. Filter State Lost on Navigation

Pagination links must include current filter parameters.

3. Inconsistent Filter Parameter Names

Use consistent naming: status=active not filter[status]=active.

4. Case-Sensitive Filter Values

Use case-insensitive comparison for text filters.

5. Not Validating Filter Values

Validate filter values against allowed options before querying.

Practice Questions

  1. Why must filters be applied to both data and count queries?
  2. How do you preserve filters across pagination links?
  3. What is the risk of inconsistent filters between pages?
  4. How do you handle search queries with pagination?
  5. Why validate filter values?

Answers:

  1. Otherwise the count doesn't match the filtered results.
  2. Include current filter params in the pagination URL query string.
  3. Results shift between pages, causing duplicates or gaps.
  4. Apply the search LIKE clause to both count and data queries.
  5. Invalid filter values can cause SQL errors or expose database structure.

Challenge: Implement a search endpoint with filtering (status, role, date range) and pagination. Show how filter parameters are preserved in next/prev links.

FAQ

How do I handle range filters with pagination?

: Use min_price and max_price parameters, not price_range.

Can filters be AND or OR?

: AND is standard. Document if your API supports OR logic.

What is the recommended way to pass filter arrays?

: Use repeated params: status=active&status=pending.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro