-
-
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