views:

80

answers:

2

Okay, this one is pretty obvious to everyone who use Django and frequently asked by newbies, but I'd like to make it clear and discuss if there are any other ways to do it. The most widespread and convenient approach now is to store email in username field as Django 1.2 allows "@", "_" and "-" characters, but this way has following issues:

  1. The worst one: username field is restricted by max_length=30 property, which is ridiculously small for emails. Even if you override form validation, DB will have varchar(30) instead of EmailField's varchar(75) unless you alter your table manually.
  2. You need to store your email data both in username and email field to make User.email_user() working. I think there are some other places when User.email is used.
  3. Code readability fail. Sure, other djangonauts know about this pitfall, but treating field called 'username' (especially when there is still email field) as email obviously makes your code less understandable.

The other approach could be authentication using email field by passing it to your auth backend like so, but it still has problems:

authenticate(self, email=None, password=None)
  1. User.email doesn't have unique=True property, which means that your DB won't have index, making your lookups by email slow like hell.
  2. You have to deal with username field, which has unique=True, by completely removing it from your table or altering it to allow NULL and removing index.

Resuming, both ways are evil and require DB-specific code to be executed after syncdb, which is unacceptable if you need DB-independent application.

A: 

Well, I haven't had to use emails as usernames in Django but I guess You could create a UserProfile model and aggregate fields to it, like another email field and make it unique. So you could do user.get_profile().email for your authentication.

I guess other way to go would be to inherit User and redefine the fields, but I think this still not recommended by Django developers.

Finally you could define your own custom User model and back on the django.contrib.auth.models.User for some logic.

Code to alter User table within Django:

 from django.db import connection
 cursor = connection.cursor()
 cursor.execute("ALTER TABLE auth_user MODIFY COLUMN username varchar(75) NOT NULL")
maraujop
The bad thing with multi-table inheritance or modifying local copy of auth app is that there is no way to define what model should other contrib apps like admin, messages or comments use.
Dmitry Gladkov
I understand. I guess adding a new field to the UserProfile is the best way to go if you don't want to follow option 1. Not sure, if there is any other approach to this at the moment.
maraujop
Another thing you could do if you want to be a little bit more DB-independent is add this code (answer edited), with a variable in your settings.py to indicate whether it should execute or it is already modified.
maraujop
+1  A: 

David Cramer came up with a solution to this problem that I love. I'm currently using it on a production site where the user has to be able to log in using their email OR their username. You can find it here:

Logging In With Email Addresses in Django

If the login name provided on the form is an email (contains the '@' symbol), it will attempt to authenticate with that, and will fall back on the username if it isn't an email. (Naturally, you just need to make sure your registration form captures an email for this work.)

Jim McGaw