Swap the field type/widget rendered in AdminPage depending on the permissions

67 views Asked by At

Like in the title I want to swap the field that is rendered on to the form. For example I have the following model:

models.py
class Project(models.Model):
    name = models.TextField(max_length=200)
    finished = models.BoolenField(default=False)

admin.py
class ProjectAdmin(admin.ModelAdmin):
    def get_form(self, request, obj=None, **kwargs):
        if request.user.is_superuser:
            #here change the name field form TextField 
            #to a disabled TextField or to other Field defined by me
            self.form['name']['widget] = MySuperDuperWidgetField() #or smth like that

Is it possible?

2

There are 2 answers

0
Ian Clelland On BEST ANSWER

You will have to override the formfield_for_dbfield method in your ModelAdmin subclass. In it, you can examine the request, the current user, and the object instance, and determine the correct formfield to use (with whatever custom widget you need)

(formfield_for_dbfield is undocumented, so proceed at your own risk :) ) if you know that the field in question is a foreign key, an m2m, or a choice field, then there are documented methods to override for those.

0
Chris Pratt On

Yes, it's possible, but not quite like you have it:

class ProjectAdmin(admin.ModelAdmin):
    def get_form(self, request, obj=None, **kwargs):
        ModelForm = super(ProjectAdmin, self).get_form(request, obj=None, **kwargs)
        class PermissionedModelForm(ModelForm):
            def __init__(self, *args, **kwargs):
                super(PermissionedModelForm, self).__init__(*args, **kwargs)

                if request.user.is_superuser:
                    self.fields['name'].widget = MySuperDuperWidgetField()

        return PermissionedModelForm

EDIT

Actually for something as simple as changing a field's widget @IanClelland's answer is more appropriate, but if you need to do anything more complicated than that, this approach is the way to go.