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

Pytest patch继承Django模型的字段default属性失效问题咨询

问题原因
  • Python 的 mock 遵循「在哪里使用,就在哪里 patch」的规则,你当前的写法 mock 的是 uuid 模块根路径下的 uuid4 函数,但实际被 BaseModel 使用的 uuid4 已经在模块导入阶段就被加载到了 common.models 的命名空间中:
    你在 common/models.py 顶部执行 from uuid import uuid4 时,就已经把 uuid 模块里的 uuid4 函数引用复制到了 common.models 作用域下,BaseModel 中 guid 字段的 default 参数绑定的是这个复制后的引用,而非原 uuid 模块的 uuid4。你直接 patch uuid.uuid4 只会修改原模块的引用,不会影响已经被导入到 common.models 里的函数,所以创建模型实例时调用的还是原始的 uuid4,mock 自然不会被触发。
  • 额外的小问题:你的测试代码里 mock 返回的是字符串,但 Django 的 UUIDField 存储的是 UUID 类型对象,即使 mock 生效,直接用字符串和 entity.guid 做相等判断也会失败。
解决方案

两种可选方案,优先选第一种,不需要修改生产代码:

方案1:patch 实际使用位置的 uuid4

把 mock 的路径改成 common.models.uuid4,也就是 uuid4 实际被调用的作用域路径,同时调整返回值为 UUID 类型即可:

import uuid
def test_model_create(mocker):
   # Given
   test_guid = uuid.UUID("3fa85f64-5717-4562-b3fc-2c963f66afa6")
   mock_guid = mocker.patch("common.models.uuid4", return_value=test_guid)

   # When
   entity = Entity.objects.create(name="test_name")

   # Then
   mock_guid.assert_called_once()
   assert test_guid == entity.guid

方案2:修改字段 default 为延迟导入路径

如果不想调整测试的 patch 路径,也可以修改生产代码中 guid 字段的 default 写法,用字符串形式的导入路径让 Django 延迟解析函数:

# common/models.py 中修改字段定义
guid = models.UUIDField(unique=True, default="uuid.uuid4", editable=False)

这种写法下你原来的 patch 写法可以生效,但需要修改生产逻辑,优先级低于方案1。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 18:36:03