Объекты модели Django и Graphene get_node

До сих пор я мог играть с Graphene без необходимости DjangoObjectType. Я стараюсь избегать этого, так как не планирую оставаться слишком близко к своим классам моделей Django. Однако у меня возникают проблемы при реализации Relay с Graphene:

class HouseholdNode(graphene.ObjectType):
  class Meta:
    interfaces = (graphene.relay.Node,)

  name = graphene.String()

  @classmethod
  def get_node(cls, info, id):
    return Household.objects.get(pk=id)

Это не удается со следующей ошибкой:

Узел абстрактного типа должен разрешаться в тип объекта во время выполнения для поля Query.node со значением «Тест», полученным «Нет».

«Тест» происходит прямо из функции __str__ Household.

Следующая попытка:

  @classmethod
  def get_node(cls, info, id):
    return cls(Household.objects.get(pk=id))

cls это HouseholdNode. Однако это дает неверный результат:

"node": {
  "id": "SG91c2Vob2xkOlRlc3Q=",
  "name": null
}

Идентификатор на самом деле «Тест».

Работающее решение:

  @classmethod
  def get_node(cls, info, id):
    household = Household.objects.get(pk=id)
    return cls(name=household.name)

Однако я очень сомневаюсь, что это все, что Graphene может сделать для меня. Мне действительно нужно обернуть реальный объект данных в HouseholdNode? У меня уже есть функции разрешения, нельзя ли их просто использовать вместо этого?

Документации по этим краям очень не хватает, пожалуйста, просветите меня.


person stschindler    schedule 19.01.2018    source источник
comment
Эта проблема на Github актуальна.   -  person user5670895    schedule 14.05.2018


Ответы (1)


Абстрактные типы (например, graphene.relay.node.Node) разрешаются с помощью исполнитель с использованием graphql.execution.executor.complete_abstract_value.

На практике ваши ObjectTypes с Node в качестве интерфейса передаются от графена к слою graphql, каждый из которых обернут как GrapheneInterfaceType. resolve_type каждого из этих объекты (которые в конечном итоге являются источником вашей ошибки) вызывают graphql.execution.executor.get_default_resolve_type_fn.

Эта функция сужает список возможных типов, которые могут быть возвращены (possible_types), а затем перебирает эти типы, проверяя, является ли атрибут is_type_of вызываемым и возвращает ли он значение True. Важно отметить, что possible_types являются определяемыми пользователем подклассами Node, унаследованными от graphene.types.objecttype.ObjectType, который имеет is_type_of = None. Следовательно, вы получаете GraphQLError поскольку ни один тип не разрешен.

Решение состоит в том, чтобы определить метод is_type_of для ваших типов объектов (или создать абстрактный ObjectType, который вы можете подклассировать с уже реализованным). Например, вот код в graphene-sqlalchemy реализует логику is_type_of, а в graphene-djangoкод здесь.

@classmethod
def is_type_of(cls, root, info):
    if isinstance(root, SimpleLazyObject):
        root._setup()
        root = root._wrapped
    if isinstance(root, cls):
        return True
    if not is_valid_django_model(type(root)):
        raise Exception((
            'Received incompatible instance "{}".'
        ).format(root))

    model = root._meta.model._meta.concrete_model
    return model == cls._meta.model
person Devin    schedule 15.03.2018