2016-09-12 07:47:34 +03:00
|
|
|
Nodes
|
|
|
|
=====
|
|
|
|
|
|
|
|
A ``Node`` is an Interface provided by ``graphene.relay`` that contains
|
|
|
|
a single field ``id`` (which is a ``ID!``). Any object that inherits
|
2017-03-01 17:30:39 +03:00
|
|
|
from it has to implement a ``get_node`` method for retrieving a
|
2016-09-12 07:47:34 +03:00
|
|
|
``Node`` by an *id*.
|
|
|
|
|
|
|
|
|
|
|
|
Quick example
|
|
|
|
-------------
|
|
|
|
|
|
|
|
Example usage (taken from the `Starwars Relay example`_):
|
|
|
|
|
|
|
|
.. code:: python
|
|
|
|
|
|
|
|
class Ship(graphene.ObjectType):
|
|
|
|
'''A ship in the Star Wars saga'''
|
|
|
|
class Meta:
|
|
|
|
interfaces = (relay.Node, )
|
|
|
|
|
|
|
|
name = graphene.String(description='The name of the ship.')
|
|
|
|
|
|
|
|
@classmethod
|
2017-07-28 06:06:48 +03:00
|
|
|
def get_node(cls, info, id):
|
2016-09-12 07:47:34 +03:00
|
|
|
return get_ship(id)
|
|
|
|
|
|
|
|
The ``id`` returned by the ``Ship`` type when you query it will be a
|
2017-03-01 17:30:39 +03:00
|
|
|
scalar which contains enough info for the server to know its type and
|
|
|
|
its id.
|
2016-09-12 07:47:34 +03:00
|
|
|
|
|
|
|
For example, the instance ``Ship(id=1)`` will return ``U2hpcDox`` as the
|
|
|
|
id when you query it (which is the base64 encoding of ``Ship:1``), and
|
|
|
|
which could be useful later if we want to query a node by its id.
|
|
|
|
|
|
|
|
|
|
|
|
Custom Nodes
|
|
|
|
------------
|
|
|
|
|
|
|
|
You can use the predefined ``relay.Node`` or you can subclass it, defining
|
|
|
|
custom ways of how a node id is encoded (using the ``to_global_id`` method in the class)
|
|
|
|
or how we can retrieve a Node given a encoded id (with the ``get_node_from_global_id`` method).
|
|
|
|
|
|
|
|
Example of a custom node:
|
|
|
|
|
|
|
|
.. code:: python
|
|
|
|
|
|
|
|
class CustomNode(Node):
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
name = 'Node'
|
|
|
|
|
|
|
|
@staticmethod
|
2020-06-27 13:18:11 +03:00
|
|
|
def to_global_id(type_, id):
|
|
|
|
return f"{type_}:{id}"
|
2016-09-12 07:47:34 +03:00
|
|
|
|
|
|
|
@staticmethod
|
2018-02-18 02:28:33 +03:00
|
|
|
def get_node_from_global_id(info, global_id, only_type=None):
|
2020-06-27 13:18:11 +03:00
|
|
|
type_, id = global_id.split(':')
|
2018-02-18 02:28:33 +03:00
|
|
|
if only_type:
|
2017-02-08 09:35:03 +03:00
|
|
|
# We assure that the node type that we want to retrieve
|
|
|
|
# is the same that was indicated in the field type
|
2020-06-27 13:18:11 +03:00
|
|
|
assert type_ == only_type._meta.name, 'Received not compatible node.'
|
2017-02-08 09:35:03 +03:00
|
|
|
|
2020-06-27 13:18:11 +03:00
|
|
|
if type_ == 'User':
|
2016-09-12 07:47:34 +03:00
|
|
|
return get_user(id)
|
2020-06-27 13:18:11 +03:00
|
|
|
elif type_ == 'Photo':
|
2016-09-12 07:47:34 +03:00
|
|
|
return get_photo(id)
|
|
|
|
|
|
|
|
|
|
|
|
The ``get_node_from_global_id`` method will be called when ``CustomNode.Field`` is resolved.
|
|
|
|
|
|
|
|
|
2017-02-08 09:35:03 +03:00
|
|
|
Accessing node types
|
|
|
|
--------------------
|
|
|
|
|
|
|
|
If we want to retrieve node instances from a ``global_id`` (scalar that identifies an instance by it's type name and id),
|
2017-11-20 18:05:28 +03:00
|
|
|
we can simply do ``Node.get_node_from_global_id(info, global_id)``.
|
2017-02-08 09:35:03 +03:00
|
|
|
|
2017-03-01 17:30:39 +03:00
|
|
|
In the case we want to restrict the instance retrieval to a specific type, we can do:
|
2017-11-20 18:05:28 +03:00
|
|
|
``Node.get_node_from_global_id(info, global_id, only_type=Ship)``. This will raise an error
|
2017-02-08 19:21:14 +03:00
|
|
|
if the ``global_id`` doesn't correspond to a Ship type.
|
2017-02-08 09:35:03 +03:00
|
|
|
|
|
|
|
|
2016-09-12 07:47:34 +03:00
|
|
|
Node Root field
|
|
|
|
---------------
|
|
|
|
|
|
|
|
As is required in the `Relay specification`_, the server must implement
|
|
|
|
a root field called ``node`` that returns a ``Node`` Interface.
|
|
|
|
|
|
|
|
For this reason, ``graphene`` provides the field ``relay.Node.Field``,
|
|
|
|
which links to any type in the Schema which implements ``Node``.
|
|
|
|
Example usage:
|
|
|
|
|
|
|
|
.. code:: python
|
|
|
|
|
|
|
|
class Query(graphene.ObjectType):
|
|
|
|
# Should be CustomNode.Field() if we want to use our custom Node
|
|
|
|
node = relay.Node.Field()
|
|
|
|
|
2017-04-26 21:41:51 +03:00
|
|
|
.. _Relay specification: https://facebook.github.io/relay/docs/graphql-relay-specification.html
|
2016-09-12 07:47:34 +03:00
|
|
|
.. _Starwars Relay example: https://github.com/graphql-python/graphene/blob/master/examples/starwars_relay/schema.py
|