5.Queries & ObjectTypes查询与对象类型
Introduction 介绍
Graphene-Django offers a host of features for performing GraphQL queries.
Graphene-Django提供了一系列用于执行GraphQL查询的特性。
Graphene-Django ships with a special DjangoObjectType
that automatically transforms a Django Model into a ObjectType
for you.
Graphene-Django附带了一个特殊的DjangoObjectType
,它可以自动将Django模型转换为ObjectType
。
Full example 完整的例子
# my_app/schema.py
import graphene
from graphene_django import DjangoObjectType
from .models import Question
class QuestionType(DjangoObjectType):
class Meta:
model = Question
fields = ("id", "question_text")
class Query(graphene.ObjectType):
questions = graphene.List(QuestionType)
question_by_id = graphene.Field(QuestionType, id=graphene.String())
def resolve_questions(root, info, **kwargs):
# Querying a list
# 查询列表
return Question.objects.all()
def resolve_question_by_id(root, info, id):
# Querying a single question
# 查询一个问题
return Question.objects.get(pk=id)
Specifying which fields to include 指定要包含哪些字段
By default, DjangoObjectType
will present all fields on a Model through GraphQL. If you only want a subset of fields to be present, you can do so using fields
or exclude
. It is strongly recommended that you explicitly set all fields that should be exposed using the fields attribute. This will make it less likely to result in unintentionally exposing data when your models change.
默认情况下,DjangoObjectType
将通过GraphQL显示模型上的所有字段。如果只想显示字段的子集,可以使用fields
或exclude
。强烈建议显式设置应该使用fields属性公开的所有字段。这将减少模型更改时无意中暴露数据的可能性。
fields
字段
Show only these fields on the model:
在模型上只显示这些字段:
from graphene_django import DjangoObjectType
from .models import Question
class QuestionType(DjangoObjectType):
class Meta:
model = Question
fields = ("id", "question_text")
You can also set the fields
attribute to the special value "__all__"
to indicate that all fields in the model should be used.
你也可以将“字段”属性设置为特殊值“__all__”
,以表示模型中的所有字段都应该被使用。
For example:
例如:
from graphene_django import DjangoObjectType
from .models import Question
class QuestionType(DjangoObjectType):
class Meta:
model = Question
fields = "__all__"
exclude
排除
Show all fields except those in exclude
:
显示除exclude
之外的所有字段:
from graphene_django import DjangoObjectType
from .models import Question
class QuestionType(DjangoObjectType):
class Meta:
model = Question
exclude = ("question_text",)
Customising fields 定制字段
You can completely overwrite a field, or add new fields, to a DjangoObjectType
using a Resolver:
您可以使用解析器完全覆盖字段,或添加新字段到DjangoObjectType
:
from graphene_django import DjangoObjectType
from .models import Question
class QuestionType(DjangoObjectType):
class Meta:
model = Question
fields = ("id", "question_text")
extra_field = graphene.String()
def resolve_extra_field(self, info):
return "hello!"
Choices to Enum conversion 枚举转换选项
By default Graphene-Django will convert any Django fields that have choices defined into a GraphQL enum type.
默认情况下,Graphene-Django将把定义了choices的任何Django字段转换为GraphQL枚举类型。
For example the following Model
and DjangoObjectType
:
例如,下面的Model
和DjangoObjectType
:
from django.db import models
from graphene_django import DjangoObjectType
class PetModel(models.Model):
kind = models.CharField(
max_length=100,
choices=(("cat", "Cat"), ("dog", "Dog"))
)
class Pet(DjangoObjectType):
class Meta:
model = PetModel
fields = ("id", "kind",)
Results in the following GraphQL schema definition:
生成以下GraphQL架构定义:
type Pet {
id: ID!
kind: PetModelKind!
}
enum PetModelKind {
CAT
DOG
}
You can disable this automatic conversion by setting convert_choices_to_enum
attribute to False
on the DjangoObjectType
Meta
class.
您可以通过在DjangoObjectType
Meta
类上设置convert_choices_to_enum
属性为False
来禁用这个自动转换。
from graphene_django import DjangoObjectType
from .models import PetModel
class Pet(DjangoObjectType):
class Meta:
model = PetModel
fields = ("id", "kind",)
convert_choices_to_enum = False
type Pet {
id: ID!
kind: String!
}
You can also set convert_choices_to_enum
to a list of fields that should be automatically converted into enums:
还可以将convert_choices_to_enum
设置为应自动转换为枚举的字段列表:
from graphene_django import DjangoObjectType
from .models import PetModel
class Pet(DjangoObjectType):
class Meta:
model = PetModel
fields = ("id", "kind",)
convert_choices_to_enum = ["kind"]
Note: Setting convert_choices_to_enum = []
is the same as setting it to False
.
注意:设置convert_choices_to_enum =[]
与设置为False
相同。
Related models 相关模型
Say you have the following models:
如果你有以下模型:
from django.db import models
class Category(models.Model):
foo = models.CharField(max_length=256)
class Question(models.Model):
category = models.ForeignKey(Category, on_delete=models.CASCADE)
When Question
is published as a DjangoObjectType
and you want to add Category
as a query-able field like so:
当Question
作为DjangoObjectType
发布,你想添加Category
作为一个可查询的字段,像这样:
from graphene_django import DjangoObjectType
from .models import Question
class QuestionType(DjangoObjectType):
class Meta:
model = Question
fields = ("category",)
Then all query-able related models must be defined as DjangoObjectType subclass, or they will fail to show if you are trying to query those relation fields. You only need to create the most basic class for this to work:
然后,必须将所有可查询的相关模型定义为DjangoObjectType子类,否则如果您试图查询这些关系字段,它们将无法显示。只需创建最基本的类即可:
from graphene_django import DjangoObjectType
from .models import Category
class CategoryType(DjangoObjectType):
class Meta:
model = Category
fields = ("foo",)
Default QuerySet 默认查询设置
If you are using DjangoObjectType
you can define a custom get_queryset method. Use this to control filtering on the ObjectType level instead of the Query object level.
如果你正在使用DjangoObjectType
,你可以定义一个自定义的get_queryset方法。使用这个来控制过滤ObjectType级别而不是查询对象的级别。
from graphene_django.types import DjangoObjectType
from .models import Question
class QuestionType(DjangoObjectType):
class Meta:
model = Question
@classmethod
def get_queryset(cls, queryset, info):
if info.context.user.is_anonymous:
return queryset.filter(published=True)
return queryset
Resolvers 解析器
When a GraphQL query is received by the Schema
object, it will map it to a “Resolver” related to it.
当Schema
对象接收到GraphQL查询时,它将把它映射到与其相关的“解析器”。
This resolve method should follow this format:
当‘Schema’对象接收到GraphQL查询时,它将把它映射到与其相关的“解析器”。
def resolve_foo(parent, info, **kwargs):
Where “foo” is the name of the field declared in the Query
object.
其中" foo "是在Query
对象中声明的字段的名称。
import graphene
from .models import Question
from .types import QuestionType
class Query(graphene.ObjectType):
foo = graphene.List(QuestionType)
def resolve_foo(root, info):
id = kwargs.get("id")
return Question.objects.get(id)
Arguments 参数
Additionally, Resolvers will receive any arguments declared in the field definition. This allows you to provide input arguments in your GraphQL server and can be useful for custom queries.
此外,解析器将接收字段定义中声明的任何参数。这允许您在GraphQL服务器中提供输入参数,并可用于自定义查询。
import graphene
from .models import Question
from .types import QuestionType
class Query(graphene.ObjectType):
question = graphene.Field(
QuestionType,
foo=graphene.String(),
bar=graphene.Int()
)
def resolve_question(root, info, foo, bar):
# If `foo` or `bar` are declared in the GraphQL query they will be here, else None.
#如果在GraphQL查询中声明了' foo '或' bar ',它们将在这里,否则没有。
return Question.objects.filter(foo=foo, bar=bar).first()
Info 信息
The info
argument passed to all resolve methods holds some useful information. For Graphene-Django, the info.context
attribute is the HTTPRequest
object that would be familiar to any Django developer. This gives you the full functionality of Django’s HTTPRequest
in your resolve methods, such as checking for authenticated users:
传递给所有解析方法的info
参数包含一些有用的信息。对于Graphene-Djangoinfo.context
属性是任何Django开发人员都熟悉的HTTPRequest
对象。这使您能够在resolve方法中使用Django的HTTPRequest
的全部功能,例如检查是否有经过身份验证的用户:
import graphene
from .models import Question
from .types import QuestionType
class Query(graphene.ObjectType):
questions = graphene.List(QuestionType)
def resolve_questions(root, info):
# See if a user is authenticated
# 查看用户是否经过身份验证
if info.context.user.is_authenticated():
return Question.objects.all()
else:
return Question.objects.none()
DjangoObjectTypes Django对象类型
A Resolver that maps to a defined DjangoObjectType should only use methods that return a queryset. Queryset methods like values will return dictionaries, use defer instead.
映射到已定义的DjangoObjectType的解析器应该只使用返回Queryset 的方法。像values这样的Queryset方法将返回字典,请改用defer。
Plain ObjectTypes 普通对象类型
With Graphene-Django you are not limited to just Django Models - you can use the standard ObjectType
to create custom fields or to provide an abstraction between your internal Django models and your external API.
使用Graphene-Django,您不仅限于Django模型,还可以使用标准的ObjectType
来创建自定义字段或在内部Django模型和外部API之间提供抽象。
import graphene
from .models import Question
class MyQuestion(graphene.ObjectType):
text = graphene.String()
class Query(graphene.ObjectType):
question = graphene.Field(MyQuestion, question_id=graphene.String())
def resolve_question(root, info, question_id):
question = Question.objects.get(pk=question_id)
return MyQuestion(
text=question.question_text
)
For more information and more examples, please see the core object type documentation.
有关更多信息和更多示例,请参阅核心对象类型文档。
Relay
Relay with Graphene-Django gives us some additional features:
RelayGraphene Django为我们提供了一些附加功能:
- Pagination and slicing.
- 分页和切片。
- An abstract
id
value which contains enough info for the server to know its type and its id. - 一个抽象的“id”值,它包含足够的信息,以便服务器知道它的类型和id。
There is one additional import and a single line of code needed to adopt this:
有一个额外的导入和一行代码需要采用这一点:
Full example 完整的例子
See the Relay documentation on the core graphene pages for more information on customizing the Relay experience.
有关定制中继体验的更多信息,请参阅核心graphene页面上的Relay documentation。
from graphene import relay
from graphene_django import DjangoObjectType
from .models import Question
class QuestionType(DjangoObjectType):
class Meta:
model = Question
interfaces = (relay.Node,) # make sure you add this
fields = "__all__"
class QuestionConnection(relay.Connection):
class Meta:
node = QuestionType
class Query:
questions = relay.ConnectionField(QuestionConnection)
def resolve_questions(root, info, **kwargs):
return Question.objects.all()
You can now execute queries like:
现在可以执行以下查询:
{
questions (first: 2, after: "YXJyYXljb25uZWN0aW9uOjEwNQ==") {
pageInfo {
startCursor
endCursor
hasNextPage
hasPreviousPage
}
edges {
cursor
node {
id
question_text
}
}
}
}
Which returns:
返回:
{
"data": {
"questions": {
"pageInfo": {
"startCursor": "YXJyYXljb25uZWN0aW9uOjEwNg==",
"endCursor": "YXJyYXljb25uZWN0aW9uOjEwNw==",
"hasNextPage": true,
"hasPreviousPage": false
},
"edges": [
{
"cursor": "YXJyYXljb25uZWN0aW9uOjEwNg==",
"node": {
"id": "UGxhY2VUeXBlOjEwNw==",
"question_text": "How did we get here?"
}
},
{
"cursor": "YXJyYXljb25uZWN0aW9uOjEwNw==",
"node": {
"id": "UGxhY2VUeXBlOjEwOA==",
"name": "Where are we?"
}
}
]
}
}
}
Note that relay implements pagination
capabilities automatically, adding a pageInfo
element, and including cursor
on nodes. These elements are included in the above example for illustration.
请注意,relay自动实现了pagination
功能,添加了一个paginfo
元素,并在节点上包含了cursor
。以上示例中包含了这些元素以供说明。
To learn more about Pagination in general, take a look at Pagination on the GraphQL community site.
要了解一般分页的更多信息,请查看GraphQL社区站点上的Pagination。