क्या अपने स्वयं के प्रमाणीकरण प्रणाली को रोल किए बिना django में ऐसा करने का एक अच्छा तरीका है? मैं चाहता हूं कि उपयोगकर्ता नाम बनाने के बजाय उपयोगकर्ता का ईमेल पता होना चाहिए।
कृपया सलाह दें, धन्यवाद।
जवाबों:
किसी और को ऐसा करने के लिए, मैं django-email-as-username पर एक नज़र डालने की सलाह दूंगा, जो एक बहुत व्यापक समाधान है, जिसमें createsuperuser
अन्य बिट्स और टुकड़ों के बीच व्यवस्थापक और प्रबंधन आदेशों को पैच करना शामिल है ।
संपादित करें : Django 1.5 के बाद आपको django-email-as-username के बजाय एक कस्टम उपयोगकर्ता मॉडल का उपयोग करने पर विचार करना चाहिए ।
यहाँ हम क्या करते हैं। यह एक "पूर्ण" समाधान नहीं है, लेकिन यह वही है जो आप खोज रहे हैं।
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
पता नहीं है कि डिफॉल्ट ऑथेंटिकेशन फॉर्म सेट करने के लिए कुछ सेटिंग है या नहीं, लेकिन आप urls.py में url को ओवरराइड भी कर सकते हैं
url(r'^accounts/login/$', 'django.contrib.auth.views.login', { 'authentication_form': EmailAuthenticationForm }, name='login'),
अमान्य ईमेल सबमिट करने पर ValidationError को उठाना 500 त्रुटियों को रोक देगा। "अमान्य_लगिन" के लिए सुपर की परिभाषा का उपयोग करने से त्रुटि संदेश अस्पष्ट हो जाता है (बनाम एक विशिष्ट "उस ईमेल द्वारा कोई उपयोगकर्ता नहीं मिला"), जिसे लीक होने से रोकने के लिए आवश्यक होगा कि आपकी सेवा पर एक खाते के लिए एक ईमेल पते पर हस्ताक्षर किए जाएं या नहीं। यदि वह जानकारी आपके आर्किटेक्चर में सुरक्षित नहीं है, तो अधिक जानकारीपूर्ण त्रुटि संदेश के लिए मित्रता हो सकती है।
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
forms.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
फ़ील्ड जोड़ा है । इस पेस्ट बिन प्रविष्टि में मैं चाहता था कि क्रियान्वयन दिखे। pastebin.com/W1PgLrD9User
null=True
अन्य विकल्प मेरे लिए बहुत जटिल लगते हैं, इसलिए मैंने एक स्निपेट लिखा जो उपयोगकर्ता नाम, ईमेल या दोनों का उपयोग करके प्रमाणित करने की अनुमति देता है, और केस संवेदनशील को सक्षम या अक्षम भी करता है। मैंने इसे django- दोहरे-प्रमाणीकरण के रूप में पाइप करने के लिए अपलोड किया है ।
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-registration का नवीनतम संस्करण कुछ अच्छे अनुकूलन की अनुमति देता है और यह काम कर सकता है - डॉक्स यहां https://bitbucket.org/ubernostrum/django-registration/src/fad7080fe769/docs/backend-api.rst
आप नीचे दिए गए लिंक पर इस विषय पर एक दिलचस्प चर्चा भी कर सकते हैं:
सबसे आसान तरीका लॉगिन दृश्य में ईमेल के आधार पर उपयोगकर्ता नाम देखना है। इस तरह आप सब कुछ अकेले छोड़ सकते हैं:
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">
और अपने यूज़रनेम / पासवर्ड इनपुट को सही नाम, यानी यूज़रनेम, पासवर्ड दें।
अद्यतन :
वैकल्पिक रूप से, यदि _is_valid_email (ईमेल): कॉल को यूजरनेम में '@' से बदला जा सकता है। इस तरह आप _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>
...
निश्चित नहीं है कि लोग इसे पूरा करने की कोशिश कर रहे हैं, लेकिन मुझे केवल ईमेल करने के लिए अच्छा (और साफ) तरीका मिला और बचत करने से पहले उपयोगकर्ता नाम ईमेल में सेट कर दें।
मेरे उपयोगकर्ता को केवल ईमेल और पासवर्ड की आवश्यकता है:
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()