Database Access — Channels 3.0.4 documentation
https://channels.readthedocs.io/en/stable/topics/databases.html
数据库访问
Django ORM 是一段同步代码,因此如果您想从异步代码访问它,您需要进行特殊处理以确保其连接正确关闭。
如果您正在使用SyncConsumer,或任何基于它的东西——比如 JsonWebsocketConsumer——你不需要做任何特别的事情,因为你的所有代码都已经在同步模式下运行,Channels 将作为SyncConsumer代码的一部分为你做清理工作。
但是,如果您正在编写异步代码,则需要在安全的同步上下文中调用数据库方法,使用database_sync_to_async.
数据库连接
如果您使用线程消费者(同步消费者),通道可能会打开比您习惯的更多的数据库连接 - 每个线程最多可以打开一个连接。
如果您希望控制使用的最大线程数,请将ASGI_THREADS环境变量设置为 您希望允许的最大数量。默认情况下,Python 3.7 及以下版本的线程数设置为“CPU 数 * 5”,Python 3.8+ 版本设置为 min(32, os.cpu_count() + 4)。
为避免连接中有太多线程空闲,您可以改写代码以使用异步使用者,并且仅在需要使用 Django 的 ORM(使用database_sync_to_async)时才使用线程。
database_sync_to_async
channels.db.database_sync_to_async是一个asgiref.sync.sync_to_async 在退出时也会清理数据库连接的版本。
要使用它,请在单独的函数或方法中编写 ORM 查询,然后database_sync_to_async像这样调用它:
from channels.db import database_sync_to_async
async def connect(self):
self.username = await database_sync_to_async(self.get_name)()
def get_name(self):
return User.objects.all()[0].name
或者
from channels.db import database_sync_to_async
async def connect(self):
self.username = await self.get_name()
@database_sync_to_async
def get_name(self):
return User.objects.all()[0].name
传参:
class test:
def checkDevice(self, deviceId):
results = equipment.objects.filter(device_id=deviceId)
return results
def get(self,device_id):
results = await database_sync_to_async(self.checkDevice)(device_id)
如果直接使用的话会提示错误
results = await database_sync_to_async(
equipment.objects.filter,
thread_sensitive=True)(device_id=message["device_id"])
if (len(results) == 0):
logger.info("Wrong check")
django.core.exceptions.SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async.
不能直接使用 results