1、修改配置文件setting.py,覆盖默认的User模型
AUTH_USER_MODEL = ‘custom_user.EmailUser’
setting.py文件中
INSTALLLED_APPS
添加用户模型
2、在models.py中重写继承AbstractBaseUser、PermissionsMixin的用户模型,代码如下:
import django
from django.contrib.auth.models import (
AbstractBaseUser, BaseUserManager, PermissionsMixin)
from django.core.mail import send_mail
from django.db import models
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth.models import Group
class EmailUserManager(BaseUserManager):
"""Custom manager for EmailUser."""
def _create_user(self, email, password,
is_staff, is_superuser, **extra_fields):
"""
Create and save an EmailUser with the given email and password.
:param str email: user email
:param str password: user password
:param bool is_staff: whether user staff or not
:param bool is_superuser: whether user admin or not
:return custom_user.models.EmailUser user: user
:raise ValueError: email is not set
"""
now = timezone.now()
if not email:
raise ValueError('The given email must be set')
email = self.normalize_email(email)
is_active = extra_fields.pop("is_active", True)
print('email:')
print(email)
user = self.model(email=email, is_staff=is_staff, is_active=is_active,
is_superuser=is_superuser, last_login=now,
date_joined=now, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_user(self, email, password=None, **extra_fields):
"""
Create and save an EmailUser with the given email and password.
:param str email: user email
:param str password: user password
:return custom_user.models.EmailUser user: regular user
"""
is_staff = extra_fields.pop("is_staff", True)
return self._create_user(email, password, is_staff, False,
**extra_fields)
def create_superuser(self, email, password, **extra_fields):
"""
Create and save an EmailUser with the given email and password.
:param str email: user email
:param str password: user password
:return custom_user.models.EmailUser user: admin user
"""
return self._create_user(email, password, True, True,
**extra_fields)
class AbstractEmailUser(AbstractBaseUser, PermissionsMixin):
"""
Abstract User with the same behaviour as Django's default User.
AbstractEmailUser does not have username field. Uses email as the
USERNAME_FIELD for authentication.
Use this if you need to extend EmailUser.
Inherits from both the AbstractBaseUser and PermissionMixin.
The following attributes are inherited from the superclasses:
* password
* last_login
* is_superuser
"""
email = models.EmailField(_('email address'), max_length=255,
unique=True, db_index=True)
is_staff = models.BooleanField(
_('staff status'), default=True, help_text=_(
'Designates whether the user can log into this admin site.'))
is_active = models.BooleanField(_('active'), default=True, help_text=_(
'Designates whether this user should be treated as '
'active. Unselect this instead of deleting accounts.'))
date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
objects = EmailUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
class Meta: # noqa: D101
verbose_name = _('user')
verbose_name_plural = _('users')
abstract = True
def get_full_name(self):
"""Return the email."""
return self.email
def get_short_name(self):
"""Return the email."""
return self.email
def email_user(self, subject, message, from_email=None, **kwargs):
"""Send an email to this User."""
send_mail(subject, message, from_email, [self.email], **kwargs)
# Monkey patch Django 1.7 to avoid detecting migrations
if django.VERSION[:2] == (1, 7):
last_login = AbstractEmailUser._meta.get_field('last_login')
last_login.blank = True
last_login.null = True
last_login.default = models.fields.NOT_PROVIDED
groups = AbstractEmailUser._meta.get_field('groups')
groups.help_text = _('The groups this user belongs to. A user will get '
'all permissions granted to each of their groups.')
class EmailUser(AbstractEmailUser):
"""
Concrete class of AbstractEmailUser.
Use this if you don't need to extend EmailUser.
"""
class Meta(AbstractEmailUser.Meta): # noqa: D101
swappable = 'AUTH_USER_MODEL'
3、forms.py重写UserCreationForm和UserChangeForm
"""EmailUser forms."""
import django
from django import forms
from django.contrib.auth import get_user_model
from django.contrib.auth.forms import ReadOnlyPasswordHashField
from django.utils.translation import ugettext_lazy as _
class EmailUserCreationForm(forms.ModelForm):
"""
A form for creating new users.
Includes all the required fields, plus a repeated password.
"""
error_messages = {
'duplicate_email': _("A user with that email already exists."),
'password_mismatch': _("The two password fields didn't match."),
}
password1 = forms.CharField(
label=_("Password"),
widget=forms.PasswordInput)
password2 = forms.CharField(
label=_("Password confirmation"),
widget=forms.PasswordInput,
help_text=_("Enter the same password as above, for verification."))
class Meta: # noqa: D101
model = get_user_model()
fields = ('email',)
def clean_email(self):
"""
Clean form email.
:return str email: cleaned email
:raise forms.ValidationError: Email is duplicated
"""
# Since EmailUser.email is unique, this check is redundant,
# but it sets a nicer error message than the ORM. See #13147.
email = self.cleaned_data["email"]
try:
get_user_model()._default_manager.get(email=email)
except get_user_model().DoesNotExist:
return email
raise forms.ValidationError(
self.error_messages['duplicate_email'],
code='duplicate_email',
)
def clean_password2(self):
"""
Check that the two password entries match.
:return str password2: cleaned password2
:raise forms.ValidationError: password2 != password1
"""
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError(
self.error_messages['password_mismatch'],
code='password_mismatch',
)
return password2
def save(self, commit=True):
"""
Save user.
Save the provided password in hashed format.
:return custom_user.models.EmailUser: user
"""
user = super(EmailUserCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
class EmailUserChangeForm(forms.ModelForm):
"""
A form for updating users.
Includes all the fields on the user, but replaces the password field
with admin's password hash display field.
"""
# In Django 1.9 the url for changing the password was changed (#15779)
# A url name was also added in 1.9 (same issue #15779),
# so reversing the url is not possible for Django < 1.9
password = ReadOnlyPasswordHashField(label=_("Password"), help_text=_(
"Raw passwords are not stored, so there is no way to see "
"this user's password, but you can change the password "
"using <a href=\"%(url)s\">this form</a>."
) % {'url': 'password/' if django.VERSION < (1, 9) else '../password/'})
class Meta: # noqa: D101
model = get_user_model()
exclude = ()
def __init__(self, *args, **kwargs):
"""Init the form."""
super(EmailUserChangeForm, self).__init__(*args, **kwargs)
f = self.fields.get('user_permissions', None)
if f is not None:
f.queryset = f.queryset.select_related('content_type')
def clean_password(self):
"""
Clean password.
Regardless of what the user provides, return the initial value.
This is done here, rather than on the field, because the
field does not have access to the initial value.
:return str password:
"""
return self.initial["password"]
4、在admin.py中注册自定义的EmailUser
"""Admin definition for EmailUser."""
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.utils.translation import ugettext_lazy as _
from .forms import EmailUserChangeForm, EmailUserCreationForm
from .models import EmailUser
class EmailUserAdmin(UserAdmin):
"""EmailUser Admin model."""
fieldsets = (
(None, {'fields': ('email', 'password')}),
(_('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', 'password1', 'password2')
}
),
)
# The forms to add and change user instances
form = EmailUserChangeForm
add_form = EmailUserCreationForm
# The fields to be used in displaying the User model.
# These override the definitions on the base UserAdmin
# that reference specific fields on auth.User.
list_display = ('email', 'is_staff')
list_filter = ('is_staff', 'is_superuser', 'is_active', 'groups')
search_fields = ('email',)
ordering = ('email',)
filter_horizontal = ('groups', 'user_permissions',)
# Register the new EmailUserAdmin
admin.site.register(EmailUser, EmailUserAdmin)