Posts About

GraphQL and Django in 5 minutes

August 5, 2017

TL;DR Jump to the coding part or get the code here.

What is GraphQL?

GraphQL query is a string that is sent to a server to be interpreted and fulfilled, which then returns JSON back to the client. It was created by Facebook in 2012 and the first specification draft was made public in 2015.

In this tutorial I will cover the basics of working with GraphQL and Django.

Getting started

Before creating the project and all, make sure you have virtualenv installed, so that the packages used in this tutorial won’t be installed system-wide.

# Clone the repo
git clone https://github.com/joaorafaelm/graphql-django-example;
cd graphql-django-example;

# Create virtualenv
virtualenv venv && source venv/bin/activate;

# Install django and graphene
pip install -r requirements.txt;

# Setup db
python manage.py migrate;

Run python manage.py loaddata books.json to populate the db, or run python manage.py createsuperuser and then add some data using the admin interface.

Models and GraphQL Schema

This example is going to use the models Author, Book and Publisher.

# bookstore/store/models.py
from django.db import models

class Publisher(models.Model):
    name = models.CharField(max_length=30)
    website = models.URLField()

    def __str__(self):
        return self.name

class Author(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=40)
    email = models.EmailField()

    def __str__(self):
        return '%s %s' % (self.first_name, self.last_name)

class Book(models.Model):
    title = models.CharField(max_length=100)
    authors = models.ManyToManyField(Author)
    publisher = models.ForeignKey(Publisher)
    publication_date = models.DateField()

    def __str__(self):
        return self.title

After creating the models, the Schema should be created, which will be used to serve the API.

At the time of writing this post, graphene-django version is 1.3 and it does not handle ManyToMany fields properly, that is why the resolve_authors method was added. This issue has been resolved for the next release.

# bookstore/schema.py
import graphene
from graphene_django.types import DjangoObjectType
from graphene_django.debug import DjangoDebug
from bookstore.store.models import Author, Book, Publisher

class AuthorType(DjangoObjectType):
    class Meta:
        model = Author

class BookType(DjangoObjectType):
    authors = graphene.List(AuthorType)

    # Many To Many fix until next release.
    # https://github.com/graphql-python/graphene-django/issues/155
    @graphene.resolve_only_args
    def resolve_authors(self):
        return self.authors.all()

    class Meta:
        model = Book

class PublisherType(DjangoObjectType):
    class Meta:
        model = Publisher

class Query(graphene.ObjectType):
    all_authors = graphene.List(AuthorType)
    all_books = graphene.List(BookType)
    all_publishers = graphene.List(PublisherType)

    # Debug field (rawSql, parameters etc).
    debug = graphene.Field(DjangoDebug, name='__debug')

    def resolve_all_authors(self, args, context, info):
        return Author.objects.all()

    def resolve_all_books(self, args, context, info):
        return Book.objects.select_related('publisher').all()

    def resolve_all_publishers(self, args, context, info):
        return Publisher.objects.all()

schema = graphene.Schema(query=Query)

Last but not least, the GraphQL URL must be added into the urls.py file.

# bookstore/urls.py
from django.conf.urls import url
from django.contrib import admin
from graphene_django.views import GraphQLView
from bookstore.schema import schema

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^graphql', GraphQLView.as_view(graphiql=True, schema=schema)),
]

You can now run python manage.py runserver and start using the API at http://localhost:8000/graphql.

Querying and debugging

GraphiQL provides a graphical interactive in-browser GraphQL IDE, including some features such as syntax highlighting, real-time error reporting, automatic query completion etc.

I will show some query examples, but you can learn more about querying at graphql.org/learn/queries/.


Given the following query, we can retrieve all books registered along with their authors.

{
  allBooks {
    title,
    authors {
      firstName,
      lastName
    }
  }
}

And the response…

{
  "data": {
    "allBooks": [
      {
        "title": "Resurrection",
        "authors": [
          {
            "firstName": "Leo",
            "lastName": "Tolstoy"
          }
        ]
      },
      {
        "title": "Childhood",
        "authors": [
          {
            "firstName": "Leo",
            "lastName": "Tolstoy"
          }
        ]
      }
    ]
  }
}

Using the __debug field you can get information about the actual SQL query.

{
  allAuthors {lastName}
  __debug {
    sql {rawSql, duration}
  }
}

Response:

{
  "data": {
    "allAuthors": [
      {
        "lastName": "King"
      },
      {
        "lastName": "Tolstoy"
      },
      {
        "lastName": "Gaiman"
      },
      {
        "lastName": "Pratchett"
      }
    ],
    "__debug": {
      "sql": [
        {
          "rawSql": "SELECT \"store_author\".\"id\", \"store_author\".\"first_name\", \"store_author\".\"last_name\", \"store_author\".\"email\" FROM \"store_author\"",
          "duration": 0.0009260177612304688
        }
      ]
    }
  }
}

All this code is on my Github. Please do fork it and make pull requests regarding any issues or improvements you may have with my code.