GraphQL with Django — simple yet powerful (CRUD) — Part 2

Muhammad Dauda
Analytics Vidhya
Published in
6 min readMay 2, 2020
Photo by timJ on Unsplash

I remember the first time i was getting started with GraphQL-with-Django, all i could find was tutorials that only covered the basics, i searched the web but most of the what i could find out there only covered basics or were too complicated to understand.

So this time around we’re going to dive-in deep and cover all the CRUD operations (Create, Read, Update, Delete). But as far as GraphQL is concerned, there are two types of operations, one that can Read and one that can Write, so it divides these basic operations into Query (Read only) and Mutation (Create, Update & Delete).

But, if you’re still not familiar with GraphQL integration in Django, you can refer to the first part of this tutorial where we covered the basics

Since you’re already thinking about integrating an API, then it’s safe to assume that you’re already familiar with Django, so lets get started 💪

Probono: How I now structure my Django projects 😇🔥

You can skip this if you already have a methodology you follow

Project Directory Setup

If like me, you don’t like the way Django structures your project, it’s a good thing to restructure it

I start by creating a directory where i will house everything, in this case; GraphQL_with_Django_2

Then i create a virtual environment in that directory;

virtualenv .

After starting my virtual environment, i create a new Django project

django-admin startproject MVP

Now i rename the Django Project directory from MVP to src

Don’t forget to git ignore the virtual environment files

This is going to be the model we’d work on;

products/models.py

It’s not the best product model out there. However, it’s meant to give you an idea on how to handle different data types in GraphQL (CharField, DecimanField, ManyToManyField, BooleanField & DateTimeField)

Lets create our app level schema

products/schema.py

Nearly all the magic happens in products/schema.py so we’d explain how most of the code works shortly.

Meanwhile include the app-level schema.py into the project’s schema.py

project level schema.py

Lets add our GraphQL endpoint to the project’s urls.py

The structure of a typical Mutation

There are three(3) particular parts of a Mutation class; class Argument, return object, & mutate method.

class mutationName(graphene.mutation):
class Arguments:
. . .
what_were_returning = graphene.Field(SomeType)
def mutate(self, info, args ...):
. . .
return mutationName(what_were_returning)

We’d use the createProduct mutation as an example

1. Let’s start with our class arguments

class Arguments: this consists of variables that can be passed as arguments. Traditionally, Python is loosely typed and does not enforce strict typing. However, GraphQL in it’s own way requires the data type of the arguments to be defined. This can be a pain in the ass but, along the way it helps.

We specify the arguments we’d likely be passing to CreateProduct

name = graphene.String()
price = graphene.Float()
category = graphene.List(graphene.ID)
in_stock = graphene.Boolean()
date_created = graphene.types.datetime.DateTime()

If you had noticed, the data types are not exactly the same with the ones used in Models , but they are somewhat equivalent.

For CharField, we’d make use of graphene.String()
Whereas for DecimalField, we’d use graphene.Float()
ManyToMany is simply a list of ForeignKeys (ID’s) so we’d use graphene.List(graphene.ID)
Boolean remains the same
DateTimeField is also somewhat the same, but we’d pick it from the list of the datetime formats in graphene.types

Note: In case you’re confused, graphene is just Python’s implementation of GraphQL

2. Our return object

Next, we’d define what the mutation would return

product = graphene.Field(ProductType)

Whenever we’re returning a non standard datatype, in this case; our custom ProductType, we have to pass it as an argument to graphene.Field(. . .)

3. Mutate method

The mutate method is basically where he logic resides, in this case this is where we create our product object, populate it with the necessary data & save it.

If you noticed, you will realize that we start off by presetting some of the parameters will None, this is because they are not required and thus we can chose to leave them blank.

The first time i was trying Mutations, i spent days 😅 debugging why i had to pass in all the variables in the mutate method. I finally realized that it’s a python problem not GraphQL and that i could use default arguments to solve it.

Default arguments serve as the default values if arguments were not specified. So, if you had specified an argument with a different value, it would override the default value.

Next, you’ll also notice that we did not include the category in the objects.create method, this is because the category is a ManyToManyField, so when the value is not None (user has passed a value for it) we loop through the values (ID’s), appending them to a list and finally setting the products’s category to that list

if category is not None:
category_set = []
for category_id in category:
category_object = Category.objects.get(pk=category_id)
category_set.append(category_object)
product.category.set(category_set)

finally we save the product product.save() and return an instance of the mutation, passing the product in it

Final Notes

In Django, GraphQL mutations are more alike than you think, one of the prominent things that might differ is the mutate method, so if you were to create a mutation for UpdateProduct, you’d simply add id in the class arguments and also in the mutate method’s arguments then do a basic update operation instead of create.

So since, going over Update and Deletion will simply be a repetition of what we’ve already done, this marks the end of our simple yet powerful tutorial

Deletion is even more simpler, refer to the full GitHub project for more

Testing

We’d start testing the the API by creating a new category

Create Category Mutation

Let’s create a new product

Create Product Mutation

Let’s create another product, but this time around we’ll pass in the list of category

Create Product Mutation

The next thing we’d test is, updating a product. So let’s change the price from 19.0 to 5.0, you’d notice that we’ve passed the same name again, it’s a mistake so don’t mind (The product name will just remain the same)

Update Product Mutation

Lastly, we’d try to delete a product 😉

Delete Product

Cool, we’ve successfully done all the CRUD operations using GraphQL.

Note: GraphQL is undoubtedly robust and it makes seamless integration with mobile applications and front-end’s like (React, Vue, etc)

However, one needs to write a lot of code in schema.py before setting it up, and most times it’s just a repetition of codes and that’s a downside.

--

--