python - 在管理面板上注册用户时不调用 Django 自定义用户管理器

标签 python django

在 Django 管理面板上创建用户时,objects = CustomUserManager() 不会被执行。但是,当我使用 python manage.py createsuperuser 从 CLI 创建 super 用户时,会执行 objects = CustomUserManager()

这是模型文件

class CustomUser(AbstractUser):
    username = None
    email = models.EmailField(_('email address'), unique=True)
    name = models.CharField(verbose_name=_("first name"), max_length=50)
    stripe_customer_id = models.CharField(max_length=120)

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['name']

    objects = CustomUserManager()

    def __str__(self):
        return self.name

这是自定义用户管理器

class CustomUserManager(BaseUserManager):

    def create_user(self, email, password, name,**extra_fields):

        if not email:
            raise ValueError(_('The Email must be set'))
        email = self.normalize_email(email)
        customer = stripe.Customer.create(
            email=email,
            name=name,
        )     
        user = self.model(email=email,name=name, stripe_customer_id=customer.id ,**extra_fields)


        user.set_password(password)
        user.save()
        return user

def create_superuser(self, email, password,name,**extra_fields):
    """
    Create and save a SuperUser with the given email and password.
    """
    extra_fields.setdefault('is_staff', True)
    extra_fields.setdefault('is_superuser', True)
    extra_fields.setdefault('is_active', True)

    if extra_fields.get('is_staff') is not True:
        raise ValueError(_('Superuser must have is_staff=True.'))
    if extra_fields.get('is_superuser') is not True:
        raise ValueError(_('Superuser must have is_superuser=True.'))
    return self.create_user(email, password, name,**extra_fields)

下面是我注册管理面板的方法。

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

from .forms import CustomUserCreationForm, CustomUserChangeForm
from .models import CustomUser
from django.utils.translation import gettext_lazy as _


class CustomUserAdmin(UserAdmin):
    add_form = CustomUserCreationForm
    form = CustomUserChangeForm
    model = CustomUser
    ....

admin.site.register(CustomUser, CustomUserAdmin)

下面是CustomUserCreationForm

class CustomUserCreationForm(UserCreationForm):

    class Meta:
        model = CustomUser
        fields = "__all__"

最佳答案

UserAdmin 依赖于 ModelAdmin 中的实现来构建实例、验证表单,然后保存实例,而不是调用模型管理器上的自定义方法。

调用链:ModelAdmin.add_view() → ... → self._changeform_view(),调用:

  • (i) form.is_valid() (ModelForm)→ ... → self._post_clean()self.instance = construct_instance(...) ,
  • (ii) self.save_form(...)new_object = form.save(commit=False)(属于 BaseModelForm)返回 self.instance
  • (iii) self.save_model(..., new_object, ...)obj.save()

您可以覆盖 ModelAdmin.save_form 以调用自定义用户管理器的 create_user 方法并替换 form.instance:

class CustomUserAdmin(UserAdmin):
    model = CustomUser
    fieldsets = (
        (None, {'fields': (model.USERNAME_FIELD, 'name', 'password')}),
    ) + UserAdmin.fieldsets[2:]
    add_fieldsets = (
        (None, {'fields': (model.USERNAME_FIELD, 'name', 'password1', 'password2')}),
    )
    ordering = (model.USERNAME_FIELD,)

    def save_form(self, request, form, change):
        if not change:
            form.instance = self.model.objects.create_user(
                form.cleaned_data['email'],
                form.cleaned_data['password1'],
                form.cleaned_data['name'],
            )
        return super().save_form(request, form, change)

⚠️ 注意在通常的调用链中 save_form() 不会调用 obj.save(),因为 ModelAdmin 处理多个表单集和m2m 模型,而 CustomUserManager.create_user 会调用 user.save()。可以在已知范围的 UserAdmin 中更改此行为,但您可以考虑将 CustomUserManager.create_user 拆分为 CustomUserManager.construct_instance CustomUserManager.save_new_model(将 stripe.Customer.create(...)user.save() 移到此处)。

关于python - 在管理面板上注册用户时不调用 Django 自定义用户管理器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72430236/

相关文章:

python - 子图上的图例和散点图例

python - 如何更改 Sage 集成的 R 版本?

django - 如何将所有元数据包装到 "meta"属性中?

python - 附加到 SQLAlchemy 列表时出错

python - 读取文本文件时写入文本文件。 (值错误: I/O operation on closed file.)

python - 如何从entrycompletion获取entry

python - 非管理员仪表板的 Django 登录页面

python - 如何将 Django 迁移设置为始终是最后一个应用

python - Django/djcelery 1.8.2 AppRegistryNotReady : Translation infrastructure cannot be initialized

python - Django - 将媒体包含到特定的管理页面中