Itās very common for websites today to basically make usersā e-mail the username, or at least make it an āalternative usernameā. For instance, when I log in using github, I can input āusername or e-mailā.
Django is more old school in that the default User model is built on the assumption that everyone has a username or a password, while everything else is more or less optional. Since the username is what primarily identifies the user it makes sense for the email field to not enforce the UNIQUE constraint. Someone who has a single e-mail might want to have multiple user accounts for instance. If you listen to the podcast Django chat this comes up now and then - Iām not sure, but it might be discussed in their authentication episode among others.
If we look in Djangoās codebase, it actually spells this out explicitly for us:
# django/contrib/auth/models.py
class AbstractUser(AbstractBaseUser, PermissionsMixin):
"""
An abstract base class implementing a fully featured User model with
admin-compliant permissions.
Username and password are required. Other fields are optional.
"""
username_validator = UnicodeUsernameValidator()
username = models.CharField(
_('username'),
max_length=150,
unique=True,
help_text=_('Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.'),
validators=[username_validator],
error_messages={
'unique': _("A user with that username already exists."),
},
)
first_name = models.CharField(_('first name'), max_length=30, blank=True)
last_name = models.CharField(_('last name'), max_length=150, blank=True)
email = models.EmailField(_('email address'), blank=True) # nothing about unique here
is_staff = models.BooleanField(
_('staff status'),
default=False,
help_text=_('Designates whether the user can log into this admin site.'),
)
is_active = models.BooleanField(
_('active'),
default=True,
help_text=_(
'Designates whether this user should be treated as active. '
'Unselect this instead of deleting accounts.'
),
)
date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
# ...
class User(AbstractUser):
"""
Users within the Django authentication system are represented by this
model.
Username and password are required. Other fields are optional.
"""
class Meta(AbstractUser.Meta):
swappable = 'AUTH_USER_MODEL'
There are different opinions on how to deal with this nowadays, as you can hear on the podcast I mentioned. wsvincent, one of the co-hosts, mostly advocates creating a custom user model, with this issue being one of his most important reasons for doing so. You can take a look at his guide on extending the User model and/or take a look at his DjangoX project which is āan open-source Django starter framework that includes a custom user model, email/password by default instead of username/email/password, social authentication, and more.ā. I tried cloning the project and something that strikes me as odd is that even though emails are handled with a separate SQL table, the āemailā field is still in the usual user table, which as far as I understand is completely unnecessary. Maybe removing it is too convoluted a process to fit the straightforward approach of DjangoX? Either way, you could try getting some inspiration from DjangoX.
I see how hackers can exploit it. Maybe.
I donāt think thatās necessarily the case, it depends more on what you do with the website and what you allow users to do/change when it comes to user settings. As long as you donāt assume that users with the same e-mail address are the same person (unless you add e. g. e-mail verification) Iām guessing youāll be fine. Maybe Iām missing something though.