138

I want django to authenticate users via email, not via usernames. One way can be providing email value as username value, but I dont want that. Reason being, I've a url /profile/<username>/, hence I cannot have a url /profile/[email protected]/.

Another reason being that all emails are unique, but it happen sometimes that the username is already being taken. Hence I'm auto-creating the username as fullName_ID.

How can I just change let Django authenticate with email?

This is how I create a user.

username = `abcd28` user_email = `[email protected]` user = User.objects.create_user(username, user_email, user_pass) 

This is how I login.

email = request.POST['email'] password = request.POST['password'] username = User.objects.get(email=email.lower()).username user = authenticate(username=username, password=password) login(request, user) 

Is there any other of of login apart from getting the username first?

1

20 Answers 20

152

You should write a custom authentication backend. Something like this will work:

from django.contrib.auth import get_user_model from django.contrib.auth.backends import ModelBackend class EmailBackend(ModelBackend): def authenticate(self, request, username=None, password=None, **kwargs): UserModel = get_user_model() try: user = UserModel.objects.get(email=username) except UserModel.DoesNotExist: return None else: if user.check_password(password): return user return None 

Then, set that backend as your auth backend in your settings:

AUTHENTICATION_BACKENDS = ['path.to.auth.module.EmailBackend'] 

Updated. Inherit from ModelBackend as it implements methods like get_user() already.

See docs here: https://docs.djangoproject.com/en/3.0/topics/auth/customizing/#writing-an-authentication-backend

Sign up to request clarification or add additional context in comments.

19 Comments

Using django 1.9.8 I've got an error: 'EmailBackend' object has no attribute 'get_user'. Solved by adding 'get_user' method according to this stackoverflow.com/a/13954358/2647009
Please specify for which Django version this code can work. Some are complaining about the get_user method missing.
Rather than just if user.check_password(password): you probably want to include what Django does by default via ModelBackend: if user.check_password(password) and self.user_can_authenticate(user): in order to check that the user has is_active=True.
Isn't this vulnerable to a timing attack as it doesn't include the Django mitigation on the source code?
@AzharUddinSheikh It's vulnerable to a timing attack as per my answer; if the user is not found it won't check the password which doesn't run the hashing algorithm which will result in a faster response, so if the attacker gets a response that takes longer than usual means the user exists (as it had to check the password which involves a hash function). My response, which is the way Django implemented on their code (as per my answer), will always hash the password, obfuscating any timing information.
|
94

If you’re starting a new project, django highly recommended you to set up a custom user model. (see https://docs.djangoproject.com/en/dev/topics/auth/customizing/#using-a-custom-user-model-when-starting-a-project)

and if you did it, add three lines to your user model:

class MyUser(AbstractUser): USERNAME_FIELD = 'email' email = models.EmailField(_('email address'), unique=True) # changes email to unique and blank to false REQUIRED_FIELDS = [] # removes email from REQUIRED_FIELDS 

Then authenticate(email=email, password=password) works, while authenticate(username=username, password=password) stops working.

5 Comments

When running createsuperuser, this itself throws an error: TypeError: create_superuser() missing 1 required positional argument: 'username'. You need to use custom user manager: class MyUserManager(BaseUserManager): def create_superuser(self, email, password, **kwargs): user = self.model(email=email, is_staff=True, is_superuser=True, **kwargs) user.set_password(password) user.save() return user
Complete instructions here: fomfus.com/articles/…
Then again, the Django docs advise against using a custom user model if you are creating a reusable app.
isn't this solution very long
@AzharUddinSheikh In other solutions, you'll end up with an improper admin section.
38

Email authentication for Django 3.x

For using email/username and password for authentication instead of the default username and password authentication, we need to override two methods of ModelBackend class: authenticate() and get_user():

The get_user method takes a user_id – which could be a username, database ID or whatever, but has to be unique to your user object – and returns a user object or None. If you have not kept email as a unique key, you will have to take care of multiple result returned for the query_set. In the below code, this has been taken care of by returning the first user from the returned list.

from django.contrib.auth.backends import ModelBackend, UserModel from django.db.models import Q class EmailBackend(ModelBackend): def authenticate(self, request, username=None, password=None, **kwargs): try: #to allow authentication through phone number or any other field, modify the below statement user = UserModel.objects.get(Q(username__iexact=username) | Q(email__iexact=username)) except UserModel.DoesNotExist: UserModel().set_password(password) except MultipleObjectsReturned: return User.objects.filter(email=username).order_by('id').first() else: if user.check_password(password) and self.user_can_authenticate(user): return user def get_user(self, user_id): try: user = UserModel.objects.get(pk=user_id) except UserModel.DoesNotExist: return None return user if self.user_can_authenticate(user) else None 

By default, AUTHENTICATION_BACKENDS is set to:

['django.contrib.auth.backends.ModelBackend'] 

In settings.py file, add following at the bottom to override the default:

AUTHENTICATION_BACKENDS = ('appname.filename.EmailBackend',) 

3 Comments

This is great, thanks. I've pretty much completed a project, templates, forms, views, the lot, so starting again isn't that appealing! Now I can authenticate on email address is there any way to remove the username field so it's not included in the authentication and the forms rendered in the templates?
Why use this instead of USERNAME_FIELD variable within the model?
so you can login with both an email and a username
30

Django 4.0

There are two main ways you can implement email authentication, taking note of the following:

  • emails should not be unique on a user model to mitigate misspellings and malicious use.
  • emails should only be used for authentication if they are verified (as in we have sent a verification email and they have clicked the verify link).
  • We should only send emails to verified email addresses.

Custom User Model

A custom user model is recommended when starting a new project as changing mid project can be tricky.

We will add an email_verified field to restrict email authentication to users with a verified email address.

# app.models.py from django.db import models from django.contrib.auth.models import AbstractUser class User(AbstractUser): email_verified = models.BooleanField(default=False) 

We will then create a custom authentication backend that will substitute a given email address for a username.

This backend will work with authentication forms that explicitly set an email field as well as those setting a username field.

# app.backends.py from django.contrib.auth import get_user_model from django.contrib.auth.backends import ModelBackend from django.db.models import Q UserModel = get_user_model() class CustomUserModelBackend(ModelBackend): def authenticate(self, request, username=None, password=None, **kwargs): if username is None: username = kwargs.get(UserModel.USERNAME_FIELD, kwargs.get(UserModel.EMAIL_FIELD)) if username is None or password is None: return try: user = UserModel._default_manager.get( Q(username__exact=username) | (Q(email__iexact=username) & Q(email_verified=True)) ) except UserModel.DoesNotExist: # Run the default password hasher once to reduce the timing # difference between an existing and a nonexistent user (#20760). UserModel().set_password(password) else: if user.check_password(password) and self.user_can_authenticate(user): return user 

We then modify our projects settings.py to use our custom user model and authentication backend.

# project.settings.py AUTH_USER_MODEL = "app.User" AUTHENTICATION_BACKENDS = ["app.backends.CustomUserModelBackend"] 

Be sure that you run manage.py makemigrations before you migrate and that the first migration contains these settings.

Extended User Model

While less performant than a custom User model (requires a secondary query), it may be better to extend the existing User model in an existing project and may be preferred depending on login flow and verification process.

We create a one-to-one relation from EmailVerification to whichever User model our project is using through the AUTH_USER_MODEL setting.

# app.models.py from django.conf import settings from django.db import models class EmailVerification(models.Model): user = models.OneToOneField( settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_query_name="verification" ) verified = models.BooleanField(default=False) 

We can also create a custom admin that includes our extension inline.

# app.admin.py from django.contrib import admin from django.contrib.auth import get_user_model from django.contrib.auth.admin import UserAdmin as BaseUserAdmin from .models import EmailVerification UserModel = get_user_model() class VerificationInline(admin.StackedInline): model = EmailVerification can_delete = False verbose_name_plural = 'verification' class UserAdmin(BaseUserAdmin): inlines = (VerificationInline,) admin.site.unregister(UserModel) admin.site.register(UserModel, UserAdmin) 

We then create a backend similar to the one above that simply checks the related models verified field.

# app.backends.py from django.contrib.auth import get_user_model from django.contrib.auth.backends import ModelBackend from django.db.models import Q UserModel = get_user_model() class ExtendedUserModelBackend(ModelBackend): def authenticate(self, request, username=None, password=None, **kwargs): if username is None: username = kwargs.get(UserModel.USERNAME_FIELD, kwargs.get(UserModel.EMAIL_FIELD)) if username is None or password is None: return try: user = UserModel._default_manager.get( Q(username__exact=username) | (Q(email__iexact=username) & Q(verification__verified=True)) ) except UserModel.DoesNotExist: # Run the default password hasher once to reduce the timing # difference between an existing and a nonexistent user (#20760). UserModel().set_password(password) else: if user.check_password(password) and self.user_can_authenticate(user): return user 

We then modify our projects settings.py to use our authentication backend.

# project.settings.py AUTHENTICATION_BACKENDS = ["app.backends.ExtendedUserModelBackend"] 

You can then makemigrations and migrate to add functionality to an existing project.

Notes

  • if usernames are case insensitive change Q(username__exact=username) to Q(username__iexact=username).
  • In production prevent a new user registering with an existing verified email address.

4 Comments

Thanks for great answer, but, what does UserModel().set_password(password) do ?
I don't understand your comment that emails should NOT be unique -- what do misspellings have to do with anything? It seems that emails should be unique, or else you could end up with two different users entering the same email.
@tadasajon There's no guarantee that a user owns the email address they enter (malicious use). You can use constraints and checks to prevent two users sharing the same verified email address docs.djangoproject.com/en/4.2/ref/models/constraints.
@tabebqena Hashes the password on an empty user object to prevent vulnerabilities where someone could determine whether a user account exists based on the time it takes the request to complete: code.djangoproject.com/ticket/20760
14

I had a similar requirement where either username/email should work for the username field.In case someone is looking for the authentication backend way of doing this,check out the following working code.You can change the queryset if you desire only the email.

from django.contrib.auth import get_user_model # gets the user_model django default or your own custom from django.contrib.auth.backends import ModelBackend from django.db.models import Q # Class to permit the athentication using email or username class CustomBackend(ModelBackend): # requires to define two functions authenticate and get_user def authenticate(self, username=None, password=None, **kwargs): UserModel = get_user_model() try: # below line gives query set,you can change the queryset as per your requirement user = UserModel.objects.filter( Q(username__iexact=username) | Q(email__iexact=username) ).distinct() except UserModel.DoesNotExist: return None if user.exists(): ''' get the user object from the underlying query set, there will only be one object since username and email should be unique fields in your models.''' user_obj = user.first() if user_obj.check_password(password): return user_obj return None else: return None def get_user(self, user_id): UserModel = get_user_model() try: return UserModel.objects.get(pk=user_id) except UserModel.DoesNotExist: return None 

Also add AUTHENTICATION_BACKENDS = ( 'path.to.CustomBackend', ) in settings.py

4 Comments

This worked for me until I upgraded from 1.11 to 2.1.5. Any idea why it won't work with this version?
@zerohedge add request to the authenticate method's parameters. See docs.djangoproject.com/en/2.2/topics/auth/customizing/…
It also leaves you open to a timing attack, it's worth trying to closely mimicking Django implementation to prevent such vulnerabilities: github.com/django/django/blob/master/django/contrib/auth/…
This will also enable inactive users to authenticate.
6

Email and Username Authentication for Django 2.X

Having in mind that this is a common question, here's a custom implementation mimicking the Django source code but that authenticates the user with either username or email, case-insensitively, keeping the timing attack protection and not authenticating inactive users.

from django.contrib.auth.backends import ModelBackend, UserModel from django.db.models import Q class CustomBackend(ModelBackend): def authenticate(self, request, username=None, password=None, **kwargs): try: user = UserModel.objects.get(Q(username__iexact=username) | Q(email__iexact=username)) except UserModel.DoesNotExist: UserModel().set_password(password) else: if user.check_password(password) and self.user_can_authenticate(user): return user def get_user(self, user_id): try: user = UserModel.objects.get(pk=user_id) except UserModel.DoesNotExist: return None return user if self.user_can_authenticate(user) else None 

Always remember to add it your settings.py the correct Authentication Backend.

2 Comments

Is my understanding right that the UserModel().set_password(password) is there to prevent attackers from determining if a user does or doesn't exist by performing roughly the same amount of cryptographic work regardless (I assume this is the timing attack you meant)?
@GrandPhuba You're 100% correct
5

It seems that the method of doing this has been updated with Django 3.0.

A working method for me has been:

authentication.py # <-- I placed this in an app (did not work in the project folder alongside settings.py

from django.contrib.auth import get_user_model from django.contrib.auth.backends import BaseBackend from django.contrib.auth.hashers import check_password from django.contrib.auth.models import User class EmailBackend(BaseBackend): def authenticate(self, request, username=None, password=None, **kwargs): UserModel = get_user_model() try: user = UserModel.objects.get(email=username) except UserModel.DoesNotExist: return None else: if user.check_password(password): return user return None def get_user(self, user_id): UserModel = get_user_model() try: return UserModel.objects.get(pk=user_id) except UserModel.DoesNotExist: return None 

Then added this to the settings.py file

AUTHENTICATION_BACKENDS = ( 'appname.authentication.EmailBackend', ) 

Comments

4

I have created a helper for that: function authenticate_user(email, password).

from django.contrib.auth.models import User def authenticate_user(email, password): try: user = User.objects.get(email=email) except User.DoesNotExist: return None else: if user.check_password(password): return user return None class LoginView(View): template_name = 'myapp/login.html' def get(self, request): return render(request, self.template_name) def post(self, request): email = request.POST['email'] password = request.POST['password'] user = authenticate_user(email, password) context = {} if user is not None: if user.is_active: login(request, user) return redirect(self.request.GET.get('next', '/')) else: context['error_message'] = "user is not active" else: context['error_message'] = "email or password not correct" return render(request, self.template_name, context) 

1 Comment

Simple and straightfoward solution! It will work, unless you have multiple users under the same email. It's a pretty nice implementation
4

July, 2023 Update:

You can set up authentication with email and password instead of username and password and in this instruction, username is removed and I tried not to change the default Django settings as much as possible. *You can also see my answer explaining how to extend User model with OneToOneField() to add extra fields and you can see my answer and my answer explaining the difference between AbstractUser and AbstractBaseUser.

First, run the command below to create account app:

python manage.py startapp account 

Then, set account app to INSTALLED_APPS and set AUTH_USER_MODEL = 'account.User' in settings.py as shown below:

# "settings.py" INSTALLED_APPS = [ ... "account", # Here ] AUTH_USER_MODEL = 'account.User' # Here 

Then, create managers.py just under account folder and create UserManager class extending (UM)UserManager in managers.py as shown below. *Just copy & paste the code below to managers.py and managers.py is necessary to make the command python manage.py createsuperuser work properly without any error:

# "account/managers.py" from django.contrib.auth.models import UserManager as UM from django.contrib.auth.hashers import make_password class UserManager(UM): def _create_user(self, email, password, **extra_fields): if not email: raise ValueError("The given email must be set") email = self.normalize_email(email) user = self.model(email=email, **extra_fields) user.password = make_password(password) user.save(using=self._db) return user def create_user(self, email=None, password=None, **extra_fields): extra_fields.setdefault("is_staff", False) extra_fields.setdefault("is_superuser", False) return self._create_user(email, password, **extra_fields) def create_superuser(self, email=None, password=None, **extra_fields): extra_fields.setdefault("is_staff", True) extra_fields.setdefault("is_superuser", True) if extra_fields.get("is_staff") is not True: raise ValueError("Superuser must have is_staff=True.") if extra_fields.get("is_superuser") is not True: raise ValueError("Superuser must have is_superuser=True.") return self._create_user(email, password, **extra_fields) 

Then, create User model extending AbstractUser and remove username by setting it None and set email with unique=True and set email to USERNAME_FIELD and set UserManager to objects in account/models.py as shown below. *Just copy & paste the code below to account/models.py:

# "account/models.py" from django.db import models from django.utils.translation import gettext_lazy as _ from django.contrib.auth.models import AbstractUser from .managers import UserManager class User(AbstractUser): username = None # Here email = models.EmailField(_("email address"), unique=True) # Here USERNAME_FIELD = 'email' # Here REQUIRED_FIELDS = [] objects = UserManager() # Here 

Or, you can also create User model extending AbstractBaseUser and PermissionsMixin as shown below. *This code below with AbstractBaseUser and PermissionsMixin is equivalent to the code above with AbstractUser:

from django.db import models from django.utils.translation import gettext_lazy as _ from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin from django.utils import timezone from .managers import UserManager class User(AbstractBaseUser, PermissionsMixin): first_name = models.CharField(_("first name"), max_length=150, blank=True) last_name = models.CharField(_("last name"), max_length=150, blank=True) email = models.EmailField(_("email address"), unique=True) 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) USERNAME_FIELD = 'email' objects = UserManager() # Here class Meta: verbose_name = _("user") verbose_name_plural = _("users") 

*Don't extend DefaultUser(User) model as shown below otherwise there is error:

# "account/models.py" from django.contrib.auth.models import User as DefaultUser class User(DefaultUser): ... 

Then, create UserAdmin class extending UA(UserAdmin) in account/admin.py as shown below. *Just copy & paste the code below to account/admin.py:

from django.contrib import admin from django.utils.translation import gettext_lazy as _ from django.contrib.auth.admin import UserAdmin as UA from .models import User @admin.register(User) class UserAdmin(UA): fieldsets = ( (None, {"fields": ("password",)}), (_("Personal info"), {"fields": ("first_name", "last_name", "email")}), ( _("Permissions"), { "fields": ( "is_active", "is_staff", "is_superuser", "groups", "user_permissions", ), }, ), (_("Important dates"), {"fields": ("last_login", "date_joined")}), ) add_fieldsets = ( ( None, { "classes": ("wide",), "fields": ("email", "password1", "password2"), }, ), ) list_display = ("email", "first_name", "last_name", "is_staff") ordering = ("-is_staff",) readonly_fields=('last_login', 'date_joined') 

Then, run the command below. *This must be the 1st migration to database when customizing User model in this way otherwise there is error according to my experiments and the doc so before you develop your Django project, you must first create custom User model:

python manage.py makemigrations && python manage.py migrate 

Then, run the command below:

python manage.py createsuperuser 

Then, run the command below:

python manage.py runserver 0.0.0.0:8000 

Then, open the url below:

http://localhost:8000/admin/login/ 

Finally, you can log in with email and password as shown below:

enter image description here

And, this is Add custom user page as shown below:

enter image description here

Comments

3

Authentication with Email and Username For Django 2.x

from django.contrib.auth import get_user_model from django.contrib.auth.backends import ModelBackend from django.db.models import Q class EmailorUsernameModelBackend(ModelBackend): def authenticate(self, request, username=None, password=None, **kwargs): UserModel = get_user_model() try: user = UserModel.objects.get(Q(username__iexact=username) | Q(email__iexact=username)) except UserModel.DoesNotExist: return None else: if user.check_password(password): return user return None 

In settings.py, add following line,

AUTHENTICATION_BACKENDS = ['appname.filename.EmailorUsernameModelBackend'] 

Comments

2

You should customize ModelBackend class. My simple code:

from django.contrib.auth.backends import ModelBackend from django.contrib.auth import get_user_model class YourBackend(ModelBackend): def authenticate(self, username=None, password=None, **kwargs): UserModel = get_user_model() if username is None: username = kwargs.get(UserModel.USERNAME_FIELD) try: if '@' in username: UserModel.USERNAME_FIELD = 'email' else: UserModel.USERNAME_FIELD = 'username' user = UserModel._default_manager.get_by_natural_key(username) except UserModel.DoesNotExist: UserModel().set_password(password) else: if user.check_password(password) and self.user_can_authenticate(user): return user 

And in settings.py file, add:

AUTHENTICATION_BACKENDS = ['path.to.class.YourBackend'] 

1 Comment

Update your code to include request parameter in authenticate method for django 2.1.1
1
from django.contrib.auth.models import User from django.db import Q class EmailAuthenticate(object): def authenticate(self, username=None, password=None, **kwargs): try: user = User.objects.get(Q(email=username) | Q(username=username)) except User.DoesNotExist: return None except MultipleObjectsReturned: return User.objects.filter(email=username).order_by('id').first() if user.check_password(password): return user return None def get_user(self,user_id): try: return User.objects.get(pk=user_id) except User.DoesNotExist: return None 

And then in settings.py:

AUTHENTICATION_BACKENDS = ( 'articles.backends.EmailAuthenticate', ) 

where articles is my django-app, backends.py is the python file inside my app and EmailAuthenticate is the authentication backend class inside my backends.py file

Comments

1

All of these are horrendously complicated for what should be a simple problem.

Check that a user exists with that email, then get that user's username for the argument in Django's authenticate() method.

try: user = User.objects.get(email = request_dict['email']) user = authenticate(username = user.username, password = request_dict['password']) except: return HttpResponse('User not found.', status = 400) 

Comments

0

For Django 2

username = get_object_or_404(User, email=data["email"]).username user = authenticate( request, username = username, password = data["password"] ) login(request, user) 

Comments

0

Authentication with Email For Django 2.x

def admin_login(request): if request.method == "POST": email = request.POST.get('email', None) password = request.POST.get('password', None) try: get_user_name = CustomUser.objects.get(email=email) user_logged_in =authenticate(username=get_user_name,password=password) if user_logged_in is not None: login(request, user_logged_in) messages.success(request, f"WelcomeBack{user_logged_in.username}") return HttpResponseRedirect(reverse('backend')) else: messages.error(request, 'Invalid Credentials') return HttpResponseRedirect(reverse('admin_login')) except: messages.warning(request, 'Wrong Email') return HttpResponseRedirect(reverse('admin_login')) else: if request.user.is_authenticated: return HttpResponseRedirect(reverse('backend')) return render(request, 'login_panel/login.html') 

Comments

0

If You created Custom database, from there if you want to validate your email id and password.

  1. Fetch the Email id and Password with models.objects.value_list('db_columnname').filter(db_emailname=textbox email)

2.assign in list fetched object_query_list

3.Convert List to String

Ex :

  1. Take the Html Email_id and Password Values in Views.py

    u_email = request.POST.get('uemail')

    u_pass = request.POST.get('upass')

  2. Fetch the Email id and password from the database

    Email = B_Reg.objects.values_list('B_Email',flat=True).filter(B_Email=u_email)

    Password = B_Reg.objects.values_list('Password',flat=True).filter(B_Email=u_email)

  3. Take the Email id and password values in the list from the Query value set

    Email_Value = Email[0]

    Password_Value=Password[0]

  4. Convert list to String

    string_email = ''.join(map(str, Email_Value))

    string_password = ''.join(map(str, Password_Value))

Finally your Login Condition

if (string_email==u_email and string_password ==u_pass) 

Comments

0

This solution is for apps that have already many users & do not want to migrate them to a new user table.

Get the user, call check_password which returns True if the form password matches the hashed password stored in auth_user. Then all you need to do is call login(request, user). For example:

def login_user(request): if request.method == "GET": data = { "form": UserForm, } return render(request, "login.html", data) else: email = request.POST["email"] password = request.POST["password"] user = User.objects.get(email=email) if user: passwords_match = user.check_password(password) if passwords_match: login(request, user) logger.info(f"User with email {user.username} logged in") return redirect("feed") data = { "form": UserForm, "error": "Email & Password do not match" } return render(request, "login.html", data) 

Then you need to alter the auth_user table's email column to include a unique constraint, I do this using a migration script:

# Generated by Django 5.0.6 on 2024-06-07 11:28 from django.db import migrations from django.contrib.auth.models import User from django.db import models class Migration(migrations.Migration): dependencies = [ ('user', '0002_email_from_username'), ] operations = [ migrations.RunSQL(""" ALTER TABLE auth_user ADD CONSTRAINT unique_email_uc UNIQUE (email); """) ] 

Comments

0

While @mipadi's EmailBackend solution works, I would argue it's not the cleanest approach. It forces Django to treat an email as a username, leading to confusing error messages, logs, and potential issues with third-party apps expecting actual usernames. A cleaner solution would be to create a proper email-based authentication by subclassing AbstractBaseUser:

# yourapp/models.py from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin from django.contrib.auth.base_user import BaseUserManager from django.db import models class UserManager(BaseUserManager): def create_user(self, email, password=None): user = self.model(email=self.normalize_email(email)) user.set_password(password) user.save() return user def create_superuser(self, email, password=None): user = self.create_user(email, password) user.is_staff = True user.is_superuser = True user.save() return user class User(AbstractBaseUser, PermissionsMixin): email = models.EmailField(unique=True) is_active = models.BooleanField(default=True) is_staff = models.BooleanField(default=False) objects = UserManager() USERNAME_FIELD = 'email' REQUIRED_FIELDS = [] 

Remember to set AUTH_USER_MODEL = 'yourapp.User' in settings.py.

Comments

-1

Pretty simple. There is no need for any additional classes.

When you create and update a user with an email, just set the username field with the email.

That way when you authenticate the username field will be the same value of the email.

The code:

# Create User.objects.create_user(username=post_data['email'] etc...) # Update user.username = post_data['email'] user.save() # When you authenticate user = authenticate(username=post_data['email'], password=password) 

2 Comments

Please add some sample code to help demonstrate how your answer can help solve the problem.
@CasmanRidder Your answer will be deleted if you don't add additional info.
-1

The default user model inherits/ Extends an Abstract class. The framework should be lenient to a certain amount of changes or alterations.

A simpler hack is to do the following: This is in a virtual environment

  1. Go to your django installation location and find the Lib folder
  2. navigate to django/contrib/auth/
  3. find and open the models.py file. Find the AbstractUser class line 315

LINE 336 on the email attribute add unique and set it to true

email = models.EmailField(_('email address'), blank=True,unique=True) USERNAME_FIELD = 'email' REQUIRED_FIELDS = ['username'] 
  1. Done, makemigrations & migrate

Do this at you own risk,

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.