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

Django 1.11测试模式下如何断开模型信号?或绕开ORM创建对象?

嘿,我来帮你搞定Django 1.11测试里的信号问题~先拆解下你遇到的错误,再给你两种可行的解决方案:

解决测试中post_save信号触发问题&修复AttributeError

先解释你遇到的AttributeError

你直接用patch(post_save)肯定会报错!因为unittest.mock.patch要求传入的是信号/接收器的字符串模块路径,而不是信号对象本身。它内部会尝试对参数做rsplit来解析模块路径,但信号对象不是字符串,自然就抛出了'ModelSignal' object has no attribute 'rsplit'的错误。

方案一:正确禁用post_save信号

1. 全局禁用所有post_save信号

最简单的方式是直接patch信号的send方法,这样所有post_save信号的接收器都不会被触发:

from django.db.models.signals import post_save
from unittest.mock import patch
from django.test import TestCase

class YourInstanceTest(TestCase):
    def setUp(self):
        with patch('django.db.models.signals.post_save.send'):
            # 这里创建对象时,post_save信号完全不会触发
            self.instance = Instance.objects.create(field1="value1", field2="value2")

2. 只禁用特定模型的接收器

如果只想禁用某个特定的post_save回调(比如你给Instance模型注册的接收器),可以直接patch那个回调函数的模块路径。假设你的接收器定义在yourapp.signals.instance_post_save:

from unittest.mock import patch
from django.test import TestCase

class YourInstanceTest(TestCase):
    def setUp(self):
        with patch('yourapp.signals.instance_post_save') as mock_receiver:
            self.instance = Instance.objects.create(field1="value1", field2="value2")
            # 还可以验证接收器确实没被调用
            mock_receiver.assert_not_called()

方案二:绕开ORM直接创建对象

如果你想彻底避开ORM的信号机制,可以直接用数据库连接执行SQL插入,这样完全不会触发任何ORM层面的信号:

from django.db import connection
from django.test import TestCase

class YourInstanceTest(TestCase):
    def setUp(self):
        with connection.cursor() as cursor:
            # 注意表名是「app名_模型名」,比如你的app叫yourapp,模型是Instance,表名就是yourapp_instance
            cursor.execute(
                "INSERT INTO yourapp_instance (field1, field2) VALUES (%s, %s)",
                ("value1", "value2")
            )
            # 获取刚插入的自增ID(MySQL用763106,PostgreSQL用currval(pg_get_serial_sequence('yourapp_instance', 'id')))
            cursor.execute("SELECT 763106")
            instance_id = cursor.fetchone()[0]
        
        # 如果需要模型实例,用get()获取——注意:get()不会触发信号,只有save/create操作才会
        self.instance = Instance.objects.get(id=instance_id)

⚠️ 小提示:不同数据库获取自增ID的SQL语句不一样,上面是MySQL的写法,PostgreSQL需要调整成对应的语句哦。另外,Django的TestCase会自动管理事务,测试结束后会回滚所有操作,不用担心数据污染。

内容的提问来源于stack exchange,提问作者Beliaf

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 08:13:23