Username still required in custom user model - django

I am trying to use the new functionality in Django 1.5 to make use of an email address as the username.
Everything is working fine, bar the admin site to update users, which I have had to fiddle with to make passwords not appear raw (and use the password change form etc.) using this code:-
class PlayerChangeForm(UserChangeForm):
class Meta(UserChangeForm.Meta):
model = Player
class PlayerCreationForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = Player
class PlayerAdmin(auth.admin.UserAdmin):
form = PlayerChangeForm
add_form = PlayerCreationForm
ordering = ['first_name', 'last_name']
list_display = ('primkey', 'email', 'mobile')
list_editable = ('email', 'mobile')
list_filter = ()
fieldsets = ((None, {'fields': ('username', 'first_name', 'last_name', 'email', 'password', 'mobile')}),
('Permissions', {'fields': ('is_active', 'is_admin')}),
('Important dates', {'fields': ('last_login', )}),
)
add_fieldsets = ((None, {
'classes': ('wide',),
'fields': ('username', 'first_name', 'last_name', 'email', 'password1', 'password2')}
),
)
filter_horizontal = ()
def primkey(self, obj):
return ("%s" % (obj.get_full_name()))
primkey.short_description = 'Player'
This makes the admin page look fine but when I actually try and update a Player, it tells me there is an error on the form but doesn't indicate where.
After a bit of messing around, it turns out that it wants the username field to be set (if I add that into the admin form, it says this field is required) but surely this isn't the case as I have set my USERNAME_FIELD to be 'email'?
If I set the field to something, I can then save any changes I've made to the other fields but it doesn't save my update to the username field. But really, I don't want to have to set the username at all - I'm using the email as the username.
Any ideas about this or is this a bug in Django?

The Django Documentation states that the forms must be rewritten:
UserCreationForm
Depends on the User model. Must be re-written for any custom user model.
UserChangeForm
Depends on the User model. Must be re-written for any custom user model.
There is a related ticket: https://code.djangoproject.com/ticket/19353 but the code still expect a username field to be present.

Related

Django admin site user password change

Django admin site used to have a form to change the password for a user that wasn't the logged in user. You would look at the user's update page, and by the password field, there was a change password link. You would click it, and it would take you to a different page for changing the password. I used to take advantage of that page to allow changing of a user's password, without having to open the admin. In Django 4, it seems to now be missing. In fact, I can't figure out how one would change a user's password other than their own, without writing my own view.
I have 2 questions:
Is there a way in the admin site now to change a different user's password?
If this view is gone, what is now the best way for a superuser to have a view that can change passwords for a user?
Edit:
This is what I see. There is no link to change the password where there used to be.
Are you sure you have checked it right? When you select an user it appears by default in the upper part, just after some semi-blinded parameters of the password.
The problem was when I am using AbstractBaseUser, and the admin site registration I was using admin.ModelAdmin instead of UserAdmin.
from django.contrib.auth import get_user_model
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
class EmployeeAdmin(UserAdmin):
ordering = ['email', ]
list_display = ['email', ]
fieldsets = (
(None, {'fields': ('email', 'password')}),
('Info', {'fields': ('first_name', 'last_name', 'phone',)}),
('Address', {'fields': ('address', 'city', 'state', 'zip_code')}),
('Schedule', {'fields': ('time_off',)}),
('Permissions', {'fields': ('is_active', 'is_staff', 'is_superuser',
'groups', 'user_permissions')}),
('Important dates', {'fields': ('last_login', 'date_joined')}),
)
add_fieldsets = (
("User Details", {'fields': ('email', 'password1', 'password2')}),
("Permission", {'fields': ('is_active', 'is_staff', 'is_admin')}),
)
admin.site.register(get_user_model(), EmployeeAdmin)

Can the User model be overridden to make the email field required?

For my application, the email field in the Django User model should be required, but by default it's optional.
I searched this question but most answers I found were talking about making the email field required in the customised UserCreationForm for example:
class CustomUserForm(UserCreationForm):
"""Provide a view for creating users with only the requisite fields."""
class Meta:
model = User
# Note that password is taken care of for us by auth's UserCreationForm.
fields = ('username', 'email')
def __init__(self, *args, **kwargs):
super(CustomUserForm, self).__init__(*args, **kwargs)
self.fields['email'].required = True
but I want to make the email mandatory in the User model as well because I was thinking maybe ModelForm are a frontend thing and the required condition maybe be turned off by the user by using the chrome dev tools, am I wrong? Will making the email required in ModelForm is same as making it required in the user model as well, or can I override the user model to make the email required?
Maybe ModelForm are a frontend thing and the required condition maybe be turned off by the user by using the chrome dev tools, am I wrong?
You are correct that a user can use tools to make an input item not required, in fact you can often alter the DOM and thus alter the HTML form, or even more simply make use of a tool like curl to make a POST request where you can post arbitrary data.
But a Form (and by extent an ModelForm) does not only render the form in HTML, it is also used to validate the data. This thus means that if you use a view with:
def my_view(request):
if request.method == 'POST':
form = CustomUserForm(request.POST, request.FILES)
if form.is_valid():
# …
# …
# …
then the form.is_valid() will return False if the user did not fill in an email address. A form is thus used to validate, clean data, store data in a model, and render a HTML form.
from django.contrib.auth.models import User
from django.db import models
User.add_to_class('email', models.EmailField(blank=False))
in your settings file
AUTH_USER_MODEL = 'yourapp.User'
in your models
from django.db import models
from django.contrib.auth.models import AbstractUser, Permission, Group
from django.utils.translation import gettext_lazy as _
class User(AbstractUser):
groups = models.ManyToManyField(
Group,
verbose_name=_('groups'),
blank=True,
help_text=_(
'The groups this user belongs to. A user will get all permissions '
'granted to each of their groups.'
),
related_name="user_groups",
related_query_name="user",
)
user_permissions = models.ManyToManyField(
Permission,
verbose_name=_('user permissions'),
blank=True,
help_text=_('Specific permissions for this user.'),
related_name="user_permissions",
related_query_name="user",
)
EMAIL_FIELD = 'email'
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['email']
# here you can add new fields and attributes
class Meta:
permissions = (
# here you can add pressiion
)
in your admin
from custodia.models import User
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.utils.translation import gettext_lazy as _
#admin.register(User)
class UserAdmin(UserAdmin):
list_display = ('email', 'first_name', 'last_name', 'customer', 'is_staff', 'is_active')
fieldsets = (
(None, {'fields': ('username', 'password')}),
(_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}),
(_('Aditional info'), {'fields': ('your_new_fields',)}),
(_('Permissions'), {
'fields': ('is_active', 'is_staff', 'is_superuser', 'groups', 'user_permissions'),
}),
(_('Important dates'), {'fields': ('last_login', 'date_joined')}),
)
list_filter = ('is_staff', 'is_superuser', 'is_active', 'groups', 'customer')

Admin Django fieldset creating new user creation form

I have two diffeent fieldsets depending on wether a user is in the 'leader' group or not. The fieldset show exactly what I want, except when I try to add a new user, from a user in the 'Leader' group, I now get a different user creation form.
I got how to do the different fieldsets from here, and I tried ensuring the form is indeed the right one by overriding the custom form as done here.
class UserCreateForm(UserCreationForm):
class Meta:
model = User
fields = ('username', 'password1', 'password2')
class UserProfileInline(admin.StackedInline):
model = UserProfile
can_delete = False
verbose_name_plural = 'UserProfile'
fk_name = 'scout_username'
class CustomUserAdmin(UserAdmin):
#ensuring it's the right form
add_form = UserCreateForm
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('username', 'password1', 'password2'),
}),
)
inlines = (UserProfileInline, )
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')}),
)
leader_fieldsets = (
((None), {'fields': ('username', 'password')}),
(('Personal'), {'fields': ('first_name', 'last_name')}),
)
#making it so leaders can only view the fields within leaders_fieldset
#removing this also removes the problem yet all the fields are shown regardless of the user's group
def get_fieldsets(self, request, obj=None):
if request.user.groups.filter(name='Leader').exists():
return self.leader_fieldsets
else:
return super(CustomUserAdmin, self).get_fieldsets(request, obj=obj)
#adding the userprofile stuff to the user change form
def get_inline_instances(self, request, obj=None):
if not obj:
return list()
return super(CustomUserAdmin, self).get_inline_instances(request, obj)
admin.site.unregister(User)
admin.site.register(User, CustomUserAdmin)
If the user is not in the 'Leader' group I get the original user creation form.
User Creation Form if user is not in Leader Group
Else I get a form with the fields, username, password (which is not a password type as anything written in it is clear text) and then I get first name and last name.
User Creation Form if user is in Leader Group
Could someone please explain to me why this is happening and what I can do to fix it?
A little trick which worked for this particular case follows the fact that the url always had 'ADD' at the end.
Thus by checking if it was the user-add form currently on the page a function could return true or false.
def is_add_form(request):
path_info = request.META.get('PATH_INFO')
last_path = str(path_info.split('/')[-2])
if last_path == 'add':
return True
else:
return False
This worked with great success and I hope it helps others.

Django-admin won't allow me to modify user permissions and groups

When editing user model through admin interface, here's what I see:
And here's what I expect to see:
The second one allows me to modify the user permissions, the first one does not.
The User model I use on the first screenshot inherits from AbstractUser and is registered in the following way:
from django.contrib import admin
import accounts.models
admin.site.register(accounts.models.User)
In my settings:
DEBUG = True
AUTH_USER_MODEL = 'accounts.User'
What can be the problem? How do I get from the first screenshot to the second?
Had the same issue but the solution is quite simple. In your admin.py file just add 'groups', 'user_permissions' to filter_horizontal = ()
i.e
filter_horizontal = ('groups', 'user_permissions')
that is basically it.
referenced from:
https://djangobook.com/customizing-change-lists-forms/
OK, the actual problem was that I inherited not from AbstractUser but from AbstractBaseUser and forgot about PermissionsMixin (the mixin adds the apropriate fields). So I should've done something like this.
The problem in my case is that, I was inheriting only from admin.UserAdmin, I had to create a UserAdmin class that inherits from admin.ModelAdmin and add the filter_horizontal to it, I'm adding the filter every time I modify the UserAdmin, it should look like:
class UserAdmin(UserAdmin):
model = User
filter_horizontal = ('groups', 'user_permissions')
add_form = UserCreationForm
form = UserChangeForm
list_display = ('email', 'is_staff', 'is_active',)
list_filter = ('email', 'is_staff', 'is_active',)
fieldsets = (
# ('Zone label',{'fields.....'})
(None, {'fields': ('email', 'username', 'password',)}),
('Permissions', {'fields': ('is_staff', 'is_active',)}),
('Personal', {'fields': ('about',)}),
)
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('email', 'password1', 'password2', 'is_staff', 'is_active')}
),
)
search_fields = ('email',)
ordering = ('date_joined',)
admin.site.register(User, UserAdmin)
admin.site.unregister(User)
class UserAdmin(admin.ModelAdmin):
list_display = ['username']
filter_horizontal = ("groups", "user_permissions")
admin.site.register(User, UserAdmin)

Django allow edit user password in admin site

I know similar questions has been asked before, but I can't get this to work.
I have overriden the user admin template so i can show only specific fields of the user. This is working.
But I can't edit the user password becouse it appears hashed. I want to ad a link as it was before.
I took a look at the solutions but they didnt worked. My code is as following:
class UserAdmin(admin.ModelAdmin):
fieldsets = (
(None, {'fields': ('username', 'password')}),
(_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}),
(_('Permissions'), {'fields': ('is_active', 'is_superuser')}),
(_('Important dates'), {'fields': ('last_login', 'date_joined')}),
)
list_display = ('username', 'email', 'first_name', 'last_name')
list_filter = ('is_active', 'groups')
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."))
admin.site.unregister(User)
admin.site.register(User,UserAdmin)
All of this works fine but the password is showing as a simple field and the text doesnt appears...
Thank you!!
You will never "edit" the password because it is not saved "in clear" but encrypted at first.
You could add a link to a different view using AdminPasswordChangeForm.
Documentation here
That's the solution:
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."))
this form will link to it. The problem is that you've miss-placed this. It should be under the UserChangeForm. For example (depending on the User table you're using):
class AdminUserChangeForm(forms.ModelForm):
password = ReadOnlyPasswordHashField(
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."
)
class Meta:
model = User
fields = (
'email', 'first_name', 'last_name',
)
def clean_password(self):
...
return self.initial["password"]
class UserAdmin(BaseUserAdmin):
...
fieldsets = (
('Login', {
'fields': [
'email',
'password',
]
}),
...
)
...
form = AdminUserChangeForm
add_form = AdminUserCreationForm