You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为GraphQL ObjectType动态添加字段列表?

动态给Graphene ObjectType添加字段的解决方案

问题背景

你尝试通过setattr直接给继承自graphene.ObjectType的MetaDataObject添加动态字段,但因为Graphene的元类机制,类定义阶段元类就已完成字段扫描和处理,后续直接设置类属性不会被Graphene的Schema识别。

解决方案1:动态创建ObjectType类(推荐)

直接通过Python的type()函数,将静态字段和动态字段合并后动态生成MetaDataObject类。这种方法让Graphene的元类在类创建时完整处理所有字段,规避元类机制的限制。

from starlette_graphene3 import GraphQLApp
import graphene
from fastapi import APIRouter, Depends

# 假设auth_middleware和table已提前定义
auth_middleware = lambda: None
table = type('MockTable', (), {
    'get_item': lambda self, Key: {
        'Item': {
            'resource_type': 'book', 
            'resource_name': '1984', 
            'length': 328, 
            'authors': ['George Orwell'], 
            'deprecated': 'false'
        }
    }
})()

app = APIRouter(
    dependencies=[Depends(auth_middleware)],
)

DYNAMIC_TYPES = {
    "length": graphene.Int(),
    # 注意:原代码的of_type=str需改为graphene.String(),Graphene列表要求接收Graphene类型
    "authors": graphene.List(graphene.String()),
    "deprecated": graphene.String()
}

# 合并静态字段与动态字段
static_fields = {
    "resource_type": graphene.String(),
    "resource_name": graphene.String()
}
all_fields = {**static_fields, **DYNAMIC_TYPES}

# 动态生成MetaDataObject类
MetaDataObject = type('MetaDataObject', (graphene.ObjectType,), all_fields)

class Query(graphene.ObjectType):
    get_metadata = graphene.Field(MetaDataObject, resource_type=graphene.String(), resource_name=graphene.String())

    def resolve_get_metadata(self, info, resource_type, resource_name):
        response = table.get_item(
            Key={
                'resource_type': resource_type,
                'resource_name': resource_name
            }
        )

        if 'Item' not in response:
            return None

        return response['Item']

schema = graphene.Schema(query=Query, auto_camelcase=False)
app.add_route("/graphql", GraphQLApp(schema=schema))

解决方案2:手动更新元类的字段存储

如果必须先定义MetaDataObject类再添加动态字段,可以直接修改类的_meta.fields字典(Graphene元类存储字段的位置),同时设置类属性:

from starlette_graphene3 import GraphQLApp
import graphene
from fastapi import APIRouter, Depends

auth_middleware = lambda: None
table = type('MockTable', (), {
    'get_item': lambda self, Key: {
        'Item': {
            'resource_type': 'book', 
            'resource_name': '1984', 
            'length': 328, 
            'authors': ['George Orwell'], 
            'deprecated': 'false'
        }
    }
})()

app = APIRouter(
    dependencies=[Depends(auth_middleware)],
)

DYNAMIC_TYPES = {
    "length": graphene.Int(),
    "authors": graphene.List(graphene.String()),
    "deprecated": graphene.String()
}

class MetaDataObject(graphene.ObjectType):
    resource_type = graphene.String()
    resource_name = graphene.String()

# 手动更新元类的字段字典,并设置类属性
for attr, g_type in DYNAMIC_TYPES.items():
    MetaDataObject._meta.fields[attr] = g_type
    setattr(MetaDataObject, attr, g_type)

class Query(graphene.ObjectType):
    get_metadata = graphene.Field(MetaDataObject, resource_type=graphene.String(), resource_name=graphene.String())

    def resolve_get_metadata(self, info, resource_type, resource_name):
        response = table.get_item(
            Key={
                'resource_type': resource_type,
                'resource_name': resource_name
            }
        )

        if 'Item' not in response:
            return None

        return response['Item']

schema = graphene.Schema(query=Query, auto_camelcase=False)
app.add_route("/graphql", GraphQLApp(schema=schema))

注意事项

  • 原代码中graphene.List(of_type=str)是错误写法,Graphene的List需要接收Graphene类型(如graphene.String()),而非Python原生类型。
  • 方案1更稳妥,避免直接修改元类内部属性可能带来的版本兼容性问题。

内容的提问来源于stack exchange,提问作者Jayjay Jay

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 05:21:57