Fix display of BitField with forms and widgets #15

Merged
merged 4 commits into from Jun 13, 2012
View
@@ -61,4 +61,19 @@ Now you can use the field using very familiar Django operations::
for f in o.flags:
print f
-Enjoy!
+Enjoy!
+
+Admin
+=====
+
+To use the widget in the admin, you'll need to update your ModelAdmin. Add the
+following lines to your ModelAdmin::
+
+ formfield_overrides = {
+ BitField: {'widget': BitFieldCheckboxSelectMultiple},
+ }
+
+Make sure you've imported the classes by adding these lines to the top of the file::
+
+ from bitfield import BitField
+ from bitfield.forms import BitFieldCheckboxSelectMultiple
View
@@ -1,4 +1,4 @@
-from django.forms import CheckboxSelectMultiple, IntegerField
+from django.forms import CheckboxSelectMultiple, IntegerField, ValidationError
from django.utils.encoding import force_unicode
from .types import BitHandler
@@ -29,14 +29,17 @@ class BitFormField(IntegerField):
accepts them).
"""
def __init__(self, choices=(), widget=BitFieldCheckboxSelectMultiple, *args, **kwargs):
- super(BitFormField, self).__init__(widget=widget, *args, **kwargs)
- self.choices = choices
+ self.widget = widget
+ super(BitFormField, self).__init__(*args, **kwargs)
+ self.choices = self.widget.choices = choices
def clean(self, value):
if not value:
return 0
-
- result = BitHandler(0, self.choices)
+ result = BitHandler(0, list(k for k,v in self.choices))
for k in value:
- setattr(result, k, True)
+ try:
+ setattr(result, str(k), True)
+ except AttributeError:
+ raise ValidationError('Unknown choice')
return int(result)
View
@@ -97,7 +97,8 @@ def south_field_triple(self):
return (field_class, args, kwargs)
def formfield(self, form_class=BitFormField, **kwargs):
- return Field.formfield(self, form_class, **kwargs)
+ choices = [(f, f) for f in self.flags]
+ return Field.formfield(self, form_class, choices=choices, **kwargs)
def pre_save(self, instance, add):
value = getattr(instance, self.attname)
@@ -1,2 +1,3 @@
+from forms import *
from models import *
from tests import *
@@ -0,0 +1,7 @@
+from django import forms
+from bitfield.tests.models import BitFieldTestModel, CompositeBitFieldTestModel
+
+class BitFieldTestModelForm(forms.ModelForm):
+
+ class Meta:
+ model = BitFieldTestModel
@@ -3,7 +3,7 @@
from django.test import TestCase
from bitfield import BitHandler, Bit
-from bitfield.tests import BitFieldTestModel, CompositeBitFieldTestModel
+from bitfield.tests import BitFieldTestModel, CompositeBitFieldTestModel, BitFieldTestModelForm
class BitHandlerTest(TestCase):
def test_defaults(self):
@@ -289,3 +289,54 @@ def test_hasattr(self):
self.assertEqual(hasattr(inst.flags, 'flag_4'),
hasattr(inst.flags_2, 'flag_4'))
+class BitFormFieldTest(TestCase):
+ def test_form_new_invalid(self):
+ invalid_data_dicts = [
+ {'flags': ['FLAG_0', 'FLAG_FLAG']},
+ {'flags': ['FLAG_4']},
+ {'flags': [1, 2]}
+ ]
+ for invalid_data in invalid_data_dicts:
+ form = BitFieldTestModelForm(data=invalid_data)
+ self.assertFalse(form.is_valid())
+
+ def test_form_new(self):
+ data_dicts = [
+ {'flags': ['FLAG_0', 'FLAG_1']},
+ {'flags': ['FLAG_3']},
+ {'flags': []},
+ {}
+ ]
+ for data in data_dicts:
+ form = BitFieldTestModelForm(data=data)
+ self.failUnless(form.is_valid())
+ instance = form.save()
+ flags = data['flags'] if 'flags' in data else []
+ for k in BitFieldTestModel.flags:
+ self.assertEquals(bool(getattr(instance.flags, k)), k in flags)
+
+ def test_form_update(self):
+ instance = BitFieldTestModel.objects.create(flags=0)
+ for k in BitFieldTestModel.flags:
+ self.assertFalse(bool(getattr(instance.flags, k)))
+
+ data = {'flags': ['FLAG_0', 'FLAG_1']}
+ form = BitFieldTestModelForm(data=data, instance=instance)
+ self.failUnless(form.is_valid())
+ instance = form.save()
+ for k in BitFieldTestModel.flags:
+ self.assertEquals(bool(getattr(instance.flags, k)), k in data['flags'])
+
+ data = {'flags': ['FLAG_2', 'FLAG_3']}
+ form = BitFieldTestModelForm(data=data, instance=instance)
+ self.failUnless(form.is_valid())
+ instance = form.save()
+ for k in BitFieldTestModel.flags:
+ self.assertEquals(bool(getattr(instance.flags, k)), k in data['flags'])
+
+ data = {'flags': []}
+ form = BitFieldTestModelForm(data=data, instance=instance)
+ self.failUnless(form.is_valid())
+ instance = form.save()
+ for k in BitFieldTestModel.flags:
+ self.assertFalse(bool(getattr(instance.flags, k)))