graphql-python / graphql-python/graphql-ws
Deep nested objects in django won't work due to async
- 主要语言
- Python
- 星标
- 270
- 派生
- 85
- PR 合并指标
- 30 天内没有已合并 PR
描述
* GraphQL AioWS version: (not using AioWS, only django-channels)
* Python version: 3.8.2
* Operating System: MacOSX
### Description
I am trying to get clients to subscribe to my graphql with a nested object in django. The request looks like this:
```
subscription {
taskUpdated(id:"04a5e92bc9084ad981481ab4314a1d33", updateInterval: 3) {
id
token
result {
id,
profiles {
id
}
}
}
}
```
Tasks contain one result which contain multiple profiles.
### What I Did
In my subscription class I used the sync_to_async method which works if used for the first level:
```python
class Subscription(graphene.ObjectType):
task_updated = graphene.Field(
TaskType, id=graphene.String(), update_interval=graphene.Int()
)
async def resolve_task_updated(root, info, id, update_interval):
print("TRYING TO RESOLVE")
while True:
print("While true")
task = await sync_to_async(Task.objects.get, thread_sensitive=True)(
pk=id
)
yield task
await asyncio.sleep(update_interval)
```
Using the query only targeting task.id everything works perfectly. Once I try to target task.result (which is a new object). I receive the error:
```
You cannot call this from an async context - use a thread or sync_to_async.
```
I managed to get a workaround by updating the TaskType and updating the resolver for the result like so:
```python
class TaskType(DjangoObjectType):
class Meta:
model = TaskModel
fields = "__all__"
result = graphene.Field(TaskResultType)
async def resolve_result(self, info):
return await sync_to_async(
TaskResult.objects.get, thread_sensitive=True
)(task=self.id)
```
That way I could get to the next level (task -> result). When I try to subscribe to task -> result -> profiles there is no way to receive the data anymore. The same error from above is thrown. Even if I update the ResultType accordingly to fetch all profiles async:
```python
class TaskResultType(DjangoObjectType):
class Meta:
model = TaskResult
fields = "__all__"
profiles = graphene.List(ProfileType)
async def resolve_profiles(self, info):
return await sync_to_async(
Profile.objects.filter, thread_sensitive=True
)(task_result=self.id)
```
I thought dynamic querying of objects and subscribing to nested objects would be an out of the box functionality but it is really difficult. I can't be the only person using this repo to actually receive ORM data?
贡献指南
调研方向
Start with the Subscription, TaskType, and TaskResultType resolver examples in the issue, then reproduce the nested task → result → profiles subscription against the Django setup. Trace where the async-context error occurs and verify that the full nested subscription returns profile data without requiring additional resolver workarounds.
由索引模型根据 Issue 内容生成。
评估
- 技术栈
- django, graphql, python
- 领域
- api, backend, database
- Issue 类型
- 缺陷
- 难度
- 4/5
- 预计耗时
- 3-5 天
- 活跃度
- 停滞
- 描述清晰度
- 基本清楚
- 新手友好度
- 35/100