มีวิธีที่ดีในการทำสิ่งนี้ใน django โดยไม่ต้องใช้ระบบการตรวจสอบสิทธิ์ของฉันเอง ฉันต้องการให้ชื่อผู้ใช้เป็นที่อยู่อีเมลของผู้ใช้แทนการสร้างชื่อผู้ใช้
กรุณาแนะนำขอบคุณ
มีวิธีที่ดีในการทำสิ่งนี้ใน django โดยไม่ต้องใช้ระบบการตรวจสอบสิทธิ์ของฉันเอง ฉันต้องการให้ชื่อผู้ใช้เป็นที่อยู่อีเมลของผู้ใช้แทนการสร้างชื่อผู้ใช้
กรุณาแนะนำขอบคุณ
คำตอบ:
สำหรับใครก็ตามที่ต้องการทำเช่นนี้ฉันขอแนะนำให้ดูdjango-email-as-usernameซึ่งเป็นวิธีแก้ปัญหาที่ค่อนข้างครอบคลุมซึ่งรวมถึงการแก้ไขผู้ดูแลระบบและcreatesuperuser
คำสั่งการจัดการรวมถึงบิตและส่วนอื่น ๆ
แก้ไข : ณ Django 1.5 เป็นต้นไปคุณควรพิจารณาการใช้รูปแบบการใช้ที่กำหนดเองแทนDjango อีเมล as-ชื่อผู้ใช้
นี่คือสิ่งที่เราทำ ไม่ใช่โซลูชันที่ "สมบูรณ์" แต่ทำสิ่งที่คุณกำลังมองหาได้มาก
from django import forms
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
class UserForm(forms.ModelForm):
class Meta:
model = User
exclude = ('email',)
username = forms.EmailField(max_length=64,
help_text="The person's email address.")
def clean_email(self):
email = self.cleaned_data['username']
return email
class UserAdmin(UserAdmin):
form = UserForm
list_display = ('email', 'first_name', 'last_name', 'is_staff')
list_filter = ('is_staff',)
search_fields = ('email',)
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
นี่เป็นวิธีหนึ่งในการดำเนินการเพื่อให้ยอมรับทั้งชื่อผู้ใช้และอีเมล:
from django.contrib.auth.forms import AuthenticationForm
from django.contrib.auth.models import User
from django.core.exceptions import ObjectDoesNotExist
from django.forms import ValidationError
class EmailAuthenticationForm(AuthenticationForm):
def clean_username(self):
username = self.data['username']
if '@' in username:
try:
username = User.objects.get(email=username).username
except ObjectDoesNotExist:
raise ValidationError(
self.error_messages['invalid_login'],
code='invalid_login',
params={'username':self.username_field.verbose_name},
)
return username
ไม่ทราบว่ามีการตั้งค่าบางอย่างเพื่อตั้งค่ารูปแบบการรับรองความถูกต้องเริ่มต้น แต่คุณสามารถแทนที่ url ใน urls.py ได้
url(r'^accounts/login/$', 'django.contrib.auth.views.login', { 'authentication_form': EmailAuthenticationForm }, name='login'),
การเพิ่ม ValidationError จะป้องกันข้อผิดพลาด 500 รายการเมื่อมีการส่งอีเมลที่ไม่ถูกต้อง การใช้คำจำกัดความของ super สำหรับ "invalid_login" ทำให้ข้อความแสดงข้อผิดพลาดไม่ชัดเจน (เทียบกับ "ไม่พบผู้ใช้โดยอีเมลนั้น") ซึ่งจะต้องมีเพื่อป้องกันการรั่วไหลไม่ว่าจะมีการลงชื่อสมัครใช้ที่อยู่อีเมลสำหรับบัญชีในบริการของคุณหรือไม่ หากข้อมูลนั้นไม่ปลอดภัยในสถาปัตยกรรมของคุณอาจเป็นมิตรกว่าหากมีข้อความแสดงข้อผิดพลาดที่ให้ข้อมูลเพิ่มเติม
ขณะนี้ Django มีตัวอย่างเต็มรูปแบบของระบบการตรวจสอบสิทธิ์แบบขยายพร้อมผู้ดูแลระบบและแบบฟอร์ม: https://docs.djangoproject.com/en/stable/topics/auth/customizing/#a-full-example
โดยทั่วไปคุณสามารถคัดลอก / วางและปรับเปลี่ยนได้ (ฉันไม่ต้องการdate_of_birth
ในกรณีของฉัน)
มีให้ใช้งานจริงตั้งแต่ Django 1.5 และยังคงมีให้บริการ ณ ตอนนี้ (django 1.7)
หากคุณจะขยายรูปแบบผู้ใช้คุณจะต้องใช้โมเดลผู้ใช้ที่กำหนดเองอยู่ดี
นี่คือตัวอย่างของ Django 1.8 Django 1.7 ต้องการการทำงานเพิ่มขึ้นเล็กน้อยโดยส่วนใหญ่จะเปลี่ยนรูปแบบเริ่มต้น (ลองดูที่UserChangeForm
& UserCreationForm
ในdjango.contrib.auth.forms
นั่นคือสิ่งที่คุณต้องการใน 1.7)
user_manager.py:
from django.contrib.auth.models import BaseUserManager
from django.utils import timezone
class SiteUserManager(BaseUserManager):
def create_user(self, email, password=None, **extra_fields):
today = timezone.now()
if not email:
raise ValueError('The given email address must be set')
email = SiteUserManager.normalize_email(email)
user = self.model(email=email,
is_staff=False, is_active=True, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, password, **extra_fields):
u = self.create_user(email, password, **extra_fields)
u.is_staff = True
u.is_active = True
u.is_superuser = True
u.save(using=self._db)
return u
Models.py:
from mainsite.user_manager import SiteUserManager
from django.contrib.auth.models import AbstractBaseUser
from django.contrib.auth.models import PermissionsMixin
class SiteUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True, blank=False)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
USERNAME_FIELD = 'email'
objects = SiteUserManager()
def get_full_name(self):
return self.email
def get_short_name(self):
return self.email
form.py:
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.forms import UserChangeForm, UserCreationForm
from mainsite.models import SiteUser
class MyUserCreationForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = SiteUser
fields = ("email",)
class MyUserChangeForm(UserChangeForm):
class Meta(UserChangeForm.Meta):
model = SiteUser
class MyUserAdmin(UserAdmin):
form = MyUserChangeForm
add_form = MyUserCreationForm
fieldsets = (
(None, {'fields': ('email', 'password',)}),
('Permissions', {'fields': ('is_active', 'is_staff', 'is_superuser',)}),
('Groups', {'fields': ('groups', 'user_permissions',)}),
)
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('email', 'password1', 'password2')}
),
)
list_display = ('email', )
list_filter = ('is_active', )
search_fields = ('email',)
ordering = ('email',)
admin.site.register(SiteUser, MyUserAdmin)
settings.py:
AUTH_USER_MODEL = 'mainsite.SiteUser'
username
ฟิลด์ลงในSiteUser
โมเดลเพราะเมื่อฉันดำเนินการpython manage.py makemigrations ...
คำสั่งฉันจะได้ผลลัพธ์นี้:ERRORS: <class 'accounts.admin.UserAdmin'>: (admin.E033) The value of 'ordering[0]' refers to 'username', which is not an attribute of 'accounts.User'.
username
ฟิลด์ในUser
โมเดลของฉันด้วยnull=True
แอตทริบิวต์ ในรายการวางถังนี้ฉันต้องการแสดงการใช้งาน pastebin.com/W1PgLrD9
ทางเลือกอื่นดูซับซ้อนเกินไปสำหรับฉันดังนั้นฉันจึงเขียนตัวอย่างข้อมูลที่อนุญาตให้ตรวจสอบสิทธิ์โดยใช้ชื่อผู้ใช้อีเมลหรือทั้งสองอย่างและยังเปิดหรือปิดใช้ตัวพิมพ์เล็กและใหญ่ ผมอัปโหลดไปยัง pip เป็นDjango-dual-รับรองความถูกต้อง
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth import get_user_model
from django.conf import settings
###################################
""" DEFAULT SETTINGS + ALIAS """
###################################
try:
am = settings.AUTHENTICATION_METHOD
except:
am = 'both'
try:
cs = settings.AUTHENTICATION_CASE_SENSITIVE
except:
cs = 'both'
#####################
""" EXCEPTIONS """
#####################
VALID_AM = ['username', 'email', 'both']
VALID_CS = ['username', 'email', 'both', 'none']
if (am not in VALID_AM):
raise Exception("Invalid value for AUTHENTICATION_METHOD in project "
"settings. Use 'username','email', or 'both'.")
if (cs not in VALID_CS):
raise Exception("Invalid value for AUTHENTICATION_CASE_SENSITIVE in project "
"settings. Use 'username','email', 'both' or 'none'.")
############################
""" OVERRIDDEN METHODS """
############################
class DualAuthentication(ModelBackend):
"""
This is a ModelBacked that allows authentication
with either a username or an email address.
"""
def authenticate(self, username=None, password=None):
UserModel = get_user_model()
try:
if ((am == 'email') or (am == 'both')):
if ((cs == 'email') or cs == 'both'):
kwargs = {'email': username}
else:
kwargs = {'email__iexact': username}
user = UserModel.objects.get(**kwargs)
else:
raise
except:
if ((am == 'username') or (am == 'both')):
if ((cs == 'username') or cs == 'both'):
kwargs = {'username': username}
else:
kwargs = {'username__iexact': username}
user = UserModel.objects.get(**kwargs)
finally:
try:
if user.check_password(password):
return user
except:
# Run the default password hasher once to reduce the timing
# difference between an existing and a non-existing user.
UserModel().set_password(password)
return None
def get_user(self, username):
UserModel = get_user_model()
try:
return UserModel.objects.get(pk=username)
except UserModel.DoesNotExist:
return None
การลงทะเบียน django เวอร์ชันล่าสุดช่วยให้สามารถปรับแต่งได้ดีและอาจทำงานได้ - เอกสารที่นี่https://bitbucket.org/ubernostrum/django-registration/src/fad7080fe769/docs/backend-api.rst
if user_form.is_valid():
# Save the user's form data to a user object without committing.
user = user_form.save(commit=False)
user.set_password(user.password)
#Set username of user as the email
user.username = user.email
#commit
user.save()
ทำงานได้อย่างสมบูรณ์แบบ ... สำหรับ django 1.11.4
คุณยังสามารถค้นหาการสนทนาที่น่าสนใจในหัวข้อนี้ได้ที่ลิงค์ด้านล่าง:
วิธีที่ง่ายที่สุดคือค้นหาชื่อผู้ใช้ตามอีเมลในมุมมองการเข้าสู่ระบบ ด้วยวิธีนี้คุณสามารถปล่อยทุกสิ่งทุกอย่างไว้ตามลำพัง:
from django.contrib.auth import authenticate, login as auth_login
def _is_valid_email(email):
from django.core.validators import validate_email
from django.core.exceptions import ValidationError
try:
validate_email(email)
return True
except ValidationError:
return False
def login(request):
next = request.GET.get('next', '/')
if request.method == 'POST':
username = request.POST['username'].lower() # case insensitivity
password = request.POST['password']
if _is_valid_email(username):
try:
username = User.objects.filter(email=username).values_list('username', flat=True)
except User.DoesNotExist:
username = None
kwargs = {'username': username, 'password': password}
user = authenticate(**kwargs)
if user is not None:
if user.is_active:
auth_login(request, user)
return redirect(next or '/')
else:
messages.info(request, "<stvrong>Error</strong> User account has not been activated..")
else:
messages.info(request, "<strong>Error</strong> Username or password was incorrect.")
return render_to_response('accounts/login.html', {}, context_instance=RequestContext(request))
ในเทมเพลตของคุณให้ตั้งค่าตัวแปรถัดไปตามนั้นเช่น
<form method="post" class="form-login" action="{% url 'login' %}?next={{ request.GET.next }}" accept-charset="UTF-8">
และป้อนชื่อผู้ใช้ / รหัสผ่านของคุณชื่อที่ถูกต้องเช่นชื่อผู้ใช้รหัสผ่าน
อัพเดท :
หรืออีกวิธีหนึ่ง if _is_valid_email (email): call สามารถแทนที่ด้วย if "@" ในชื่อผู้ใช้ ด้วยวิธีนี้คุณสามารถวางฟังก์ชัน _is_valid_email สิ่งนี้ขึ้นอยู่กับว่าคุณกำหนดชื่อผู้ใช้ของคุณอย่างไร จะใช้ไม่ได้หากคุณอนุญาตให้ใช้อักขระ "@" ในชื่อผู้ใช้ของคุณ
ฉันคิดว่าวิธีที่เร็วที่สุดคือการสร้างแบบฟอร์มที่สืบทอดมาจากUserCreateForm
นั้นจึงแทนที่username
ฟิลด์ด้วยforms.EmailField
สนามจากนั้นสำหรับผู้ใช้ที่ลงทะเบียนใหม่ทุกคนจะต้องลงชื่อเข้าใช้ด้วยที่อยู่อีเมลของตน
ตัวอย่างเช่น:
urls.py
...
urlpatterns += url(r'^signon/$', SignonView.as_view(), name="signon")
views.py
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
from django import forms
class UserSignonForm(UserCreationForm):
username = forms.EmailField()
class SignonView(CreateView):
template_name = "registration/signon.html"
model = User
form_class = UserSignonForm
signon.html
...
<form action="#" method="post">
...
<input type="email" name="username" />
...
</form>
...
UserCreationForm
คลาสได้โดยตรง และไม่แนะนำให้เขียนออกมาว่า<input …
เมื่อไร{{form.username}}
จะดีกว่าอย่างแน่นอน
ไม่แน่ใจว่ามีคนพยายามทำสิ่งนี้หรือไม่ แต่ฉันพบวิธีที่ดี (และสะอาด) ในการขออีเมลเท่านั้นจากนั้นตั้งชื่อผู้ใช้เป็นอีเมลในมุมมองก่อนบันทึก
UserForm ของฉันต้องการอีเมลและรหัสผ่านเท่านั้น:
class UserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput())
class Meta:
model = User
fields = ('email', 'password')
จากนั้นในมุมมองของฉันฉันเพิ่มตรรกะต่อไปนี้:
if user_form.is_valid():
# Save the user's form data to a user object without committing.
user = user_form.save(commit=False)
user.set_password(user.password)
#Set username of user as the email
user.username = user.email
#commit
user.save()