How to set the custom UserModel field value upon creation of the user in Django?

Hi there,

I have a custom UserModel which has a CharField named as pbc_id. I want it to be set as something like below:

pbc_id = "PBC-" + str(user.pk)

In other words, I want to attach the newly created user’s primary key value at the end of the string “PBC-” and then assign this value to the pbc_id field.

I have kind of done it, but it only work when I create a superuser using the terminal. But when I create a normal user using Django Administration Interface, it does not work and pbc-id gets empty value.

My User model is below

class User(AbstractBaseUser, PermissionsMixin):    
    username = models.CharField(max_length=254, null=True, blank=True)
    email = models.EmailField(max_length=254, unique=True)
    first_name = models.CharField(max_length=254, null=True, blank=True)
    last_name = models.CharField(max_length=254, null=True, blank=True)
    pbc_id = models.CharField(max_length=254, null=True, blank=True)
    is_staff = models.BooleanField(default=False)
    is_superuser = models.BooleanField(default=False)
    is_active = models.BooleanField(default=True)
    is_candidate = models.BooleanField(default=False)
    is_voter = models.BooleanField(default=False)
    votes = models.IntegerField(default=0)
    last_login = models.DateTimeField(null=True, blank=True)
    date_joined = models.DateTimeField(auto_now_add=True)
    
    USERNAME_FIELD = 'email'
    EMAIL_FIELD = 'email'
    REQUIRED_FIELDS = []

    objects = UserManager()

    def get_absolute_url(self):
        return "/users/%i/" % (self.pk)

My UserManager class is below:

class UserManager(BaseUserManager):
    def _create_user(self, email, password, is_staff, is_superuser, is_candidate, is_voter, **extra_fields):
        if not email:
            raise ValueError('Users must have an email address')

        now = timezone.now()
        email = self.normalize_email(email)

        user = self.model(
            username=email,
            email=email,
            is_staff=is_staff, 
            is_active=True,
            is_superuser=is_superuser, 
            is_candidate=is_candidate,
            is_voter=is_voter,
            last_login=now,
            date_joined=now, 
            **extra_fields
        )
        user.set_password(password)
        user.save(using=self._db)
        user.pbc_id = "PBC-" + str(user.pk)
        user.save(using=self._db)
        return user

    def create_user(self, email, password, **extra_fields):
        user = self._create_user(email, password, False, False, False, False, **extra_fields)
        user.pbc_id = "PBC-" + str(user.pk)
        user.save(using=self._db)
        
        return user


    def create_superuser(self, email, password, **extra_fields):
        user=self._create_user(email, password, True, True, False, False, **extra_fields)
        return user

In admins.py, I have UserAdmin class a below:

class UserAdmin(BaseUserAdmin):
    fieldsets = (
        (None, {'fields': ('username', 'email', 'password', 'first_name', 'last_name', 'last_login')}),
        ('Permissions', {'fields': (
            'is_active', 
            'is_staff', 
            'is_superuser',
            'is_candidate',
            'is_voter',
            'groups', 
            'user_permissions',
        )}),
    )
    add_fieldsets = (
        (
            None,
            {
                'classes': ('wide',),
                'fields': ('email', 'password1', 'password2')
            }
        ),
    )

    list_display = ('username', 'email', 'first_name', 'last_name', 'pbc_id', 'is_staff', 'is_candidate', 'is_voter', 'last_login')
    list_filter = ('is_staff', 'is_candidate', 'is_voter', 'is_superuser', 'is_active', 'groups')
    search_fields = ('email',)
    ordering = ('email',)
    filter_horizontal = ('groups', 'user_permissions',)

Any help would be appreciated.

Just like your other question, you could probably take advantage of the save_model method to add that functionality for this, too.

1 Like

Thank you @KenWhitesell , can you tell me which instance should I use to assign the specific value to field pbc_id? Should I use request or the obj? Also do I need to call super().save_model() method prior to assigning the specific value to pbc_id field or now? Because in case if I don’t call, the instance would it have been created and I might not be able to access pbc_id field. Please explain this.

You’ll want to save it first so that the primary key gets created, then you’ll update the instance with your value for that constructed field.

@KenWhitesell OK and I want to know that why does my implementation work for create_superuser() method but does not work for create_user() method?

If you’re curious about that, you can look at your admin classes to see how they create users, and compare that to the createsuperuser command in django.contrib.auth.management.commands.

(Note: I can’t be any more specific than that, since there is no system-provided classes named BaseUserAdmin. It must either be an existing module imported under a different name, coming from a third-party library or is user-written. Either way, there’s not enough information here for me to know which.)