Задача
Я использую 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
Запрос
Я застрял на данный момент. У меня есть несколько вопросов:
- Это необычное требование для начала? Я спрашиваю неправильно
вопрос, когда я хочу сохранить способность фильтровать по pk
- Существует ли стандартный шаблон для решения этой проблемы?
Связанные проблемы на Github
https://github.com/graphql-python/graphene-django/issues/349
Версия
- графен-джанго == 2.1.0
- django == 1.9.12
- Джанго фильтр == 1.0.1
- питон == 2.7.13