为两种不同的用户类型(客户、供应商)扩展抽象用户模型

extending the abstractuser model for two different user types (customer,vendor)

models.py

 from django.contrib.auth.models import AbstractUser, BaseUserManager
 from django.db import models
 from django.utils.translation import ugettext_lazy as _


 class CustomUserManager(BaseUserManager):
"""Define a model manager for User model with no username field."""

def _create_user(self, email, password=None, **extra_fields):
    """Create and save a User with the given email and password."""
    if not email:
        raise ValueError('The given email must be set')
    email = self.normalize_email(email)
    user = self.model(email=email, **extra_fields)
    user.set_password(password)
    user.save(using=self._db)
    return user

def create_user(self, email, password=None, **extra_fields):
    extra_fields.setdefault('is_staff', False)
    extra_fields.setdefault('is_superuser', False)
    return self._create_user(email, password, **extra_fields)

def create_superuser(self, email, password=None, **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)

    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, **extra_fields)




 class CustomUser(AbstractUser):
     is_customer = models.BooleanField('customer status', default=False)
     is_vendor = models.BooleanField('vendor status', default=False)


 class Customer(models.Model):
     customeruser = models.OneToOneField(CustomUser, on_delete=models.CASCADE, 
      primary_key=True)
     username = None
     email = models.EmailField(_('email address'), unique=True)
     firstname = models.CharField(max_length=200)
     lastname = models.CharField(max_length=200)
      mobileno = models.IntegerField(blank=True, null=True)

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = []

    objects = CustomUserManager()


 class Vendor(models.Model):
     vendoruser = models.OneToOneField(CustomUser, on_delete=models.CASCADE, primary_key=True)
     username = None
     email = models.EmailField(_('email address'), unique=True)
     firstname = models.CharField(max_length=200)
     lastname = models.CharField(max_length=200)
     mobileno = models.IntegerField(blank=True, null=True)

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = []

    objects = CustomUserManager()
  1. 我使用电子邮件字段作为主要字段而不是用户名字段来注册和登录。此外,在 admin.py 中,我使用电子邮件作为主要字段。尝试 makemigrations 时显示错误(django.core.exceptions.FieldError:为 CustomUser 指定的未知字段(mobileno))这是正确的方法吗?

  2. 我可以为这两种用户类型使用 django 默认身份验证登录、注销、密码重置功能吗?

admin.py

 from django.contrib import admin
 from django.contrib.auth.admin import UserAdmin
 from django.utils.translation import ugettext_lazy as _
 from django.contrib.auth import get_user_model


 class CustomUserAdmin(UserAdmin):
     """Define admin model for custom User model with no username 
 field."""
     fieldsets = (
         (None, {'fields': ('email', 'password')}),
         (_('Personal info'), {'fields': ('first_name', 'last_name', 
 'mobileno')}),
         (_('Permissions'), {'fields': ('is_active', 'is_staff', 
 'is_superuser',
                                   'groups', 'user_permissions')}),
         (_('Important dates'), {'fields': ('last_login', 
 'date_joined')}),
     )
     add_fieldsets = (
         (None, {
             'classes': ('wide',),
            'fields': ('email','first_name', 'last_name', 'password1', 
 'password2','mobileno'),
         }),
     )
     list_display = ('email', 'first_name', 'last_name','mobileno', 
 'is_staff')
     search_fields = ('email', 'first_name', 'last_name', 'mobileno')
     ordering = ('email',)


 admin.site.register(get_user_model(), CustomUserAdmin)

forms.py

 from django.contrib.auth import get_user_model
 from django.contrib.auth.forms import UserCreationForm



 class UserAdminCreationForm(UserCreationForm):
     """
     A Custom form for creating new users.
     """

     class Meta:
         model = get_user_model()
         fields = ['email','first_name','last_name','mobileno']



 class VendorAdminCreationForm(UserCreationForm):

     class Meta:
         model = get_user_model()
         fields = ['email','first_name','last_name','mobileno']

迁移错误...我会说你在 admin.py 某处有 mobileno 在 CustomUser ModelAdmin class.

关于用户模型。你实际上做的是你仍然有一个用户模型(我认为 Django 的 auth 不支持更多)和一些额外的客户和供应商数据。所以 USERNAME_FIELDREQUIRED_FIELDS 等应该在 CustomUser class 上,并且只有为客户和供应商指定的字段应该在这些模型上。

因此您的模型应如下所示:

class CustomUser(AbstractUser):
    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = []
    
    username = None
    email = models.EmailField(_("email address"), unique=True)
    mobileno = models.IntegerField(blank=True, null=True)

    objects = CustomUserManager()

    def is_customer(self):
        return hasattr(self, "customer")

    def is_vendor(self):
        return hasattr(self, "vendor")



class Customer(models.Model):
    user = models.OneToOneField(CustomUser, on_delete=models.CASCADE, 
    primary_key=True)
    customer_number = models.CharField(max_length=32)  # just some customer specific field
    

class Vendor(models.Model):
    user = models.OneToOneField(CustomUser, on_delete=models.CASCADE, primary_key=True)
    vendor_number = models.CharField(max_length=32)  # just some vendor specific field

并且您可以向管理器添加 create_customercreate_vendor 方法:

class CustomUserManager(BaseUserManager):
    """Define a model manager for User model with no username field."""

    def _create_user(self, email, password=None, **extra_fields):
        """Create and save a User with the given email and password."""
        if not email:
            raise ValueError('The given email must be set')
        email = self.normalize_email(email)
        user = self.model(email=email, **extra_fields)
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_user(self, email, password=None, **extra_fields):
        extra_fields.setdefault('is_staff', False)
        extra_fields.setdefault('is_superuser', False)
        return self._create_user(email, password, **extra_fields)

    def create_superuser(self, email, password=None, **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)

        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, **extra_fields)
    
    def create_customer(self, email, password=None, customer_number, **extra_fields):
        user = self.create_user(email, password, **extra_fields)
        Customer.objects.create(user=user, customer_number=customer_number)
        return user
    
    def create_vendor(self, email, password=None, vendor_number, **extra_fields):
        user = self.create_user(email, password, **extra_fields)
        Vendor.objects.create(user=user, vendor_number=vendor_number)
        return user

您可以在 Django 的文档中阅读它 https://docs.djangoproject.com/en/3.2/topics/auth/customizing/#extending-the-existing-user-model