In my django app I have modified the User entity to include a worker field (OneToOneField). But from the django admin site that field yiels so many result , so it is difficult for the logged user to select a worker. Is there any way to use the select2 (ModelSelect2Widget) widgets from the django admin site?
For any regular form I have define the widgets in the following way:
from django_select2.forms import ModelSelect2Widget
class ProcessForm(forms.ModelForm):
class Meta:
model = ProcessModel
exclude = ('id',)
widgets = {
'name':forms.TextInput(attrs={'class': 'form-control'}),
'code':forms.TextInput(attrs={'class': 'form-control'}),
'description':forms.Textarea(attrs={'class': 'form-control'}),
'geom': LeafletWidget(),
'product': ModelSelect2Widget(model=ProductModel, queryset=ProductModel.objects.filter(),
search_fields=['name__icontains'],
attrs={'style': 'width: 100%;'}),
}
Is there any way to use the ModelSelect2Widget for the worker field in the admin site form?
Here is my code:
class User(AbstractUser):
worker = models.OneToOneField(WorkerModel, on_delete=models.CASCADE,
related_name="user", verbose_name=_("Trabajador"), null=True, blank=True)
class Meta:
default_permissions = ()
verbose_name="Usuario"
verbose_name_plural="Usuarios"
permissions = (
("secretario", "Secretario(a)"),
("director", "Director"),
)
from django.contrib.auth.admin import UserAdmin
class UserAdminInherited(UserAdmin):
fieldsets = (
(None, {'fields': ('username', 'password')}),
(_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}),
(_('Worker info'), {'fields': ('worker',)}),
(_('Permissions'), {
'fields': ('is_active', 'is_staff', 'is_superuser', 'groups', 'user_permissions'),
}),
(_('Important dates'), {'fields': ('last_login', 'date_joined')}),
)
admin.site.register(User, UserAdminInherited)
Since Django 2.0., we can use autocomplete_fields.
autocomplete_fields is a list of ForeignKey and/or ManyToManyField
fields you would like to change to Select2 autocomplete inputs.
ModelAdmin(is parent of UserAdmin) has the property autocomplete_fields (Django Docs):
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth import get_user_model
User = get_user_model()
class UserAdminInherited(UserAdmin):
autocomplete_fields = ['worker']
...
admin.site.register(User, UserAdminInherited)
You must define search_fields on the related object’s ModelAdmin
because the autocomplete search uses it.
from django.contrib import admin
#admin.register(WorkerModel)
class WorkerModelAdmin(admin.ModelAdmin):
search_fields = ['model_field']
Related
So to use email as username I override the build-in User model like this (inspired by Django source code)
models.py
class User(AbstractUser):
username = None
email = models.EmailField(unique=True)
objects = UserManager()
USERNAME_FIELD = "email"
REQUIRED_FIELDS = []
def __str__(self):
return self.email
admin.py
#admin.register(User)
class UserAdmin(admin.ModelAdmin):
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"),
},
),
)
list_display = ("email", "is_active", "is_staff", "is_superuser")
list_filter = ("is_active", "is_staff", "is_superuser")
search_fields = ("email",)
ordering = ("email",)
filter_horizontal = ("groups", "user_permissions",)
But this is how it looks like when I go to Admin site to change a user:
Password is visible and not hashed and no link to change password form.
Comparing to what it looks like on a default Django project:
Password is not visible and there's a link to change password form
So clearly I'm missing something but I can't figure out what it is.
It's likely that the Django Admin look problem has to do with inheritance. More precisely, change the class to inherit from UserAdmin.
from django.contrib.auth.admin import UserAdmin as DefaultUserAdmin
class UserAdmin(DefaultUserAdmin):
Doing this will make it look closer to the default Django project.
The problem of the password not being encrypted is likely because it's not encrypted in the database. OP has this question and that's not a problem of the Django Admin.
Notes:
I also use AbstractUser when wanting to remove username.
Since this current question doesn't have enough info to answer the problem of the pwd being hashed, I'll leave that to OP's other question.
You are not able to see the password in hashed state because the password field is a CharField which renders it as normal text field. In Django's admin side there's a field called ReadOnlyPasswordHashField in django.contrib.auth.forms which renders the password field to be in hashed state with password change link.
Django's UserAdmin uses different form classes for user creation and updation.
form = UserChangeForm
add_form = UserCreationForm
change_password_form = AdminPasswordChangeForm
To edit user details UserAdmin uses form = UserChangeForm(source code) where the password field is set as ReadOnlyPasswordHashField(source code).
class UserChangeForm(forms.ModelForm):
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.'
),
)
So, Just by inheriting from UserAdmin from django.contrib.auth.admin would make the password to be in hashed state with all the other essentials as seen in default admin site for users.
OR
you could simply import UserChangeForm from django.contrib.auth.forms and set form = UserChangeForm in custom UserAdmin
from django.contrib.auth.forms import UserChangeForm,AdminPasswordChangeForm
# code
#admin.register(User)
class UserAdmin(admin.ModelAdmin):
# code
form = UserChangeForm
change_password_form = AdminPasswordChangeForm
# code
Django Documentation clearly explains how to do this by Customizing authentication in Django
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.forms import ReadOnlyPasswordHashField
from django.core.exceptions import ValidationError
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 ValidationError("Passwords don't match")
return password2
def save(self, commit=True):
# Save the provided password in hashed format
user = super().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
disabled password hash display field.
"""
password = ReadOnlyPasswordHashField()
class Meta:
model = MyUser
fields = ('email', 'password', 'date_of_birth', 'is_active', 'is_admin')
class UserAdmin(BaseUserAdmin):
# 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',)}),
)
# 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': ('email', 'date_of_birth', 'password1', 'password2'),
}),
)
search_fields = ('email',)
ordering = ('email',)
filter_horizontal = ()
# Now register the new UserAdmin...
admin.site.register(MyUser, UserAdmin)
One way is to define a custom fieldset for the UserAdmin in admin.py.
fieldsets = (
(None, {"fields": ("username")}),
(_("Personal info"), {"fields": ("first_name", "last_name", "email")}),
(
_("Permissions"),
{
"fields": (
"is_active",
"is_staff",
"is_superuser",
"groups",
"user_permissions",
),
},
),
(_("Important dates"), {"fields": ("last_login", "date_joined")}),
)
I am trying to display the password in the Admin backend table in the following way, containing the algorithm, iterations, salt and hash:
However, my current page looks like the following:
As you can see it is just the hashed password, not displaying any of the information unlike the above. Can anyone see where I am going wrong?
Please find my code below:
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from hobbies.models import extendedUser, User, Hobby
from .forms import LoginForm, SignUpForm
from django.forms import ModelForm
from django.contrib.auth.forms import ReadOnlyPasswordHashField
#admin.site.register(User,UserAdmin)
class CustomUserAdmin(UserAdmin):
add_form = SignUpForm
form = LoginForm
model = extendedUser
readonly_fields = ["password"]
list_display = ('email', 'is_staff', 'is_active',)
list_filter = ('email', 'is_staff', 'is_active',)
fieldsets = (
(None, {'fields': ('email', 'password', 'city')}),
('Permissions', {'fields': ('is_staff', 'is_active')}),
)
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('email', 'password', 'is_staff', 'is_active')}
),
)
search_fields = ('email',)
ordering = ('email',)
admin.site.register(User, CustomUserAdmin)
Thank you for your time,
Alex
I think they use display using this function:
get_session_auth_hash() which is a part of the base abstract user in django.contrib.auth.base_user
The problem:
I would like to use django admin site User model to register new users. The default option offers you to register new username with password and password confirmation, which are required fields.
My idea is to make few changes. I would like to keep username field and add email-field, however delete password and password confirmation. The principal idea is, I would register a user and he would receive an email with generated password. He would then be able to login with generated password and change the password.
I am facing huge problems with templates, errors and most of all overriding the classes.
I have spent many many hours checking django documentation, goolge and the best I could do so far is:
admin.py
from django.contrib import admin
from django.contrib.auth import admin as upstream
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from django.contrib.auth.models import Group, User
from django.utils.translation import ugettext, ugettext_lazy as _
class UserAdmin(upstream.UserAdmin):
fieldsets = (
(None, {'fields': ('username', 'password','email')}),
(_('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': ('username','email')}
),
)
form = UserChangeForm
add_form = UserCreationForm
try:
admin.site.unregister(User)
except NotRegistered:
pass
admin.site.register(User, UserAdmin)
This is a code I have found on stackoverflow. Within add_fieldsets I removed password1, and password2. If I go to admin page, everything looks great, however I can not register a user.
I think it is because of UserCreationForm, which insists of creating an password, but perhaps I could be wrong. Can anyone please let me know how to override UsercreationForm, so passwords wouldn't be mandatory anymore and errors from UserCreationForm would not be seen on the site.
Customizing Django auth can be very difficult and that's why I would recommend looking into 3rd party apps to help you achieve your goals. One you might want to check out is: https://github.com/bee-keeper/django-invitations
even though it is an old question and no real answer, one way to do most of the stuff (without knowing how to act on the "send password") would be:
from django.contrib.auth.admin import UserAdmin as DjangoUserAdmin
from django.contrib.auth.forms import UserCreationForm as DjangoUserCreationForm
class UserCreationForm(DjangoUserCreationForm):
password1 = None
password2 = None
def clean(self):
password = get_random_string() # here you want to maybe send a signal which can be picked up or something
self.cleaned_data['password1'] = password
self.cleaned_data['password2'] = password
return super().clean()
class UserAdmin(DjangoUserAdmin):
add_form = UserCreationForm
fieldsets = (
(None, {'fields': ('username',)}),
(_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}),
)
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('username', 'email'),
}),
)
list_filter = tuple()
list_display = ('username', 'email', 'first_name', 'last_name')
admin.site.register(User, UserAdmin)
I want to add my settings.AUTH_USER_MODEL to my admin insted of User model.
I register it with the snippet I found in the docs:
class UserAdmin(BaseUserAdmin):
# 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', 'bdate')
fieldsets = (
(None, {'fields': ('email', 'password')}),
('Personal info', {'fields': ('bdate', 'website', 'location')}),
)
# 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': ('email', 'password1', 'password2')}
),
)
search_fields = ('email',)
ordering = ('email',)
filter_horizontal = ()
In fieldsets Personal info I added all my custom info. Now I also want to display all inherited fields like first_name, username, etc. I can add them one by one to fieldsets, but I am not sure if that's the right way.
Is there a way just to inherit them from User model without specifying explicitly?
You could make use of ModelAdmin.get_fieldsets():
class UserAdmin(BaseUserAdmin):
def get_fieldsets(self, request, obj=None):
fieldsets = list(super(UserAdmin, self).get_fieldsets(request, obj))
# update the `fieldsets` with your specific fields
fieldsets.append(
('Personal info', {'fields': ('bdate', 'website', 'location')}))
return fieldsets
I enabled the user auth module in Django, however when I use UserCreationForm it only asks for username and the two password/password confirmation fields. I also want email and fullname fields, all set as required fields.
I've done this:
from django.contrib.auth.forms import UserCreationForm
from django import forms
from django.contrib.auth.models import User
class RegisterForm(UserCreationForm):
email = forms.EmailField(label = "Email")
fullname = forms.CharField(label = "Full name")
class Meta:
model = User
fields = ("username", "fullname", "email", )
Now the form shows the new fields but it doesn't save them to the database.
How can I fix this?
There is no such field called fullname in the User model.
If you wish to store the name using the original model then you have to store it separately as a first name and last name.
Edit: If you want just one field in the form and still use the original User model use the following:
You can do something like this:
from django.contrib.auth.forms import UserCreationForm
from django import forms
from django.contrib.auth.models import User
class RegisterForm(UserCreationForm):
email = forms.EmailField(label = "Email")
fullname = forms.CharField(label = "First name")
class Meta:
model = User
fields = ("username", "fullname", "email", )
Now you have to do what manji has said and override the save method, however since the User model does not have a fullname field it should look like this:
def save(self, commit=True):
user = super(RegisterForm, self).save(commit=False)
first_name, last_name = self.cleaned_data["fullname"].split()
user.first_name = first_name
user.last_name = last_name
user.email = self.cleaned_data["email"]
if commit:
user.save()
return user
Note: You should add a clean method for the fullname field that will ensure that the fullname entered contains only two parts, the first name and last name, and that it has otherwise valid characters.
Reference Source Code for the User Model:
http://code.djangoproject.com/browser/django/trunk/django/contrib/auth/models.py#L201
You have to override UserCreationForm.save() method:
def save(self, commit=True):
user = super(RegisterForm, self).save(commit=False)
user.fullname = self.cleaned_data["fullname"]
user.email = self.cleaned_data["email"]
if commit:
user.save()
return user
http://code.djangoproject.com/browser/django/trunk/django/contrib/auth/forms.py#L10
In django 1.10 this is what I wrote in admin.py to add first_name, email and last_name to the default django user creation form
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib import admin
from django.contrib.auth.models import Group, User
# first unregister the existing useradmin...
admin.site.unregister(User)
class UserAdmin(BaseUserAdmin):
# 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 specific fields on auth.User.
list_display = ('username', 'email', 'first_name', 'last_name', 'is_staff')
fieldsets = (
(None, {'fields': ('username', 'password')}),
('Personal info', {'fields': ('first_name', 'last_name', 'email',)}),
('Permissions', {'fields': ('is_active', 'is_staff', 'is_superuser', 'groups', 'user_permissions')}),
('Important dates', {'fields': ('last_login', 'date_joined')}),)
# 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', 'email', 'first_name', 'last_name', 'password1', 'password2')}),)
list_filter = ('is_staff', 'is_superuser', 'is_active', 'groups')
search_fields = ('username', 'first_name', 'last_name', 'email')
ordering = ('username',)
filter_horizontal = ('groups', 'user_permissions',)
# Now register the new UserAdmin...
admin.site.register(User, UserAdmin)