简体   繁体   中英

Understanding django admin readonly_fields

I created some code to differentiate between two usergroups in Django admin, resulting in showing all fields readonly or only some of them, which are set directly in the ModelAdmin class.

At first here is the code:

class PersonAdmin(admin.ModelAdmin):
    readonly_fields = ('created_at','created_by',)

def get_form(self, request, obj=None, **kwargs):
    if obj:     # we are in edit mode
        if request.user.is_superuser:
            self.readonly_fields = ()
        else:
            for group in request.user.groups.all():
                if str(group) == 'readonlyuser':
                    allfields = tuple(obj._meta.get_all_field_names())
                    self.readonly_fields = allfields

    return super(PersonAdmin, self).get_form(request, obj, **kwargs)

I divide between the groups and set the fields accordingly. Everything works fine if users from the two groups are not logged in at the same time! After a 'readonly' user logged in, the adminuser will get all fields readonly too.

My inspections provided a solution also: If I put an additional if statement for the adminuser within the for block everything works as expected.

if str(group) == 'adminuser':
    self.readonly_fields = PersonAdmin.readonly_fields

Why is that and what's happening there?

I have no special cache settings made and it happens on the dev server as well as on an Apache with WSGI.

From my understanding request.user.groups.all() should return all groups the currently logged in user belongs to. Where does Django get the allfields (readonly) from, if another user on a different IP and session match this if block?

The ModelAdmin is only instantiated once for all requests that it receives. So when you define the readonly fields like that, you're setting it across the board permanently.

As long as you're running Django 1.2+, there's a get_readonly_fields method you can use instead for exactly this purpose:

class MyModelAdmin(admin.ModelAdmin):
    ...

    def get_readonly_fields(self, request, obj=None):
        if request.user.is_superuser:
            return super(MyModelAdmin, self).get_readonly_fields(request, obj)
        else:
            return ('created_at', 'created_by')

Remove the readonly_fields attribute from your ModelAdmin or set it to the fields that should be readonly for everyone . Then, in the else block specify all the fields that should be readonly only for non-superusers.

Because the fields in Django Admin are being set (ie cached) after being run the first time when the webserver was restarted. You could probably get around it by re-declaring the readonly_fields tuple. Something like this (untested):

def get_form(self, request, obj=None, **kwargs):  
    self.readonly_fields = ('created_at','created_by',)
    # ...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM