在运行时石墨烯上创建动态模式 [英] Creating Dynamic Schema on Runtime Graphene

查看:63
本文介绍了在运行时石墨烯上创建动态模式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我几乎花了3天的时间来找到一种在python石墨烯中创建动态模式的方法.我唯一可以找到的相关结果是以下链接: https://github.com/graphql-python/graphene/blob/master/graphene/types/dynamic.py 但是我找不到任何文档.

整个想法是创建一个动态模式.我想提供一个GraphQL兼容的API,即使代码中未定义模型,用户也可以查询我的内容.换句话说,我想即时创建模型.我不知道该怎么办.

如果您能提供一个例子,那将是一个很大的帮助.

更新:

我的项目是无头CMS,它具有用户可以创建自己的内容类型的功能,我想提供一个GraphQL界面来使一切变得更加轻松和灵活.

以下是我在DB中的内容类型的示例:

 <代码> {"id":"author","name":"Book Author","desc":",选项":[{"id":"author_faname",标签":样品样品","type":"text","required":是的,占位符":一二三四"},{"id":"author_enname","label":"Sample label","type":"text","required":是的,占位符":"Sample Placeholder"}]} 

这是基于该内容类型存储在数据库中的内容:

 <代码> {"id":"9rqgbrox10","content_type":作者",数据":{"author_fname":"Jimmy","author_ename":"Hello"}} 

现在,由于我的模型没有在代码中声明,并且它们完全在DB中声明,因此我想即时创建自己的模式,而且我不知道哪种解决方案是最好的解决方案.我知道应该有办法,因为其他无头CMS项目正在提供这种方法.

提前谢谢!

解决方案

基本上,架构是这样创建的:

  class MyType(graphene.ObjectType):东西= graphene.String()Query(graphene.ObjectType)类:值= graphene.Field(MyType)schema = graphene.Schema(query =查询,类型= [MyType]) 

首先,为了添加某种动态效果,您很可能希望将上述代码包装在类似 create_schema()的函数中.

然后,当您想在运行时动态创建类时,可以按以下方式重写上面的代码:

  def create_schema():MyType = type('MyType',(graphene.ObjectType,),{'某物':graphene.String(),})Query = type('Query',(graphene.ObjectType,),{'值':graphene.Field(MyType),})返回graphene.Schema(查询=查询,类型= [MyType]) 

对于您的示例,它可能看起来像这样:

  def make_resolver(record_name,record_cls):def解析器(自身,信息):数据= ...返回record_cls(...)resolver .__ name__ ='resolve_%s'%记录名称返回解析器def create_schema(db):record_schemas = {}对于db.get_record_types()中的record_type:classname = record_type ['id'].title()#'作者'字段= {}对于record_type ['options']中的选项:field_type = {'文字':graphene.String,...} [option ['type']fields [option ['id']] = field_type()#可能添加标签作为描述?rec_cls =类型(班级名称,(graphene.ObjectType,),领域name = record_type ['name'],description = record_type ['desc'],)record_schemas [record_type ['id']] = rec_cls#以类似方式创建查询字段= {}对于密钥,请在record_schemas中进行记录:字段[关键字] = graphene.Field(rec)字段['resolve_%s'%键] = make_resolver(键,记录)查询=类型('查询',(graphene.ObjectType,),字段)返回graphene.Schema(查询=查询,类型=列表(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 __ 的代码.

因此,如果您的架构是动态更改的,那么最好是从头开始完全重新创建它,而不是对其进行修补.

I almost spent 3 days to find a way for creating a dynamic schema in python graphene. the only related result I could find is the below link: https://github.com/graphql-python/graphene/blob/master/graphene/types/dynamic.py But I couldn't find any documentation for it.

The whole idea is to create a dynamic schema. I want to provide a GraphQL compatible API that makes users able to query my contents even if Models are not defined in the code. In other words, I want to create Models on the fly. I have no idea about what shall I do.

It would be a great favor if you can provide an example for that.

Update :

My Project is a Headless CMS which has a feature that users can create their own content types and I want to provide a GraphQL interface to make everything easier and more flexible.

Here is example of my Content Types in DB :

{
  "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"
    }
  ]
}

And Here is Stored content in DB based on that content type :

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

Now as my Models are not declared in Code and they are completely in DB, I want to make my schemas on the fly and I don't know what is best the solution for this. I know there should be a way because the other Headless CMS Projects are providing this.

Thanks in advance!

解决方案

Basically, schema is created something like this:

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

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

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

First, in order to add some kind of dynamics, you will most likely want to wrap the above code in a function like create_schema().

Then, when you want to dynamically create a class during runtime, the above code can be rewritten like this:

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])

For your example it could look something like this:

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()))

Note that if you try to insert new fields into already existing class, like this - MyType.another_field = graphene.String(), then it won't work: that is because when graphene.ObjectType class is instantiated, all its fields are recorded in self._meta.fields OrderedDict. And updating it is not as straightforward as just MyType._meta.fields['another_field'] = thefield - see the code of graphene.ObjectType.__init_subclass_with_meta__ for details.

So if your schema is dynamically changed then it might be better to fully re-create it from scratch than to patch it.

这篇关于在运行时石墨烯上创建动态模式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆