0
votes

I am new to Django, and currently experimenting with creating a custom user. Apart from some additional fields that my custom user has, I implemented that email is used for authentication instead of username. Also, username is generated by concatenating first name, last name and a number so that unique username would be obtained. Now, I've checked the email authentication and username generation which seems to work, however, the problem that I face is when I enter the Django Administration panel and open User table instead of 'admin' username there is blank. Furthermore, other fields, such as first name, last name, etc don't show for all users.

Screenshot of the admin panel

Custom user and pre_save method for username generation (users.models.py):

class User(AbstractUser):
    personal_no = models.CharField(verbose_name=_('personal number'), max_length=13)
    address = models.CharField(verbose_name=_('address'), max_length=50)


@receiver(pre_save, sender=User)
def generate_username_callback(**kwargs):
    instance = kwargs['instance']
    if not instance.pk:
        instance.username = generate_username(instance.first_name, instance.last_name)


def generate_username(first_name, last_name):
    val = "{0}{1}".format(first_name, last_name).lower()
    count = 0
    while True:
        if count == 0 and User.objects.filter(username=val).count() == 0:
            return val
        else:
            new_val = "{0}{1}".format(val, count)
            if User.objects.filter(username=new_val).count() == 0:
                return new_val
        count += 1
        if count > 10000:
            raise Exception("Too many users named {0}".format(val))

Custom backend for email authentication (users.backends.py):

class EmailBackend(object):
def authenticate(self, username=None, password=None, **kwargs):
    try:
        user = User.objects.get(email=username)
    except User.DoesNotExist:
        return None
    else:
        if getattr(user, 'is_active', False) and 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

users.admin.py:

from django.contrib import admin
from .models import User

admin.site.register(User)

settings.py:

AUTHENTICATION_BACKENDS = [
  'users.backends.EmailBackend'
]

AUTH_USER_MODEL = 'users.User'

I am using Django 1.10.4

1
If you are using email to authenticate, then you might find it easier to set USERNAME_FIELD = 'email'. Then you wouldn't need the username field or custom authentication backend. See the example in the docs. - Alasdair
At first I wanted to include an username in the url when a user is accessing his/her account settings, but afterwards I used the example that you send from the docs to both implement a solution without an username and at the same time it solved the problem about the admin panel. Thanks! - makons

1 Answers

1
votes

The first_name and last_name fields are missing from the table on the changelist field, because you have not specified a ModelAdmin class when you registered your model. To use the default UserAdmin class, you would do:

from django.contrib.auth.admin import UserAdmin

admin.site.register(User, UserAdmin)