Email and activation key in django.contrib.auth

922 views
Skip to first unread message

Micah Carrick

unread,
Jan 11, 2011, 8:18:09 PM1/11/11
to django...@googlegroups.com
Hey guys,

I've been looking into this for a few hours now and don't have a good solution. I want to use the built in authentication system for a project. However, it's essential that (a) users login using their email address and password only (no username or username=email) and that (b) they must "activate" their account via email containing an activation key.

This is a VERY common authentication paradigm and I can only assume I'm missing something. I've seen many people with the same problem, however, most responses seem to be hacks or very outdated. I'm relatively new to Django (10 years PHP) and am hoping somebody has a link or a few vocabulary words to point me in the right direction. Obviously I could implement this myself, but, I really want to use the built-in auth system. DRY. I would expect it to be relatively simple... override a few class methods or something along those lines.

Any help would be much appreciated. Thanks!

--
Micah Carrick, Founder

    Green Tackle - Environmentally Friendly Fishing Tackle
    www.GreenTackle.com

     Email: mi...@greentackle.com
     Phone: 971.270.2206
     Toll Free: 877.580.9165
     Fax: 503.946.3106



Shawn Milochik

unread,
Jan 11, 2011, 8:42:10 PM1/11/11
to django...@googlegroups.com
Yes, it's very easy to do.

For the e-mail address as the login, all you have to do is create your own auth backend. That is a LOT simpler than it sounds -- just a few lines of code.


As for the need to activate their account, that's very simply handled in your custom auth backend, since you'll be writing it anyway. Just check for activation status in your custom authenticate function.

Here's my "custom" auth backend. It uses the e-mail address for the login. You'll still have to give the User instance a unique username, but then you can ignore it. You can copy this verbatim and be done, other than "activating" the account, which you can easily work out.


Note: If you can work with the 1.3 beta (and eventually the final release), then you can just use the e-mail address as the username, as they've expanded the allowed characters in the username field of the User model. Chances are you can do that, since 1.3 is scheduled for final release in a few weeks.

Shawn


Micah Carrick

unread,
Jan 12, 2011, 9:44:13 AM1/12/11
to django...@googlegroups.com
Thanks for the great information. I've tinkered with it and it seems to be working pretty good. Still need to make the email unique but all in all a pretty good solution.

What do you think about using django-registration instead? Does anybody know of a pro/con comparison of the built-in auth versus django-registration?

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To post to this group, send email to django...@googlegroups.com.
To unsubscribe from this group, send email to django-users...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/django-users?hl=en.

Shawn Milochik

unread,
Jan 12, 2011, 10:50:49 AM1/12/11
to django...@googlegroups.com
If you're using 1.3, you can make the e-mail address the username, which will automatically require it to be unique.

I haven't used django-registration, but many others have, so maybe they'll be able to answer. On face-value, I'd say that your question is a bit off, though; django-registration doesn't replace the contrib.auth system. It just provides a way for you to create a user-friendly registration system for your users, but it still uses contrib.auth on the backend.

Shawn


Micah Carrick

unread,
Jan 12, 2011, 12:04:00 PM1/12/11
to django...@googlegroups.com
Ah yes, thanks again.

I tinkered with the django-registration and was a bit more than I need.

While the username can store an email address, it's 30 character limit prevents me from relying on that. Looking over an existing database I have, there are quite a few email addresses over that character limit. I suppose I could check if an email exists before saving a user creation form, but I don't like not having that constraint in the DB. Can I alter the DB field at creation with a fixture or something? I guess then I wouldn't have that nice DB abstraction.

I have created the custom auth backend to allow users to sign in with an email address. It works great. I then subclassed the UserCreationForm to add an email address field which also works. In this case, the web users will not need access to the admin so I'm not too concerned about what username shows up there--I could even auto-generate one. So now what I need to do is:

1. Remove the "username" field from my subclassed version of UserCreationForm. Not sure how to do that. I will then create the username in the save() method.
2. Rename the "username" field in the login form to "Email Address". I am using the built-in login view, so I probably will have to write my own view?




Shawn


--
You received this message because you are subscribed to the Google Groups "Django users" group.
To post to this group, send email to django...@googlegroups.com.
To unsubscribe from this group, send email to django-users...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/django-users?hl=en.

Shawn Milochik

unread,
Jan 12, 2011, 12:19:50 PM1/12/11
to django...@googlegroups.com
Without changing or subclassing the User model (which shouldn't be done, because it causes problems), I don't know how you can put the unique e-mail address constraint on the database, except manually via your database's own tool. I don't know if that can cause problems with Django's ORM, and it is probably a very complicated question with answers that differ greatly depending on the database backend and driver being used. So I can't offer any useful info here.

However, on the front end you can certainly override the clean() methods of your fields, and gracefully handle checking of duplicates and user-friendly error messages. I know you like the DB constraints because it's a best-practice, but if no other software will be accessing your database then this is all you'll need.

For your two questions:

You don't need to remove the username from the ModelForm -- just don't include it in the template.
Override the default template (copy the default template and modify your changed version).

To change the label on the template, you can change the 'label' property of the field in your subclassed ModelForm.
Something like this (in the __init__, after calling the __init__ of super():

self.fields['username'].label = 'E-mail Address'


Shawn

Micah Carrick

unread,
Jan 12, 2011, 12:39:33 PM1/12/11
to django...@googlegroups.com
Shawn,

Thank you so very much. This is coming along quite nicely. Your answers have been perfect.



Shawn

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To post to this group, send email to django...@googlegroups.com.
To unsubscribe from this group, send email to django-users...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/django-users?hl=en.

Shawn Milochik

unread,
Jan 12, 2011, 1:00:08 PM1/12/11
to django...@googlegroups.com
You're welcome. Enjoy!

Egor Smolyakov

unread,
Dec 7, 2017, 8:33:29 AM12/7/17
to Django users
I know that topic is old, but I also find a method for this functionality. I don't found so I create it by myself.

See this commit: https://github.com/egorsmkv/simple-django-login-and-register/commit/a8ca21f1a6bb4fa4eacbc4e904d9ce9adebdf576
Reply all
Reply to author
Forward
0 new messages