如何解决如何在连接上使用石墨烯数据加载器以及如何仅选择必要的字段
我想使用一些带有 python 石墨烯的非标准数据库来创建一个 GraphQL 端点。该数据库没有现有的 sqlAlchemy 方言,Django ORM 等不支持,所以我尝试使用 DataLoader
类来批量提取数据并最大限度地减少对数据库的查询次数。
我阅读了https://docs.graphene-python.org/en/latest/execution/dataloader/。为了说明我的问题,我创建了下一个简化的即用型示例:
import graphene
from graphql.execution.executors.asyncio import AsyncioExecutor
from starlette.applications import Starlette
from starlette.routing import Route
from starlette.graphql import GraphQLApp
from graphene.relay import Node,Connection,ConnectionField
from graphene import String,ObjectType,Field,List,NonNull
from promise import Promise
from promise.DataLoader import DataLoader
class User(ObjectType):
"""User information."""
class Meta:
interfaces = (Node,)
user_id = String(description='User id.',name='userID')
user_name = String(description='User name.')
@classmethod
def get_node(cls,info,_id):
return user_loader.load(_id)
class UserConnection(Connection):
class Meta:
node = User
def get_user(_id):
return User(id=_id,user_id=_id,user_name='Bill Gates',)
user_data = {x.id: x for x in [get_user(f'EEE-{x}') for x in range(8)]}
class UserLoader(DataLoader):
def batch_load_fn(self,keys):
return Promise.resolve([user_data.get(key) for key in keys])
user_loader = UserLoader()
class Query(ObjectType):
user = Field(User,user_id=String(description='User ID',name='userID',required=True),description='User information')
users = List(User,user_ids=List(NonNull(String),name='userIDs',required=True)
all_users = ConnectionField(UserConnection)
node = Node.Field()
def resolve_user(self,user_id):
return user_loader.load(user_id)
def resolve_users(self,user_ids):
return user_loader.load_many(user_ids)
def resolve_all_users(self,**args):
return list(user_data.values())
routes = [
Route('/',GraphQLApp(schema=graphene.Schema(query=Query),executor_class=AsyncioExecutor)
),]
app = Starlette(routes=routes)
if __name__ == "__main__":
import uvicorn
uvicorn.run(app,host='127.0.0.1',port=8000)
我希望以下 GraphQL 查询能够正常工作:
fragment userFields on User {
userID
userName
}
query getUser {
user(userID: "EEE-3") {
id
...userFields
}
}
query getUsers {
users(userIDs: ["EEE-3","EEE-4","EEE-5"]) {
id
...userFields
}
}
query getNode {
node(id: "VXNlcjpFRUUtMw==") {
id
... on User {
...userFields
}
}
}
query getAllUsers {
allUsers(first: 2) {
edges {
node {
id
...userFields
}
cursor
}
pageInfo{
hasNextPage
hasPrevIoUsPage
startCursor
endCursor
}
}
}
这里我不使用该数据库来使示例保持简单,因为我的问题是关于如何正确使用 DataLoader
,或者我还应该做什么才能达到我的目的。我在 user_data
变量中有数据并使用 get_user
函数访问它们,但在实际情况下它会查询我的数据库。
这里似乎一切正常,除了两件事:
-
函数
resolve_all_users
直接作用于基础数据集或完整查询。虽然我希望它作为一些分页界面,根据first
、after
等参数仅提取必要的数据。我可以在resolve_connection
类上显式调用UserConnection
函数,并且我看到它使用了一些数组切片函数。但是示例中的DataLoader
使用User
id 而不是索引。此外,创建索引DataLoader
似乎很昂贵,因为我想获得连续间隔并且不想将所有索引作为列表传递。我应该怎么做才能仅使用一个请求来解析此字段? -
还有
DataLoader
我从数据库中提取完整的User
对象,即使不是所有的字段都是必需的。是否可以优化它以仅提取 GraphQL 查询字段中所需的内容?
提前致谢。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。