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

Django自定义User模型测试报错:Manager isn't available问题排查

问题描述

已将默认User模型替换为自定义User模型,使用标准UserManager,创建CustomUserChangeForm用于UserAdmin,并在settings中设置AUTH_USER_MODEL = "accounts.User"。

通过浏览器正常使用站点及管理后台时一切正常,使用自定义User模型的视图测试也无问题。但直接对CustomUserChangeForm运行测试时,出现错误:AttributeError: Manager isn't available; 'auth.User' has been swapped for 'accounts.User'。

测试代码

from .forms import CustomUserChangeForm
from .models import User

def test_admin_user_change_form(self):
    self.register_user()
    self.register_user("email2@site.com", "username2")
    user = User.objects.get(username="username")
    # Test valid change
    form = CustomUserChangeForm({ "username": "username3", "email": "email3@site.com" }, user)
    self.assertTrue(form.is_valid())
    # Test case insensitive username change
    form = CustomUserChangeForm({ "username": "Username2" }, user)
    self.assertFalse(form.is_valid())
    # Test case insensitive email change
    form = CustomUserChangeForm({ "email": "Email2@site.com" }, user)
    self.assertFalse(form.is_valid())

表单代码

from .models import User

class CustomUserChangeForm(UserChangeForm):
    def clean_username(self):
        username = self.cleaned_data.get("username")
        if username and self._meta.model.objects.exclude(id=self.instance.id).filter(username__iexact=username).exists():
            self._update_errors(ValidationError({ "username": self.instance.unique_error_message(self._meta.model, ["username"]) }))
        else:
            return username
        
    def clean_email(self):
        return self.cleaned_data.get("email").lower()

Admin代码

from django.contrib.auth.admin import UserAdmin
from .models import User

@admin.register(User)
class UserAdmin(UserAdmin):
# ...
    form = CustomUserChangeForm
# ...
问题原因及解决方法

问题核心在于CustomUserChangeForm继承的UserChangeForm默认关联原生auth.User模型,即便settings中配置了自定义用户模型,表单内部的_meta.model在测试场景下仍可能指向原生User,调用其objects管理器时触发错误。

解决步骤

  1. 显式指定表单关联的模型:通过get_user_model()动态获取当前配置的用户模型,并在表单的Meta类中显式声明
  2. 规范表单实例化参数:测试代码中显式传递instance参数,替代直接传对象的写法

修改后的表单代码

from django.contrib.auth.forms import UserChangeForm
from django.contrib.auth import get_user_model
from django.core.exceptions import ValidationError

User = get_user_model()

class CustomUserChangeForm(UserChangeForm):
    class Meta:
        model = User
        fields = '__all__'  # 或指定与原UserChangeForm一致的字段集合

    def clean_username(self):
        username = self.cleaned_data.get("username")
        if username and User.objects.exclude(id=self.instance.id).filter(username__iexact=username).exists():
            self._update_errors(ValidationError({ "username": self.instance.unique_error_message(User, ["username"]) }))
        else:
            return username
        
    def clean_email(self):
        return self.cleaned_data.get("email").lower()

修改后的测试代码片段

# 替换原表单实例化代码
form = CustomUserChangeForm({ "username": "username3", "email": "email3@site.com" }, instance=user)
# 其余测试用例同理,均需显式指定instance参数

说明

  • get_user_model()会自动读取settings中的AUTH_USER_MODEL配置,确保表单始终关联正确的用户模型,不受环境影响
  • 显式设置Meta.model覆盖UserChangeForm默认的模型指向,彻底避免原生模型的关联问题
  • 测试代码中显式传递instance参数,符合Django表单的官方调用规范,消除潜在参数解析歧义

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 18:57:04