Admin Django fieldset creating new user creation form - django

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.

Related

Django admin error ValidationError: ['ManagementForm data is missing or has been tampered with'] due to conditional inline use

I have a custom User model(AbstractUser) and a Stock model. Assume there's multiple user roles manager, supplier etc. The manager can be able to view other manager's details and supplier details.
The User model got a conditional inline which shows the stocks of each supplier if the user role is equalled to supplier.(Here role is a PositiveSmallIntegerField with choices and SUPPLIER = 2)
class SupplierStockInline(admin.StackedInline):
""" Inline to show stocks of a supplier """
model = Stock
extra = 0
#admin.register(User)
class UserAdmin(UserAdmin):
""" User """
fieldsets = [
(None, {'fields': ('username', 'password')}),
('Personal info', {'fields': (
'first_name',
'last_name',
'email',
... some custom fields...
)}),
('Permissions', {'fields': (
'is_active',
'is_staff',
'is_superuser',
'role',
'groups',
'user_permissions',
)}),
('Important dates', {'fields': ('last_login', 'date_joined')})
]
list_display = [...]
search_fields = [...]
# --- the source of the problem ---
inlines = []
def get_inlines(self, request, obj):
""" Show inlines, stocks of supplier """
try:
if obj.role == SUPPLIER:
return [SupplierStockInline]
except:
pass
return []
# --- ---- -----
This works just fine till I tried to change the role of a new user to supplier.
ValidationError: ['ManagementForm data is missing or has been tampered with']
The issue is due to that overridden get_inlines() method. When I comment out the get_inlines() it works fine and this is only happening for the role supplier. I tried to tackle this but unabled to come up with a solution.
Hoping for guidance to solve the issue, thanks in advance.
After hours of research finally found a solution, although I cannot exactly explain why it happening (might be related to not having related stock instances and suddenly having relations to stock instances when changed into role supplier).
Anyway, instead of overriding the get_inlines() method, overriding change_view()and using a conditional approach can solve the problem,
class UserAdmin(admin.ModelAdmin):
...
inlines = []
def change_view(self, request, object_id, form_url='', extra_context=None):
self.inlines = []
try:
obj = self.model.objects.get(pk=object_id)
except self.model.DoesNotExist:
pass
else:
if obj.role == SUPPLIER:
self.inlines = [SupplierStockInline,]
return super(UserAdmin, self).change_view(request, object_id, form_url, extra_context)

Django admin error "Please correct the errors below."

I have made custom BaseUserManager to create user but I am getting error of "please correct the errors below" when I add user from django admin panel and I can't find what's going wrong.
Models.py:
class UserManager(BaseUserManager):
def create_user(self,email,password):
user = self.model(email=email)
user.set_password(password)
def create_superuser(self,email,password):
user = self.model(email=email)
user.set_password(password)
user.is_admin = True
user.is_superuser = True
user.is_staff=True
user.save(using=self._db)
class User(AbstractBaseUser,PermissionsMixin):
COMPANY='CO'
EMPLOYEE='EM'
STATUS_CHOICES=(
(COMPANY,'Company'),
(EMPLOYEE,'Employee'),
)
Status=models.CharField(max_length=2,
choices=STATUS_CHOICES,
default=EMPLOYEE)
user_image = models.CharField(max_length=100)
is_admin=models.BooleanField()
email=models.EmailField(unique=True)
is_staff=models.BooleanField(default=False)
object = UserManager()
USERNAME_FIELD='email'
REQUIRED_FIELDS = []
objects=models.Manager()
def get_short_name(self):
return self.email
Admin.py files:
class UserAdmin(UserAdmin):
list_display = ('email', 'is_admin')
list_filter = ('is_admin',)
fieldsets = (
(None, {'fields': ('email', 'password','Status','user_image','last_login')}),
('Permissions', {'fields': ('is_admin','is_staff','is_superuser','user_permissions','groups')}),
)
add_fieldsets= (
(None, {'fields': ('email', 'password','Status','user_image','last_login')}),
('Permissions', {'fields': ('is_admin','is_staff','is_superuser','user_permissions','groups')}),
)
search_fields = ('password',)
ordering = ('password',)
filter_horizontal = ()
admin.site.register(User,UserAdmin)
admin.site.register(Company)
admin.site.register(Employee)
admin.site.register(Job)
admin.site.register(AppliedJobs)
Can someone suggest what I am doing wrong? I always get the error when I add user from admin panel.I can't figure out as I am working first time on baseusermanager.
I can suggest how to try and find the problem. Usually, your UserAdmin will refer to forms, see below:
class UserAdmin(UserAdmin):
add_form = SignUpForm
form = CustomUserChangeForm
You can find out what is causing the errors by using logging. Add the following Mixin to your SignUpForm and CustomUserChangeForm:
import logging
logger = logging.getLogger(__name__)
# see https://stackoverflow.com/questions/20833638/how-to-log-all-django-form-validation-errors
class LoggingMixin(object):
def add_error(self, field, error):
if field:
logger.info('Form error on field %s: %s', field, error)
else:
logger.info('Form error: %s', error)
super().add_error(field, error)
# e.g.
class SignUpForm(LoggingMixin, UserCreationForm):
....
Now, either sign in or change a user and check the logs to find out what is causing the "Please correct the errors below.".
Had the same problem and answer is pretty simple.
The problem is in your add_fieldsets. Django use his own pattern for adding new users (you can check it in UserAdmin model in django.contrib.auth.admin.py file). You need to define fields for password1 and password2.
For your convenience I will paste it there:
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('username', 'password1', 'password2'),
}),
)
Here you have 2 options:
P.S. in any case you need to define username, password1 and password2 fields.
Use superclass field and add your custom:
add_fieldsets = UserAdmin.add_fieldsets + (
(None, {'fields': ('email', 'Status', 'user_image', 'last_login')}),
('Permissions', {'fields': ('is_admin', 'is_staff', 'is_superuser', 'user_permissions', 'groups')}),
)
Define by your own:
add_fieldsets = (
(None, {'fields': ('username', 'email', 'password1', 'password2', 'Status', 'user_image', 'last_login')}),
('Permissions', {'fields': ('is_admin', 'is_staff', 'is_superuser', 'user_permissions', 'groups')}),
)

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

Username still required in custom user model

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.

Changing Django prebuild form to add new user

I was given a task to add a field "location" to the django prebuilt user module
I found the location of the module itself and added the location field as well as the admin modules
eg:
class UserAdmin(admin.ModelAdmin):
add_form_template = 'admin/auth/user/add_form.html'
change_user_password_template = None
fieldsets = (
(None, {'fields': ('username', 'password')}),
(_('Personal info'), {'fields': ('first_name', 'last_name', 'email', 'location')}),
(_('Permissions'), {'fields': ('is_active', 'is_staff', 'is_superuser', 'user_permissions')}),
(_('Important dates'), {'fields': ('last_login', 'date_joined')}),
(_('Groups'), {'fields': ('groups',)}),
)
I rebuilt the database hoping it would show up in the adding of new user form.
But It didn't seem to work. So I assume I forgot to change something else.
I was looking around in the html code for ages trying to find the location of where the actual "change user" form is called, but couldn't find it.
I would appreciate help from someone who dealt with the pre built django admin backend before.
Thank you!
It's not recommended to modify django's user model because it complicates things. Instead, you can add a user profile as documented here.
If you want the profile to show up in the admin side, you can attach the profile as an inline and force it by unregistering the user and then re-registering it. Here's how I do it:
from django.contrib.auth.models import User
from reversion.admin import VersionAdmin
from profiles.models import Profile
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
class ProfileInline(admin.StackedInline):
model = Profile
fk_name = 'user'
extra = 0
max_num = 1
fieldsets = [
('Company', {'fields': ['company', 'office']}),
('User Information', {'fields': ['role', 'gender', 'phone', 'mobile', 'fax', 'street', 'street2', 'city', 'state', 'zip']}),
('Site Information', {'fields': ['sites']}),
]
class NewUserAdmin(VersionAdmin):
inlines = [ProfileInline, ]
admin.site.unregister(User)
admin.site.register(User, NewUserAdmin)