我正在尝试使用电子邮件作为用户名为我的 Django 项目创建 customuser,并为卡车和公司添加一个单选按钮。这样在注册过程中,电子邮件 ID 将按照卡车或公司进行注册。我提到单选按钮为“标签”,并在 EmailUser 模型中的标签中添加了一个多对多字段。当我进行迁移时,它引发了一个错误:(fields.E300)字段定义了与模型“AbstractEmailUser”的关系,该模型要么未安装,要么是抽象的。
我对 Django 很陌生,不确定我是否为我真正想要的东西创建了正确的代码。请帮我解决这个问题。这是我的代码,
模型.py:
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 _
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)
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", False)
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=False, 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:
verbose_name = _('user')
verbose_name_plural = _('users')
abstract = True
# def __init__(self, *args, **kwargs):
# super(AbstractEmailUser, self).__init__(*args, **kwargs)
# if self.instance.pk:
# self.fields['Tag'].initial = self.instance.Tag_set.all()
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.
"""
CHOICES = (('Truck', 'Truck'),('Company', 'Company'),)
Tag = models.ManyToManyField(AbstractEmailUser)
class Meta(AbstractEmailUser.Meta):
swappable = 'AUTH_USER_MODEL'
表格.py:
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."))
CHOICES= (('Truck', 'Truck'),('Company', 'Company'),)
Tag = forms.ChoiceField(choices=CHOICES, label='Tag', widget=forms.RadioSelect())
class Meta:
model = get_user_model()
fields = ('email', 'Tag',)
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.
"""
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=\"password/\">this form</a>."))
class Meta:
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"]
管理员.py:
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', 'Tag')}),
(_('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', 'Tag')
}
),
)
# 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', 'Tag')
search_fields = ('email',)
ordering = ('email',)
filter_horizontal = ('groups', 'user_permissions', 'Tag',)
# Register the new EmailUserAdmin
admin.site.register(EmailUser, EmailUserAdmin)