Question

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.

Was it helpful?

Solution

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

OTHER TIPS

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

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top