If you are new to Django-Allauth, checkout one of the many tutorials. The docs are pretty good too.
These are my notes for setting up Django-Allauth to do the following:
- All users will use their email address as their username
- Users will have the option of manually entering their email and password or using a social account for both login and signup.
- The web forms will be based on Bootstrap
Here are the settings options to make that happen:
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_USERNAME_REQUIRED = False
ACCOUNT_AUTHENTICATION_METHOD = 'email'
ACCOUNT_EMAIL_VERIFICATION = 'mandatory'
SOCIALACCOUNT_EMAIL_VERIFICATION = 'none'
Login is pretty straight forward. All-Auth makes it easy to add buttons to login with social accounts (e.g. “Login using Google”, etc…). What is less obvious is how to signup using social authentication. If you use the settings above, Allauth social authentication login will create a new user if that user’s email is not already in the system. Signup is not necessary. For me, that was the missing piece.
Django-Allauth is extendable is just about every dimension you can imagine. Maybe that is part of what makes it difficult to use; there are some many options, it’s difficult to decide which ones you need/want. One thing I wanted to do was replace the Allauth templates with one of my own. Django has built in functionality for over-riding templates. Allauth uses that. To create your own login and signup templates, just add an folder called “account” to your main templates folder. In that folder, put “login.html” and “signup.html”. You may also want to add “base.html”.
Here is a snippet for sending an attachment by email in Django:
from django.core.mail import EmailMessage
def send_mail_w_attachment(to, subject, message, attachment_path,
:param to: a list of email addresses
:param subject: a string
:param message: a string
:param attachment_path: full path to attachment fil
email = EmailMessage(subject, message, to=to)
# Load file and Base64 encode
file_name = os.path.basename(attachment_path)
data = open(attachment_path, 'rb').read()
encoded = base64.b64encode(data)
email.attach(file_name, encoded, mimetype=mimetype)
# Send it
I just started using Django-AllAuth. I chose it because it supports “normal” login as well as Oauth based login.
For “normal” login, I have switched to using email address as the username. In general, people do not like having to think up a username and they do not remember it. Email is already unique and easier to remember because the user uses it all the time.
AllAuth says it can do email based logins. But how? Turns out its just a setting:
ACCOUNT_AUTHENTICATION_METHOD = “email”
For at least a year we have known that Django 1.5 would contain functionality to significantly alter the User model. For years, I thought I wanted to get rid of the Django User.username field and have email be the username. A few versions back, Django changed the username to allow the char @, which made it possible to put an email address in the username. Not a bad hack. I just modified the save method to copy the email into the username field. Now with Django 1.5 we don’t have to do that. But maybe I still want to…
Many years ago, I first considered using the email address as a username. I was motivated by the number of users who hand trouble logging in. A surprising number forgot their username. Email as username seemed like a good way to solve that problem. Not everyone was on board with this change. One objection was that some people share email addresses, thus they could not have individual accounts on our system. I think that problem is so rare, its worth ignoring. The other objection was that if there is something like a discussion board or messaging on the website, some users will not want their email displayed. This seems like a reasonable objection. Maybe even more so today.
So now that I can get rid of the User.username, I am not going to. With the exception of over-riding some of the methods, I am going to stick with the default Django User model.Since I am just over-riding methods, I will use a proxy model of User. Here’s how it will work:
When a new user is created, if a username is not specified, email address will be copied into the username field on save. Although its not completely DRY, this process will be done in forms because username is still a required field. Update: as of Django 1.5 the username is limited to 30 chars. Its not uncommon for a email address to exceed 30 chars. Thus not all usernames can be set to the email address. Thus is does not make sense to make any usernames be email addresses. I think the solution to this is to set the username to a unique random string.
- Users can edit their username to be whatever they want (but it still must be unique)
- I am using a custom authentication backend that allows users to login with either their username or email address. For more info, check out this blog post.
I was also considering adding some new fields to the User model, but the Django documentation convinced me to put those fields in another model with User as a foreign key. The reason for this is that User is a foreign key in lots of models. If you mess up a migration of User, lots of things will break. By putting those fields in another model, adding or removing fields is much less likely to break everything. This is similar to the UserProfile functionality in previous versions of Django. That functionality is deprecated in Django 1.5. With Django 1.5, this mechanism is normalized to be like any other one-to-one relationship.