|
| 1 | +Inheritance Examples |
| 2 | +==================== |
| 3 | + |
| 4 | +Create interfaces from inheritance relationships |
| 5 | +------------------------------------------------ |
| 6 | + |
| 7 | +SQLAlchemy has excellent support for class inheritance hierarchies. |
| 8 | +These hierarchies can be represented in your GraphQL schema by means |
| 9 | +of interfaces_. Much like ObjectTypes, Interfaces in |
| 10 | +Graphene-SQLAlchemy are able to infer their fields and relationships |
| 11 | +from the attributes of their underlying SQLAlchemy model: |
| 12 | + |
| 13 | +.. _interfaces: https://docs.graphene-python.org/en/latest/types/interfaces/ |
| 14 | + |
| 15 | +.. code:: python |
| 16 | +
|
| 17 | + from sqlalchemy import Column, Date, Integer, String |
| 18 | + from sqlalchemy.ext.declarative import declarative_base |
| 19 | +
|
| 20 | + import graphene |
| 21 | + from graphene import relay |
| 22 | + from graphene_sqlalchemy import SQLAlchemyInterface, SQLAlchemyObjectType |
| 23 | +
|
| 24 | + Base = declarative_base() |
| 25 | +
|
| 26 | + class Person(Base): |
| 27 | + id = Column(Integer(), primary_key=True) |
| 28 | + type = Column(String()) |
| 29 | + name = Column(String()) |
| 30 | + birth_date = Column(Date()) |
| 31 | +
|
| 32 | + __tablename__ = "person" |
| 33 | + __mapper_args__ = { |
| 34 | + "polymorphic_on": type, |
| 35 | + } |
| 36 | +
|
| 37 | + class Employee(Person): |
| 38 | + hire_date = Column(Date()) |
| 39 | +
|
| 40 | + __mapper_args__ = { |
| 41 | + "polymorphic_identity": "employee", |
| 42 | + } |
| 43 | + |
| 44 | + class Customer(Person): |
| 45 | + first_purchase_date = Column(Date()) |
| 46 | +
|
| 47 | + __mapper_args__ = { |
| 48 | + "polymorphic_identity": "customer", |
| 49 | + } |
| 50 | +
|
| 51 | + class PersonType(SQLAlchemyInterface): |
| 52 | + class Meta: |
| 53 | + model = Person |
| 54 | +
|
| 55 | + class EmployeeType(SQLAlchemyObjectType): |
| 56 | + class Meta: |
| 57 | + model = Employee |
| 58 | + interfaces = (relay.Node, PersonType) |
| 59 | + |
| 60 | + class CustomerType(SQLAlchemyObjectType): |
| 61 | + class Meta: |
| 62 | + model = Customer |
| 63 | + interfaces = (relay.Node, PersonType) |
| 64 | +
|
| 65 | +Keep in mind that `PersonType` is a `SQLAlchemyInterface`. Interfaces must |
| 66 | +be linked to an abstract Model that does not specify a `polymorphic_identity`, |
| 67 | +because we cannot return instances of interfaces from a GraphQL query. |
| 68 | +If Person specified a `polymorphic_identity`, instances of Person could |
| 69 | +be inserted into and returned by the database, potentially causing |
| 70 | +Persons to be returned to the resolvers. |
| 71 | + |
| 72 | +When querying on the base type, you can refer directly to common fields, |
| 73 | +and fields on concrete implementations using the `... on` syntax: |
| 74 | + |
| 75 | + |
| 76 | +.. code:: |
| 77 | +
|
| 78 | + people { |
| 79 | + name |
| 80 | + birthDate |
| 81 | + ... on EmployeeType { |
| 82 | + hireDate |
| 83 | + } |
| 84 | + ... on CustomerType { |
| 85 | + firstPurchaseDate |
| 86 | + } |
| 87 | + } |
| 88 | + |
| 89 | + |
| 90 | +Please note that by default, the "polymorphic_on" column is *not* |
| 91 | +generated as a field on types that use polymorphic inheritance, as |
| 92 | +this is considered an implentation detail. The idiomatic way to |
| 93 | +retrieve the concrete GraphQL type of an object is to query for the |
| 94 | +`__typename` field. |
| 95 | +To override this behavior, an `ORMField` needs to be created |
| 96 | +for the custom type field on the corresponding `SQLAlchemyInterface`. This is *not recommended* |
| 97 | +as it promotes abiguous schema design |
| 98 | + |
| 99 | +If your SQLAlchemy model only specifies a relationship to the |
| 100 | +base type, you will need to explicitly pass your concrete implementation |
| 101 | +class to the Schema constructor via the `types=` argument: |
| 102 | + |
| 103 | +.. code:: python |
| 104 | +
|
| 105 | + schema = graphene.Schema(..., types=[PersonType, EmployeeType, CustomerType]) |
| 106 | + |
| 107 | +See also: `Graphene Interfaces <https://docs.graphene-python.org/en/latest/types/interfaces/>`_ |
0 commit comments