Skip to content

Relay Pagination example

Denys Vitali edited this page Aug 28, 2020 · 4 revisions

For this example, we're using DjangoObjectType and a hypothetical django model for Place. Neither of these is necessary, and it's being included only to present a complete (almost) example. Simply replace the model assignment, and use the appropriate ObjectType in place of DjangoObjectType in the initial type declaration (class Place_Node_Type(DjangoObjectType) herein) for your application, and pagination will be yours!

For this example, we're going to assume a basic understanding of what startCursor and endCursor, and really, pagination as a concept, actually are, and just quickly provide you with the basics of pagination-in-graphene's how.

In a nutshell, pagination is implemented via graphene relay's Connection and ConnectionField pairing. With these in place, you'll see pageInfo available within your queries. It looks something like this:

"pageInfo": {
    "startCursor": "YXJyYXljb25uZWN0aW9uOjQx",
    "endCursor": "YXJyYXljb25uZWN0aW9uOjQz",
    "hasNextPage": false,
    "hasPreviousPage": true
},

In addition to a cursor element within edges that will show you the cursor id for each element, like so:

edges {
  cursor
  node {
    <whatever>
  }
}

The basic implementation below provides the elements for cursor-based pagination that you'll need to do your thing in your code. Hope this helps.

from graphene import Connection, ConnectionField, Node, Int
from graphene_django import DjangoObjectType
from <wherever your models exist> import Place

class Place_Node_Type(DjangoObjectType):
    class Meta:
        model = Place
        interfaces = (Node, )


class Place_Connection(Connection):
    class Meta:
        node = Place_Node_Type
    count = Int()

    def resolve_count(root, info):
        return len(root.edges)


class Query(object):
    places = ConnectionField(Place_Connection)

    def resolve_places(root, info, **kwargs):
        return Place.objects.all()

The following query, (the pageInfo element is included for illustration, but isn't necessary for the query to resolve):

{
  places(first: 3, after: "YXJyYXljb25uZWN0aW9uOjQx") {
    pageInfo {
      startCursor
      endCursor
      hasNextPage
      hasPreviousPage
    }
    edges {
      cursor
      node {
        id
        name
      }
    }
  }
}

Gives us:

{
  "data": {
    "places": {
      "pageInfo": {
        "startCursor": "YXJyYXljb25uZWN0aW9uOjQy",
        "endCursor": "YXJyYXljb25uZWN0aW9uOjQ0",
        "hasNextPage": true,
        "hasPreviousPage": false
      },
      "edges": [
        {
          "cursor": "YXJyYXljb25uZWN0aW9uOjQy",
          "node": {
            "id": "UGxhY2VfTm9kZV9UeXBlOjQz",
            "name": "Wilton, Franklin, Maine, United States"
          }
        },
        {
          "cursor": "YXJyYXljb25uZWN0aW9uOjQz",
          "node": {
            "id": "UGxhY2VfTm9kZV9UeXBlOjQ0",
            "name": "Boise City, Ada, Idaho, United States"
          }
        },
        {
          "cursor": "YXJyYXljb25uZWN0aW9uOjQ0",
          "node": {
            "id": "UGxhY2VfTm9kZV9UeXBlOjQ1",
            "name": "Helena, Shelby, Akabama, USA"
          }
        }
      ]
    }
  }
}