django-authtools UserCreationForm 偶发KeyError 'email'问题求助
偶发KeyError: 'email'在Django后台添加用户表单(django-authtools)
问题描述
使用django-authtools的UserCreationForm自定义表单时,打开Django后台「添加用户」表单偶发KeyError: 'email',提示email不在self.fields[User.USERNAME_FIELD]中,且实际self.fields里确实没有email字段。
错误的偶发特征:
- 主浏览器窗口报错时,无痕窗口可正常访问;
- 重启应用后错误消失,但运行一段时间后会复现,目前只能靠重启解决。
相关代码
自定义UserCreationForm
class UserCreationForm(UserCreationForm): """ A UserCreationForm with optional password inputs. """ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.fields["password1"].required = False self.fields["password2"].required = False # If one field gets autocompleted but not the other, our 'neither # password or both password' validation will be triggered. self.fields["password1"].widget.attrs["autocomplete"] = "off" self.fields["password2"].widget.attrs["autocomplete"] = "off" def clean_password2(self): password1 = self.cleaned_data.get("password1") password2 = super().clean_password2() if bool(password1) ^ bool(password2): raise forms.ValidationError("Fill out both fields") return password2
add_fieldsets配置
add_fieldsets = ( ( None, { "description": ( "Enter the new user's name and email address and click Save." " The user will be emailed a link allowing him/her to login to" " the site and set his/her password." ), "fields": ( "first_name", "last_name", "email", "is_pi", ), }, ), ( "Password", { "description": "Optionally, you may set the user's password here.", "fields": ("password1", "password2"), "classes": ("collapse", "collapse-closed"), }, ), )
UserAdmin代码
@admin.register(User) class UserAdmin(NamedUserAdmin): inlines = [CostUnitInline, OIDCGroupInline] form = UserChangeForm add_form = UserCreationForm
额外疑问:错误信息中common.admin.UserCreationForm将self引用为UserForm,这是否属于异常情况?
排查思路
- 解决类命名冲突:自定义表单和父类同名(都叫
UserCreationForm),可能导致初始化或导入时的混淆。尝试把自定义类改名(比如CustomUserCreationForm),同步更新UserAdmin的add_form引用,观察错误是否复现。 - 检查表单字段缓存:Django生产环境会缓存表单类的字段定义,可能存在请求触发意外字段修改的情况。可以在自定义表单的
__init__中强制确保email字段存在:def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) if 'email' not in self.fields: self.fields['email'] = forms.EmailField(required=True) # 原有逻辑... - 验证用户模型配置:确认
User模型的USERNAME_FIELD是否设置为'email'——django-authtools的NamedUserAdmin依赖这个配置处理用户名字段。若配置正确,可尝试在自定义表单中显式声明email字段。 - 排查并发导致的类属性篡改:偶发问题可能和并发请求修改表单类属性有关。在
__init__中添加日志,记录self.__class__.__name__和self.fields内容,错误出现时检查是否是类级别的fields被意外修改。 - 溯源django-authtools源码:查看父类
UserCreationForm的初始化逻辑,确认是否存在条件性移除email字段的逻辑,以及是否依赖add_fieldsets的配置格式。
内容的提问来源于stack exchange,提问作者Nicola Zilio
相关产品推荐
相关产品推荐

