Skip to main content

石墨烯 Pydantic 集成

项目描述

石墨烯标志石墨烯-pydantic构建状态 PyPI 版本 覆盖状态

GraphenePydantic集成。

安装

pip install "graphene-pydantic"

例子

这是一个简单的 Pydantic 模型:

import uuid
import pydantic

class PersonModel(pydantic.BaseModel):
    id: uuid.UUID
    first_name: str
    last_name: str

要为其创建 GraphQL 模式,您只需编写以下代码:

import graphene
from graphene_pydantic import PydanticObjectType

class Person(PydanticObjectType):
    class Meta:
        model = PersonModel
        # exclude specified fields
        exclude_fields = ("id",)

class Query(graphene.ObjectType):
    people = graphene.List(Person)

    @staticmethod
    def resolve_people(parent, info):
        # fetch actual PersonModels here
        return [PersonModel(id=uuid.uuid4(), first_name="Beth", last_name="Smith")]

schema = graphene.Schema(query=Query)

然后您可以简单地查询架构:

query = """
    query {
      people {
        firstName,
        lastName
      }
    }
"""
result = schema.execute(query)
print(result.data['people'][0])

输入对象类型

您还可以从 Pydantic 模型为突变和查询创建输入对象类型:

from graphene_pydantic import PydanticInputObjectType

class PersonInput(PydanticInputObjectType):
    class Meta:
        model = PersonModel
        # exclude specified fields
        exclude_fields = ("id",)

class CreatePerson(graphene.Mutation):
    class Arguments:
        person = PersonInput()

    Output = Person

    @staticmethod
    def mutate(parent, info, person):
        personModel = PersonModel(id=uuid.uuid4(), first_name=person.first_name, last_name=person.last_name)
        # save PersonModel here
        return person

class Mutation(graphene.ObjectType):
    createPerson = CreatePerson.Field()

schema = graphene.Schema(mutation=Mutation)

然后使用输入执行:

mutation = '''
mutation {
    createPerson(person: {
        firstName: "Jerry",
        lastName: "Smith"
    }) {
        firstName
    }
}
'''
result = schema.execute(mutation)
print(result.data['createPerson']['firstName'])

自定义解析函数

由于PydanticObjectType继承自graphene.ObjectType您,因此可以添加自定义解析函数,如此所述。例如:

class Person(PydanticObjectType):
    class Meta:
        model = PersonModel
        # exclude specified fields
        exclude_fields = ("id",)
        
    full_name = graphene.String()

    def resolve_full_name(self, info, **kwargs):
        return self.first_name + ' ' + self.last_name

前向声明和循环引用

graphene_pydantic支持前向声明和循环引用,但您需要调用该resolve_placeholders()方法以确保在执行 GraphQL 查询之前完全更新类型。例如:

class NodeModel(BaseModel):
    id: int
    name: str
    labels: 'LabelsModel'
    
class LabelsModel(BaseModel):
    node: NodeModel
    labels: typing.List[str]
    
class Node(PydanticObjectType):
    class Meta:
        model = NodeModel
        
class Labels(PydanticObjectType):
    class Meta:
        model = LabelsModel
        

Node.resolve_placeholders()  # make the `labels` field work
Labels.resolve_placeholders()  # make the `node` field work

完整示例

有关更多信息,请参阅示例目录

执照

这个项目在Apache 许可下

第三方代码

该项目依赖于第三方代码,该代码受第三方许可中规定的许可的约束。

贡献

请参阅投稿指南。请注意,您必须签署CLA

注意事项

映射

请注意,即使 Pydantic 对包含映射的字段(例如字典)非常满意,因为GraphQL 的类型系统没有它们,这些字段不能导出到 Graphene 类型。例如,这将失败并出现错误Don't know how to handle mappings in Graphene

import typing
from graphene_pydantic import PydanticObjectType

class Pet:
  pass

class Person:
  name: str
  pets_by_name: typing.Dict[str, Pet]
  
class GraphQLPerson(PydanticObjectType):  
  class Meta:
    model = Person

但是,请注意,如果您使用exclude_fieldsonly_fields排除这些值,则不会有问题:

class GraphQLPerson(PydanticObjectType):
  class Meta:
    model = Person
    exclude_fields = ("pets_by_name",)

联合类型

使用 Unions 时有一些注意事项。让我们以以下 pydantic 模型作为本节的示例:

class EmployeeModel(pydantic.BaseModel):
    name: str


class ManagerModel(EmployeeModel):
    title: str


class DepartmentModel(pydantic.BaseModel):
    employees: T.List[T.Union[ManagerModel, EmployeeModel]]
您必须is_type_of在石墨烯模型中实现类方法

要在石墨烯中获得ManagerModelEmployeeModel成功解析,您需要is_type_of像这样实现:

class Employee(PydanticObjectType):
    class Meta:
        model = EmployeeModel

    @classmethod
    def is_type_of(cls, root, info):
        return isinstance(root, (cls, EmployeeModel))


class Manager(PydanticObjectType):
    class Meta:
        model = ManagerModel

    @classmethod
    def is_type_of(cls, root, info):
        return isinstance(root, (cls, ManagerModel))


class Department(PydanticObjectType):
    class Meta:
        model = DepartmentModel

否则 GraphQL 会抛出类似的错误"[GraphQLError('Abstract type UnionOfManagerModelEmployeeModel must resolve to an Object type at runtime for field Department.employees ..."

对于子类之间的联合,需要把子类放在类型注解的前面

employees上面的字段,如果你先用Employee写类型注解 employees: T.List[T.Union[EmployeeModel, ManagerModel]],你将无法查询到经理相关的字段(在这种情况下title)。在包含这样一个价差的查询中:

...on Employee {
  name
}
...on Manager {
  name
  title
}

...对象将始终解析为Employee. 如果将子类放在注释列表的首位,则可以避免这种情况:employees: T.List[T.Union[ManagerModel, EmployeeModel]].

子类之间的联合在 Python 3.6 中不起作用

如果模型上的字段是类和子类之间的联合(如我们的示例中所示),Python 3.6 的类型将不会保留联合并丢弃子类的注释。有关详细信息,请参阅此问题。目前的解决方案是使用 Python 3.7。

输入对象类型不支持联合作为字段

这是 GraphQL 的限制。有关支持输入联合的进展,请参阅此 RFC。如果您看到“{union-type} 可能仅包含对象类型”之类的错误,则您很可能遇到此限制。

项目详情


下载文件

下载适用于您平台的文件。如果您不确定要选择哪个,请了解有关安装包的更多信息。

源分布

graphene_pydantic-0.4.0.tar.gz (14.1 kB 查看哈希

已上传 source

内置分布

graphene_pydantic-0.4.0-py3-none-any.whl (13.6 kB 查看哈希

已上传 py3