Django 信号 - 如何使用 post_save 发送保存在模型中的内容?

Django signals - how do I send what was saved in the model using post_save?

尝试使用信号通过 websockets 发送使用 .save() 保存的最后一条记录。我在 data 中输入什么?

#models.py
from django.db import models
from django.db.models.signals import post_save
from channels.layers import get_channel_layer
from asgiref.sync import async_to_sync

class DataModel(models.Model):
    time = models.DateTimeField()
    value = models.FloatField()

    def __str__(self):
        return str(self.time)

def save_post(sender, instance, **kwargs):
    channel_layer = get_channel_layer()
    async_to_sync(channel_layer.group_send)(
        "echo_group",
        {"type": "on.message", "data": data},
    )

post_save.connect(save_post, sender=DataModel)

我想我可以只获取索引最高的记录并发送它,但想知道是否有更优雅的解决方案。

我认为instance.__dict__是你想要的。它将所有模型属性转换为字典键值对

所以你可以做类似的事情

def save_post(sender, instance, **kwargs):
    channel_layer = get_channel_layer()
    async_to_sync(channel_layer.group_send)(
        "echo_group",
        {"type": "on.message", "data": instance.__dict__},
    )

已更新

我没有提到 instance 是刚刚保存并触发了 post_save 信号的实际对象。所以在给定的问题中 instance 将类似于 instance = DataModel.objects.create(**kwargs)

前奏:处理通道水合作用

要了解上次修改的内容,您需要一个上次修改字段。这是一个非常著名的模式,Django 使用 DateTimeFields 的 auto_now=True 参数来帮助实现它。这些字段不可编辑,并尽可能使用数据库触发器来获得结果(这就是它们不可编辑的原因)。

据说这很常见,所以我通常使用基本模型:

class AuditableBase(models.Model):
    """
    Base class that adds created_at and last_modified fields for audit purposes.
    """

    created_at = models.DateTimeField(auto_now_add=True)
    last_modified = models.DateTimeField(auto_now=True)

    class Meta:
        abstract = True

现在无论是否保存,获取最后修改的记录并用最后修改的通道填充通道都是微不足道的:

class DataModel(AuditableBase):
    time = models.DateTimeField()
    value = models.FloatField()

    def __str__(self):
        return str(self.time)

# On channel start:
latest = DataModel.objects.latest('last_modified')

信号处理器

但是,如果我们使用 post 保存信号,我们已经在 "instance" 参数中有了刚刚保存的对象。为了方便地转换为json,我们可以使用model_to_dict和DjangoJSONEncoder来处理大部分问题:

from django.forms.models import model_to_dict
from django.core.serializers import DjangoJSONEncoder
import json

def save_post(sender, instance, **kwargs):
    channel_layer = get_channel_layer()
    data = model_to_dict(instance)
    json_data = json.dumps(data, cls=DjangoJSONEncoder)
    async_to_sync(channel_layer.group_send)(
        "echo_group",
        {"type": "on.message", "data": json_data},
    )

Model_to_dict 会将模型转换为字典,并且可以使用 fields=(显式包含)或 exclude=(显式排除)进行限制。 DjangoJSONEncoder 处理时间数据,json 的默认编码器不支持。