首页 > 解决方案 > 使用 GraphQL、Graphene 和 Python 从查询中返回任何数据

问题描述

我收到以下错误:

{
  "errors": [
    {
      "message": "Unknown argument \"project_id\" on field" +
                 \"get_project_detail_summary\" of type \"Query\".",
      "locations": [
        {
          "line": 2,
          "column": 30
        }
      ]
    }
  ]
}

使用以下查询:

query GetProjectDetailSummary($project_id: Int) {
  get_project_detail_summary(project_id: $project_id) {
    comments {
      ... on ManagerCommentNode {
        id
        text
        created
      }
      ... on VendorCommentNode {
        id
        text
        created
      }
      ... on TenantCommentNode {
        id
        text
        created
      }
    }
  }
}

使用以下后端代码,我怎样才能到达断点?,或者我如何发回给定数字的自定义数据?:

class CommentsUnion(graphene.types.union.Union):
    class Meta:
        name = 'CommentsUnion'
        types = (ManagerCommentNode, VendorCommentNode, TenantCommentNode, )


class ProjectSummaryInput(graphene.InputObjectType):
    project_id = graphene.Int()


class ProjectSummaryNode(graphene.ObjectType):
    Input = ProjectSummaryInput

    project_id = graphene.Int()
    comments = graphene.List(CommentsUnion)

    @classmethod
    def resolve_comments(self, *args, **kwargs):
        import pdb;pdb.set_trace()
        return ProjectSummary.select_related('comments').objects.filter(comments__created__lt=dt)

class Query(graphene.ObjectType):
    get_project_detail_summary = Field(ProjectSummaryNode)

标签: graphqlgraphene-pythongraphene-django

解决方案


关于错误。

请务必在 for 中添加一个 kwarg(例如project_id,在此示例中,这是“字段上的未知参数”错误的原因graphene.Fieldget_project_detail_summary

像这样:

class Query(graphene.ObjectType):
    get_project_detail_summary = Field(ProjectSummaryNode, # see below for example
                                       project_id=graphene.Int() # kwarg here
                                      )

    def resolve_get_project_detail_summary(self, info, **kwargs):
        return ProjectSummary.objects.get(id=kwargs.get('project_id'))

关于返回任何数据。

这是一种方式(返回 a graphene.String),但它通过将所有内容放入字符串中来取消类型化响应:


from django.core.serializers.json import DjangoJSONEncoder

class ProjectSummaryRecentUpdatesNode(graphene.ObjectType):
    Input = ProjectSummaryInput
    recent_updates = graphene.String()

    def resolve_recent_updates(self, resolve, **kwargs):
        instance = Project.objects.get(id=resolve.variable_values.get("project_id"))
        things = instance.things.all()
        # these are all from different models, and the list is a bit longer than this.
        querysets = (
            ("scheduled", get_scheduled(things, resolve, **kwargs)),
            ("completed", get_completed(things, resolve, **kwargs)),
            ("invoices", get_invoices(things, resolve, **kwargs)),
            ("expenditures", get_expenditures(things, resolve, **kwargs)),
            ("comments", get_comments(things, resolve, **kwargs)),
            ("files", get_files(things, resolve, **kwargs)),
        )
        recent_updates = []
        for update_type, qs in querysets:
            for item in qs:
                item.update(
                    {
                        "recent_update_type": update_type
                    }
                )
                recent_updates.append(item)
        return json.dumps(recent_updates, cls=DjangoJSONEncoder)

而在前端,import { Query } from "react-apollo";我们可以使用一个元素来JSON.parse字段......其中包含“任何”(json序列化)数据:

<Query
    query={GET_PROJECT_DETAIL_SUMMARY_RECENT_UPDATES}
    fetchPolicy="network-only"
    variables={{ project_id: this.props.projectId }}
>
    {({ loading, error, data }: QueryResult) => {
        if (
            data &&
            data.get_project_detail_summary_recent_updates &&
            data.get_project_detail_summary_recent_updates.recent_updates
        ) {
            console.log(JSON.parse(data.get_project_detail_summary_recent_updates.recent_updates))
        }    
    }}
</Query>

边注:

如果没有大量数据类型列表,则创建一个Union类似的对象,该对象具有不同模型所需的所有字段,或者一个实际的对象Union,这似乎是正确的方法,因为这样类型不会丢失:

class ProjectSummaryNode(graphene.ObjectType):
    # from FileNode graphene.ObjectType class
    file__id = graphene.Int()
    file__brief_description = graphene.String()
    file_count = graphene.Int()
    last_file_created = graphene.String()
    last_file = graphene.String()

    # from UploaderNode graphene.ObjectType class
    uploader__first_name = graphene.String()
    uploader__last_name = graphene.String()

    # from CommentNode graphene.ObjectType class
    comment = graphene.String()

    class Meta:
        name = "ProjectSummaryNode"
        # example of Union, the above fields would be commented out, as they are part of 
        # the different graphene.ObjectType classes, and this line below would be uncommented
        # types = ( FileNode, UploaderNode, CommentNode, )

仍然愿意接受有关更好方法的建议。


推荐阅读