Custom user model and custom authentication not working in django. Authentication form is not passing validation tests
<p>I am trying to implement the custom User model and custom authentication for my application.<br>
I am able to create models and make migrations. But when I created a form and implemented the login template, I am getting this error -  </p>

<pre><code>login
User model with this Login already exists.
</code></pre>

<p><strong>View where I am authenticating user -</strong> </p>

<pre><code>from django.shortcuts import render_to_response, redirect, render
from django.template import RequestContext
from django.contrib.auth import login, logout , authenticate
from accounts.forms import AuthenticationForm
from django.contrib.auth.decorators import login_required
def accounts_login(request):
    context = {}
    if request.method == "POST":
        form = AuthenticationForm(request.POST) #getting error here
        print(form)
        if form.is_valid():
        user = authenticate(login = request.POST["login"], password = request.POST["password"])
        if user is not None:
            print(user)
            login(request,user)
            next_url = request.POST["next"]
            return redirect(next_url, args=(), kwargs={})
        #more code - not required here. Let me know if needed.
</code></pre>

<p><strong>Authentication form:</strong></p>

<pre><code>from django import forms
from accounts.models import UserModel

class AuthenticationForm(forms.Form):
    login = forms.CharField(max_length=128, required=True)
    password = forms.CharField(max_length=128, required=True)
</code></pre>

<p><strong>My custom user model and user manager -</strong></p>

<pre><code>from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
from django.utils import timezone
from django.db.models import Max

class MyUserManager(BaseUserManager):
    use_in_migrations = True
    def create_user(self,login, parent_type, last_name, first_name, password):
        return create_superuser(self,login, parent_type, last_name, first_name, password)


    def create_superuser(self,login, parent_type, last_name, first_name, password):
        maxx = self.model.objects.all().aggregate(Max('sys_id'))
        print(maxx)
        user = self.model(
                          sys_id = maxx["sys_id__max"] + 1,
                          login = login,
                          password = password,
                          parent_type = parent_type,
                          last_name = last_name,
                          first_name = first_name,
                          display_name = last_name + " " + first_name,
                          created_when = timezone.now()
                          )
        user.save(using=self._db)
        # no difference here...actually can set is_admin = True or something like that.
        return user

class UserModel(AbstractBaseUser):
    # custom user class
    SYSTEM = 0
    TENANT = 1
    parent_type_choices = (
                           (SYSTEM, 'System'),
                           (TENANT, 'Tenant')
                           )
    sys_id = models.BigIntegerField(primary_key=True, blank=True)
    parent_type = models.PositiveIntegerField(choices=parent_type_choices, null=False, blank=False)
    parent_sys_id = models.ForeignKey('tenant.TenantModel', on_delete = models.SET_NULL, null=True, blank=True)
    last_name = models.CharField(null=False, blank=False, max_length=40)
    first_name = models.CharField(max_length=40, null=False, blank=False)
    display_name = models.CharField(max_length=80, unique=True, null=False, blank=True)
    login = models.CharField(max_length=40, unique=True, null=False, blank=False)
    authentication_method = models.CharField(max_length=80, null=True, blank=True)
    access_valid_start = models.DateTimeField(null=True, blank=True)
    access_valid_end = models.DateTimeField(null=True, blank=True)
    created_when = models.DateTimeField(null=True, blank=True, )
    created_by = models.BigIntegerField(null=True, blank=True)
    last_updated_when = models.DateTimeField(null=True, blank=True)
    last_updated_by = models.BigIntegerField(null=True, blank=True)
    notes = models.CharField(max_length=2048, null=True, blank=True)
    is_active = models.BooleanField(default=True)

    objects = MyUserManager()

    USERNAME_FIELD = "login"
    # REQUIRED_FIELDS must contain all required fields on your User model, 
    # but should not contain the USERNAME_FIELD or password as these fields will always be prompted for.
    REQUIRED_FIELDS = ['parent_type', 'last_name', 'first_name']

    class Meta:
        app_label = "accounts"
        db_table = "Users"

    def __str__(self):
        return self.display_name

    def get_full_name(self):
        return self.display_name

    def get_short_name(self):
        return self.last_name

    def check_password(self,password):
        return True
        if self.password ==password:
            return true
</code></pre>

<p><strong>Custom backend</strong></p>

<pre><code>from django.conf import settings
from accounts.models import UserModel

class MyAuthBackend(object):
    def authenticate(self, login, password):
        try:
            user = UserModel.objects.get(login=login)
            if user.check_password(password):
                return user
            else:
                print("wrong password")
                return None
        except User.DoesNotExist:
            return None
        except Exception as e:
            print(repr(e))
            return None

    def get_user(self, user_id):
        try:
            user = User.objects.get(pk=user_id)
            if user.is_active:
                return user
            return None
        except User.DoesNotExist:
            return None
</code></pre>

<p><strong>Added these two variables in setting.py</strong></p>

<pre><code>AUTH_USER_MODEL = 'accounts.UserModel'
AUTHENTICATION_BACKENDS = ('accounts.backends.MyAuthBackend',)
</code></pre>

<p><strong>Getting backend from command line</strong></p>

<pre><code>&gt;&gt;&gt; get_backends()
[&lt;accounts.backends.MyAuthBackend object at 0x7f2c438afe80&gt;]
</code></pre>

<p>A user with username lets say xyz and password 'ABC' exists in db.<br>
1. When I am trying to login with existing username and password it throws me error <code>User model with this Login already exists.</code><br>
2. When I try to login with non-existing username and password (lets say xyz123) it throws me error <code>authenticate() takes 0 positional arguments but 2 were given</code></p>

<p>I followed multiple articles but mainly django official documentation for this. Read multiple articles to solve the issue but failed.<br>
Please suggest what I am doing wrong.</p>

<p>Update 1: chnged the AuthenticationForm from ModelForm to normal Form class. Error 1 is solved.<br>
Update 2: Not using my custom backend as pointed by Daniel, it is useless because I am not doing anything new in it. Hence error 2 is also solved.<br>
Update 3: Now hashing password before saving user to db in create super user function. <code>user.set_password(password)</code></p>

<p>Firstly, you are storing passwords in plain text in your overwritten <code>create_superuser</code> method. You <strong>must absolutely not do this</strong>. Quite apart from the security issues, it won't actually work, as the authentication backend will hash a submitted password before comparing it with the saved version, so it will never match.</p>

<p>Secondly, your actual problem is that your AuthenticationForm is a ModelForm; as such it will attempt to see if it can <em>create</em> a user with that email and password. There is no reason to make it a modelform, you should just have a plain form with CharFields for email and password.</p>

<p>Note though that you won't actually be able to log in, until you have fixed the plain text password issue. Note also that your custom auth backend - as well as breaking the authenticate method by not conforming to the interface described <a href="https://docs.djangoproject.com/en/1.10/topics/auth/customizing/#writing-an-authentication-backend" rel="nofollow">in the docs</a> - does not do anything that the built-in one does not do; it is pointless and you should remove it.</p>

python django authentication