From 343fb04ea7cad06d2a7aca55ab23af3bfe8e7f14 Mon Sep 17 00:00:00 2001 From: Yuefii Date: Sun, 25 Aug 2024 15:41:39 +0700 Subject: [PATCH] chore: reusable pagination code --- app/routes.py | 34 +++++++------------------- app/utils/__init__.py | 0 app/utils/pagination_query.py | 46 +++++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 25 deletions(-) create mode 100644 app/utils/__init__.py create mode 100644 app/utils/pagination_query.py diff --git a/app/routes.py b/app/routes.py index a7b0c8d..c89652d 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,5 +1,6 @@ from flask import Blueprint, jsonify, request from app.models import Districts, Provinces, Regencies, Villages +from app.utils.pagination_query import Pagination province_bp = Blueprint("provinces", __name__) regency_bp = Blueprint("regencies", __name__) @@ -12,38 +13,21 @@ def get_provinces(): show_all = request.args.get("show_all", "false").lower() == "true" page = request.args.get("page", 1, type=int) per_page = request.args.get("per_page", 10, type=int) - if per_page <= 0: return jsonify({"error": "invalid per_page value"}), 400 - if show_all: provinces = Provinces.query.all() - response = [ - {"code": province.code, "name": province.name} for province in provinces - ] - else: - total_provinces = Provinces.query.count() - total_pages = (total_provinces + per_page - 1) // per_page - - if page > total_pages: - return jsonify({"error": "Page number exceeds total pages"}), 400 - - provinces_query = Provinces.query.paginate( - page=page, per_page=per_page, error_out=False - ) - response = { - "pagination": { - "total_items": provinces_query.total, - "total_pages": provinces_query.pages, - "current_page": provinces_query.page, - "per_page": provinces_query.per_page, - }, "data": [ - {"code": province.code, "name": province.name} - for province in provinces_query.items - ], + {"code": province.code, "name": province.name} for province in provinces + ] } + else: + try: + pagination = Pagination(Provinces.query, page, per_page) + response = pagination.get_paginated_data() + except ValueError as e: + return jsonify({"error": str(e)}), 400 return jsonify(response) diff --git a/app/utils/__init__.py b/app/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/utils/pagination_query.py b/app/utils/pagination_query.py new file mode 100644 index 0000000..a00f689 --- /dev/null +++ b/app/utils/pagination_query.py @@ -0,0 +1,46 @@ +class Pagination: + def __init__(self, query, page=1, per_page=10): + self.query = query + self.page = self._validate_page(page) + self.per_page = self._validate_per_page(per_page) + + def _validate_page(self, page): + try: + page = int(page) + except ValueError: + raise ValueError("Page must be an integer") + if page < 1: + raise ValueError("Page number must be greater than zero") + return page + + def _validate_per_page(self, per_page): + try: + per_page = int(per_page) + except ValueError: + raise ValueError("per_page must be an integer") + if per_page <= 0: + raise ValueError("per_page must be greater than zero") + return per_page + + def get_paginated_data(self): + total_items = self.query.count() + total_pages = (total_items + self.per_page - 1) // self.per_page + + if self.page > total_pages: + raise ValueError("Page number exceeds total pages") + + paginated_query = self.query.paginate( + page=self.page, per_page=self.per_page, error_out=False + ) + + return { + "pagination": { + "total_items": paginated_query.total, + "total_pages": paginated_query.pages, + "current_page": paginated_query.page, + "per_page": paginated_query.per_page, + }, + "data": [ + {"code": item.code, "name": item.name} for item in paginated_query.items + ], + }