Last active
September 24, 2023 10:45
-
-
Save mbrochh/f92594ab8188393bd83c892ef2af25e6 to your computer and use it in GitHub Desktop.
Using pagination with Django, graphene and Apollo
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator | |
# First we create a little helper function, becase we will potentially have many PaginatedTypes | |
# and we will potentially want to turn many querysets into paginated results: | |
def get_paginator(qs, page_size, page, paginated_type, **kwargs): | |
p = Paginator(qs, page_size) | |
try: | |
page_obj = p.page(page) | |
except PageNotAnInteger: | |
page_obj = p.page(1) | |
except EmptyPage: | |
page_obj = p.page(p.num_pages) | |
return paginated_type( | |
page=page_obj.number, | |
pages=p.num_pages, | |
has_next=page_obj.has_next(), | |
has_prev=page_obj.has_previous(), | |
objects=page_obj.object_list, | |
**kwargs | |
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from theartling.utils import get_paginator | |
from . import models | |
# Let's assume you have some ObjectType for one of your models: | |
class ProductType(DjangoObjectType): | |
class Meta: | |
model = models.Product | |
# Now we create a corresponding PaginatedType for that object type: | |
class ProductPaginatedType(graphene.ObjectType): | |
page = graphene.Int() | |
pages = graphene.Int() | |
has_next = graphene.Boolean() | |
has_prev = graphene.Boolean() | |
objects = graphene.List(ProductType) | |
class Query(object): | |
products = graphene.Field(ProductPaginatedType, page=graphene.Int()) | |
# Now, in your resolver functions, you just query your objects and turn the queryset into the PaginatedType using the helper function: | |
def resolve_products(self, info, page): | |
page_size = 10 | |
qs = models.Product.objects.all() | |
return get_paginator(qs, page_size, page, ProductPaginatedType) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// In your frontend, you just query your endpoint and request all the fields from the PaginatedType: | |
const gql = ` | |
{ | |
products(page: 1) { | |
page | |
pages | |
has_next | |
has_prev | |
objects { | |
id | |
name | |
slug | |
whatever | |
} | |
} | |
} | |
` |
how to handle this solution when you have filters in a class level filterset_class in the Query.
Basically doing this you would have to do all filters by hand and then paginate them as I haven't figured it out how to fetch in resolve methods what the filters have filtered before.
Actually, I've got lots of filters in the all app with filterset_class, so it shouldn't be nice removing all of them to do it in the resolvers side.
Any idea?
Hello,
Thanks for this code. It working fine. I try to set up this pagination with DjangoFilterConnectionField but I get an error.
I try to set the pagination before the filter end. Do you have an idea on how to do setup this pagination with DjangoFilterConnectionField ?
thanks alot for this
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@mbrochh
Ouch!
Here's what I did so far:
I did this just to remove redundancy and make it a little neat. I feel there's more that can be done. Please let me know when you figure something out. Thanks!