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

Sphinx构建Django自定义包文档时get_user_model未被Mock的问题

Django自定义认证后端Sphinx文档构建Mock失效问题解决

问题场景

我正在为Django项目开发自定义包,包含两个认证后端模块,代码如下:

Backend 1 模块

from django.contrib.auth import get_user_model
from django.contrib.auth.backends import ModelBackend

UserModel = get_user_model()
# ModelBackend = object  # 此操作可临时修复导入问题

class AuthBackendOne(ModelBackend):
    pass

Backend 2 模块

from django.contrib.auth import get_user_model
from django.contrib.auth.backends import ModelBackend

UserModel = get_user_model()  # 此处会调用实际Django方法,导致Mock失效

class AuthBackendTwo(ModelBackend):
    pass

Sphinx配置文件conf.py中的Mock设置:

autodoc_mock_imports = [ "django.conf", "django.contrib.auth" ]

核心问题

执行sphinx-build生成文档时,Backend 2中的get_user_model()未被Mock,会调用真实的Django方法。测试确认问题出在继承ModelBackend时,虽然导入操作正常,但继承行为会触发真实模块的导入逻辑,导致Mock失效。手动将ModelBackend重赋值为object后,构建可成功完成。

测试现象对比

在两个模块中打印get_user_model及其类型(未调用函数),其中cognito对应AuthBackendOne,ldap对应AuthBackendTwo:

  • 未重赋值ModelBackend时:

cognito sources... [ 33%] kala_common.auth.cognito
django.contrib.auth.get_user_model
<class 'django.contrib.auth.get_user_model'>
ldaping sources... [ 40%] kala_common.auth.ldap
<function get_user_model at 0x7f386829f1c0>
<class 'function'>

  • 将ModelBackend重赋值为object时:

cognito sources... [ 33%] kala_common.auth.cognito
django.contrib.auth.get_user_model
<class 'django.contrib.auth.get_user_model'>
ldaping sources... [ 40%] kala_common.auth.ldap
django.contrib.auth.get_user_model
<class 'django.contrib.auth.get_user_model'>

可见未重赋值时,Backend 2中的get_user_model是真实函数类型,而非Mock对象。尝试将ModelBackend单独加入Mock列表,问题仍未解决。

解决方案

1. 精确Mock子模块

调整autodoc_mock_imports,将django.contrib.auth.backends也加入Mock列表,确保完整覆盖ModelBackend所在的子模块:

autodoc_mock_imports = [
    "django.conf",
    "django.contrib.auth",
    "django.contrib.auth.backends"
]

这种方式能避免继承ModelBackend时触发真实模块的加载逻辑,让Mock生效。

2. 延迟get_user_model()调用

将模块级别的UserModel = get_user_model()移到类的方法内部执行,避免Sphinx构建时触发函数调用:

# Backend 2 模块修改后
from django.contrib.auth import get_user_model
from django.contrib.auth.backends import ModelBackend

class AuthBackendTwo(ModelBackend):
    def authenticate(self, request, username=None, password=None, **kwargs):
        UserModel = get_user_model()
        # 后续业务逻辑...

3. 用钩子跳过模块级代码

在conf.py中添加autodoc-skip-member钩子,跳过模块级的UserModel变量解析,避免触发get_user_model()调用:

def skip_module_level_usermodel(app, what, name, obj, skip, options):
    if what == "module" and name == "UserModel":
        return True
    return skip

def setup(app):
    app.connect("autodoc-skip-member", skip_module_level_usermodel)

4. 初始化Django环境

如果需要保留模块级代码,可以在conf.py中手动初始化Django基础环境,让Sphinx在合法环境下构建文档:

import django
from django.conf import settings

if not settings.configured:
    settings.configure(
        DEBUG=True,
        INSTALLED_APPS=[
            "django.contrib.auth",
            "django.contrib.contenttypes",
        ]
    )
    django.setup()

这种方式无需依赖Mock,直接让Sphinx在正确的Django环境中处理模块代码。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 11:59:53