Editor’s note: This article was updated on 3 May 2022 to reflect the most recent versions of GraphQL and Django and to better detail the GraphQL and Django demo project, including the use of Graphene for integration.
For the past eight years or so, Django has been the most effective framework for making quick web applications, API endpoints, or admin panels for other applications.
One of the biggest advantages of Django is its ability to enable users to write less code and get started quicker, especially if you’re including an admin panel and a fully manageable database migration process as base functionality.
Django REST Framework, an external toolkit, makes it easy to build API endpoints. It basically wraps full CRUD API around the Django Model with just a few lines of code.
This means that building any basic CRUD API with Django helps to keep more of a development focus on UI parts, which are key elements of all software products.
Similarly, GraphQL aims to automate backend APIs by providing type strict query language and a single API Endpoint where you can query all information that you need from UI and trigger actions (mutations) to send data to the backend.
My journey with GraphQL started with Facebook’s API, where GraphQL comes from.
Naturally, GraphQL is considered to be very close to the JavaScript world, mostly because browser-based apps are the first adopters of that technology.
That’s why my first GraphQL server+client was done in Node.js and React.js. After having the first app built on top of GraphQL API, I started to use it exclusively for my Web-based projects.
In this article, I’ll review the advantages of GraphQL and GraphQL Subscriptions. I’ll also build a sample project using GraphQL and Django to demonstrate how powerful this combination can be for web development. I’ll use Graphene for the integration.
As you may have guessed, there is a library for Django to support GraphQL called Graphene-Django, which is very similar to the Django REST Framework. However, there are significant differences between Django REST and Django with GraphQL.
The key difference lies in UI usability: with a REST API, you’re getting endless URLs with specific parameter names where you have to check types and specific values.
Meanwhile, with GraphQL you’re defining mutations similar to the code below and getting strictly defined variable names and types, which become part of an automatic GraphQL type validation.
type Mutation { userLogin(email: String!, password: String!): UserLoginResponse } type UserLoginResponse { token: String error: Boolean message: String }
GraphQL also comes with another bonus packaged inside its type system: it automatically generates documentation where you can get available queries and mutations with their parameters/return types.
Django REST also generates some form of documentation, but it is not as usable as the GraphQL Playground.
If you think this type of interface is available for all kinds of GraphQL endpoints, you’re wrong — this is only available in development mode servers. Although, you can download software like GraphQL Playground standalone and manually configure it for any public GraphQL endpoint.
In terms of security, having one API endpoint is naturally more manageable than having hundreds of them — especially when you consider the fact that GraphQL automatically keeps specific type rules and won’t allow requests with incorrect parameter names or values.
Let’s build a basic project with Django and GraphQL just to demonstrate how powerful this setup can be. On one hand, you’re getting easy CRUD management with database. On the other hand, you’re getting a very powerful API query language with a single endpoint.
python -m venv venv
source ./venv/bin/activate
pip install django graphene_django
django-admin startproject graphqlpractice
graphqlpractice
directoryNow, let’s create and define our models. Create a new Django app django-admin startapp postusers
, and register the app in settings.py
like so:
INSTALLED_APPS = [ ... "postusers.apps.PostusersConfig" ]
Next, define the models in postusers/models.py
like so:
from django.db import models class Author(models.Model): name = models.CharField(max_length=100) def __str__(self): return self.name class Post(models.Model): title = models.CharField(maxlength=100) body = models.TextField() author = models.ForeignKey( Author, relatedname="posts", on_delete=models.CASCADE ) def str(self): return self.title
Now, let’s register the models with the admin panel by adding the following code to postusers/admin.py
:
from django.contrib import admin from .models import Author, Post admin.site.register(Author) admin.site.register(Post)
Next, make migrations: python manage.py makemigrations
.
N.B., if you get an error regarding
force_text
this has to do with breaking changes in Django 4; either downgrade to Django 3 or follow the directions here
Now, run the migrations: python manage.py migrate
Create a superuser — python manage.py createsuperuser
— and run your server with python manage.py runserver
. Then head over to localhost:8000/admin
and add a few authors and posts.
Now, let’s set up Graphene, a powerful library that integrates with Django. First, add Graphene to installed apps in /graphqlpractices/settings.py
like so:
INSTALLEDAPPS = [ ... 'django.contrib.staticfiles', "graphenedjango" ... ]
Then, add the GraphQL endpoint to /graphqlpractice/urls.py
:
from django.contrib import admin from django.urls import path from graphenedjango.views import GraphQLView urlpatterns = [ path('admin/', admin.site.urls), path("graphql", GraphQLView.asview(graphiql=True)), ]
Next, add the following settings.py
to identify where your GraphQL schema is located, postusers/schma/schema.py
; you will need to make the schema directory and file.
GRAPHENE = { "SCHEMA": "postusers.schema.schema" }
The most interesting part of this project is defining GraphQL types and queries in Python. It’s actually based on your database models, but you can also define custom queries without using Django Models.
Add the following to the postusers/schema/schema.py
:
from graphene_django import DjangoObjectType import graphene from postusers.models import Post as PostModel from postusers.models import Author as AuthorModel class Post(DjangoObjectType): class Meta: model = PostModel fields = ['id', 'title', 'body', 'author'] class Author(DjangoObjectType): class Meta: model = AuthorModel fields = ['id', 'name', 'posts'] def resolve_posts(self, info): return PostModel.objects.filter(author=self) @classmethod def get_node(cls, info, id): return Author.objects.get(id=id) class Query(graphene.ObjectType): authors = graphene.List(Author) posts = graphene.List(Post) def resolve_authors(self, info): return AuthorModel.objects.all() def resolve_posts(self, info): return PostModel.objects.all() schema = graphene.Schema(query=Query)
Now you can run the server and go to localhost:8000/graphql
to test out some GraphQL queries like this one:
query { authors { name posts { title } } }
The most important thing to remember is that you can query any fields you want, which will affect the overall load time and traffic usage on the UI side.
For larger user bases, it’s important to keep traffic low and only query the fields you need. In the case of REST API, you will get all fields anyway.
query { posts { title author { name } } }
This is the basic query outcome from the Python definition. It’s pretty simple and, compared to REST APIs, more expressive than you may think. You can find the final code for this exercise here for reference.
GraphQL Subscriptions function as a way to tell the server to retrieve data based on a specific query whenever the data is available.
It all works with WebSockets in near real time, which means we have to somehow include Django Websockets and configure our backend server for accepting WebSockets.
Basically, GraphQL is just an API query language interpretation that works with any kind of network transportation when handling client and server-side GraphQL language interpretation.
It may seem difficult at first, but there’s an open source library and Django GraphQL Subscriptions over at the Django WebSockets module.
# settings.py GRAPHENE = { 'SCHEMA_INDENT': 4, 'MIDDLEWARE': [ # Other middlewares 'graphenedjangosubscriptions.depromise_subscription', ] }
This will be enough to handle the subscription schema later on as a Subscription query.
As a quick aside, Pinterest actually works entirely on GraphQL Subscriptions, which is all built on top of Django Backend (but probably modified quite a bit).
In my opinion, Django with GraphQL is more powerful and extensible than Django with REST API.
However, it isn’t battle tested and large companies are still in the process of adopting this kind of combination. Still, based on what you can get out of this simple configuration, imagine how much more comfortable web development will be when you use Django with GraphQL with modern technologies.
LogRocket is like a DVR for web and mobile apps, recording literally everything that happens on your site. Instead of guessing why problems happen, you can aggregate and report on problematic GraphQL requests to quickly understand the root cause. In addition, you can track Apollo client state and inspect GraphQL queries' key-value pairs.
LogRocket instruments your app to record baseline performance timings such as page load time, time to first byte, slow network requests, and also logs Redux, NgRx, and Vuex actions/state. Start monitoring for free.Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowEfficient initializing is crucial to smooth-running websites. One way to optimize that process is through lazy initialization in Rust 1.80.
Design React Native UIs that look great on any device by using adaptive layouts, responsive scaling, and platform-specific tools.
Angular’s two-way data binding has evolved with signals, offering improved performance, simpler syntax, and better type inference.
Fix sticky positioning issues in CSS, from missing offsets to overflow conflicts in flex, grid, and container height constraints.
3 Replies to "Django and GraphQL: Demo project with Graphene"
Any and all graphQL servers can be introspected with GraphiQL. Dev mode has nothing to do with it. The spec itself specifies that.
Under “setting up models” and “…graphene” sections above…
There are a couple code examples with indentation issues, publishing issues?
Just noting that ‘cut n paste’ will not work from those sections.
Thanks for the catch, that should be fixed now. There’s also a link to the GitHub repo for further reference.