2016-09-12 07:47:34 +03:00
|
|
|
|
ObjectTypes
|
|
|
|
|
===========
|
|
|
|
|
|
|
|
|
|
An ObjectType is the single, definitive source of information about your
|
|
|
|
|
data. It contains the essential fields and behaviors of the data you’re
|
|
|
|
|
querying.
|
|
|
|
|
|
|
|
|
|
The basics:
|
|
|
|
|
|
2016-10-07 11:56:01 +03:00
|
|
|
|
- Each ObjectType is a Python class that inherits from
|
2016-09-25 15:01:12 +03:00
|
|
|
|
``graphene.ObjectType``.
|
2016-09-12 07:47:34 +03:00
|
|
|
|
- Each attribute of the ObjectType represents a ``Field``.
|
|
|
|
|
|
|
|
|
|
Quick example
|
|
|
|
|
-------------
|
|
|
|
|
|
2016-10-07 11:56:01 +03:00
|
|
|
|
This example model defines a Person, with a first and a last name:
|
2016-09-12 07:47:34 +03:00
|
|
|
|
|
|
|
|
|
.. code:: python
|
|
|
|
|
|
|
|
|
|
import graphene
|
|
|
|
|
|
|
|
|
|
class Person(graphene.ObjectType):
|
|
|
|
|
first_name = graphene.String()
|
|
|
|
|
last_name = graphene.String()
|
|
|
|
|
full_name = graphene.String()
|
|
|
|
|
|
2018-12-26 23:22:34 +03:00
|
|
|
|
def resolve_full_name(root, info):
|
|
|
|
|
return '{} {}'.format(root.first_name, root.last_name)
|
2016-09-12 07:47:34 +03:00
|
|
|
|
|
|
|
|
|
**first\_name** and **last\_name** are fields of the ObjectType. Each
|
|
|
|
|
field is specified as a class attribute, and each attribute maps to a
|
|
|
|
|
Field.
|
|
|
|
|
|
2016-10-07 11:56:01 +03:00
|
|
|
|
The above ``Person`` ObjectType has the following schema representation:
|
2016-09-12 07:47:34 +03:00
|
|
|
|
|
2016-09-25 15:01:12 +03:00
|
|
|
|
.. code::
|
2016-09-12 07:47:34 +03:00
|
|
|
|
|
|
|
|
|
type Person {
|
|
|
|
|
firstName: String
|
|
|
|
|
lastName: String
|
|
|
|
|
fullName: String
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Resolvers
|
|
|
|
|
---------
|
|
|
|
|
|
2018-10-30 15:17:44 +03:00
|
|
|
|
A resolver is a method that resolves certain fields within an
|
2018-10-22 16:19:55 +03:00
|
|
|
|
``ObjectType``. If not specified otherwise, the resolver of a
|
2016-10-07 11:56:01 +03:00
|
|
|
|
field is the ``resolve_{field_name}`` method on the ``ObjectType``.
|
2016-09-12 07:47:34 +03:00
|
|
|
|
|
2018-04-20 15:21:59 +03:00
|
|
|
|
By default resolvers take the arguments ``info`` and ``*args``.
|
2016-09-12 07:47:34 +03:00
|
|
|
|
|
2018-10-30 15:17:44 +03:00
|
|
|
|
NOTE: The resolvers on an ``ObjectType`` are always treated as ``staticmethod``\ s,
|
2016-10-07 11:56:01 +03:00
|
|
|
|
so the first argument to the resolver method ``self`` (or ``root``) need
|
|
|
|
|
not be an actual instance of the ``ObjectType``.
|
2016-09-28 23:57:41 +03:00
|
|
|
|
|
2018-12-26 23:22:34 +03:00
|
|
|
|
If an explicit resolver is not defined on the ``ObjectType`` then Graphene will
|
|
|
|
|
attempt to use a property with the same name on the object that is passed to the
|
|
|
|
|
``ObjectType``.
|
2016-09-28 23:57:41 +03:00
|
|
|
|
|
2018-12-26 23:22:34 +03:00
|
|
|
|
.. code:: python
|
|
|
|
|
|
|
|
|
|
import graphene
|
|
|
|
|
|
|
|
|
|
class Person(graphene.ObjectType):
|
|
|
|
|
first_name = graphene.String()
|
|
|
|
|
last_name = graphene.String()
|
|
|
|
|
|
|
|
|
|
class Query(graphene.ObjectType):
|
|
|
|
|
me = graphene.Field(Person)
|
2016-09-12 07:47:34 +03:00
|
|
|
|
|
2018-12-26 23:22:34 +03:00
|
|
|
|
def resolve_me(_, info):
|
|
|
|
|
# returns an object that represents a Person
|
|
|
|
|
return get_human(name='Luke Skywalker')
|
|
|
|
|
|
|
|
|
|
If you are passing a dict instead of an object to your ``ObjectType`` you can
|
|
|
|
|
change the default resolver in the ``Meta`` class like this:
|
2016-09-12 07:47:34 +03:00
|
|
|
|
|
|
|
|
|
.. code:: python
|
|
|
|
|
|
|
|
|
|
import graphene
|
2018-12-26 23:22:34 +03:00
|
|
|
|
from graphene.types.resolver import dict_resolver
|
|
|
|
|
|
|
|
|
|
class Person(graphene.ObjectType):
|
|
|
|
|
class Meta:
|
|
|
|
|
default_resolver = dict_resolver
|
|
|
|
|
|
|
|
|
|
first_name = graphene.String()
|
|
|
|
|
last_name = graphene.String()
|
2016-09-12 07:47:34 +03:00
|
|
|
|
|
|
|
|
|
class Query(graphene.ObjectType):
|
2018-12-26 23:22:34 +03:00
|
|
|
|
me = graphene.Field(Person)
|
|
|
|
|
|
|
|
|
|
def resolve_me(_, info):
|
|
|
|
|
return {
|
|
|
|
|
"first_name": "Luke",
|
|
|
|
|
"last_name": "Skywalker",
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Or you can change the default resolver globally by calling ``set_default_resolver``
|
|
|
|
|
before executing a query.
|
|
|
|
|
|
|
|
|
|
.. code:: python
|
|
|
|
|
|
|
|
|
|
import graphene
|
|
|
|
|
from graphene.types.resolver import dict_resolver, set_default_resolver
|
|
|
|
|
|
|
|
|
|
set_default_resolver(dict_resolver)
|
|
|
|
|
|
|
|
|
|
schema = graphene.Schema(query=Query)
|
|
|
|
|
result = schema.execute('''
|
|
|
|
|
query {
|
|
|
|
|
me {
|
|
|
|
|
firstName
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
''')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Resolvers with arguments
|
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
|
|
Any arguments that a field defines gets passed to the resolver function as
|
|
|
|
|
kwargs. For example:
|
|
|
|
|
|
|
|
|
|
.. code:: python
|
|
|
|
|
|
|
|
|
|
import graphene
|
|
|
|
|
|
|
|
|
|
class Query(graphene.ObjectType):
|
|
|
|
|
human_by_name = graphene.Field(Human, name=graphene.String(required=True))
|
|
|
|
|
|
|
|
|
|
def resolve_human_by_name(_, info, name):
|
|
|
|
|
return get_human(name=name)
|
|
|
|
|
|
|
|
|
|
You can then execute the following query:
|
|
|
|
|
|
|
|
|
|
.. code::
|
|
|
|
|
|
|
|
|
|
query {
|
|
|
|
|
humanByName(name: "Luke Skywalker") {
|
|
|
|
|
firstName
|
|
|
|
|
lastName
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NOTE: if you define an argument for a field that is not required (and in a query
|
|
|
|
|
execution it is not provided as an argument) it will not be passed to the
|
|
|
|
|
resolver function at all. This is so that the developer can differenciate
|
|
|
|
|
between a ``undefined`` value for an argument and an explicit ``null`` value.
|
|
|
|
|
|
|
|
|
|
For example, given this schema:
|
|
|
|
|
|
|
|
|
|
.. code:: python
|
|
|
|
|
|
|
|
|
|
import graphene
|
|
|
|
|
|
|
|
|
|
class Query(graphene.ObjectType):
|
|
|
|
|
hello = graphene.String(required=True, name=graphene.String())
|
|
|
|
|
|
|
|
|
|
def resolve_hello(_, info, name):
|
|
|
|
|
return name if name else 'World'
|
|
|
|
|
|
|
|
|
|
And this query:
|
|
|
|
|
|
|
|
|
|
.. code::
|
|
|
|
|
|
|
|
|
|
query {
|
|
|
|
|
hello
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
An error will be thrown:
|
|
|
|
|
|
|
|
|
|
.. code::
|
|
|
|
|
|
|
|
|
|
TypeError: resolve_hello() missing 1 required positional argument: 'name'
|
|
|
|
|
|
|
|
|
|
You can fix this error in 2 ways. Either by combining all keyword arguments
|
|
|
|
|
into a dict:
|
|
|
|
|
|
|
|
|
|
.. code:: python
|
|
|
|
|
|
|
|
|
|
class Query(graphene.ObjectType):
|
|
|
|
|
hello = graphene.String(required=True, name=graphene.String())
|
|
|
|
|
|
|
|
|
|
def resolve_hello(_, info, **args):
|
|
|
|
|
return args.get('name', 'World')
|
|
|
|
|
|
|
|
|
|
Or by setting a default value for the keyword argument:
|
|
|
|
|
|
|
|
|
|
.. code:: python
|
|
|
|
|
|
|
|
|
|
class Query(graphene.ObjectType):
|
|
|
|
|
hello = graphene.String(required=True, name=graphene.String())
|
|
|
|
|
|
|
|
|
|
def resolve_hello(_, info, name='World'):
|
|
|
|
|
return name
|
2016-09-12 07:47:34 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Resolvers outside the class
|
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
2016-10-07 11:56:01 +03:00
|
|
|
|
A field can use a custom resolver from outside the class:
|
2016-09-12 07:47:34 +03:00
|
|
|
|
|
|
|
|
|
.. code:: python
|
|
|
|
|
|
|
|
|
|
import graphene
|
|
|
|
|
|
2018-12-26 23:22:34 +03:00
|
|
|
|
def resolve_full_name(person, info):
|
|
|
|
|
return '{} {}'.format(person.first_name, person.last_name)
|
2016-09-12 07:47:34 +03:00
|
|
|
|
|
2018-12-26 23:22:34 +03:00
|
|
|
|
class Person(graphene.ObjectType):
|
|
|
|
|
first_name = graphene.String()
|
|
|
|
|
last_name = graphene.String()
|
|
|
|
|
full_name = graphene.String(resolver=resolve_full_name)
|
2016-09-12 07:47:34 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Instances as data containers
|
|
|
|
|
----------------------------
|
|
|
|
|
|
2016-10-07 11:56:01 +03:00
|
|
|
|
Graphene ``ObjectType``\ s can act as containers too. So with the
|
|
|
|
|
previous example you could do:
|
2016-09-12 07:47:34 +03:00
|
|
|
|
|
|
|
|
|
.. code:: python
|
|
|
|
|
|
|
|
|
|
peter = Person(first_name='Peter', last_name='Griffin')
|
|
|
|
|
|
|
|
|
|
peter.first_name # prints "Peter"
|
|
|
|
|
peter.last_name # prints "Griffin"
|
|
|
|
|
|
|
|
|
|
.. _Interface: /docs/interfaces/
|