[Answered ]-Conditionally require password when creating user in Django Admin page

1👍

Here’s what I ended up doing:

Models.py

from django.db import models
from django.contrib.auth.models import (AbstractUser, BaseUserManager, )
from django_auth_ldap.backend import LDAPBackend
from django.dispatch import receiver
# Create your models here.

class CustomUserManager(BaseUserManager):

    def create_user(self, username, is_ldap, password, **extra_fields):

        if not username:
            raise ValueError(_('The username must be set'))
        user = self.model(username=username,
                          is_ldap=is_ldap,
                          **extra_fields)
        user.set_password(password)
        user.save()
        return user


    def create_superuser(self, username, is_ldap, password=None, **extra_fields):

        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', 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(username, is_ldap, password, **extra_fields)


class CustomUser(AbstractUser):
    is_ldap = models.BooleanField(default=False)

    USERNAME_FIELD = 'username'
    REQUIRED_FIELDS = ['is_ldap']

    objects = CustomUserManager()

    def __str__(self):
        return self.username

@receiver(models.signals.post_save, sender=CustomUser)
def user_created(sender, instance, created, **kwargs):
    if created and instance.is_ldap:
        user = LDAPBackend().populate_user(instance.username)

admin.py

from django import forms
from django.contrib import admin
from django.contrib.auth.models import Group
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.forms import ReadOnlyPasswordHashField
from django.core.exceptions import ValidationError

from .models import CustomUser


class CustomUserCreationForm(forms.ModelForm):
    """A form for creating new users. Includes all the required
    fields, plus a repeated password."""
    password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
    password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)


    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['password1'].required = False
        self.fields['password2'].required = False


    class Meta:
        model = CustomUser
        fields = ('username','is_ldap',)


    def clean_password2(self):
        # Check that the two password entries match
        password1 = self.cleaned_data.get("password1")
        password2 = self.cleaned_data.get("password2")
        is_ldap = self.cleaned_data.get("is_ldap")

        if is_ldap:
            if password1 or password2:
                raise ValidationError("Leave password fields empty for an LDAP user")
        else:
            if not password1 or not password2:
                raise ValidationError("Passwords don't match")
            elif password1 and password2 and password1 != password2:
                raise ValidationError("Passwords don't match")

        return password2

    def save(self, commit=True):
        # Save the provided password in hashed format
        user = super().save(commit=False)

        if self.cleaned_data['is_ldap']:
            user.set_unusable_password()
        else:
            user.set_password(self.cleaned_data["password1"])

        if commit:
            user.save()
        return user


class CustomUserChangeForm(forms.ModelForm):
    """A form for updating users. Includes all the fields on
    the user, but replaces the password field with admin's
    disabled password hash display field.
    """
    password = ReadOnlyPasswordHashField()

    class Meta:
        model = CustomUser
        fields = ('username','is_ldap',)


class CustomUserAdmin(UserAdmin):
    # The forms to add and change user instances
    form = CustomUserChangeForm
    add_form = CustomUserCreationForm
    model = CustomUser

    # The fields to be used in displaying the User model.
    # These override the definitions on the base UserAdmin
    # that reference specific fields on auth.User.
    list_display = ('username', 'first_name', 'last_name', 'is_staff', 'is_active', 'is_ldap',)
    # list_filter = ('username', 'is_staff', 'is_active',)
    fieldsets = (
        (None, {'fields': ('username', 'is_ldap', 'password')}),
        ('Personal info', {'fields': ('first_name', 'last_name')}),
        ('Permissions', {'fields': ('is_superuser','groups')}),
    )

    # add_fieldsets is not a standard ModelAdmin attribute. UserAdmin
    # overrides get_fieldsets to use this attribute when creating a user.
    add_fieldsets = (
        (None, {
            'classes': ('wide',),
            'fields': ('username', 'is_ldap', 'password1', 'password2'),
        }),
    )
    search_fields = ('username',)
    ordering = ('username',)
    filter_horizontal = (['groups',])


admin.site.register(CustomUser, CustomUserAdmin)

Leave a comment