为两种不同的用户类型(客户、供应商)扩展抽象用户模型
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()
我使用电子邮件字段作为主要字段而不是用户名字段来注册和登录。此外,在 admin.py 中,我使用电子邮件作为主要字段。尝试 makemigrations 时显示错误(django.core.exceptions.FieldError:为 CustomUser 指定的未知字段(mobileno))这是正确的方法吗?
我可以为这两种用户类型使用 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_FIELD
、REQUIRED_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_customer
和 create_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
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()
我使用电子邮件字段作为主要字段而不是用户名字段来注册和登录。此外,在 admin.py 中,我使用电子邮件作为主要字段。尝试 makemigrations 时显示错误(django.core.exceptions.FieldError:为 CustomUser 指定的未知字段(mobileno))这是正确的方法吗?
我可以为这两种用户类型使用 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_FIELD
、REQUIRED_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_customer
和 create_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