Включить фильтрацию на основе PK в Django Graphene Relay, сохраняя при этом глобальные идентификаторы - PullRequest
0 голосов
/ 23 января 2019

Задача

Я использую django-графен с Relay на нашем сервере GraphQL. Реализация налагает требование Global ID в классе graphene.relay.Node, которое переопределяет и скрывает поле идентификатора Django .

В результате я могу запросить это так:

{
    allBatches(id:"QmF0Y2hOb2RlOjE=") {
    edges {
      node {
        id
        pk
      }
    }
  }
}

И получите этот ответ:

{
  "data": {
    "allBatches": {
      "edges": [
        {
          "node": {
            "id": "QmF0Y2hOb2RlOjE=",
            "pk": 1
          }
        }
      ]
    }
  }
}

Однако, что я теряю, так это возможность фильтровать по полю оригинального идентификатора (или PK) самого объекта:

{
    allBatches(id:1) {
    edges {
      node {
        id
        pk
      }
    }
  }
}

На самом деле, я просто не могу фильтровать объекты по идентификатору . Я могу думать о двух возможных обходных путях к этому: 1. Предотвратите django-graphene-relay от перехвата и затенения поля id, возможно, вынудите его использовать другое имя поля, такое как gid 2. Найдите способ включить pk в качестве специального поля, которое доступно как в качестве свойства, так и в фильтре

Решение 1

Я не продвинулся на 1, так как кажется, что django-graphene (и, возможно, стандарт реле) накладывает ограничение на то, что это поле называется id. Я вижу, что id использовался как Волшебная Строка во многих местах, и не существует стандартного способа изменить имя поля.

Решение 2

В 2 я могу заставить свойство работать с Mixin следующим образом:

class PKMixin(object):
    pk = graphene.Field(type=graphene.Int, source='pk')

Однако я не могу заставить работать фильтрацию через django-filter, так как FilterSet не имеет объявленного поля pk и прерывается со следующей ошибкой

Meta.fields содержит поля, которые не определены в этом FilterSet: рк

Обновление на 2

Я попробовал следующее:

class PKFilteringNode(Node):

    @classmethod
    def get_node_from_global_id(cls, info, global_id, only_type=None):
        # So long as only_type is set; if we detect that the global_id is a pk and not a global ID;
        # then coerce it to be a proper global ID before fetching
        if only_type:
            try:
                int(global_id)
                global_id = cls.to_global_id(only_type._meta.name, global_id)
                return super(PKFilteringNode, cls).get_node_from_global_id(info, global_id, only_type)
            except ValueError:
                pass
        return super(PKFilteringNode, cls).get_node_from_global_id(info, global_id, only_type)

И теперь я могу заставить GraphQL сделать это:

{
  batchA: batch(id: "QmF0Y2hOb2RlOjE=") {
    id
    name
  }
  batchB: batch(id: 1) {
    id
    name
  }
}
{
  "data": {
    "batchA": {
      "id": "QmF0Y2hOb2RlOjE=",
      "name": "Default Batch"
    },
    "batchB": {
      "id": "QmF0Y2hOb2RlOjE=",
      "name": "Default Batch"
    }
  }
}

Но я довольно сильно боюсь, что это сломает что-то вниз по течению, на уровне кеширования что ли? Также это не позволяет выполнять фильтрацию по идентификатору, поскольку фильтрация зависит от DjangoFilterConnectionField

Запрос

Я застрял на данный момент. У меня есть несколько вопросов:

  1. Это необычное требование для начала? Я спрашиваю неправильно вопрос, когда я хочу сохранить способность фильтровать по pk
  2. Существует ли стандартный шаблон для решения этой проблемы?

Связанные проблемы на Github

https://github.com/graphql-python/graphene-django/issues/349

Версия

  • графен-джанго == 2.1.0
  • django == 1.9.12
  • Джанго фильтр == 1.0.1
  • питон == 2.7.13

1 Ответ

0 голосов
/ 24 января 2019

Вы пробовали решение 2, но вместо этого использовали id в качестве источника?

class PKMixin(object):
    pk = graphene.Field(type=graphene.Int, source='id')

Кроме того, если вы хотите получить только одну запись, вам все равно не следует проходить через поле подключения. Вместо этого вы должны определить что-то вроде batchByPk поля в вашей схеме.

Последняя вещь, о которой следует знать, это то, что в настоящее время графен-джанго DjangoFilterConnectionField не реализован эффективным способом, поэтому вы, возможно, даже не захотите его использовать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...