mirror of
				https://github.com/graphql-python/graphene-django.git
				synced 2025-11-04 09:57:53 +03:00 
			
		
		
		
	Update tutorial docs (#994)
This commit is contained in:
		
							parent
							
								
									b552dcac24
								
							
						
					
					
						commit
						97de26bf2e
					
				| 
						 | 
				
			
			@ -25,8 +25,8 @@ Add ``graphene_django`` to the ``INSTALLED_APPS`` in the ``settings.py`` file of
 | 
			
		|||
 | 
			
		||||
    INSTALLED_APPS = [
 | 
			
		||||
        ...
 | 
			
		||||
        'django.contrib.staticfiles', # Required for GraphiQL
 | 
			
		||||
        'graphene_django'
 | 
			
		||||
        "django.contrib.staticfiles", # Required for GraphiQL
 | 
			
		||||
        "graphene_django"
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -63,7 +63,7 @@ Finally, define the schema location for Graphene in the ``settings.py`` file of
 | 
			
		|||
.. code:: python
 | 
			
		||||
 | 
			
		||||
    GRAPHENE = {
 | 
			
		||||
        'SCHEMA': 'django_root.schema.schema'
 | 
			
		||||
        "SCHEMA": "django_root.schema.schema"
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
Where ``path.schema.schema`` is the location of the ``Schema`` object in your Django project.
 | 
			
		||||
| 
						 | 
				
			
			@ -75,7 +75,7 @@ The most basic ``schema.py`` looks like this:
 | 
			
		|||
    import graphene
 | 
			
		||||
 | 
			
		||||
    class Query(graphene.ObjectType):
 | 
			
		||||
        pass
 | 
			
		||||
        hello = graphene.String(default_value="Hi!")
 | 
			
		||||
 | 
			
		||||
    schema = graphene.Schema(query=Query)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										151
									
								
								docs/queries.rst
									
									
									
									
									
								
							
							
						
						
									
										151
									
								
								docs/queries.rst
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -20,27 +20,26 @@ Full example
 | 
			
		|||
    # my_app/schema.py
 | 
			
		||||
 | 
			
		||||
    import graphene
 | 
			
		||||
    from graphene_django import DjangoObjectType
 | 
			
		||||
 | 
			
		||||
    from graphene_django.types import DjangoObjectType
 | 
			
		||||
    from .models import Question
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    class QuestionType(DjangoObjectType):
 | 
			
		||||
        class Meta:
 | 
			
		||||
            model = Question
 | 
			
		||||
            fields = ("id", "question_text")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    class Query:
 | 
			
		||||
    class Query(graphene.ObjectType):
 | 
			
		||||
        questions = graphene.List(QuestionType)
 | 
			
		||||
        question = graphene.Field(QuestionType, question_id=graphene.String())
 | 
			
		||||
        question_by_id = graphene.Field(QuestionType, id=graphene.String())
 | 
			
		||||
 | 
			
		||||
        def resolve_questions(self, info, **kwargs):
 | 
			
		||||
        def resolve_questions(root, info, **kwargs):
 | 
			
		||||
            # Querying a list
 | 
			
		||||
            return Question.objects.all()
 | 
			
		||||
 | 
			
		||||
        def resolve_question(self, info, question_id):
 | 
			
		||||
        def resolve_question_by_id(root, info, id):
 | 
			
		||||
            # Querying a single question
 | 
			
		||||
            return Question.objects.get(pk=question_id)
 | 
			
		||||
            return Question.objects.get(pk=id)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Specifying which fields to include
 | 
			
		||||
| 
						 | 
				
			
			@ -60,21 +59,27 @@ Show **only** these fields on the model:
 | 
			
		|||
 | 
			
		||||
.. code:: python
 | 
			
		||||
 | 
			
		||||
    from graphene_django import DjangoObjectType
 | 
			
		||||
    from .models import Question
 | 
			
		||||
 | 
			
		||||
    class QuestionType(DjangoObjectType):
 | 
			
		||||
        class Meta:
 | 
			
		||||
            model = Question
 | 
			
		||||
            fields = ('id', 'question_text')
 | 
			
		||||
            fields = ("id", "question_text")
 | 
			
		||||
 | 
			
		||||
You can also set the ``fields`` attribute to the special value ``'__all__'`` to indicate that all fields in the model should be used.
 | 
			
		||||
You can also set the ``fields`` attribute to the special value ``"__all__"`` to indicate that all fields in the model should be used.
 | 
			
		||||
 | 
			
		||||
For example:
 | 
			
		||||
 | 
			
		||||
.. code:: python
 | 
			
		||||
 | 
			
		||||
    from graphene_django import DjangoObjectType
 | 
			
		||||
    from .models import Question
 | 
			
		||||
 | 
			
		||||
    class QuestionType(DjangoObjectType):
 | 
			
		||||
        class Meta:
 | 
			
		||||
            model = Question
 | 
			
		||||
            fields = '__all__'
 | 
			
		||||
            fields = "__all__"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
``exclude``
 | 
			
		||||
| 
						 | 
				
			
			@ -84,10 +89,13 @@ Show all fields **except** those in ``exclude``:
 | 
			
		|||
 | 
			
		||||
.. code:: python
 | 
			
		||||
 | 
			
		||||
    from graphene_django import DjangoObjectType
 | 
			
		||||
    from .models import Question
 | 
			
		||||
 | 
			
		||||
    class QuestionType(DjangoObjectType):
 | 
			
		||||
        class Meta:
 | 
			
		||||
            model = Question
 | 
			
		||||
            exclude = ('question_text',)
 | 
			
		||||
            exclude = ("question_text",)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Customising fields
 | 
			
		||||
| 
						 | 
				
			
			@ -97,16 +105,19 @@ You can completely overwrite a field, or add new fields, to a ``DjangoObjectType
 | 
			
		|||
 | 
			
		||||
.. code:: python
 | 
			
		||||
 | 
			
		||||
    from graphene_django import DjangoObjectType
 | 
			
		||||
    from .models import Question
 | 
			
		||||
 | 
			
		||||
    class QuestionType(DjangoObjectType):
 | 
			
		||||
 | 
			
		||||
        class Meta:
 | 
			
		||||
            model = Question
 | 
			
		||||
            fields = ('id', 'question_text')
 | 
			
		||||
            fields = ("id", "question_text")
 | 
			
		||||
 | 
			
		||||
        extra_field = graphene.String()
 | 
			
		||||
 | 
			
		||||
        def resolve_extra_field(self, info):
 | 
			
		||||
            return 'hello!'
 | 
			
		||||
            return "hello!"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Choices to Enum conversion
 | 
			
		||||
| 
						 | 
				
			
			@ -121,12 +132,19 @@ For example the following ``Model`` and ``DjangoObjectType``:
 | 
			
		|||
 | 
			
		||||
.. code:: python
 | 
			
		||||
 | 
			
		||||
   class PetModel(models.Model):
 | 
			
		||||
      kind = models.CharField(max_length=100, choices=(('cat', 'Cat'), ('dog', 'Dog')))
 | 
			
		||||
    from django.db import models
 | 
			
		||||
    from graphene_django import DjangoObjectType
 | 
			
		||||
 | 
			
		||||
   class Pet(DjangoObjectType):
 | 
			
		||||
      class Meta:
 | 
			
		||||
         model = PetModel
 | 
			
		||||
    class PetModel(models.Model):
 | 
			
		||||
        kind = models.CharField(
 | 
			
		||||
            max_length=100,
 | 
			
		||||
            choices=(("cat", "Cat"), ("dog", "Dog"))
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    class Pet(DjangoObjectType):
 | 
			
		||||
        class Meta:
 | 
			
		||||
            model = PetModel
 | 
			
		||||
            fields = ("id", "kind",)
 | 
			
		||||
 | 
			
		||||
Results in the following GraphQL schema definition:
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -148,27 +166,35 @@ You can disable this automatic conversion by setting
 | 
			
		|||
 | 
			
		||||
.. code:: python
 | 
			
		||||
 | 
			
		||||
   class Pet(DjangoObjectType):
 | 
			
		||||
      class Meta:
 | 
			
		||||
         model = PetModel
 | 
			
		||||
         convert_choices_to_enum = False
 | 
			
		||||
    from graphene_django import DjangoObjectType
 | 
			
		||||
    from .models import PetModel
 | 
			
		||||
 | 
			
		||||
    class Pet(DjangoObjectType):
 | 
			
		||||
        class Meta:
 | 
			
		||||
            model = PetModel
 | 
			
		||||
            fields = ("id", "kind",)
 | 
			
		||||
            convert_choices_to_enum = False
 | 
			
		||||
 | 
			
		||||
.. code::
 | 
			
		||||
 | 
			
		||||
   type Pet {
 | 
			
		||||
     id: ID!
 | 
			
		||||
     kind: String!
 | 
			
		||||
   }
 | 
			
		||||
  type Pet {
 | 
			
		||||
    id: ID!
 | 
			
		||||
    kind: String!
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
You can also set ``convert_choices_to_enum`` to a list of fields that should be
 | 
			
		||||
automatically converted into enums:
 | 
			
		||||
 | 
			
		||||
.. code:: python
 | 
			
		||||
 | 
			
		||||
   class Pet(DjangoObjectType):
 | 
			
		||||
      class Meta:
 | 
			
		||||
         model = PetModel
 | 
			
		||||
         convert_choices_to_enum = ['kind']
 | 
			
		||||
    from graphene_django import DjangoObjectType
 | 
			
		||||
    from .models import PetModel
 | 
			
		||||
 | 
			
		||||
    class Pet(DjangoObjectType):
 | 
			
		||||
        class Meta:
 | 
			
		||||
            model = PetModel
 | 
			
		||||
            fields = ("id", "kind",)
 | 
			
		||||
            convert_choices_to_enum = ["kind"]
 | 
			
		||||
 | 
			
		||||
**Note:** Setting ``convert_choices_to_enum = []`` is the same as setting it to
 | 
			
		||||
``False``.
 | 
			
		||||
| 
						 | 
				
			
			@ -181,6 +207,8 @@ Say you have the following models:
 | 
			
		|||
 | 
			
		||||
.. code:: python
 | 
			
		||||
 | 
			
		||||
    from django.db import models
 | 
			
		||||
 | 
			
		||||
    class Category(models.Model):
 | 
			
		||||
        foo = models.CharField(max_length=256)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -192,10 +220,13 @@ When ``Question`` is published as a ``DjangoObjectType`` and you want to add ``C
 | 
			
		|||
 | 
			
		||||
.. code:: python
 | 
			
		||||
 | 
			
		||||
    from graphene_django import DjangoObjectType
 | 
			
		||||
    from .models import Question
 | 
			
		||||
 | 
			
		||||
    class QuestionType(DjangoObjectType):
 | 
			
		||||
        class Meta:
 | 
			
		||||
            model = Question
 | 
			
		||||
            fields = ('category',)
 | 
			
		||||
            fields = ("category",)
 | 
			
		||||
 | 
			
		||||
Then all query-able related models must be defined as DjangoObjectType subclass,
 | 
			
		||||
or they will fail to show if you are trying to query those relation fields. You only
 | 
			
		||||
| 
						 | 
				
			
			@ -203,9 +234,13 @@ need to create the most basic class for this to work:
 | 
			
		|||
 | 
			
		||||
.. code:: python
 | 
			
		||||
 | 
			
		||||
    from graphene_django import DjangoObjectType
 | 
			
		||||
    from .models import Category
 | 
			
		||||
 | 
			
		||||
    class CategoryType(DjangoObjectType):
 | 
			
		||||
        class Meta:
 | 
			
		||||
            model = Category
 | 
			
		||||
            fields = ("foo",)
 | 
			
		||||
 | 
			
		||||
.. _django-objecttype-get-queryset:
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -220,7 +255,6 @@ Use this to control filtering on the ObjectType level instead of the Query objec
 | 
			
		|||
    from graphene_django.types import DjangoObjectType
 | 
			
		||||
    from .models import Question
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    class QuestionType(DjangoObjectType):
 | 
			
		||||
        class Meta:
 | 
			
		||||
            model = Question
 | 
			
		||||
| 
						 | 
				
			
			@ -240,18 +274,22 @@ This resolve method should follow this format:
 | 
			
		|||
 | 
			
		||||
.. code:: python
 | 
			
		||||
 | 
			
		||||
    def resolve_foo(self, info, **kwargs):
 | 
			
		||||
    def resolve_foo(parent, info, **kwargs):
 | 
			
		||||
 | 
			
		||||
Where "foo" is the name of the field declared in the ``Query`` object.
 | 
			
		||||
 | 
			
		||||
.. code:: python
 | 
			
		||||
 | 
			
		||||
    class Query:
 | 
			
		||||
    import graphene
 | 
			
		||||
    from .models import Question
 | 
			
		||||
    from .types import QuestionType
 | 
			
		||||
 | 
			
		||||
    class Query(graphene.ObjectType):
 | 
			
		||||
        foo = graphene.List(QuestionType)
 | 
			
		||||
 | 
			
		||||
        def resolve_foo(self, info, **kwargs):
 | 
			
		||||
            id = kwargs.get('id')
 | 
			
		||||
            return QuestionModel.objects.get(id)
 | 
			
		||||
        def resolve_foo(root, info):
 | 
			
		||||
            id = kwargs.get("id")
 | 
			
		||||
            return Question.objects.get(id)
 | 
			
		||||
 | 
			
		||||
Arguments
 | 
			
		||||
~~~~~~~~~
 | 
			
		||||
| 
						 | 
				
			
			@ -260,10 +298,18 @@ Additionally, Resolvers will receive **any arguments declared in the field defin
 | 
			
		|||
 | 
			
		||||
.. code:: python
 | 
			
		||||
 | 
			
		||||
    class Query:
 | 
			
		||||
        question = graphene.Field(Question, foo=graphene.String(), bar=graphene.Int())
 | 
			
		||||
    import graphene
 | 
			
		||||
    from .models import Question
 | 
			
		||||
    from .types import QuestionType
 | 
			
		||||
 | 
			
		||||
        def resolve_question(self, info, foo, bar):
 | 
			
		||||
    class Query(graphene.ObjectType):
 | 
			
		||||
        question = graphene.Field(
 | 
			
		||||
            QuestionType,
 | 
			
		||||
            foo=graphene.String(),
 | 
			
		||||
            bar=graphene.Int()
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        def resolve_question(root, info, foo, bar):
 | 
			
		||||
            # If `foo` or `bar` are declared in the GraphQL query they will be here, else None.
 | 
			
		||||
            return Question.objects.filter(foo=foo, bar=bar).first()
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -278,7 +324,15 @@ of Django's ``HTTPRequest`` in your resolve methods, such as checking for authen
 | 
			
		|||
 | 
			
		||||
.. code:: python
 | 
			
		||||
 | 
			
		||||
    def resolve_questions(self, info, **kwargs):
 | 
			
		||||
    import graphene
 | 
			
		||||
 | 
			
		||||
    from .models import Question
 | 
			
		||||
    from .types import QuestionType
 | 
			
		||||
 | 
			
		||||
    class Query(graphene.ObjectType):
 | 
			
		||||
        questions = graphene.List(QuestionType)
 | 
			
		||||
 | 
			
		||||
    def resolve_questions(root, info):
 | 
			
		||||
        # See if a user is authenticated
 | 
			
		||||
        if info.context.user.is_authenticated():
 | 
			
		||||
            return Question.objects.all()
 | 
			
		||||
| 
						 | 
				
			
			@ -305,15 +359,13 @@ Django models and your external API.
 | 
			
		|||
    import graphene
 | 
			
		||||
    from .models import Question
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    class MyQuestion(graphene.ObjectType):
 | 
			
		||||
        text = graphene.String()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    class Query:
 | 
			
		||||
    class Query(graphene.ObjectType):
 | 
			
		||||
        question = graphene.Field(MyQuestion, question_id=graphene.String())
 | 
			
		||||
 | 
			
		||||
        def resolve_question(self, info, question_id):
 | 
			
		||||
        def resolve_question(root, info, question_id):
 | 
			
		||||
            question = Question.objects.get(pk=question_id)
 | 
			
		||||
            return MyQuestion(
 | 
			
		||||
                text=question.question_text
 | 
			
		||||
| 
						 | 
				
			
			@ -343,25 +395,22 @@ the core graphene pages for more information on customizing the Relay experience
 | 
			
		|||
    from graphene_django import DjangoObjectType
 | 
			
		||||
    from .models import Question
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    class QuestionType(DjangoObjectType):
 | 
			
		||||
        class Meta:
 | 
			
		||||
            model = Question
 | 
			
		||||
            interfaces = (relay.Node,)
 | 
			
		||||
 | 
			
		||||
            interfaces = (relay.Node,)  # make sure you add this
 | 
			
		||||
            fields = "__all__"
 | 
			
		||||
 | 
			
		||||
    class QuestionConnection(relay.Connection):
 | 
			
		||||
        class Meta:
 | 
			
		||||
            node = QuestionType
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    class Query:
 | 
			
		||||
        questions = relay.ConnectionField(QuestionConnection)
 | 
			
		||||
 | 
			
		||||
        def resolve_questions(root, info, **kwargs):
 | 
			
		||||
            return Question.objects.all()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
You can now execute queries like:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,15 +3,11 @@ 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.
 | 
			
		||||
understanding of how to connect models from Django ORM to Graphene object types.
 | 
			
		||||
 | 
			
		||||
Set up the Django project
 | 
			
		||||
-------------------------
 | 
			
		||||
 | 
			
		||||
You can find the entire project in ``examples/cookbook-plain``.
 | 
			
		||||
 | 
			
		||||
----
 | 
			
		||||
 | 
			
		||||
We will set up the project, create the following:
 | 
			
		||||
 | 
			
		||||
-  A Django project called ``cookbook``
 | 
			
		||||
| 
						 | 
				
			
			@ -28,13 +24,12 @@ We will set up the project, create the following:
 | 
			
		|||
    source env/bin/activate  # On Windows use `env\Scripts\activate`
 | 
			
		||||
 | 
			
		||||
    # Install Django and Graphene with Django support
 | 
			
		||||
    pip install django
 | 
			
		||||
    pip install graphene_django
 | 
			
		||||
    pip install django graphene_django
 | 
			
		||||
 | 
			
		||||
    # Set up a new project with a single application
 | 
			
		||||
    django-admin.py startproject cookbook .  # Note the trailing '.' character
 | 
			
		||||
    django-admin startproject cookbook .  # Note the trailing '.' character
 | 
			
		||||
    cd cookbook
 | 
			
		||||
    django-admin.py startapp ingredients
 | 
			
		||||
    django-admin startapp ingredients
 | 
			
		||||
 | 
			
		||||
Now sync your database for the first time:
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -54,19 +49,18 @@ Let's get started with these models:
 | 
			
		|||
    # 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)
 | 
			
		||||
            Category, related_name="ingredients", on_delete=models.CASCADE
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        def __str__(self):
 | 
			
		||||
            return self.name
 | 
			
		||||
| 
						 | 
				
			
			@ -75,10 +69,12 @@ Add ingredients as INSTALLED_APPS:
 | 
			
		|||
 | 
			
		||||
.. code:: python
 | 
			
		||||
 | 
			
		||||
    # cookbook/settings.py
 | 
			
		||||
 | 
			
		||||
    INSTALLED_APPS = [
 | 
			
		||||
        ...
 | 
			
		||||
        # Install the ingredients app
 | 
			
		||||
        'cookbook.ingredients',
 | 
			
		||||
        "cookbook.ingredients",
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -102,13 +98,13 @@ following:
 | 
			
		|||
 | 
			
		||||
.. code:: bash
 | 
			
		||||
 | 
			
		||||
    $ python ./manage.py loaddata ingredients
 | 
			
		||||
    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 (``./manage.py createsuperuser``).
 | 
			
		||||
create a login for yourself too (``python manage.py createsuperuser``).
 | 
			
		||||
 | 
			
		||||
Register models with admin panel:
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -138,66 +134,48 @@ order to create this representation, Graphene needs to know about each
 | 
			
		|||
This graph also has a *root type* through which all access begins. This
 | 
			
		||||
is the ``Query`` class below.
 | 
			
		||||
 | 
			
		||||
This means, for each of our models, we are going to create a type, subclassing ``DjangoObjectType``
 | 
			
		||||
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/ingredients/schema.py`` and type the following:
 | 
			
		||||
Create ``cookbook/schema.py`` and type the following:
 | 
			
		||||
 | 
			
		||||
.. code:: python
 | 
			
		||||
 | 
			
		||||
    # cookbook/ingredients/schema.py
 | 
			
		||||
    # cookbook/schema.py
 | 
			
		||||
    import graphene
 | 
			
		||||
 | 
			
		||||
    from graphene_django.types import DjangoObjectType
 | 
			
		||||
    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(object):
 | 
			
		||||
        all_categories = graphene.List(CategoryType)
 | 
			
		||||
    class Query(graphene.ObjectType):
 | 
			
		||||
        all_ingredients = graphene.List(IngredientType)
 | 
			
		||||
        category_by_name = graphene.Field(CategoryType, name=graphene.String(required=True))
 | 
			
		||||
 | 
			
		||||
        def resolve_all_categories(self, info, **kwargs):
 | 
			
		||||
            return Category.objects.all()
 | 
			
		||||
 | 
			
		||||
        def resolve_all_ingredients(self, info, **kwargs):
 | 
			
		||||
        def resolve_all_ingredients(root, info):
 | 
			
		||||
            # We can easily optimize query count in the resolve method
 | 
			
		||||
            return Ingredient.objects.select_related('category').all()
 | 
			
		||||
            return Ingredient.objects.select_related("category").all()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Note that the above ``Query`` class is a mixin, inheriting from
 | 
			
		||||
``object``. This is because we will now create a project-level query
 | 
			
		||||
class which will combine all our app-level mixins.
 | 
			
		||||
 | 
			
		||||
Create the parent project-level ``cookbook/schema.py``:
 | 
			
		||||
 | 
			
		||||
.. code:: python
 | 
			
		||||
 | 
			
		||||
    import graphene
 | 
			
		||||
 | 
			
		||||
    import cookbook.ingredients.schema
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    class Query(cookbook.ingredients.schema.Query, graphene.ObjectType):
 | 
			
		||||
        # This class will inherit from multiple Queries
 | 
			
		||||
        # as we begin to add more apps to our project
 | 
			
		||||
        pass
 | 
			
		||||
        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 (although it currently lacks any namespacing).
 | 
			
		||||
file.
 | 
			
		||||
 | 
			
		||||
Testing everything so far
 | 
			
		||||
-------------------------
 | 
			
		||||
| 
						 | 
				
			
			@ -216,18 +194,21 @@ Add ``graphene_django`` to ``INSTALLED_APPS`` in ``cookbook/settings.py``:
 | 
			
		|||
 | 
			
		||||
.. code:: python
 | 
			
		||||
 | 
			
		||||
    # cookbook/settings.py
 | 
			
		||||
 | 
			
		||||
    INSTALLED_APPS = [
 | 
			
		||||
        ...
 | 
			
		||||
        # This will also make the `graphql_schema` management command available
 | 
			
		||||
        'graphene_django',
 | 
			
		||||
        "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'
 | 
			
		||||
        "SCHEMA": "cookbook.schema.schema"
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
Alternatively, we can specify the schema to be used in the urls definition,
 | 
			
		||||
| 
						 | 
				
			
			@ -245,14 +226,17 @@ aforementioned GraphiQL we specify that on the parameters with ``graphiql=True``
 | 
			
		|||
 | 
			
		||||
.. code:: python
 | 
			
		||||
 | 
			
		||||
    from django.conf.urls import url, include
 | 
			
		||||
    # 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 = [
 | 
			
		||||
        url(r'^admin/', admin.site.urls),
 | 
			
		||||
        url(r'^graphql$', GraphQLView.as_view(graphiql=True)),
 | 
			
		||||
        path("admin/", admin.site.urls),
 | 
			
		||||
        path("graphql", csrf_exempt(GraphQLView.as_view(graphiql=True))),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -261,16 +245,19 @@ as explained above, we can do so here using:
 | 
			
		|||
 | 
			
		||||
.. code:: python
 | 
			
		||||
 | 
			
		||||
    from django.conf.urls import url, include
 | 
			
		||||
    # 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 = [
 | 
			
		||||
        url(r'^admin/', admin.site.urls),
 | 
			
		||||
        url(r'^graphql$', GraphQLView.as_view(graphiql=True, schema=schema)),
 | 
			
		||||
        path("admin/", admin.site.urls),
 | 
			
		||||
        path("graphql", csrf_exempt(GraphQLView.as_view(graphiql=True, schema=schema))),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -283,10 +270,10 @@ from the command line.
 | 
			
		|||
 | 
			
		||||
.. code:: bash
 | 
			
		||||
 | 
			
		||||
    $ python ./manage.py runserver
 | 
			
		||||
    python manage.py runserver
 | 
			
		||||
 | 
			
		||||
    Performing system checks...
 | 
			
		||||
    Django version 1.11, using settings 'cookbook.settings'
 | 
			
		||||
    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.
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -329,24 +316,25 @@ If you are using the provided fixtures, you will see the following response:
 | 
			
		|||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
You can experiment with ``allCategories`` too.
 | 
			
		||||
 | 
			
		||||
Something to have in mind is the `auto camelcasing <http://docs.graphene-python.org/en/latest/types/schema/#auto-camelcase-field-names>`__ that is happening.
 | 
			
		||||
Congratulations, you have created a working GraphQL server 🥳!
 | 
			
		||||
 | 
			
		||||
Note: Graphene `automatically camelcases <http://docs.graphene-python.org/en/latest/types/schema/#auto-camelcase-field-names>`__ all field names for better compatibility with JavaScript clients.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Getting relations
 | 
			
		||||
-----------------
 | 
			
		||||
 | 
			
		||||
Right now, with this simple setup in place, we can query for relations too. This is where graphql becomes really powerful!
 | 
			
		||||
Using the current schema we can query for relations too. This is where GraphQL becomes really powerful!
 | 
			
		||||
 | 
			
		||||
For example, we may want to list all categories and in each category, all ingredients that are in that category.
 | 
			
		||||
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 {
 | 
			
		||||
      allCategories {
 | 
			
		||||
      categoryByName(name: "Dairy") {
 | 
			
		||||
        id
 | 
			
		||||
        name
 | 
			
		||||
        ingredients {
 | 
			
		||||
| 
						 | 
				
			
			@ -356,43 +344,26 @@ We can do that with the following query:
 | 
			
		|||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
This will give you (in case you are using the fixtures) the following result:
 | 
			
		||||
 | 
			
		||||
.. code::
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
      "data": {
 | 
			
		||||
        "allCategories": [
 | 
			
		||||
          {
 | 
			
		||||
            "id": "1",
 | 
			
		||||
            "name": "Dairy",
 | 
			
		||||
            "ingredients": [
 | 
			
		||||
              {
 | 
			
		||||
                "id": "1",
 | 
			
		||||
                "name": "Eggs"
 | 
			
		||||
              },
 | 
			
		||||
              {
 | 
			
		||||
                "id": "2",
 | 
			
		||||
                "name": "Milk"
 | 
			
		||||
              }
 | 
			
		||||
            ]
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "id": "2",
 | 
			
		||||
            "name": "Meat",
 | 
			
		||||
            "ingredients": [
 | 
			
		||||
              {
 | 
			
		||||
                "id": "3",
 | 
			
		||||
                "name": "Beef"
 | 
			
		||||
              },
 | 
			
		||||
              {
 | 
			
		||||
                "id": "4",
 | 
			
		||||
                "name": "Chicken"
 | 
			
		||||
              }
 | 
			
		||||
            ]
 | 
			
		||||
          }
 | 
			
		||||
        ]
 | 
			
		||||
        "categoryByName": {
 | 
			
		||||
          "id": "1",
 | 
			
		||||
          "name": "Dairy",
 | 
			
		||||
          "ingredients": [
 | 
			
		||||
            {
 | 
			
		||||
              "id": "1",
 | 
			
		||||
              "name": "Eggs"
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              "id": "2",
 | 
			
		||||
              "name": "Milk"
 | 
			
		||||
            }
 | 
			
		||||
          ]
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -411,71 +382,12 @@ We can also list all ingredients and get information for the category they are i
 | 
			
		|||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
Getting single objects
 | 
			
		||||
----------------------
 | 
			
		||||
 | 
			
		||||
So far, we have been able to fetch list of objects and follow relation. But what about single objects?
 | 
			
		||||
 | 
			
		||||
We can update our schema to support that, by adding new query for ``ingredient`` and ``category`` and adding arguments, so we can query for specific objects.
 | 
			
		||||
Add the **Highlighted** lines to ``cookbook/ingredients/schema.py``
 | 
			
		||||
 | 
			
		||||
.. literalinclude:: schema.py
 | 
			
		||||
  :emphasize-lines: 19-21,25-27,36-58
 | 
			
		||||
 | 
			
		||||
Now, with the code in place, we can query for single objects.
 | 
			
		||||
 | 
			
		||||
For example, lets query ``category``:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.. code::
 | 
			
		||||
 | 
			
		||||
    query {
 | 
			
		||||
      category(id: 1) {
 | 
			
		||||
        name
 | 
			
		||||
      }
 | 
			
		||||
      anotherCategory: category(name: "Dairy") {
 | 
			
		||||
        ingredients {
 | 
			
		||||
          id
 | 
			
		||||
          name
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
This will give us the following results:
 | 
			
		||||
 | 
			
		||||
.. code::
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
      "data": {
 | 
			
		||||
        "category": {
 | 
			
		||||
          "name": "Dairy"
 | 
			
		||||
        },
 | 
			
		||||
        "anotherCategory": {
 | 
			
		||||
          "ingredients": [
 | 
			
		||||
            {
 | 
			
		||||
              "id": "1",
 | 
			
		||||
              "name": "Eggs"
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              "id": "2",
 | 
			
		||||
              "name": "Milk"
 | 
			
		||||
            }
 | 
			
		||||
          ]
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
As an exercise, you can try making some queries to ``ingredient``.
 | 
			
		||||
 | 
			
		||||
Something to keep in mind - since we are using one field several times in our query, we need `aliases <http://graphql.org/learn/queries/#aliases>`__
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Summary
 | 
			
		||||
-------
 | 
			
		||||
 | 
			
		||||
As you can see, GraphQL is very powerful but there are a lot of repetitions in our example. We can do a lot of improvements by adding layers of abstraction on top of ``graphene-django``.
 | 
			
		||||
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 **relay tutorial.**
 | 
			
		||||
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 <http://docs.graphene-python.org/en/latest/>`__
 | 
			
		||||
documentation but it is not essential to understand and use Graphene-Django in your project.
 | 
			
		||||
A good idea is to check the `Graphene <http://docs.graphene-python.org/en/latest/>`__
 | 
			
		||||
documentation so that you are familiar with it as well.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,5 @@
 | 
			
		|||
.. _Relay tutorial:
 | 
			
		||||
 | 
			
		||||
Relay tutorial
 | 
			
		||||
========================================
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue
	
	Block a user