Skip to content

Async paginator

AsyncPaginator

the AsyncPaginator class is an async version of django's Paginator.

although AsyncPaginator inherits from django's Paginator, but this is only for code reuse and easier migration from sync to async, and you should not call the sync methods from an async environment.

the paginator can take a queryset or a list, but they have slightly different behaviours, if you pass in a queryset to the paginator, the queryset is preserved until it has to be evaluated, so until it is evaluated it needs to be treated as a queryset, and using querysets in an async environment is different from using querysets in sync environments.

Examples

note: in normal django shell you can not await, to use await you need a shell tht supports that, such as ipython

Example of list pagination

In [1]: from django_async_extensions.core.paginator import AsyncPaginator

In [2]: objects = ["john", "paul", "george", "ringo"]

In [3]: p = AsyncPaginator(objects, 2)

In [4]: await p.acount()
Out[4]: 4

In [5]: await p.anum_pages()
Out[5]: 2

In [6]: type(await p.apage_range())
Out[6]: range

In [7]: await p.apage_range()
Out[7]: range(1, 3)

In [8]: page1 = await p.apage(1)

In [9]: page1
Out[9]: <Async Page 1>

In [10]: page1.object_list
Out[10]: ['john', 'paul']

In [11]: page2 = await p.apage(2)

In [12]: page2.object_list
Out[12]: ['george', 'ringo']

In [13]: await page2.ahas_next()
Out[13]: False

In [14]: await page2.ahas_previous()
Out[14]: True

In [15]: await page2.ahas_other_pages()
Out[15]: True

await page2.anext_page_number()
Traceback (most recent call last):
...
EmptyPage: That page contains no results

In [17]: await page2.aprevious_page_number()
Out[17]: 1

In [18]: await page2.astart_index()
Out[18]: 3

In [19]: await page2.aend_index()
Out[19]: 4

In [20]: await p.apage(0)
Traceback (most recent call last):
...
EmptyPage: That page number is less than 1

In [21]: await p.apage(3)
Traceback (most recent call last):
...
EmptyPage: That page contains no results

Example of queryset pagination

In [1]: from django.contrib.auth.models import User

In [2]: objs = [User(username=f"test{i}", password="testpass123") for i in range
   ...: (1, 5)]

In [3]: User.objects.bulk_create(objs)
Out[3]: [<User: test1>, <User: test2>, <User: test3>, <User: test4>]

In [4]: from django_async_extensions.core.paginator import AsyncPaginator

In [5]: users = User.objects.order_by("username")

In [6]: p = AsyncPaginator(users, 2)

In [7]: p.object_list
Out[7]: <QuerySet [<User: test1>, <User: test2>, <User: test3>, <User: test4>]>

In [8]: page1 = await p.apage(1)

In [9]: page1
Out[9]: <Async Page 1>

In [10]: page1.object_list
Out[10]: <QuerySet [<User: test1>, <User: test2>]>

In [11]: page2 = await p.apage(2)

In [12]: page2.object_list
Out[12]: <QuerySet [<User: test3>, <User: test4>]>

In [13]: await page2.ahas_next()
Out[13]: False

In [14]: await page2.alen()  # use this instead of `len()`
Out[14]: 2

In [15]: len(page2)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[15], line 1
----> 1 len(page2)

TypeError: object of type 'AsyncPage' has no len()

In [16]: await page2.alist()  # use this instead of `list()`
Out[16]: [<User: test3>, <User: test4>]

In [17]: list(page2)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[17], line 1
----> 1 list(page2)

TypeError: 'AsyncPage' object is not iterable

In [18]: page2.object_list
Out[19]: <QuerySet [<User: test3>, <User: test4>]>

In [20]: await page2.agetitem(1)  # use this instead of `__getitem__()`
Out[20]: <User: test4>

In [21]: page2.object_list
Out[21]: [<User: test3>, <User: test4>]  # after `agetitem()` is called, the object list gets turned into a list

In [22]: page1.object_list
Out[22]: <QuerySet [<User: test1>, <User: test2>]>

In [23]: page1[0]
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[23], line 1
----> 1 page1[0]

TypeError: 'AsyncPage' object is not subscriptable

In [24]: await page1.agetitem(slice(2))  # you can pass a slice to `agetitem()`
Out[24]: [<User: test1>, <User: test2>]

In [25]: page1.object_list
Out[25]: [<User: test1>, <User: test2>]  # turned into a list