如何通过Django Channels将数据保存至PostgreSQL?报错求助
解决Django Channels异步环境下保存数据到PostgreSQL的错误
问题根源
Django ORM操作是同步实现的,而你在Channels的异步connect方法里直接调用saverecord.save(),触发了SynchronousOnlyOperation错误——异步上下文不允许直接执行同步数据库操作,必须通过线程或sync_to_async工具包装同步代码。
另外你的models.py还有两处错误:
is_live = True不是合法的字段定义,数据库无法识别这个配置created_at设为DateField,但你存入的是带时分秒的字符串,会导致类型不匹配
修改方案
1. 修正models.py字段定义
from django.db import models class Rawdata(models.Model): ref_waterplant = models.CharField(max_length=100) # 改为DateTimeField存储完整时间信息 created_at = models.DateTimeField() # 正确定义布尔字段,设置默认值 is_live = models.BooleanField(default=True) class Meta: db_table = "rawdata"
2. 改造consumers.py,用sync_to_async包装数据库操作
导入Channels提供的sync_to_async,将同步的ORM操作封装成异步可调用的函数:
from channels.db import sync_to_async import datetime import random import json from .models import Rawdata import eventhubreader async def connect(self): event = eventhubreader.EventReader() # 把数据库操作放到同步函数中,用sync_to_async包装 @sync_to_async def save_raw_record(ref_waterplant, created_at): saverecord = Rawdata() saverecord.ref_waterplant = str(ref_waterplant) # 转字符串适配CharField saverecord.created_at = created_at saverecord.save() return saverecord async def cb(partition, events): data = events[len(events)-1] await self.send(json.dumps({'value': data.body_as_json()})) now = datetime.datetime.now() dataFormat = { "IotData": { "temperature": data.body_as_json()["temperature"], "humidity": data.body_as_json()["humidity"] }, "MessageDate": now, "DeviceId": data.body_as_json()['deviceId'] } # 异步调用包装后的保存函数 await save_raw_record(random.randint(20, 25), dataFormat['MessageDate']) print(dataFormat) await self.accept()
关键说明
sync_to_async是Channels专为异步上下文执行同步ORM操作设计的工具,它会在独立线程中运行同步代码,避免阻塞异步事件循环ref_waterplant是CharField类型,必须把随机整数转为字符串再赋值,否则会触发类型错误created_at直接传入datetime对象即可,无需转成字符串,DateTimeField会自动处理存储格式
内容的提问来源于stack exchange,提问作者user19052774
相关产品推荐
相关产品推荐

