from django.db import models
# Decorator for django models that contain readonly fields.
def has_readonly_fields(original_class):
def store_read_only_fields(sender, instance, **kwargs):
if not instance.id:
return
for field_name in sender.read_only_fields:
val = getattr(instance, field_name)
setattr(instance, field_name + "_oldval", val)
def check_read_only_fields(sender, instance, **kwargs):
if not instance.id:
return
for field_name in sender.read_only_fields:
old_value = getattr(instance, field_name + "_oldval")
new_value = getattr(instance, field_name)
if old_value != new_value:
raise ValueError("Field %s is read only." % field_name)
models.signals.post_init.connect(store_read_only_fields, original_class, weak=False) # for load
models.signals.post_save.connect(store_read_only_fields, original_class, weak=False) # for save
models.signals.pre_save.connect(check_read_only_fields, original_class, weak=False)
return original_class
# decorator for django modelforms that contain readonly fields
def modelform_with_readonly_fields(origin_class):
origin_init = origin_class.__init__
def lambder(field, old_method):
return lambda this : clean_field(this, field, old_method)
def clean_field(self, field_name, old_method):
instance = getattr(self, 'instance', None)
if instance and instance.id:
return getattr(instance, field_name)
else:
if old_method:
return old_method(self)
else:
return self.cleaned_data.get(field_name, None)
def __init__(self, *args, **kws):
origin_init(self, *args, **kws)
instance = getattr(self, 'instance', None)
if instance and instance.id:
for field in origin_class.Meta.model.read_only_fields:
self.fields[field].required = False
self.fields[field].widget.attrs['disabled'] = 'disabled'
origin_class.__init__ = __init__
for field in origin_class.Meta.model.read_only_fields:
field_name = "clean_" + field
old_method = getattr(origin_class, field_name, None)
setattr(origin_class, field_name, lambder(field, old_method))
return origin_class
Comments