From 2f9e8e007eccc48e956d757bff8b33c42e2c57a9 Mon Sep 17 00:00:00 2001 From: Red Date: Thu, 5 Feb 2026 17:08:55 +0800 Subject: [PATCH 1/3] [UPD] add pagination to GET API response Signed-off-by: Red --- spp_api/__manifest__.py | 2 +- spp_api/controllers/api.py | 16 +++++++++++++--- spp_api/models/spp_api_path.py | 25 +++++++++++++++++-------- 3 files changed, 31 insertions(+), 12 deletions(-) diff --git a/spp_api/__manifest__.py b/spp_api/__manifest__.py index 73a1911ce..303ec0adf 100644 --- a/spp_api/__manifest__.py +++ b/spp_api/__manifest__.py @@ -7,7 +7,7 @@ "images": [ "images/icon.png", ], - "version": "17.0.1.3.1", + "version": "17.0.1.4.1", "application": False, "author": "OpenSPP.org", "development_status": "Production/Stable", diff --git a/spp_api/controllers/api.py b/spp_api/controllers/api.py index ca1a44d62..6b085a51e 100644 --- a/spp_api/controllers/api.py +++ b/spp_api/controllers/api.py @@ -207,19 +207,29 @@ def read_multi__GET(self, namespace, version, model, **kw): path = kw.get("path") del kw["path"] + page = kw.get("page", 1) + kw = path.search_treatment_kwargs(kw) + limit = kw.get("limit") + records = self.get_records(path.model, kw) records_data = records.search_read(**kw) records_all = records.search_count(kw.get("domain")) records_data = path._get_response_treatment(records_data) + + pagination = { + "page": page, + "limit": limit, + "total_records": records_all, + "total_pages": (records_all + limit - 1) // limit, + } + response_data = { "results": records_data, - "count": records_all, - "offset": kw.get("offset", 0), - "limit": kw.get("limit", 0), "version": version, "timestamp": datetime_format(datetime.datetime.now()), "reply_id": self.get_reply_id(), + "pagination": pagination, } return successful_response(200, response_data) diff --git a/spp_api/models/spp_api_path.py b/spp_api/models/spp_api_path.py index 26bc81900..22fd69b3e 100644 --- a/spp_api/models/spp_api_path.py +++ b/spp_api/models/spp_api_path.py @@ -89,7 +89,7 @@ class SPPAPIPath(models.Model): # Read filter_domain = fields.Char(default="[]") field_ids = fields.Many2many("ir.model.fields", domain="[('model_id', '=', model_id)]", string="Fields") - limit = fields.Integer(string="Limit of results", default=500) + limit = fields.Integer(string="Limit of results", default=80, help="Limit of results per page") # Create / Update warning_required = fields.Boolean(compute="_compute_warning_required", compute_sudo=True) api_field_ids = fields.One2many("spp_api.field", "path_id", string="API Fields", copy=True) @@ -663,15 +663,24 @@ def search_treatment_kwargs(self, kwargs): """ self.ensure_one() - # Limit - limit = kwargs.get("limit", 0) - max_limit = self.limit if self.limit else MAX_LIMIT - kwargs["limit"] = limit if (limit and limit <= max_limit) else max_limit + # Page + page = kwargs.get("page", 1) + + # Get defined limit first in spp_api.path + # if limit is defined in kwargs (query parameter), use it; else use self.limit or MAX_LIMIT + limit = kwargs.get("limit", self.limit if self.limit else MAX_LIMIT) + + # Validate limit + try: + limit = int(limit) + except (ValueError, TypeError): + limit = self.limit if self.limit else MAX_LIMIT + + kwargs["limit"] = limit # Offset - kwargs["offset"] = kwargs.get("start_from", 0) - if "start_from" in kwargs: - del kwargs["start_from"] + offset = (page - 1) * limit if page > 1 else kwargs.get("offset", 0) + kwargs["offset"] = offset # Domain kwargs["domain"] = self.get_domain(kwargs) From 5bcd52eff62d65ae6f1d06f8d25ee9c3b9c1a1c3 Mon Sep 17 00:00:00 2001 From: Red Date: Thu, 5 Feb 2026 17:48:32 +0800 Subject: [PATCH 2/3] [REF] refactor code and add backward compatibility --- spp_api/controllers/api.py | 32 +++++++++++++------ spp_api/models/spp_api_path.py | 57 ++++++++++++++++++++++------------ 2 files changed, 61 insertions(+), 28 deletions(-) diff --git a/spp_api/controllers/api.py b/spp_api/controllers/api.py index 6b085a51e..848e1fd4b 100644 --- a/spp_api/controllers/api.py +++ b/spp_api/controllers/api.py @@ -207,7 +207,17 @@ def read_multi__GET(self, namespace, version, model, **kw): path = kw.get("path") del kw["path"] - page = kw.get("page", 1) + # For backward compatibility + # Will not use pagination + backward_compat = False + if "start_from" in kw: + backward_compat = True + + try: + page = int(kw.get("page", 1)) + except (ValueError, TypeError): + page = 1 + page = max(1, page) kw = path.search_treatment_kwargs(kw) limit = kw.get("limit") @@ -217,21 +227,25 @@ def read_multi__GET(self, namespace, version, model, **kw): records_all = records.search_count(kw.get("domain")) records_data = path._get_response_treatment(records_data) - pagination = { - "page": page, - "limit": limit, - "total_records": records_all, - "total_pages": (records_all + limit - 1) // limit, - } - response_data = { "results": records_data, "version": version, "timestamp": datetime_format(datetime.datetime.now()), "reply_id": self.get_reply_id(), - "pagination": pagination, } + if backward_compat: + response_data["count"] = records_all + response_data["offset"] = kw.get("offset", 0) + response_data["limit"] = limit + else: + response_data["pagination"] = { + "page": page, + "limit": limit, + "total_records": records_all, + "total_pages": (records_all + limit - 1) // limit if limit > 0 else 1, + } + return successful_response(200, response_data) # ReadOne (optional: include_fields, exclude_fields) diff --git a/spp_api/models/spp_api_path.py b/spp_api/models/spp_api_path.py index 22fd69b3e..84ec5043a 100644 --- a/spp_api/models/spp_api_path.py +++ b/spp_api/models/spp_api_path.py @@ -89,7 +89,7 @@ class SPPAPIPath(models.Model): # Read filter_domain = fields.Char(default="[]") field_ids = fields.Many2many("ir.model.fields", domain="[('model_id', '=', model_id)]", string="Fields") - limit = fields.Integer(string="Limit of results", default=80, help="Limit of results per page") + limit = fields.Integer(string="Limit of results", default=500, help="Limit of results per page") # Create / Update warning_required = fields.Boolean(compute="_compute_warning_required", compute_sudo=True) api_field_ids = fields.One2many("spp_api.field", "path_id", string="API Fields", copy=True) @@ -663,24 +663,43 @@ def search_treatment_kwargs(self, kwargs): """ self.ensure_one() - # Page - page = kwargs.get("page", 1) - - # Get defined limit first in spp_api.path - # if limit is defined in kwargs (query parameter), use it; else use self.limit or MAX_LIMIT - limit = kwargs.get("limit", self.limit if self.limit else MAX_LIMIT) - - # Validate limit - try: - limit = int(limit) - except (ValueError, TypeError): - limit = self.limit if self.limit else MAX_LIMIT - - kwargs["limit"] = limit - - # Offset - offset = (page - 1) * limit if page > 1 else kwargs.get("offset", 0) - kwargs["offset"] = offset + backward_compat = False + if "start_from" in kwargs: + backward_compat = True + + if backward_compat: + limit = kwargs.get("limit", 0) + max_limit = self.limit if self.limit else MAX_LIMIT + kwargs["limit"] = limit if (limit and limit <= max_limit) else max_limit + kwargs["offset"] = kwargs.get("start_from", 0) + if "start_from" in kwargs: + del kwargs["start_from"] + else: + # Page + try: + page = int(kwargs.get("page", 1)) + except (ValueError, TypeError): + page = 1 + page = max(1, page) + + # Get defined limit first in spp_api.path + # if limit is defined in kwargs (query parameter), use it; else use self.limit or MAX_LIMIT + max_limit = self.limit if self.limit else MAX_LIMIT + limit = kwargs.get("limit", max_limit) + + # Validate limit + try: + limit = int(limit) + if limit <= 0 or limit > max_limit: + limit = max_limit + except (ValueError, TypeError): + limit = max_limit + + kwargs["limit"] = limit + + # Offset + offset = (page - 1) * limit + kwargs["offset"] = offset # Domain kwargs["domain"] = self.get_domain(kwargs) From 156107342f9d0fb44e7bd68d4c886917ebd4f73d Mon Sep 17 00:00:00 2001 From: Red Date: Thu, 5 Feb 2026 18:20:31 +0800 Subject: [PATCH 3/3] [REF] refactor code --- spp_api/controllers/api.py | 3 ++- spp_api/models/spp_api_path.py | 6 +----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/spp_api/controllers/api.py b/spp_api/controllers/api.py index 848e1fd4b..f877aa17b 100644 --- a/spp_api/controllers/api.py +++ b/spp_api/controllers/api.py @@ -218,6 +218,7 @@ def read_multi__GET(self, namespace, version, model, **kw): except (ValueError, TypeError): page = 1 page = max(1, page) + kw["page"] = page kw = path.search_treatment_kwargs(kw) limit = kw.get("limit") @@ -243,7 +244,7 @@ def read_multi__GET(self, namespace, version, model, **kw): "page": page, "limit": limit, "total_records": records_all, - "total_pages": (records_all + limit - 1) // limit if limit > 0 else 1, + "total_pages": max(1, (records_all + limit - 1) // limit if limit > 0 else 1), } return successful_response(200, response_data) diff --git a/spp_api/models/spp_api_path.py b/spp_api/models/spp_api_path.py index 84ec5043a..711c8f089 100644 --- a/spp_api/models/spp_api_path.py +++ b/spp_api/models/spp_api_path.py @@ -676,11 +676,7 @@ def search_treatment_kwargs(self, kwargs): del kwargs["start_from"] else: # Page - try: - page = int(kwargs.get("page", 1)) - except (ValueError, TypeError): - page = 1 - page = max(1, page) + page = int(kwargs.get("page", 1)) # Get defined limit first in spp_api.path # if limit is defined in kwargs (query parameter), use it; else use self.limit or MAX_LIMIT