diff --git a/orp/orp_search/public_gateway.py b/orp/orp_search/public_gateway.py index b8b4286..d1da0bb 100644 --- a/orp/orp_search/public_gateway.py +++ b/orp/orp_search/public_gateway.py @@ -1,5 +1,7 @@ import logging +from typing import Tuple + import pandas as pd import requests # type: ignore @@ -7,6 +9,8 @@ from orp_search.config import SearchDocumentConfig from orp_search.dummy_data import get_construction_data_as_dataframe +from django.core.paginator import InvalidPage, Paginator + logger = logging.getLogger(__name__) @@ -35,20 +39,40 @@ def _build_like_conditions(self, field, terms): """ return " OR ".join([f"{field} LIKE '%{term}%'" for term in terms]) - def paginate_results(self, config: SearchDocumentConfig, results): + def paginate_results( + self, config: SearchDocumentConfig, results, context + ) -> Tuple[dict, Paginator]: """ - Paginates the search results. + Paginates the given search results based on the provided configuration. - Args: - results (list): The search results to paginate. + Arguments: + config (SearchDocumentConfig): Configuration parameters for search, + including pagination limits. + results: A collection of search results to be paginated. + context: A dictionary containing context data which will be updated + with pagination details. Returns: - list: The paginated search results. - count: Total number of pages from results + A tuple containing: + - Updated context dictionary with pagination information. + - Paginator instance used for paginating the results. + + The context dictionary is updated with the following keys: + is_paginated: A boolean indicating if the results span multiple pages. + reports: The paginated results for the current page. + paginator: The Paginator instance. + page_obj: The current page of results. """ - start = (config.offset - 1) * config.limit - end = start + config.limit - return results[start:end] + paginator = Paginator(results, config.limit) + try: + paginated_reports = paginator.page(config.offset) + except InvalidPage: + paginated_reports = paginator.page(1) + context["is_paginated"] = paginator.num_pages > 1 + context["reports"] = paginated_reports + context["paginator"] = paginator + context["page_obj"] = paginated_reports + return context, paginator def calculate_total_pages(self, config, results_count): """ @@ -61,6 +85,7 @@ def calculate_total_pages(self, config, results_count): Returns: int: The total number of pages. """ + if config.limit <= 0: raise ValueError("limit must be greater than 0") return (results_count + config.limit - 1) // config.limit diff --git a/orp/orp_search/views.py b/orp/orp_search/views.py index 8b3d850..0d23782 100644 --- a/orp/orp_search/views.py +++ b/orp/orp_search/views.py @@ -174,32 +174,40 @@ def search(request: HttpRequest) -> HttpResponse: # on the landing page. if search_results: - paginated_search_results = public_gateway.paginate_results( - config, search_results - ) - logger.info( - "paginated search results after paginate: %s", - paginated_search_results, + context, paginator = public_gateway.paginate_results( + config, search_results, context ) + # Initialize a list to hold all results from all pages + paginated_search_results = [] + + # Iterate over each page + for page_num in paginator.page_range: + # Get the page + page = paginator.page(page_num) + # Add the objects of the current page to the aggregate list + + for result in page.object_list: + paginated_search_results.append( + { + "id": result["id"], + "title": result["title"], + "publisher": result["publisher"], + "description": ( + result["description"][:100] + "..." + if len(result["description"]) > 100 + else result["description"] + ), + "date_issued": result["date_issued"], + "date_modified": result["date_modified"], + "document_type": result["type"], + "regulatory_topics": result["regulatory_topics"].split( + "\n" + ), + } + ) + # We can use the following code to filter the search_results list: - paginated_search_results = [ - { - "id": result["id"], - "title": result["title"], - "publisher": result["publisher"], - "description": ( - result["description"][:100] + "..." - if len(result["description"]) > 100 - else result["description"] - ), - "date_issued": result["date_issued"], - "date_modified": result["date_modified"], - "document_type": result["type"], - "regulatory_topics": result["regulatory_topics"].split("\n"), - } - for result in paginated_search_results - ] context["results_count"] = len(paginated_search_results) else: paginated_search_results = []