JSONField Models in Graphene Django
JSONField Models in Graphene Django

Graphene + GraphQL

In my humble opinion, Graphene is very stable and is probably the best library for creating GraphQL endpoints in Python.

While working with Graphene, I came across an issue where JSONFields were always returned with quotation marks and backslashes — JSONString .

Example — meta field is returned as a JSON string rather than a JSON object

This article aims to address this issue using GenericScalar , which is currently an undocumented type in the current version of Graphene documentation.

TL;DR

This can be easily solved by overriding your meta field type in your DjangoObjectType to GenericScalar such as below.

Example

Detailed Example with Code

In this section, I am going to run through a few snippets of codes for creating a simple mutation and query that we can work with.

Example folder structure of a Django app

Database Model

Simple database model for demonstration.

GraphQL Types

Creating a DjangoObjectType for our Person object.

Django Filters

Let’s add some basic filters to our code while we are at it.

GraphQL Mutations

For simplicity’s sake, we will only need a single createPerson mutation for this example. We are going to pass in metadata as a dictionary/ JSON data input for our mutation.

GraphQL Schema

Finally, we will stitch everything together inside schema.py and we are ready to try things out!

Results

Trying Out The Mutation

Let’s create a Person object using our newly created CreatePerson mutation at your /graphql endpoint using the built-in GraphiQL IDE or any API client of your choice (Postman, Insomnia REST Client, etc.)

# Create a Person object

mutation createPerson($input: CreatePersonInput!) {

createPerson(input: $input) {

person {

id

}

}

}

{

"input": {

"firstName": "Albert",

"lastName": "Joe",

"metadata": {

"is_admin": true,

"email": '

}

}

} # Query Variable"input": {"firstName": "Albert","lastName": "Joe","metadata": {"is_admin": true,"email": ' albert@example.com

Solution

As you can see in the meta field below, it’s returned as a JSONString which is not what we wanted. Things could get uglier especially when you’re dealing with a large JSON object.

The issue was apparently caused by the fact that JSONFields are by default treated as JSONString in Graphene.

However, this can simply be fixed by applying GenericScalar to types.py such as below.
['Jerry Ng']
['Python', 'GraphQL', 'Graphene', 'Technology', 'Django']