from django import forms class FieldAccessLevel: '''Represents an access level for a form.''' def __init__(self, rule, enable=None, exclude=None): self.rule = rule self.enable = enable self.exclude = exclude class FieldAccessForm(forms.ModelForm): '''This class will grant or deny access to individual fields according to simple rules. Example: class MyForm(FieldAccessForm): class FieldAccess: staff = FieldAccessLevel(lambda u, i: u.is_staff, enable = ('field1', 'field2'), exclude = ('field3',)) ''' def __init__(self, request_user, *args, **kwargs): super(FieldAccessForm, self).__init__(*args,**kwargs) if request_user.is_superuser: # superuser has full access to all fields return instance = kwargs.get('instance',None) # get available access levels access_levels = list() for FieldAccess in (getattr(self, 'FieldAccess', None), getattr(self.Meta.model, 'FieldAccess', None)): if not FieldAccess: continue for attr in dir(FieldAccess): if attr.startswith('_'): continue access_levels += [getattr(FieldAccess, attr)] # for any access level which the user falls under, retrieve the field # access data for those levels enable = None exclude = None for level in access_levels: if not level.rule(request_user, instance): continue if level.enable: if enable: enable += level.enable else: enable = level.enable if level.exclude: if exclude: exclude += level.exclude else: exclude = level.exclude # disable all fields except those in enable or exclude for fieldname, field in self.fields.items(): if exclude and fieldname in exclude: self.fields.pop(fieldname) elif not enable or fieldname not in enable: field.widget.attrs['readonly'] = 'readonly' field.widget.attrs['disabled'] = 'disabled' field.disabled = True field.value = getattr(instance, fieldname, '')