3

I have added a custom backend to allow a user to log in with a username or email in addition to password. It works fine except when the email is longer than 30 characters. The form error I get is:

"Ensure this value has at most 30 characters (it has 35)."

In one my my apps' urls.py file I've overridden the max_length of the username field like this:

from django.contrib.auth.forms import AuthenticationForm
AuthenticationForm.base_fields['username'].max_length = 75

I've even tried the class_prepared signal technique described here:

http://stackoverflow.com/questions/2610088/can-djangos-auth-user-username-be-varchar75-how-could-that-be-done/2613385#2613385

I'm not sure where I'm going wrong here and I appreciate the help.

asciitaxi
  • 1,369
  • 1
  • 16
  • 16
  • Have you made sure that the username field in the database can hold strings longer than 30 chars? The `class_prepare` signal will only help before you have run syncdb and created the table. Syncdb never alters existing tables. – OmerGertel Nov 06 '10 at 06:09

3 Answers3

4

If your aim is to simply alter the length of the username field for the form (and not to alter the length of the username field in the database), then the correct solution is to subclass AuthenticationForm like so:

from django import forms
from django.contrib.auth.forms import AuthenticationForm

class MyAuthenticationForm(AuthenticationForm):
    username = forms.CharField(label="Username", max_length=75)

In fact, the docstring for AuthenticationForm even says "Base class for authenticating users. Extend this to get a form that accepts username/password logins."

Use your new form in place of the old AuthenticationForm in your templates, views, etc.

As for why your code isn't working, my guess is that your app's urls.py isn't being loaded before the AuthenticationForm is being imported elsewhere. I couldn't swear to that being the reason, but it's the most likely.

Gabriel Hurley
  • 39,690
  • 13
  • 62
  • 88
  • That works great! And the subclassed form can be passed to the login view, so I'm all set. Thanks. – asciitaxi Nov 06 '10 at 10:08
  • Are you guys using django-registration? If so, where did you put the above code? Right now the login form is being auto-generated through that, so i'm not sure where to replace that with this – Brenden Aug 08 '11 at 23:34
0

Best way is this code added to the top level init:

# Added so the login field can take email addresses longer than 30 characters
from django.contrib.auth.forms import AuthenticationForm

AuthenticationForm.base_fields['username'].max_length = 75
AuthenticationForm.base_fields['username'].widget.attrs['maxlength'] = 75
AuthenticationForm.base_fields['username'].validators[0].limit_value = 75

However, if you choose to us @Gabriel Hurley answer above, you can pass it to the login form by using the following code:

(r'^accounts/login/$', 'django.contrib.auth.views.login', {
    'authentication_form': AuthenticationForm
}),
keithhackbarth
  • 9,317
  • 5
  • 28
  • 33
0

My guess: on urls.py use:

from django.contrib.auth.views import login

...

    (r'^accounts/login/$', login),

instead of the "lazy evaluation" form:

(r'^accounts/login/$', 'django.contrib.auth.views.login'),
Paulo Scardine
  • 73,447
  • 11
  • 124
  • 153