-
-
Save mbrochh/f92594ab8188393bd83c892ef2af25e6 to your computer and use it in GitHub Desktop.
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 | |
) |
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) |
// 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 | |
} | |
} | |
} | |
` |
@Cimmanuel so far I haven't bothered to figure out a reusable way 🙈
@mbrochh
Ouch!
Here's what I did so far:
class PaginatedType(graphene.ObjectType):
page = graphene.Int()
pages = graphene.Int()
has_next = graphene.Boolean()
has_prev = graphene.Boolean()
class ProductPaginatedType(PaginatedType):
objects = graphene.List(ProductType)
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!
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
@mbrochh this is really nice. How would you make PaginatedType reusable though? I mean instead of creating a PaginatedType for each DjangoObjectType, how do you think the DRY principle can be honoured? I'm trying to figure something out