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, '')
Comments
I've updated this to the newest code that I'm using, where I made a few improvements to the syntax of the FieldAccess inner class.
#