Django में उपयोगकर्ता नाम के रूप में ईमेल पता स्वीकार करना


84

क्या अपने स्वयं के प्रमाणीकरण प्रणाली को रोल किए बिना django में ऐसा करने का एक अच्छा तरीका है? मैं चाहता हूं कि उपयोगकर्ता नाम बनाने के बजाय उपयोगकर्ता का ईमेल पता होना चाहिए।

कृपया सलाह दें, धन्यवाद।


डुप्लिकेट: stackoverflow.com/questions/704168/…
S.Lott

जवाबों:


35

किसी और को ऐसा करने के लिए, मैं django-email-as-username पर एक नज़र डालने की सलाह दूंगा, जो एक बहुत व्यापक समाधान है, जिसमें createsuperuserअन्य बिट्स और टुकड़ों के बीच व्यवस्थापक और प्रबंधन आदेशों को पैच करना शामिल है ।

संपादित करें : Django 1.5 के बाद आपको django-email-as-username के बजाय एक कस्टम उपयोगकर्ता मॉडल का उपयोग करने पर विचार करना चाहिए ।


3
यदि आप तय करते हैं कि एक कस्टम उपयोगकर्ता मॉडल सबसे अच्छा विकल्प है, तो आप इस ट्यूटोरियल को काकटस समूह ब्लॉग पर जांचना चाहते हैं , यह django डॉक्स में दिए गए इस उदाहरण से मिलता जुलता है लेकिन उत्पादन वातावरण के लिए आवश्यक कुछ विवरणों की देखभाल करता है (जैसे)।
गाबोरोनकिएनो

4
Django 1.5 और इसके बाद के संस्करण के लिए, django-custom-user ऐप में एक डिब्बाबंद कस्टम उपयोगकर्ता मॉडल है जो इसे लागू करता है।
जोश केली

29

यहाँ हम क्या करते हैं। यह एक "पूर्ण" समाधान नहीं है, लेकिन यह वही है जो आप खोज रहे हैं।

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)

मेरे लिये कार्य करता है। हालांकि मैं इसे भविष्य के रखरखाव के लिए भ्रमित होने वाला देख सकता हूं।
निक बोल्टन

यह शायद सबसे चतुर जवाब है जो मैंने एसओ में देखा है।
एम्मेट बी

on व्यवस्थापक बनाएं उपयोगकर्ता इसे बनाएं: = ('ईमेल') बाहर रखें, मुझे एक त्रुटि है कि कुंजी ['ईमेल'] UserForm से गायब है, यह स्पष्ट है।
CristiC777

22

यहां ऐसा करने का एक तरीका है ताकि उपयोगकर्ता नाम और ईमेल दोनों स्वीकार किए जाएं:

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 त्रुटियों को रोक देगा। "अमान्य_लगिन" के लिए सुपर की परिभाषा का उपयोग करने से त्रुटि संदेश अस्पष्ट हो जाता है (बनाम एक विशिष्ट "उस ईमेल द्वारा कोई उपयोगकर्ता नहीं मिला"), जिसे लीक होने से रोकने के लिए आवश्यक होगा कि आपकी सेवा पर एक खाते के लिए एक ईमेल पते पर हस्ताक्षर किए जाएं या नहीं। यदि वह जानकारी आपके आर्किटेक्चर में सुरक्षित नहीं है, तो अधिक जानकारीपूर्ण त्रुटि संदेश के लिए मित्रता हो सकती है।


मैं Cort.views.login का उपयोग नहीं कर रहा हूं। कस्टम का उपयोग करना यह मेरा url url (r'accounts / login ',' login_view ')) है। अगर मैं EmailAuthenticationForm दे रहा हूं, तो त्रुटि login_view () को एक अप्रत्याशित कीवर्ड तर्क 'प्रमाणीकरण_रूप' मिला
राजा साइमन

यह मेरे लिए सफाई से काम करता है, मैंने वास्तव में अपने कस्टम उपयोगकर्ता प्रोफ़ाइल का उपयोग किया है (क्योंकि मेरी वास्तुकला में उपयोगकर्ता को ईमेल पते को संलग्न करने की गारंटी नहीं है)। उपयोगकर्ता मॉडल को कस्टमाइज़ करने या उपयोगकर्ता नाम के बराबर उपयोगकर्ता बनाने से बहुत अच्छा लगता है (उदाहरण के लिए उपयोगकर्ता नाम उजागर करते समय मित्र के ईमेल को निजी रखने की अनुमति देता है)।
ओवेनफी

8

Django अब व्यवस्थापक और फ़ॉर्म के साथ विस्तारित प्रमाणीकरण प्रणाली का एक पूरा उदाहरण प्रदान करता है: https://docs.djangoproject.com/en/stable/topics/auth/customizing/#a-full-example

आप मूल रूप से इसे कॉपी / पेस्ट कर सकते हैं और अनुकूलित कर सकते हैं (मुझे date_of_birthमेरे मामले में इसकी आवश्यकता नहीं थी )।

यह वास्तव में Django 1.5 के बाद से उपलब्ध है और अब भी उपलब्ध है (django 1.7)।


मैं djangoproject ट्यूटोरियल का पालन करता हूं और यह पूरी तरह से काम करता है
Evhz

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'.
bgarcial

मैंने उनकी विशेषता के साथ अपने मॉडल में usernameफ़ील्ड जोड़ा है । इस पेस्ट बिन प्रविष्टि में मैं चाहता था कि क्रियान्वयन दिखे। pastebin.com/W1PgLrD9Usernull=True
bgarcial

2

अन्य विकल्प मेरे लिए बहुत जटिल लगते हैं, इसलिए मैंने एक स्निपेट लिखा जो उपयोगकर्ता नाम, ईमेल या दोनों का उपयोग करके प्रमाणित करने की अनुमति देता है, और केस संवेदनशील को सक्षम या अक्षम भी करता है। मैंने इसे 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


1
     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



0

सबसे आसान तरीका लॉगिन दृश्य में ईमेल के आधार पर उपयोगकर्ता नाम देखना है। इस तरह आप सब कुछ अकेले छोड़ सकते हैं:

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 फ़ंक्शन को छोड़ सकते हैं। यह वास्तव में इस बात पर निर्भर करता है कि आप अपने उपयोगकर्ता नाम को कैसे परिभाषित करते हैं। यदि आप अपने उपयोगकर्ता नाम में '@' वर्ण की अनुमति देते हैं तो यह काम नहीं करेगा।


1
यह कोड छोटी गाड़ी है, क्योंकि उपयोगकर्ता नाम में '@' चिन्ह भी हो सकता है, इसलिए यदि '@' मौजूद है, तो यह आवश्यक नहीं है कि कोई ईमेल हो।
Mrssn

वास्तव में आप पर निर्भर करता है, मैं उपयोगकर्ता नाम @ प्रतीक के लिए अनुमति नहीं है। यदि आप करते हैं तो उपयोगकर्ता नाम से उपयोगकर्ता द्वारा खोज के लिए एक और फ़िल्टर क्वेरी जोड़ सकते हैं। पुनश्च। उपयोगकर्ता नाम एक ईमेल भी हो सकता है, इसलिए आपको सावधान रहना होगा कि आप अपने उपयोगकर्ता प्रबंधन को कैसे डिज़ाइन करते हैं।
राडेक

Django.core.validators से सत्यापन करें आप ValidationError ब्लॉक को validate_email ('your@email.com ') के अलावा आज़मा सकते हैं। यह अभी भी आपके ऐप के आधार पर छोटी गाड़ी हो सकती है।
राडेक

बेशक, आप सही हैं, यह इस बात पर निर्भर करता है कि लॉगिन तर्क कैसे सेट किया गया है। मैंने उल्लेख किया है कि क्योंकि यूज़रनेम में '@' की संभावना django की डिफ़ॉल्ट है। कोई व्यक्ति आपके कोड को कॉपी कर सकता है और समस्या हो सकती है जब उपयोगकर्ता नाम 'Gladi @ tor' लॉगिन नहीं कर सकता क्योंकि लॉगिन कोड को लगता है कि यह एक ईमेल है।
Mrssn

अच्छा निर्णय। मुझे आशा है कि लोग समझते हैं कि यह क्या है वे नकल कर रहे हैं। मैं ईमेल सत्यापन में जोड़ूंगा और वर्तमान सत्यापन पर टिप्पणी करूंगा, इसे एक विकल्प के रूप में छोड़ दें। मुझे लगता है कि मेरे उपयोगकर्ता नाम @ के अलावा सत्यापन का उपयोग न करने का एकमात्र अन्य कारण मुझे लगता है कि यह कोड को django पर कम निर्भर बनाता है। चीजें एक संस्करण से दूसरे संस्करण में घूमती रहती हैं। चीयर्स!
राडटेक

0

मुझे लगता है कि सबसे तेज़ी से तरीका है कि आप एक इनहेरिट फॉर्म बनाएँ 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}}बेहतर है।
जोनास जी।

0

निश्चित नहीं है कि लोग इसे पूरा करने की कोशिश कर रहे हैं, लेकिन मुझे केवल ईमेल करने के लिए अच्छा (और साफ) तरीका मिला और बचत करने से पहले उपयोगकर्ता नाम ईमेल में सेट कर दें।

मेरे उपयोगकर्ता को केवल ईमेल और पासवर्ड की आवश्यकता है:

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()

1
उपयोगकर्ता नाम ईमेल में संग्रहीत नहीं कर सका क्योंकि समस्याएँ हैं क्योंकि उपयोगकर्ता नाम 30 वर्ण है जबकि ईमेल 75 वर्ण है?
user2233706
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.