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

测试Django Model.clean()时unittest.mock patch报F()表达式错误求助

问题描述

在Django开发中,我通过Model.clean()方法验证用户提交的表单,验证过程会根据HTTP请求响应更新部分字段。想用Python的unittest模拟HTTP请求测试Model.clean()方法,但运行测试时出错。

相关代码

app/models.py

import logging

from django.core.exceptions import ValidationError
from django.db import models

from .aid import GitHosting

logger = logging.getLogger(__name__)

class Resource(models.Model):
    code_repository = models.URLField(
        help_text="Link to the repository where the un-compiled, human readable code and related code is located."
    )
    version = models.CharField(
        blank=True,
        # Git hash contains 40 characters
        max_length=50,
        default="HEAD",
        help_text="The version of the resource in the format of a Git commit ID or Git tag.",
    )

    def clean(self):
        git_host = GitHosting()
        self.version = git_host.get_version()

app/tests.py

import logging
from unittest.mock import patch

from django.test import TestCase
from django.urls import reverse

from .models import Resource

logger = logging.getLogger(__name__)

@patch("app.models.GitHosting.get_version")
class ResourceViewTestCase(TestCase):
    def test_add_resource(self, mock_get_version):
        mock_get_version = "5678"

        logger.error("Submitting form ...")

        response = self.client.post(reverse("app:index"), {
            "code_repository": "http://mygit.com/foo/bar"
        })

        resource = Resource.objects.get(id=1)

        self.assertEqual(resource.version, "5678")

错误信息

运行python manage.py test时抛出:

ValueError: Failed to insert expression "<MagicMock name='get_version().resolve_expression()' id='139668720464128'>" on app.Resource.version. F() expressions can only be used to update, not to insert.
修复方案

问题出在测试代码对Mock对象的赋值方式错误。直接把mock_get_version赋值为字符串"5678",并没有改变被patch方法的返回值,原MagicMock对象仍在生效,导致Django将其识别为数据库表达式,从而报错。

正确做法是通过return_value属性设置Mock方法的返回值,修改测试方法如下:

def test_add_resource(self, mock_get_version):
    # 替换原赋值语句
    mock_get_version.return_value = "5678"

    logger.error("Submitting form ...")

    response = self.client.post(reverse("app:index"), {
        "code_repository": "http://mygit.com/foo/bar"
    })

    resource = Resource.objects.get(id=1)

    self.assertEqual(resource.version, "5678")

设置后,GitHosting.get_version()被调用时会返回指定字符串"5678",而非MagicMock对象,Django就能正确处理该值并插入数据库。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 00:17:08