Package: graphene-pydantic
graphene-pydanticAPydanticintegration forGraphene.Installationpipinstall"graphene-pydantic"ExamplesHere is a simple Pydantic model:importuuidimportpydanticclassPersonModel(pydantic.BaseModel):id:uuid.UUIDfirst_name:strlast_name:strTo create a GraphQL schema for it you simply have to write the following:importgraphenefromgraphene_pydanticimportPydanticObjectTypeclassPerson(PydanticObjectType):classMeta:model=PersonModel# exclude specified fieldsexclude_fields=("id",)classQuery(graphene.ObjectType):people=graphene.List(Person)@staticmethoddefresolve_people(parent,info):# fetch actual PersonModels herereturn[PersonModel(id=uuid.uuid4(),first_name="Beth",last_name="Smith")]schema=graphene.Schema(query=Query)Then you can simply query the schema:query="""query {people {firstName,lastName}}"""result=schema.execute(query)print(result.data['people'][0])Input Object TypesYou can also create input object types from Pydantic models for mutations and queries:fromgraphene_pydanticimportPydanticInputObjectTypeclassPersonInput(PydanticInputObjectType):classMeta:model=PersonModel# exclude specified fieldsexclude_fields=("id",)classCreatePerson(graphene.Mutation):classArguments:person=PersonInput()Output=Person@staticmethoddefmutate(parent,info,person):personModel=PersonModel(id=uuid.uuid4(),first_name=person.first_name,last_name=person.last_name)# save PersonModel herereturnpersonclassMutation(graphene.ObjectType):createPerson=CreatePerson.Field()schema=graphene.Schema(mutation=Mutation)Then execute with the input:mutation='''mutation {createPerson(person: {firstName: "Jerry",lastName: "Smith"}) {firstName}}'''result=schema.execute(mutation)print(result.data['createPerson']['firstName'])Custom resolve functionsSincePydanticObjectTypeinherits fromgraphene.ObjectTypeyou can add custom resolve functions as explainedhere. For instance:classPerson(PydanticObjectType):classMeta:model=PersonModel# exclude specified fieldsexclude_fields=("id",)full_name=graphene.String()defresolve_full_name(self,info,**kwargs):returnself.first_name+' '+self.last_nameForward declarations and circular referencesgraphene_pydanticsupports forward declarations and circular references, but you will need to call theresolve_placeholders()method to ensure the types are fully updated before you execute a GraphQL query. For instance:classNodeModel(BaseModel):id:intname:strlabels:'LabelsModel'classLabelsModel(BaseModel):node:NodeModellabels:typing.List[str]classNode(PydanticObjectType):classMeta:model=NodeModelclassLabels(PydanticObjectType):classMeta:model=LabelsModelNode.resolve_placeholders()# make the `labels` field workLabels.resolve_placeholders()# make the `node` field workFull ExamplesPlease seethe examples directoryfor more.LicenseThis project is under theApache License.Third Party CodeThis project depends on third-party code which is subject to the licenses set forth inThird Party Licenses.ContributingPlease see theContributing Guide.CaveatsMappingsNote that even though Pydantic is perfectly happy with fields that hold mappings (e.g. dictionaries), becauseGraphQL's type system doesn't have themthose fields can't be exported to Graphene types. For instance, this will fail with an errorDon't know how to handle mappings in Graphene:importtypingfromgraphene_pydanticimportPydanticObjectTypeclassPet:passclassPerson:name:strpets_by_name:typing.Dict[str,Pet]classGraphQLPerson(PydanticObjectType):classMeta:model=PersonHowever, note that if you useexclude_fieldsoronly_fieldsto exclude those values, there won't be a problem:classGraphQLPerson(PydanticObjectType):classMeta:model=Personexclude_fields=("pets_by_name",)Union typesThere are some caveats when using Unions. Let's take the following pydantic models as an example for this section:classEmployeeModel(pydantic.BaseModel):name:strclassManagerModel(EmployeeModel):title:strclassDepartmentModel(pydantic.BaseModel):employees:T.List[T.Union[ManagerModel,EmployeeModel]]You have to implement the class methodis_type_ofin the graphene modelsTo get the Union betweenManagerModelandEmployeeModelto successfully resolve
in graphene, you need to implementis_type_oflike this:classEmployee(PydanticObjectType):classMeta:model=EmployeeModel@classmethoddefis_type_of(cls,root,info):returnisinstance(root,(cls,EmployeeModel))classManager(PydanticObjectType):classMeta:model=ManagerModel@classmethoddefis_type_of(cls,root,info):returnisinstance(root,(cls,ManagerModel))classDepartment(PydanticObjectType):classMeta:model=DepartmentModelOtherwise GraphQL will throw an error similar to"[GraphQLError('Abstract type UnionOfManagerModelEmployeeModel must resolve to an Object type at runtime for field Department.employees ..."For unions between subclasses, you need to put the subclass first in the type annotationLooking at theemployeesfield above, if you write the type annotation with Employee first,employees: T.List[T.Union[EmployeeModel, ManagerModel]], you will not be able to query
manager-related fields (in this casetitle). In a query containing a spread like this:...on Employee {
  name
}
...on Manager {
  name
  title
}... the objects will always resolve to being anEmployee. This can be avoided if you put
the subclass first in the list of annotations:employees: T.List[T.Union[ManagerModel, EmployeeModel]].Unions between subclasses don't work in Python 3.6If a field on a model is a Union between a class and a subclass (as in our example),
Python 3.6's typing will not preserve the Union and throws away the annotation for the subclass.
Seethis issuefor more details.
The solution at present is to use Python 3.7.Input Object Types don't support unions as fieldsThis is a GraphQL limitation. Seethis RFCfor the progress on supporting input unions. If you see an error like '{union-type} may only contain Object types', you are most likely encountering this limitation.