Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django- how to use built-in login view with email instead of username?

I am using built-in login in my app. There is some custom backends or packages to handle this. but many of them are not what i am looking.

i made email unique via django-registration while registering. now all i want is to ask email in login page instead of username.

but if i use some custom backends like django email as username it crashes when using with django-registration.

i dont want to change all authentication backend , i just want to change login page.

in the rest of site , i am gonna use username. p.e in my custom admin page when i write:

welcome {{user}}

it must render username. not e-mail.

i need to find the way out from this. i am stuck.

thank you.

like image 963
alioguzhan Avatar asked Nov 18 '12 12:11

alioguzhan


2 Answers

The above approach does not work anymore on django 1.9. A different approach might be to override the auth form used in the view as:

class EmailLoginForm(AuthenticationForm):
def clean(self):
    try:
        self.cleaned_data["username"] = get_user_model().objects.get(email=self.data["username"])
    except ObjectDoesNotExist:
        self.cleaned_data["username"] = "a_username_that_do_not_exists_anywhere_in_the_site"
    return super(EmailLoginForm, self).clean()

Then when defining the login url, define as this:

url(r'^login/$', django.contrib.auth.views.login, name="login", kwargs={"authentication_form": EmailLoginForm}),
url(r'^', include('django.contrib.auth.urls')),

The best thing about the above approach you are not really touching anything in the auth process. It's not really a "clean" solution but it's a quick workaround. As you define the login path before including auth.urls, it will be evaluated instead of the base login form

like image 21
radalin Avatar answered Oct 24 '22 15:10

radalin


By default django.contrib.auth.urls will create a log in page from this pattern

(r'^login/$', 'django.contrib.auth.views.login'),

You need to avoid/override this url then create a new view to handle a new type of login.

e.g.

create a new login url in your urls.py

(r'^emaillogin/$', 'email_login_view'),

create view to support login with email in views.py

# get default authenticate backend
from django.contrib.auth import authenticate, login
from django.contrib.auth.models import User

# create a function to resolve email to username
def get_user(email):
    try:
        return User.objects.get(email=email.lower())
    except User.DoesNotExist:
        return None

# create a view that authenticate user with email
def email_login_view(request):
    email = request.POST['email']
    password = request.POST['password']
    username = get_user(email)
    user = authenticate(username=username, password=password)
    if user is not None:
        if user.is_active:
            login(request, user)
            # Redirect to a success page.
        else:
            # Return a 'disabled account' error message
    else:
        # Return an 'invalid login' error message.

Ref : https://docs.djangoproject.com/en/1.4/topics/auth/#django.contrib.auth.login

like image 124
Pattapong J Avatar answered Oct 24 '22 14:10

Pattapong J