Dear Ali,
   First, Collin's code works if you just want a workaround to the default 
authentication class. However, if you mean having User Authentication with 
email as the primary attribute, then you have to override the default 
authentication/user object. Django currently allows custom user models, 
forms, etc. The following code works for me if you want to work with email 
through out the project instead of the default username:

#models.py
#here, I basically create a user class that can be authenticated using 
email and password through a user manager and a user model object
class MyUserManager(BaseUserManager):
    """
    A custom user manager to deal with emails as unique identifiers for auth
    instead of usernames. The default that's used is "UserManager"
    """
    def _create_user(self, email, password, first_name=None, 
last_name=None, is_active=True, is_staff=False, is_admin=False, 
**extra_fields):
        """
        Creates and saves a User with the given email and password.
        """
        if not email:
            raise ValueError('Users must have an email address')
        email = self.normalize_email(email)
        user = self.model(email=email, firstName=first_name, 
lastName=last_name)
        user.set_password(password)
        user.staff = is_staff
        user.admin = is_admin
        user.is_superuser = extra_fields.get('is_superuser', False)
        user.is_active = is_active
        user.save()
        return user

    def create_user(self, email, password = None, first_name=None, 
last_name=None, is_active=True, is_staff=False, is_admin=False, 
**extra_fields):
        user_obj =self.model.objects.filter(email=email)

        if(user_obj.exists() and not None):
            return user_obj[0]

        return self._create_user(email, password = password, 
first_name=first_name, last_name=last_name, is_active=is_active, 
is_staff=is_staff, is_admin=is_admin, **extra_fields)

    def create_staffuser(self, email, first_name=None, last_name=None, 
password=None):
        user = self.create_user(
                email,
                password=password,
                first_name = first_name,
                last_name = last_name,
                is_staff=True
        )
        return user

    def create_superuser(self, email, password, **extra_fields):
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)
        extra_fields.setdefault('is_admin', True)
        extra_fields.setdefault('is_active', 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)

class User(AbstractBaseUser, PermissionsMixin):

    email       = models.EmailField(verbose_name='email address', 
max_length=255, unique = True, null = True)
    is_active   = models.BooleanField(verbose_name='active', default=True)
    staff    = models.BooleanField(verbose_name= 'staff status', default = 
False)
    admin    = models.BooleanField(verbose_name= 'admin status', default = 
False)
    firstName   = models.CharField(max_length=32, default='', null=True, 
blank=True)
    lastName    = models.CharField(max_length=32, default='', null=True, 
blank=True)
    phone_regex = RegexValidator(regex=r'^\+?1?\d{9,15}$', message="Phone 
number must be entered in the format: '+999999999'. Up to 15 digits 
allowed.")
    phone       = models.CharField(validators=[phone_regex],max_length = 
15, null=True, blank = True)

    USERNAME_FIELD = 'email'
    objects = MyUserManager()

    def __str__(self):
        return self.email

#settings.py make sure to include AUTH_USER_MODEL= '<path to your user 
model>'

#forms.py
#note that the form styling is embedded into the form as widgets (you might 
want something different). 
class UserCreateFormbyEmail(forms.ModelForm):
    """
    A form that creates a user, with no privileges, from the given username 
and
    password.
    """
    error_messages = {
        'password_mismatch': _("The two password fields didn't match."),
    }
    password1 = forms.CharField(
        label=_("Password"),
        strip=False,
        widget=forms.PasswordInput,
        help_text=password_validation.password_validators_help_text_html(),
    )
    password2 = forms.CharField(
        label=_("Password confirmation"),
        widget=forms.PasswordInput,
        help_text=_("Enter the same password as before, for verification."),
    )

    class Meta:
        model = get_user_model()
        fields = ("email", "firstName", "lastName")
        field_classes = {'email': UsernameField,}

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if self._meta.model.USERNAME_FIELD in self.fields:
            
self.fields[self._meta.model.USERNAME_FIELD].widget.attrs.update({'autofocus': 
True})

    def clean_password2(self):
        password1 = self.cleaned_data.get("password1")
        password2 = self.cleaned_data.get("password2")
        if password1 and password2 and password1 != password2:
            raise forms.ValidationError(
                self.error_messages['password_mismatch'],
                code='password_mismatch',
            )
        return password2

    def clean_email(self):
        email = self.cleaned_data.get('email')
        if(email and get_user_model().objects.filter(email=email).exists()):
            raise forms.ValidationError('This email address has been 
registered')
        return email

    def _post_clean(self):
        super()._post_clean()
        # Validate the password after self.instance is updated with form 
data
        # by super().
        password = self.cleaned_data.get('password2')
        if password:
            try:
                password_validation.validate_password(password, 
self.instance)
            except forms.ValidationError as error:
                self.add_error('password2', error)

    def save(self, commit=True):
        user = super().save(commit=False)
        user.set_password(self.cleaned_data["password1"])
        if commit:
            user.save()
        return user

class UserAuthenticatebyEmail(AuthenticationForm):
    """ because we override the default user class, the username field is 
now email, not strings"""
    username = UsernameField(required=True,label="Username",
                               widget=forms.TextInput(attrs={
                                   'class': 'form-control login-field',
                                   'name': 'email',
                                   'placeholder': 'Email'}))
    password = ReadOnlyPasswordHashField(required=True,label="Password",
                               widget=forms.PasswordInput(attrs={
                                   'class': 'form-control login-field',
                                   'name': 'password',
                                   'placeholder':'Username'}))

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers  (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-developers+unsubscr...@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-developers/0ae3c698-ffbf-4bd6-b27a-2f43f3d13d58%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to