Login

Read only form & model field

Author:
StanislavKraev
Posted:
June 30, 2011
Language:
Python
Version:
1.2
Tags:
forms model field readonly
Score:
1 (after 1 ratings)

These decorators can be used to make some model/form fields readonly.

Sample usage:

# Use this decorator on form with readonly fields.`
@modelform_with_readonly_fields`
class FooAdminForm(forms.ModelForm):`

...

# This decorator shoud be used to protect selected fields `
# from modification after initial save.`
@has_readonly_fields`
class Foo(models.Model):`
    read_only_fields = ('name', )`

...

Result will be the same as shown in this post: Readonly field and Readonly model field

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
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

More like this

  1. Read-only Model Form Base Class by tgandor 1 year ago
  2. Replace model select widget in admin with a readonly link to the related object by ekellner 6 years, 8 months ago
  3. Readonly fields on Form/Modelform by Killarny 6 years, 2 months ago
  4. FieldAccessForm (per-field user access for forms derived from models) by Killarny 6 years, 6 months ago
  5. Obfuscator for django project sources by audial 7 years, 5 months ago

Comments

Please login first before commenting.