使用 Graphene 和 SQLAlchemy 通过 GraphQL API 更新记录

Posted

技术标签:

【中文标题】使用 Graphene 和 SQLAlchemy 通过 GraphQL API 更新记录【英文标题】:Update a record via a GraphQL API using Graphene and SQLAlchemy 【发布时间】:2018-06-29 17:29:25 【问题描述】:

我正在使用 python 包 Flask、SQLAlchemy、Graphene 和 Graphene-SQLAlchemy 构建 GraphQL API。我关注了SQLAlchemy + Flask Tutorial。我能够执行查询和突变来创建记录。现在我想知道更新现有记录的最佳方法是什么。

这是我当前的脚本schema.py

from graphene_sqlalchemy import SQLAlchemyObjectType
from database.batch import BatchOwner as BatchOwnerModel
import api_utils  # Custom methods to create records in database
import graphene


class BatchOwner(SQLAlchemyObjectType):
    """Batch owners."""
    class Meta:
        model = BatchOwnerModel
        interfaces = (graphene.relay.Node,)


class CreateBatchOwner(graphene.Mutation):
    """Create batch owner."""
    class Arguments:
        name = graphene.String()

    # Class attributes
    ok = graphene.Boolean()
    batch_owner = graphene.Field(lambda: BatchOwner)

    def mutate(self, info, name):
        record = 'name': name
        api_utils.create('BatchOwner', record) # Custom methods to create records in database
        batch_owner = BatchOwner(name=name)
        ok = True
        return CreateBatchOwner(batch_owner=batch_owner, ok=ok)


class Query(graphene.ObjectType):
    """Query endpoint for GraphQL API."""
    node = graphene.relay.Node.Field()
    batch_owner = graphene.relay.Node.Field(BatchOwner)
    batch_owners = SQLAlchemyConnectionField(BatchOwner)


class Mutation(graphene.ObjectType):
    """Mutation endpoint for GraphQL API."""
    create_batch_owner = CreateBatchOwner.Field()


schema = graphene.Schema(query=Query, mutation=Mutation)

备注:

我的对象 BatchOwner 只有 2 个属性(Id、name) 为了能够更新 BatchOwner 名称,我假设我需要提供数据库 ID(而不是中继全局 ID)作为某些更新方法的输入参数 但是当我从客户端查询BatchOwner 时,Graphene 只返回base64 编码的全局ID(例如:QmF0Y2hPd25lcjox,对应于BatchOwner:1

响应示例:


    "data": 
        "batchOwners": 
            "edges": [
                
                    "node": 
                        "id": "QmF0Y2hPd25lcjox",
                        "name": "Alexis"
                    
                
            ]
        
    

我现在想到的解决方案是:

创建一个以全局 Id 作为参数的更新突变 解码全局 ID(如何?) 使用解码后的全局Id获取的数据库Id查询数据库并更新对应记录

有没有更好的方法来做到这一点?

【问题讨论】:

【参考方案1】:

我找到了使用方法from_global_id(documented here)的解决方案

from graphql_relay.node.node import from_global_id

我在 schema.py 中添加了以下类:

class UpdateBatchOwner(graphene.Mutation):
    """Update batch owner."""
    class Arguments:
        id = graphene.String()
        name = graphene.String()

    # Class attributes
    ok = graphene.Boolean()
    batch_owner = graphene.Field(lambda: BatchOwner)

    def mutate(self, info, id, name):
        id = from_global_id(id)
        record = 'id': id[1], 'name': name
        api_utils.update('BatchOwner', record)
        batch_owner = BatchOwner(id=id, name=name)
        ok = True
        return UpdateBatchOwner(batch_owner=batch_owner, ok=ok)

我更新了 Mutation 类:

class Mutation(graphene.ObjectType):
    """Mutation endpoint for GraphQL API."""
    create_batch_owner = CreateBatchOwner.Field()
    update_batch_owner = UpdateBatchOwner.Field()

我想知道是否有更直接的方法可以做到这一点?

【讨论】:

我不太明白,你创建一个模型的新实例BatchOwner,然后返回它,这将自动更新现有行(因为它具有正确的主键id )?您能否详细说明您的解决方案及其作用,为什么会起作用? UpdateBatchOwner 类接受两个参数全局 id 和名称。在它的 mutate 方法中,我使用 from_global_id 方法将全局 id 转换为数据库 id,然后使用自定义方法 api_utils.update 使用类名、db id 和名称来更新相应记录的名称。我想我现在会做一些不同的事情,看看这个例子/教程:github.com/alexisrolland/flask-graphene-sqlalchemy/wiki 如果你不介意改变技术堆栈,我强烈推荐这个graphile.org/postgraphile 它比 SQLAlchemy 容易得多

以上是关于使用 Graphene 和 SQLAlchemy 通过 GraphQL API 更新记录的主要内容,如果未能解决你的问题,请参考以下文章

在 graphene-sqlalchemy 查询中按 id 过滤

将 SQL 查询限制为 Graphene-SQLAlchemy 中定义的字段/列

石墨烯和 SQLAlchemy:派生自基础对象类型

Graphene/GraphQL 查找特定列值

将 SqlAlchemy group_by/func 查询转换为 GraphQL

graphene.Node 和 graphene.relay.Node 有啥区别?