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

Django创建自定义用户报错:CustomUser对象无save_m2m属性

报错原因

运行代码触发如下报错:

'CustomUser' object has no attribute 'save_m2m'

核心触发原因有两个:

  1. save_m2m()是Django ModelForm实例的方法,不是模型实例自带的方法,给CustomUser模型实例调用这个方法本身属于用法错误。
  2. 重写save()方法时完全绕开了父类表单的原生保存逻辑,直接用CustomUser.objects.create()生成模型实例,这个实例自然不会附带表单提供的save_m2m方法。
现有代码的其他问题
  • 重写__init__手动从入参里取email、密码的逻辑冗余,且裸except会吞掉所有异常,隐藏潜在问题。表单校验通过后,所有合法字段值都会存在self.cleaned_data中,不需要手动从入参抓取。
  • 先调用objects.create()写入明文密码,再调用set_password(),会产生两次数据库写入,且第一次写入的密码是明文,存在严重安全隐患。
  • 把commit参数默认值写死为False,无视调用方传入的参数值,不符合Django表单save()方法的设计规范。
  • 多对多字段的保存逻辑调用位置错误。
修复方案

直接复用父类表单的保存逻辑,不要手动调用objects.create()创建用户,冗余的__init__方法可以整个删除,父类UserCreationForm已经自带密码校验、密码加密逻辑,不需要手动处理。
修复后代码如下:

class CustomUserCreationForm(UserCreationForm):
    class Meta:
        model = CustomUser
        fields = "__all__"

    def save(self, commit=True, **kwargs):
        # 调用父类save方法,commit=False时暂不写入数据库,此时表单实例会提供save_m2m方法
        user = super().save(commit=False, **kwargs)
        
        # 执行Stripe客户创建逻辑
        stripe_customer = stripe.Customer.create(
            email=user.email,
            name="test",
        )
        # 如果用户模型需要绑定Stripe客户ID,在这里赋值即可
        # user.stripe_customer_id = stripe_customer.id

        if commit:
            user.save()
            # 多对多字段在主实例写入数据库后再保存
            self.save_m2m()
        
        return user

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 06:21:30