Django Custom Authentication - BaseUserManager's create_user not being used - python

I customizes Django's authentication and now every time I try to create a new user using Django Admin this user's password is saved directly, without being hashed. I found out that create_user method from BaseUserManager class is not being called. When I create a superuser using bash it is done properly. Is there anything wrong with my model?
settings.py
AUTH_USER_MODEL = 'authentication.BaseAccount'
apps/authentication/models.py
class BaseAccountManager(BaseUserManager):
def create_user(self, email, password=None, **kwargs):
if not email:
raise ValueError('Users must have a valid email address.')
account = self.model(
email=self.normalize_email(email)
)
account.set_password(password)
account.save()
return account
def create_superuser(self, email, password, **kwargs):
account = self.create_user(email, password, **kwargs)
account.is_admin = True
account.is_staff = True
account.save()
return account
class BaseAccount(AbstractBaseUser):
email = models.EmailField(unique=True)
first_name = models.CharField(max_length=40, blank=True)
last_name = models.CharField(max_length=40, blank=True)
is_admin = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
objects = BaseAccountManager()
USERNAME_FIELD = 'email'
def __unicode__(self):
return self.email
def get_full_name(self):
return ' '.join([self.first_name, self.last_name])
def get_short_name(self):
return self.first_name
def has_perm(self, perm, obj=None):
return self.is_admin
def has_module_perms(self, app_label):
return self.is_admin

For future readers, because this issue also got me banging my head against the wall...
To access that precious create_user() method from anywhere in your django project :
from django.contrib.auth import get_user_model
class SomeClass():
# This could be a form, for example...
def some_function():
get_user_model().objects.create_user()
If you call it from the save() method of some custom form, please take proper care of the commit parameter, and don't forget to register your custom user model in the settings.py file, as per the Django documentation.

I found an answer to your question about passwords, but I still don't know how to get the create_user function to be called correctly. The example removes username in favor of just an email. I am still looking for a way to hit the create_user function defined in the custom UserManager inerhiting from BaseUserManager. My custom manager sends an email with a password reset link and a one time token... which would avoid the need to actually set a hashed password from django admin.
https://www.caktusgroup.com/blog/2013/08/07/migrating-custom-user-model-django/
first create your own forms:
# appname/forms.py
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from appname.models import CustomUser
class CustomUserCreationForm(UserCreationForm):
"""
A form that creates a user, with no privileges, from the given email and
password.
"""
def __init__(self, *args, **kargs):
super(CustomUserCreationForm, self).__init__(*args, **kargs)
del self.fields['username']
class Meta:
model = CustomUser
fields = ("email",)
class CustomUserChangeForm(UserChangeForm):
"""A form for updating users. Includes all the fields on
the user, but replaces the password field with admin's
password hash display field.
"""
def __init__(self, *args, **kargs):
super(CustomUserChangeForm, self).__init__(*args, **kargs)
del self.fields['username']
class Meta:
model = CustomUser
then use those forms:
# appname/admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.utils.translation import ugettext_lazy as _
from appname.models import CustomUser
from appname.forms import CustomUserChangeForm, CustomUserCreationForm
class CustomUserAdmin(UserAdmin):
# The forms to add and change user instances
# The fields to be used in displaying the User model.
# These override the definitions on the base UserAdmin
# that reference the removed 'username' field
fieldsets = (
(None, {'fields': ('email', 'password')}),
(_('Personal info'), {'fields': ('first_name', 'last_name')}),
(_('Permissions'), {'fields': ('is_active', 'is_staff', 'is_superuser',
'groups', 'user_permissions')}),
(_('Important dates'), {'fields': ('last_login', 'date_joined')}),
)
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('email', 'password1', 'password2')}
),
)
form = CustomUserChangeForm
add_form = CustomUserCreationForm
list_display = ('email', 'first_name', 'last_name', 'is_staff')
search_fields = ('email', 'first_name', 'last_name')
ordering = ('email',)
admin.site.register(CustomUser, CustomUserAdmin)

Related

Django Custom User Manager is not called when registering users on the admin panel

When a user is created on Django admin panel, objects = CustomUserManager() is not being executed. However, when I create a superuser from the CLI using python manage.py createsuperuser, objects = CustomUserManager() is executed.
Here is the model file
class CustomUser(AbstractUser):
username = None
email = models.EmailField(_('email address'), unique=True)
name = models.CharField(verbose_name=_("first name"), max_length=50)
stripe_customer_id = models.CharField(max_length=120)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['name']
objects = CustomUserManager()
def __str__(self):
return self.name
Here is the customUserManager
class CustomUserManager(BaseUserManager):
def create_user(self, email, password, name,**extra_fields):
if not email:
raise ValueError(_('The Email must be set'))
email = self.normalize_email(email)
customer = stripe.Customer.create(
email=email,
name=name,
)
user = self.model(email=email,name=name, stripe_customer_id=customer.id ,**extra_fields)
user.set_password(password)
user.save()
return user
def create_superuser(self, email, password,name,**extra_fields):
"""
Create and save a SuperUser with the given email and password.
"""
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(email, password, name,**extra_fields)
Below is how I registered the admin panel.
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .forms import CustomUserCreationForm, CustomUserChangeForm
from .models import CustomUser
from django.utils.translation import gettext_lazy as _
class CustomUserAdmin(UserAdmin):
add_form = CustomUserCreationForm
form = CustomUserChangeForm
model = CustomUser
....
admin.site.register(CustomUser, CustomUserAdmin)
Below is the CustomUserCreationForm
class CustomUserCreationForm(UserCreationForm):
class Meta:
model = CustomUser
fields = "__all__"
UserAdmin relies on the implementation in ModelAdmin to construct an instance, validate the form, and then save the instance, rather than calling a custom method on the model's manager.
Call chain: ModelAdmin.add_view() → ... → self._changeform_view(), which calls:
(i) form.is_valid() (of ModelForm) → ... → self._post_clean() → self.instance = construct_instance(...),
(ii) self.save_form(...) → new_object = form.save(commit=False) (of BaseModelForm) returning self.instance, and
(iii) self.save_model(..., new_object, ...) → obj.save().
You can override ModelAdmin.save_form to call the custom user manager's create_user method and replace form.instance:
class CustomUserAdmin(UserAdmin):
model = CustomUser
fieldsets = (
(None, {'fields': (model.USERNAME_FIELD, 'name', 'password')}),
) + UserAdmin.fieldsets[2:]
add_fieldsets = (
(None, {'fields': (model.USERNAME_FIELD, 'name', 'password1', 'password2')}),
)
ordering = (model.USERNAME_FIELD,)
def save_form(self, request, form, change):
if not change:
form.instance = self.model.objects.create_user(
form.cleaned_data['email'],
form.cleaned_data['password1'],
form.cleaned_data['name'],
)
return super().save_form(request, form, change)
⚠️ Notice in the usual call chain that save_form() does not call obj.save(), as ModelAdmin handles multiple formsets and m2m models, while CustomUserManager.create_user does call user.save(). It is ok to change this behaviour in UserAdmin with known scope, though you may consider splitting CustomUserManager.create_user into CustomUserManager.construct_instance and CustomUserManager.save_new_model (move stripe.Customer.create(...) and user.save() here).
As a matter of fact, your custom methods create_user (and create_superuser, which you probably overwrote as well) are not called when you create a new user from the admin panel. I'm not sure neither to understand why but I think the create_user function is just a shortcut.
Why not overriding the save() method of your CustomUser? From the Django documentation:
A classic use-case for overriding the built-in methods is if you want something to happen whenever you save an object.
Isn't exactly what you're looking for? Check the Django documentation here (to do so at the form level) and here (if you prefer change the model itself directly, no matter which form is used) for more information.
For instance, if you prefer the second option, you can add this method to CustomUser:
from django.apps.apps import get_model
from django.db import transaction
class CustomUser(AbstractUser):
# your initial code goes here ...
def save(self, *args, **kwargs):
# make the distinction between the creation and the update of the instance
if not self._state.adding:
# doesn't change the initial method if the user has already been saved in DB
return super(CustomUser, self).save(*args, **kwargs)
# guarantee of atomicity
with transaction.atomic():
# dynamic resolution to avoid a circular import, might not be necessary
customer = get_model("stripe", "Customer").create(
email=self.email,
name=self.name,
)
self.stripe_customer_id = customer.id
super(CustomUser, self).save(*args, **kwargs)
return self
Don't forget to make the distinction between the creation and the update of an instance.

Django - credentials not working for CustomUser

I'm trying to make a custom user, but there's one problem, when i get request.user, it’s an instance of User, not an instance of CustomUser, so i don’t get the extra fields and methods. I've found this, but when i'm trying to login in the django admin it won't work anymore.
Here is my code:
models.py
class CustomUser(User):
timezone = models.CharField(max_length=50, default='Europe/Bucharest')
porecla = models.CharField(max_length=50, null=True)
selectat = models.BooleanField(default=False)
objects = UserManager()
auth_backends.py - so i can use the methods of the custom user when using request.user
from django.conf import settings
from django.contrib.auth.backends import ModelBackend
from django.core.exceptions import ImproperlyConfigured
from django.apps import apps
class CustomUserModelBackend(ModelBackend):
def authenticate(self, username=None, password=None):
try:
user = self.user_class.objects.get(username=username)
if user.check_password(password):
return user
except self.user_class.DoesNotExist:
return None
def get_user(self, user_id):
try:
return self.user_class.objects.get(pk=user_id)
except self.user_class.DoesNotExist:
return None
#property
def user_class(self):
if not hasattr(self, '_user_class'):
self._user_class = apps.get_model(*settings.CUSTOM_USER_MODEL.split('.', 2))
if not self._user_class:
raise ImproperlyConfigured('Could not get custom user model')
return self._user_class
settings.py
AUTHENTICATION_BACKENDS = ('football_app.auth_backends.CustomUserModelBackend', )
CUSTOM_USER_MODEL = 'football_app.CustomUser'
admin.py
class CustomUserAdmin(admin.ModelAdmin):
list_display = ('username', 'email', 'first_name', 'last_name', 'is_staff', 'is_active', 'selectat', )
admin.site.register(CustomUser, CustomUserAdmin)
The article you are referring to is outdated. If you want to create a custom User model, the way to go is to subclass AbstractUser in stead of User. This is explained here in the official docs.

UserCreateForm bypassing UserManager, regular users created through UserCreateForm CAN authenticate but superuser created in shell CAN NOT?

I have a custom user model and a user manager defined as follows:
/accounts/models.py
from django.contrib.auth.models import (
AbstractBaseUser,
BaseUserManager,
PermissionsMixin
)
from django.db import models
from django.utils import timezone
class UserManager(BaseUserManager):
def create_user(self, email, first_name, last_name, username=None, password=None):
if not email:
raise ValueError("Users must have a valid email address")
if not first_name and last_name:
raise ValueError("Users must have a first and last name")
created_username = ''.join([first_name.lower(), last_name[:1].lower()])
i=2
while User.objects.filter(username=created_username).exists():
created_username = ''.join([first_name.lower(), last_name[:i].lower()])
i+=1
user = self.model(
email=self.normalize_email(email),
first_name=first_name,
last_name=last_name,
username=created_username
)
user.set_password(password)
user.save()
return user
def create_superuser(self, email, first_name, last_name, password):
user = self.create_user(
email,
first_name,
last_name,
password
)
user.is_staff = True
user.is_admin = True
user.is_superuser = True
user.save()
return user
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True)
first_name = models.CharField(max_length=40, blank=True)
last_name = models.CharField(max_length=40, blank=True)
username = models.CharField(max_length=40, unique=True, blank=True, editable=False)
# display_name = models.CharField(max_length=150)
bio = models.TextField(blank=True, null=True)
avatar = models.ImageField(blank=True, null=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_admin = models.BooleanField(default=False)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['first_name','last_name']
def __str__(self):
return "{} #{}".format(self.email, self.username)
def get_short_name(self):
return self.first_name
def get_full_name(self):
return ' '.join([self.first_name, self.last_name])
This seems to work perfectly when registering a superuser from the shell. I have a form and a view set up to register regular users on my site as follows:
/accounts/forms.py
from django import forms
from django.contrib.auth import get_user_model
from django.contrib.auth.forms import UserCreationForm
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _
auth_code = 'hamburger'
def validate_authorization(value):
if value != auth_code:
raise ValidationError(
_('Must have valid authorization code in order to register.')
)
class UserCreateForm(UserCreationForm):
authorization_code = forms.CharField(max_length=10, required=True, validators=[validate_authorization])
class Meta:
model = get_user_model()
fields = ("email", "first_name", "last_name", "password1", "password2", "authorization_code")
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["email"].label = "Email Address"
self.fields["first_name"].label = "First Name"
self.fields["last_name"].label = "Last Name"
self.fields["password1"].label = "Password"
self.fields["password2"].label = "Password Confirmation"
self.fields["authorization_code"].label = "Authorization Code"
/accounts/views.py
from django.shortcuts import render
from django.template import RequestContext
from django.contrib.auth import login, logout
from django.contrib.auth.forms import AuthenticationForm, UserCreationForm
from django.core.urlresolvers import reverse_lazy
from django.views import generic
from django.http import HttpResponseRedirect
from django.contrib.auth import get_user_model
from . import forms
class SigninView(generic.FormView):
form_class = AuthenticationForm
success_url = '/dashboard/' #reverse_lazy('index')
template_name = 'accounts/signin.html'
def get_form(self, form_class=None):
if form_class is None:
form_class = self.get_form_class()
return form_class(self.request, **self.get_form_kwargs())
def form_valid(self, form):
login(self.request, form.get_user())
return super().form_valid(form)
class SignoutView(generic.RedirectView):
url = '/' #reverse_lazy("home")
def get(self, request, *args, **kwargs):
logout(request)
return super().get(request, *args, **kwargs)
class RegisterView(generic.CreateView):
form_class = forms.UserCreateForm
success_url = '/'
template_name = 'accounts/register.html'
def form_valid(self, form):
self.object = form.save(commit=False)
form.instance.username = ''.join([form.instance.first_name.lower(), form.instance.last_name[:1].lower()])
i=2
while get_user_model().objects.filter(username=form.instance.username).exists():
form.instance.username = ''.join([form.instance.first_name.lower(), form.instance.last_name[:i].lower()])
i+=1
form.save()
return HttpResponseRedirect(self.get_success_url())
# return super(RegisterView, self).form_valid(form)
I am at a loss as to why my superuser cannot log into the website but my regular users can. Also you will notice I have a while statement that auto generates a username based on the entered first and last name. Initially I had this only in the UserManager however, the form was bypassing the user manager and so I had to add the same block of code to my view. So there seems to be a disconnect between users created from the form versus users created from the shell (UserManager).
The authorization_code is in place because I don't want just anybody to be able to register on my site and I didn't know a better way. I am open to better suggestions.
Additional information that may be helpful
settings.py
# Set user authentication model
AUTH_USER_MODEL = 'accounts.User'
Python 3.5, Django 1.10
Thank you in advance for any advice or insight.
Problem solved.
In
def create_superuser(self, email, first_name, last_name, password):
user = self.create_user(
email,
first_name,
last_name,
password
)
I was forgetting to set password=password,. From looking at the password field in the database, it seems this was also resulting in (as close as I can tell) bypassing <algorithm>$<iterations>$<salt> (per the Django docs https://docs.djangoproject.com/en/1.10/topics/auth/passwords/) though the password was still being hashed in some way (not being stored in plain text) the password field for superusers was considerably shorter than the password field for normal users. Whatever it was doing, it was not storing the actual password and was giving me an invalid username/password when attempting to log in with a superuser account.
So the proper way is
def create_superuser(self, email, first_name, last_name, password):
user = self.create_user(
email,
first_name,
last_name,
password=password,
)
I still don't understand why created_username is being bypassed in the UserManager when saving a user from the AuthenticationForm but I found a workaround by adding the same while statement to the view. At least all is functional now. I'm still interested to learn if anybody has further insight into this matter.

Updating Custom User Model in Django with Class Based UpdateView

I am using Django 1.7.1 with Python 3.4. I created a custom user model and now I have a need for users to be able to update their details. What I need is that, when users go to the form to update their details, the form is pre-populated with their data i.e. username, email and so on. So far, the form is showing but not with the current user data.
I have the following code:
models.py
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin
... # Some code left out for brevity
class AuthUser(AbstractBaseUser, PermissionsMixin):
"""
A fully featured User model with admin-compliant permissions that uses
a full-length email field as the username.
Email and password are required. Other fields are optional.
"""
username = models.CharField(_('username'), max_length=30, unique=True,
help_text=_('Required. 30 characters or fewer. Letters, numbers and #/./+/-/_ characters'),
validators=[validators.RegexValidator(re.compile('^[\w.#+-]+$'), _('Enter a valid username.'), _('invalid'))])
email = models.EmailField(_('email address'), max_length=254, unique=True)
is_staff = models.BooleanField(_('staff status'), default=False,
help_text=_('Designates whether the user can log into this admin site.'))
is_active = models.BooleanField(_('active'), default=True,
help_text=_('Designates whether this user should be treated as '
'active. Unselect this instead of deleting accounts.'))
date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
objects = AuthUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username'] # Not needed since it has been mentioned in USERNAME_FIELD and is required by default and cannot be listed in REQUIRED_FIELDS
class Meta:
verbose_name = _('user')
verbose_name_plural = _('users')
def get_absolute_url(self):
return "/users/%s/" % urlquote(self.username)
def __str__(self):
return self.username
def get_full_name(self):
# The user is identified by their email address
return self.email
def get_short_name(self):
# The user is identified by their username
return self.username
def email_user(self, subject, message, from_email=None):
"""
Sends an email to this User.
"""
send_mail(subject, message, from_email, [self.email])
forms.py
from django.contrib.auth.forms import UserChangeForm
from .models import AuthUser
class AuthUserChangeForm(UserChangeForm):
"""
A form for updating users. Includes all the fields on the user, but
replaces the password field with admin's password hash display field.
"""
password = ReadOnlyPasswordHashField(label="password",
help_text="""Raw passwords are not stored, so there is no way to see this
user's password, but you can change the password using <a href=\"password/\">
this form</a>""")
class Meta:
model = AuthUser
fields = ('username', 'email', 'password', 'is_active', 'is_staff', 'is_superuser', 'user_permissions')
widgets = {
'email': TextInput(),
}
def clean_password(self):
# Regardless of what the user provides, return the initial value.
# This is done here, rather than on the field, because the field does
# not have access to the initial value
return self.initial["password"]
views.py
class UpdateUserView(LoginRequiredMixin, FormView):
template_name = 'users/update_user.html'
form_class = AuthUserChangeForm
# get current user object
def get_object(self, queryset=None):
return self.request.user
urls.py
url(r'^profile/update/', UpdateUserView.as_view(), name='update_profile'),
What I'm I missing?
FormView is not the appropriate base class here: it doesn't know about model forms and doesn't define a get_object method. Use UpdateView instead.

Changing password in Django Admin

I recently created the admin.py based in the Django Project Document:
https://docs.djangoproject.com/en/dev/topics/auth/customizing/#django.contrib.auth.models.AbstractBaseUser
But I really missed the functionality that allow the administrator the possibility to change the users passwords. How is possible to add this functionality? I just copied and pasted the code the is in the link above.
from django import forms
from django.contrib import admin
from django.contrib.auth.models import Group
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.forms import ReadOnlyPasswordHashField
from customauth.models import MyUser
class UserCreationForm(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)
class Meta:
model = MyUser
fields = ('email', 'date_of_birth')
def clean_password2(self):
# Check that the two password entries match
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords don't match")
return password2
def save(self, commit=True):
# Save the provided password in hashed format
user = super(UserCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
class UserChangeForm(forms.ModelForm):
"""A form for updating users. Includes all the fields on
the user, but replaces the password field with admin's
password hash display field.
"""
password = ReadOnlyPasswordHashField()
class Meta:
model = MyUser
def clean_password(self):
# Regardless of what the user provides, return the initial value.
# This is done here, rather than on the field, because the
# field does not have access to the initial value
return self.initial["password"]
class MyUserAdmin(UserAdmin):
# The forms to add and change user instances
form = UserChangeForm
add_form = UserCreationForm
# 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 = ('email', 'date_of_birth', 'is_admin')
list_filter = ('is_admin',)
fieldsets = (
(None, {'fields': ('email', 'password')}),
('Personal info', {'fields': ('date_of_birth',)}),
('Permissions', {'fields': ('is_admin',)}),
('Important dates', {'fields': ('last_login',)}),
)
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('email', 'date_of_birth', 'password1', 'password2')}
),
)
search_fields = ('email',)
ordering = ('email',)
filter_horizontal = ()
# Now register the new UserAdmin...
admin.site.register(MyUser, MyUserAdmin)
# ... and, since we're not using Django's builtin permissions,
# unregister the Group model from admin.
admin.site.unregister(Group)
[UPDATE - Added Information]
I changed the following information but I still seeing just the password (crypted) in a read-only field. How is possible to add a link to change the password?
fieldsets = (
('Permissions', {'fields': ('is_active', 'is_admin','password')}),
)
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('email', 'password')}
),
)
Put this in your UserChangeForm:
password = ReadOnlyPasswordHashField(label=("Password"),
help_text=("Raw passwords are not stored, so there is no way to see "
"this user's password, but you can change the password "
"using this form."))
password = ReadOnlyPasswordHashField(label= ("Password"),
help_text= ("Raw passwords are not stored, so there is no way to see "
"this user's password, but you can change the password "
"using this form."))
There is change in the href, for previous versions of django you can use
this form.
For django 1.9+
this form
I added this method to my UserAdmin class:
def save_model(self, request, obj, form, change):
# Override this to set the password to the value in the field if it's
# changed.
if obj.pk:
orig_obj = models.User.objects.get(pk=obj.pk)
if obj.password != orig_obj.password:
obj.set_password(obj.password)
else:
obj.set_password(obj.password)
obj.save()
You can the show the password field normally, but admins will only see the hashed password. If they alter it, the new value is then hashed and save.
This adds a single query to each time you save a user via the admin. It should generally not be an issue, since most systems don't have admins intensively editing users.
You can also do like this, in this way you just have to write over the field password and once you will save it, it will create the hash for it :
class UserModelAdmin(admin.ModelAdmin):
"""
User for overriding the normal user admin panel, and add the extra fields added to the user
"""
def save_model(self, request, obj, form, change):
user_database = User.objects.get(pk=obj.pk)
# Check firs the case in which the password is not encoded, then check in the case that the password is encode
if not (check_password(form.data['password'], user_database.password) or user_database.password == form.data['password']):
obj.password = make_password(obj.password)
else:
obj.password = user_database.password
super().save_model(request, obj, form, change)
You could also consider extending the UserAdmin this way:
from django.contrib import admin
from myapp.models import CustomUser
from django.contrib.auth.admin import UserAdmin
class CustomUserAdmin(UserAdmin):
list_display = []
admin.site.register(CustomUser, CustomUserAdmin)
For a django version independent solution you can reverse the url in the UserChangeForm.__init__ with something like:
from django.core.urlresolvers import reverse
class UserChangeForm(forms.ModelForm):
password = ReadOnlyPasswordHashField()
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['password'].help_text = (
"Raw passwords are not stored, so there is no way to see "
"this user's password, but you can <a href=\"%s\"> "
"<strong>Change the Password</strong> using this form</a>."
) % reverse_lazy('admin:auth_user_password_change', args=[self.instance.id])
('Permissions', {'fields': ('is_active', 'is_superuser',)}),
Just delete "password" input in your class form:
class MyUserChangeForm(forms.ModelForm):
# password = forms.CharField(label='Password', required=True, widget=forms.PasswordInput)
# password = ReadOnlyPasswordHashField()
class Meta:
model = CustomUser
fields = '__all__'
def save(self, commit=True):
user = super().save(commit=False)
user.set_password(self.cleaned_data["password"])
if commit:
user.save()
return user
django 3.2.8

Categories