Basic Tutorial =========================================== Graphene Django has a number of additional features that are designed to make working with Django easy. Our primary focus in this tutorial is to give a good understanding of how to connect models from Django ORM to Graphene object types. Set up the Django project ------------------------- We will set up the project, create the following: - A Django project called ``cookbook`` - An app within ``cookbook`` called ``ingredients`` .. code:: bash # Create the project directory mkdir cookbook cd cookbook # Create a virtualenv to isolate our package dependencies locally virtualenv env source env/bin/activate # On Windows use `env\Scripts\activate` # Install Django and Graphene with Django support pip install django graphene_django # Set up a new project with a single application django-admin startproject cookbook . # Note the trailing '.' character cd cookbook django-admin startapp ingredients Now sync your database for the first time: .. code:: bash cd .. python manage.py migrate Let's create a few simple models... Defining our models ^^^^^^^^^^^^^^^^^^^ Let's get started with these models: .. code:: python # cookbook/ingredients/models.py from django.db import models class Category(models.Model): name = models.CharField(max_length=100) def __str__(self): return self.name class Ingredient(models.Model): name = models.CharField(max_length=100) notes = models.TextField() category = models.ForeignKey( Category, related_name="ingredients", on_delete=models.CASCADE ) def __str__(self): return self.name Add ingredients as INSTALLED_APPS: .. code:: python # cookbook/settings.py INSTALLED_APPS = [ ... # Install the ingredients app "cookbook.ingredients", ] Make sure the app name in ``cookbook.ingredients.apps.IngredientsConfig`` is set to ``cookbook.ingredients``. .. code:: python # cookbook/ingredients/apps.py from django.apps import AppConfig class IngredientsConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' name = 'cookbook.ingredients' Don't forget to create & run migrations: .. code:: bash python manage.py makemigrations python manage.py migrate Load some test data ^^^^^^^^^^^^^^^^^^^ Now is a good time to load up some test data. The easiest option will be to `download the ingredients.json `__ fixture and place it in ``cookbook/ingredients/fixtures/ingredients.json``. You can then run the following: .. code:: bash python manage.py loaddata ingredients Installed 6 object(s) from 1 fixture(s) Alternatively you can use the Django admin interface to create some data yourself. You'll need to run the development server (see below), and create a login for yourself too (``python manage.py createsuperuser``). Register models with admin panel: .. code:: python # cookbook/ingredients/admin.py from django.contrib import admin from cookbook.ingredients.models import Category, Ingredient admin.site.register(Category) admin.site.register(Ingredient) Hello GraphQL - Schema and Object Types --------------------------------------- In order to make queries to our Django project, we are going to need few things: * Schema with defined object types * A view, taking queries as input and returning the result GraphQL presents your objects to the world as a graph structure rather than a more hierarchical structure to which you may be accustomed. In order to create this representation, Graphene needs to know about each *type* of object which will appear in the graph. This graph also has a *root type* through which all access begins. This is the ``Query`` class below. To create GraphQL types for each of our Django models, we are going to subclass the ``DjangoObjectType`` class which will automatically define GraphQL fields that correspond to the fields on the Django models. After we've done that, we will list those types as fields in the ``Query`` class. Create ``cookbook/schema.py`` and type the following: .. code:: python # cookbook/schema.py import graphene from graphene_django import DjangoObjectType from cookbook.ingredients.models import Category, Ingredient class CategoryType(DjangoObjectType): class Meta: model = Category fields = ("id", "name", "ingredients") class IngredientType(DjangoObjectType): class Meta: model = Ingredient fields = ("id", "name", "notes", "category") class Query(graphene.ObjectType): all_ingredients = graphene.List(IngredientType) category_by_name = graphene.Field(CategoryType, name=graphene.String(required=True)) def resolve_all_ingredients(root, info): # We can easily optimize query count in the resolve method return Ingredient.objects.select_related("category").all() def resolve_category_by_name(root, info, name): try: return Category.objects.get(name=name) except Category.DoesNotExist: return None schema = graphene.Schema(query=Query) You can think of this as being something like your top-level ``urls.py`` file. Testing everything so far ------------------------- We are going to do some configuration work, in order to have a working Django where we can test queries, before we move on, updating our schema. Update settings ^^^^^^^^^^^^^^^ Next, install your app and GraphiQL in your Django project. GraphiQL is a web-based integrated development environment to assist in the writing and executing of GraphQL queries. It will provide us with a simple and easy way of testing our cookbook project. Add ``graphene_django`` to ``INSTALLED_APPS`` in ``cookbook/settings.py``: .. code:: python # cookbook/settings.py INSTALLED_APPS = [ ... "graphene_django", ] And then add the ``SCHEMA`` to the ``GRAPHENE`` config in ``cookbook/settings.py``: .. code:: python # cookbook/settings.py GRAPHENE = { "SCHEMA": "cookbook.schema.schema" } Alternatively, we can specify the schema to be used in the urls definition, as explained below. Creating GraphQL and GraphiQL views ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Unlike a RESTful API, there is only a single URL from which GraphQL is accessed. Requests to this URL are handled by Graphene's ``GraphQLView`` view. This view will serve as GraphQL endpoint. As we want to have the aforementioned GraphiQL we specify that on the parameters with ``graphiql=True``. .. code:: python # cookbook/urls.py from django.contrib import admin from django.urls import path from django.views.decorators.csrf import csrf_exempt from graphene_django.views import GraphQLView urlpatterns = [ path("admin/", admin.site.urls), path("graphql", csrf_exempt(GraphQLView.as_view(graphiql=True))), ] If we didn't specify the target schema in the Django settings file as explained above, we can do so here using: .. code:: python # cookbook/urls.py from django.contrib import admin from django.urls import path from django.views.decorators.csrf import csrf_exempt from graphene_django.views import GraphQLView from cookbook.schema import schema urlpatterns = [ path("admin/", admin.site.urls), path("graphql", csrf_exempt(GraphQLView.as_view(graphiql=True, schema=schema))), ] Testing our GraphQL schema ^^^^^^^^^^^^^^^^^^^^^^^^^^ We're now ready to test the API we've built. Let's fire up the server from the command line. .. code:: bash python manage.py runserver Performing system checks... Django version 3.0.7, using settings 'cookbook.settings' Starting development server at http://127.0.0.1:8000/ Quit the server with CONTROL-C. Go to `localhost:8000/graphql `__ and type your first query! .. code:: query { allIngredients { id name } } If you are using the provided fixtures, you will see the following response: .. code:: { "data": { "allIngredients": [ { "id": "1", "name": "Eggs" }, { "id": "2", "name": "Milk" }, { "id": "3", "name": "Beef" }, { "id": "4", "name": "Chicken" } ] } } Congratulations, you have created a working GraphQL server 🥳! Note: Graphene `automatically camelcases `__ all field names for better compatibility with JavaScript clients. Getting relations ----------------- Using the current schema we can query for relations too. This is where GraphQL becomes really powerful! For example, we may want to get a specific categories and list all ingredients that are in that category. We can do that with the following query: .. code:: query { categoryByName(name: "Dairy") { id name ingredients { id name } } } This will give you (in case you are using the fixtures) the following result: .. code:: { "data": { "categoryByName": { "id": "1", "name": "Dairy", "ingredients": [ { "id": "1", "name": "Eggs" }, { "id": "2", "name": "Milk" } ] } } } We can also list all ingredients and get information for the category they are in: .. code:: query { allIngredients { id name category { id name } } } Summary ------- As you can see, GraphQL is very powerful and integrating Django models allows you to get started with a working server quickly. If you want to put things like ``django-filter`` and automatic pagination in action, you should continue with the :ref:`Relay tutorial`. A good idea is to check the `Graphene `__ documentation so that you are familiar with it as well.