Created
July 16, 2015 02:31
-
-
Save edgabaldi/5b7ccb32195d2d87f083 to your computer and use it in GitHub Desktop.
ReadOnlyFieldsMixin
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.utils import six | |
from django.utils.encoding import force_str | |
class ReadOnlyFieldsMixin(object): | |
readonly_fields = () | |
def __init__(self, *args, **kwargs): | |
super(ReadOnlyFieldsMixin, self).__init__(*args, **kwargs) | |
self.define_readonly_fields(self.fields) | |
def clean(self): | |
cleaned_data = super(ReadOnlyFieldsMixin, self).clean() | |
for field_name, field in six.iteritems(self.fields): | |
if self._must_be_readonly(field_name): | |
cleaned_data[field_name] = getattr(self.instance, field_name) | |
return cleaned_data | |
def define_readonly_fields(self, field_list): | |
fields = [field for field_name, field in six.iteritems(field_list) | |
if self._must_be_readonly(field_name)] | |
map(lambda field: self._set_readonly(field), fields) | |
def _all_fields(self): | |
return not bool(self.readonly_fields) | |
def _set_readonly(self, field): | |
field.widget.attrs['disabled'] = 'true' | |
field.required = False | |
def _must_be_readonly(self, field_name): | |
return field_name in self.readonly_fields or self._all_fields() | |
def new_readonly_form_class(klass, all_fields=False, readonly_fields=()): | |
name = force_str("ReadOnly{}".format(klass.__name__)) | |
klass_fields = {'all_fields': all_fields, 'readonly_fields': readonly_fields} | |
return type(name, (ReadOnlyFieldsMixin, klass), klass_fields) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.test import TestCase | |
from django.forms import ModelForm | |
from django.db import models | |
from django.utils import six | |
from readonly import ReadOnlyFieldsMixin | |
class Dummy(models.Model): | |
foo = models.CharField(max_length=100) | |
bar = models.CharField(max_length=100) | |
class FooModelForm(ReadOnlyFieldsMixin, ModelForm): | |
class Meta: | |
model = Dummy | |
class BarModelForm(ReadOnlyFieldsMixin, ModelForm): | |
readonly_fields = ('foo',) | |
class Meta: | |
model = Dummy | |
class ReadOnlyFieldsMixinTestCase(TestCase): | |
def test_readonly_fields_attr_empty_all_fields_should_be_readonly(self): | |
form = FooModelForm() | |
self.assertEqual(['foo', 'bar'], self._get_readonly_fields(form)) | |
def test_readonly_fields_just_defined_fields_should_be_readonly(self): | |
form = BarModelForm() | |
self.assertEqual(['foo',], self._get_readonly_fields(form)) | |
def test_clean_all_fields_readonly(self): | |
form = FooModelForm({'foo':'FOO'}) # bar empty is invalid | |
form.is_valid() | |
self.assertEqual(['foo', 'bar'], self._get_fields_cleaned(form)) | |
def test_clean_attr_empty_all_fields_0(self): | |
form = BarModelForm({'foo': 'FOO'}) | |
form.is_valid() | |
self.assertEqual(['foo'], self._get_fields_cleaned(form)) | |
self.assertTrue('bar' in form.errors.keys()) | |
def test_clean_attr_empty_all_fields_1(self): | |
form = BarModelForm({'bar': 'BAR'}) | |
form.is_valid() | |
self.assertEqual(['foo', 'bar'], self._get_fields_cleaned(form)) | |
def _widget_attr_is_disabled(self, field): | |
return 'disabled' in field.widget.attrs and \ | |
field.widget.attrs['disabled'] == 'true' | |
def _is_readonly(self, field): | |
return self._widget_attr_is_disabled(field) and not field.required | |
def _get_readonly_fields(self, form): | |
return [field_name for field_name, field in six.iteritems(form.fields) | |
if self._is_readonly(field)] | |
def _get_fields_cleaned(self, form): | |
return [field_name for field_name, field in | |
six.iteritems(form.cleaned_data)] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment