Browse Source

Fixed #27505 -- Allowed customizing Paginator's error messages.

Marcelo Galigniana 1 year ago
parent
commit
dfc720c521
4 changed files with 91 additions and 6 deletions
  1. 22 5
      django/core/paginator.py
  2. 35 1
      docs/ref/paginator.txt
  3. 6 0
      docs/releases/5.0.txt
  4. 28 0
      tests/pagination/tests.py

+ 22 - 5
django/core/paginator.py

@@ -28,13 +28,30 @@ class Paginator:
     # Translators: String used to replace omitted page numbers in elided page
     # range generated by paginators, e.g. [1, 2, '…', 5, 6, 7, '…', 9, 10].
     ELLIPSIS = _("…")
-
-    def __init__(self, object_list, per_page, orphans=0, allow_empty_first_page=True):
+    default_error_messages = {
+        "invalid_page": _("That page number is not an integer"),
+        "min_page": _("That page number is less than 1"),
+        "no_results": _("That page contains no results"),
+    }
+
+    def __init__(
+        self,
+        object_list,
+        per_page,
+        orphans=0,
+        allow_empty_first_page=True,
+        error_messages=None,
+    ):
         self.object_list = object_list
         self._check_object_list_is_ordered()
         self.per_page = int(per_page)
         self.orphans = int(orphans)
         self.allow_empty_first_page = allow_empty_first_page
+        self.error_messages = (
+            self.default_error_messages
+            if error_messages is None
+            else self.default_error_messages | error_messages
+        )
 
     def __iter__(self):
         for page_number in self.page_range:
@@ -47,11 +64,11 @@ class Paginator:
                 raise ValueError
             number = int(number)
         except (TypeError, ValueError):
-            raise PageNotAnInteger(_("That page number is not an integer"))
+            raise PageNotAnInteger(self.error_messages["invalid_page"])
         if number < 1:
-            raise EmptyPage(_("That page number is less than 1"))
+            raise EmptyPage(self.error_messages["min_page"])
         if number > self.num_pages:
-            raise EmptyPage(_("That page contains no results"))
+            raise EmptyPage(self.error_messages["no_results"])
         return number
 
     def get_page(self, number):

+ 35 - 1
docs/ref/paginator.txt

@@ -14,7 +14,7 @@ For examples, see the :doc:`Pagination topic guide </topics/pagination>`.
 ``Paginator`` class
 ===================
 
-.. class:: Paginator(object_list, per_page, orphans=0, allow_empty_first_page=True)
+.. class:: Paginator(object_list, per_page, orphans=0, allow_empty_first_page=True, error_messages=None)
 
     A paginator acts like a sequence of :class:`Page` when using ``len()`` or
     iterating it directly.
@@ -56,6 +56,40 @@ For examples, see the :doc:`Pagination topic guide </topics/pagination>`.
     ``False`` and ``object_list`` is  empty, then an ``EmptyPage`` error will
     be raised.
 
+.. attribute:: Paginator.error_messages
+
+    .. versionadded:: 5.0
+
+    The ``error_messages`` argument lets you override the default messages that
+    the paginator will raise. Pass in a dictionary with keys matching the error
+    messages you want to override. Available error message keys are:
+    ``invalid_page``, ``min_page``, and ``no_results``.
+
+    For example, here is the default error message:
+
+    .. code-block:: pycon
+
+        >>> from django.core.paginator import Paginator
+        >>> paginator = Paginator([1, 2, 3], 2)
+        >>> paginator.page(5)
+        Traceback (most recent call last):
+          ...
+        EmptyPage: That page contains no results
+
+    And here is a custom error message:
+
+    .. code-block:: pycon
+
+        >>> paginator = Paginator(
+        ...     [1, 2, 3],
+        ...     2,
+        ...     error_messages={"no_results": "Page does not exist"},
+        ... )
+        >>> paginator.page(5)
+        Traceback (most recent call last):
+          ...
+        EmptyPage: Page does not exist
+
 Methods
 -------
 

+ 6 - 0
docs/releases/5.0.txt

@@ -284,6 +284,12 @@ Models
   :ref:`Choices classes <field-choices-enum-types>` directly instead of
   requiring expansion with the ``choices`` attribute.
 
+Pagination
+~~~~~~~~~~
+
+* The new :attr:`django.core.paginator.Paginator.error_messages` argument
+  allows customizing the error messages raised by :meth:`.Paginator.page`.
+
 Requests and Responses
 ~~~~~~~~~~~~~~~~~~~~~~
 

+ 28 - 0
tests/pagination/tests.py

@@ -128,6 +128,34 @@ class PaginationTests(SimpleTestCase):
         with self.assertRaises(PageNotAnInteger):
             paginator.validate_number(1.2)
 
+    def test_error_messages(self):
+        error_messages = {
+            "invalid_page": "Wrong page number",
+            "min_page": "Too small",
+            "no_results": "There is nothing here",
+        }
+        paginator = Paginator([1, 2, 3], 2, error_messages=error_messages)
+        msg = "Wrong page number"
+        with self.assertRaisesMessage(PageNotAnInteger, msg):
+            paginator.validate_number(1.2)
+        msg = "Too small"
+        with self.assertRaisesMessage(EmptyPage, msg):
+            paginator.validate_number(-1)
+        msg = "There is nothing here"
+        with self.assertRaisesMessage(EmptyPage, msg):
+            paginator.validate_number(3)
+
+        error_messages = {"min_page": "Too small"}
+        paginator = Paginator([1, 2, 3], 2, error_messages=error_messages)
+        # Custom message.
+        msg = "Too small"
+        with self.assertRaisesMessage(EmptyPage, msg):
+            paginator.validate_number(-1)
+        # Default message.
+        msg = "That page contains no results"
+        with self.assertRaisesMessage(EmptyPage, msg):
+            paginator.validate_number(3)
+
     def test_float_integer_page(self):
         paginator = Paginator([1, 2, 3], 2)
         self.assertEqual(paginator.validate_number(1.0), 1)