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显示模型上的所有字段。如果只想显示字段的子集,可以使用fieldsexclude。强烈建议显式设置应该使用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:

例如,下面的ModelDjangoObjectType

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相同。

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

posted @ 2020-09-25 07:23  双葫  阅读(293)  评论(0编辑  收藏  举报