You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 07:54:19