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管理器时触发错误。
解决步骤
- 显式指定表单关联的模型:通过
get_user_model()动态获取当前配置的用户模型,并在表单的Meta类中显式声明 - 规范表单实例化参数:测试代码中显式传递
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
相关产品推荐
相关产品推荐

