Создание динамической схемы на графене во время выполнения - PullRequest
0 голосов
/ 28 мая 2018

Я почти потратил 3 дня, чтобы найти способ создания динамической схемы в графене python.Единственный связанный с этим результат, который я смог найти, это ссылка ниже: https://github.com/graphql-python/graphene/blob/master/graphene/types/dynamic.py Но я не смог найти для него никакой документации.

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

Было бы очень полезно, если бы вы могли привести пример для этого.

Обновление:

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

Вот пример моих типов контента в БД: { "id": "author", "name": "Book Author", "desc": "", "options":[ { "id": "author_faname", "label": "Sample Sample", "type": "text", "required": true, "placeholder":"One Two Three Four" }, { "id": "author_enname", "label": "Sample label", "type": "text", "required": true, "placeholder":"Sample Placeholder" } ] }

А вот хранящийся контент в БД на основе этого типа контента:

{ "id": "9rqgbrox10", "content_type": "author", "data":{ "author_fname":"Jimmy", "author_ename":"Hello" } }

Теперь, когда мои Модели не объявлены в Коде, и они полностью в БД, я хочу создавать свои схемы на лету, и я не знаю, какое решение лучше для этого.Я знаю, что должен быть способ, потому что другие проекты безголовых CMS предоставляют это.

Заранее спасибо!

1 Ответ

0 голосов
/ 07 октября 2018

По сути, схема создается примерно так:

class MyType(graphene.ObjectType):
    something = graphene.String()

class Query(graphene.ObjectType):
    value = graphene.Field(MyType)

schema = graphene.Schema(query=Query, types=[MyType])

Во-первых, чтобы добавить какую-то динамику, вы, скорее всего, захотите обернуть вышеуказанный код в функцию, подобную create_schema().

Затем, когда вы хотите динамически создать класс во время выполнения, приведенный выше код можно переписать так:

def create_schema():
    MyType = type('MyType', (graphene.ObjectType,), {
        'something': graphene.String(),
    })

    Query = type('Query', (graphene.ObjectType,), {
        'value': graphene.Field(MyType),
    })

    return graphene.Schema(query=Query, types=[MyType])

Для вашего примера это может выглядеть примерно так:

def make_resolver(record_name, record_cls):
    def resolver(self, info):
        data = ...
        return record_cls(...)
    resolver.__name__ = 'resolve_%s' % record_name
    return resolver

def create_schema(db):
    record_schemas = {}
    for record_type in db.get_record_types():
        classname = record_type['id'].title()  # 'Author'
        fields = {}
        for option in record_type['options']:
            field_type = {
                'text': graphene.String,
                ...
            }[option['type']
            fields[option['id']] = field_type()  # maybe add label as description?
        rec_cls = type(
            classname,
            (graphene.ObjectType,), 
            fields,
            name=record_type['name'],
            description=record_type['desc'],
        )
        record_schemas[record_type['id']] = rec_cls

    # create Query in similar way
    fields = {}
    for key, rec in record_schemas:
        fields[key] = graphene.Field(rec)
        fields['resolve_%s' % key] = make_resolver(key, rec)
    Query = type('Query', (graphene.ObjectType,), fields)

    return graphene.Schema(query=Query, types=list(record_schemas.values()))

Обратите внимание, что если вы попытаетесь вставить новые поля в уже существующий класс, например - MyType.another_field = graphene.String(), то это не сработает: это потому, что когда создается экземпляр класса graphene.ObjectType, записываются все его поляв self._meta.fields OrderedDict.И обновить его не так просто, как просто MyType._meta.fields['another_field'] = thefield - подробности см. В коде graphene.ObjectType.__init_subclass_with_meta__.

Так что, если ваша схема динамически изменяется, то может быть лучше полностью заново создать ее с нуля, чемзалатать его.

...