簡體   English   中英

在管理面板上注冊用戶時不調用 Django 自定義用戶管理器

[英]Django Custom User Manager is not called when registering users on the admin panel

在 Django 管理面板上創建用戶時,不會執行objects = CustomUserManager() 但是,當我使用python manage.py createsuperuser從 CLI 創建超級用戶時,會執行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

這是customUserManager

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_instanceCustomUserManager.save_new_model (在此處移動 stripe.Customer.create stripe.Customer.create(...)user.save() )。

事實上,當您從管理面板創建新用戶時,不會調用您的自定義方法create_user (和create_superuser ,您可能也重寫了)。 我不確定既不明白為什么,但我認為create_user函數只是一個快捷方式。

為什么不重寫CustomUsersave()方法? 從 Django 文檔中:

覆蓋內置方法的經典用例是,如果您希望在保存對象時發生某些事情。

不正是你要找的嗎? 此處(在表單級別執行此操作)和此處(如果您更喜歡直接更改模型本身,無論使用哪種表單)查看 Django 文檔以獲取更多信息。

例如,如果您更喜歡第二個選項,您可以將此方法添加到CustomUser

from django.apps.apps import get_model
from django.db import transaction

class CustomUser(AbstractUser):

    # your initial code goes here ...

    def save(self, *args, **kwargs):
        # make the distinction between the creation and the update of the instance
        if not self._state.adding:
               # doesn't change the initial method if the user has already been saved in DB
               return super(CustomUser, self).save(*args, **kwargs)
        # guarantee of atomicity
        with transaction.atomic():
                # dynamic resolution to avoid a circular import, might not be necessary
                customer = get_model("stripe", "Customer").create(
                    email=self.email,
                    name=self.name,
                )
                self.stripe_customer_id = customer.id
                super(CustomUser, self).save(*args, **kwargs)
                return self

不要忘記區分實例的創建和更新。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM