python - 应用程序内部的异常:您不能从异步上下文中调用它 - 使用线程或 sync_to_async
问题描述
我一直在使用 django-channels,我使用单线程为 2 个用户创建了一个房间
from django.db import models
from django.contrib.auth import get_user_model
from django.db.models import Q
from channels.db import SyncToAsync
# Create your models here.
model = get_user_model()
class threadmanager(models.Manager):
def get_or_create(self,firstuser,seconduser):
thread = self.get_queryset().filter(((Q(first=firstuser)and Q(second = seconduser ))) or ((Q(first=seconduser)and Q(second = firstuser ))))
if thread:
print(thread.first())
return thread
thread = self.model(first=firstuser,second=seconduser)
thread.save()
return(thread)
class thread(models.Model):
first = models.ForeignKey(model,on_delete=models.CASCADE,related_name="first")
second = models.ForeignKey(model,on_delete=models.CASCADE,related_name="second")
objects = threadmanager()
def __str__(self):
return self.first.username + "-" + self.second.username
我的聊天消费者是
from channels.consumer import AsyncConsumer
import asyncio
from channels.db import database_sync_to_async
import json
from accounts.models import thread
from django.contrib.auth import get_user_model
model = get_user_model()
class ChatConsumer(AsyncConsumer):
async def websocket_connect(self,event):
await self.send(
{
'type':'websocket.accept',
}
)
print("connected",event)
async def websocket_receive(self,event):
print("received",event)
firstuser,seconduser = await self.get_socket_users(event)
currentthread = await self.get_current_thread(firstuser,seconduser)
print(currentthread)
async def websocket_disconnect(self,event):
print("disconnected",event)
@database_sync_to_async
def get_socket_users(self,event):
first = self.scope['user']
second = model.objects.get(username=event['text'])
return first,second
@database_sync_to_async
def get_current_thread(self,firstuser,seconduser):
return thread.objects.get_or_create(firstuser,seconduser)
每当我尝试在 2 个用户之间创建一个新线程时,我都会成功获得它:例如,我的第一个用户是 root,第二个用户是 rusker。
WebSocket HANDSHAKING /profile [127.0.0.1:35432]
WebSocket CONNECT /profile [127.0.0.1:35432]
connected {'type': 'websocket.connect'}
received {'type': 'websocket.receive', 'text': 'rusker'}
root-rusker
但是,每当我试图在相同的 2 个用户之间获取相同的线程时,我都会从数据库中接收线程,但是在返回线程期间,我会收到如下错误:
WebSocket CONNECT /profile [127.0.0.1:35432]
connected {'type': 'websocket.connect'}
received {'type': 'websocket.receive', 'text': 'rusker'}
root-rusker
received {'type': 'websocket.receive', 'text': 'rusker'}
root-rusker
Exception inside application: You cannot call this from an async context - use a thread or sync_to_async.
Traceback (most recent call last):
File "/root/Desktop/pydjango/tenv/lib/python3.8/site-packages/django/db/models/fields/related_descriptors.py", line 173, in __get__
rel_obj = self.field.get_cached_value(instance)
File "/root/Desktop/pydjango/tenv/lib/python3.8/site-packages/django/db/models/fields/mixins.py", line 15, in get_cached_value
return instance._state.fields_cache[cache_name]
KeyError: 'first'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/root/Desktop/pydjango/tenv/lib/python3.8/site-packages/channels/sessions.py", line 183, in __call__
return await self.inner(receive, self.send)
File "/root/Desktop/pydjango/tenv/lib/python3.8/site-packages/channels/middleware.py", line 41, in coroutine_call
await inner_instance(receive, send)
File "/root/Desktop/pydjango/tenv/lib/python3.8/site-packages/channels/consumer.py", line 62, in __call__
await await_many_dispatch([receive], self.dispatch)
File "/root/Desktop/pydjango/tenv/lib/python3.8/site-packages/channels/utils.py", line 51, in await_many_dispatch
await dispatch(result)
File "/root/Desktop/pydjango/tenv/lib/python3.8/site-packages/channels/consumer.py", line 73, in dispatch
await handler(message)
File "/root/Desktop/pydjango/django-project/Game/Game/consumer.py", line 28, in websocket_receive
print(currentthread)
File "/root/Desktop/pydjango/tenv/lib/python3.8/site-packages/django/db/models/query.py", line 266, in __repr__
return '<%s %r>' % (self.__class__.__name__, data)
File "/root/Desktop/pydjango/tenv/lib/python3.8/site-packages/django/db/models/base.py", line 519, in __repr__
return '<%s: %s>' % (self.__class__.__name__, self)
File "/root/Desktop/pydjango/django-project/Game/accounts/models.py", line 42, in __str__
return self.first.username + "-" + self.second.username
File "/root/Desktop/pydjango/tenv/lib/python3.8/site-packages/django/db/models/fields/related_descriptors.py", line 187, in __get__
rel_obj = self.get_object(instance)
File "/root/Desktop/pydjango/tenv/lib/python3.8/site-packages/django/db/models/fields/related_descriptors.py", line 154, in get_object
return qs.get(self.field.get_reverse_related_filter(instance))
File "/root/Desktop/pydjango/tenv/lib/python3.8/site-packages/django/db/models/query.py", line 425, in get
num = len(clone)
File "/root/Desktop/pydjango/tenv/lib/python3.8/site-packages/django/db/models/query.py", line 269, in __len__
self._fetch_all()
File "/root/Desktop/pydjango/tenv/lib/python3.8/site-packages/django/db/models/query.py", line 1308, in _fetch_all
self._result_cache = list(self._iterable_class(self))
File "/root/Desktop/pydjango/tenv/lib/python3.8/site-packages/django/db/models/query.py", line 53, in __iter__
results = compiler.execute_sql(chunked_fetch=self.chunked_fetch, chunk_size=self.chunk_size)
File "/root/Desktop/pydjango/tenv/lib/python3.8/site-packages/django/db/models/sql/compiler.py", line 1154, in execute_sql
cursor = self.connection.cursor()
File "/root/Desktop/pydjango/tenv/lib/python3.8/site-packages/django/utils/asyncio.py", line 24, in inner
raise SynchronousOnlyOperation(message)
django.core.exceptions.SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async.
WebSocket DISCONNECT /profile [127.0.0.1:35432]
解决方案
推荐阅读
- java - 从存储过程 simpleJdbcCall 获取结果数组时出现关闭连接异常
- azure - Azure 门户扩展加载失败
- javascript - 将对象与 2 个具有相同键但来自 JSON API 的值不同的数组匹配,并与状态值进行比较并返回该对象
- vue.js - VueJs - 如何在切换页面/刷新时验证用户是否经过身份验证而不重新验证
- laravel - Laravel Model Broadcasting 如何处理私有频道认证?还有其他一些关于 Laravel 广播的问题
- regex - 如何从shell中的标签中提取href和链接的文本或标签?
- scala - 如何在同一目录/项目中同时使用 IntelliJ Idea 和/或 VSCode IDE 进行 mill 和 sbt 构建?
- php - 从子类和子类访问/填充 PHP 数组
- typescript - 在打字稿中使用不同的类型来获取和设置属性
- typescript - 在 Typescript 中优雅地相交两种函数类型