diff --git a/bitfield/models.py b/bitfield/models.py index 3543da3..3780736 100644 --- a/bitfield/models.py +++ b/bitfield/models.py @@ -57,7 +57,8 @@ def __get__(self, obj, type=None): if obj is None: return BitFieldFlags(self.field.flags) retval = obj.__dict__[self.field.name] - if self.field.__class__ is BitField: + # handle case where value of field is None + if not retval is None and self.field.__class__ is BitField: # Update flags from class in case they've changed. retval._keys = self.field.flags return retval @@ -106,7 +107,11 @@ def pre_save(self, instance, add): def get_prep_value(self, value): if isinstance(value, (BitHandler, Bit)): value = value.mask - return int(value) + # handle case where value is None + if value is not None: + return int(value) + else: + return value # def get_db_prep_save(self, value, connection): # if isinstance(value, Bit): @@ -133,7 +138,10 @@ def get_prep_lookup(self, lookup_type, value): def to_python(self, value): if isinstance(value, Bit): value = value.mask - if not isinstance(value, BitHandler): + # handle case where value is None + if value is None: + pass + elif not isinstance(value, BitHandler): # Regression for #1425: fix bad data that was created resulting # in negative values for flags. Compute the value that would # have been visible ot the application to preserve compatibility. diff --git a/bitfield/tests/models.py b/bitfield/tests/models.py index be6641a..b1bec94 100644 --- a/bitfield/tests/models.py +++ b/bitfield/tests/models.py @@ -28,3 +28,10 @@ class CompositeBitFieldTestModel(models.Model): 'flags_2', )) +class BitFieldNullDefaultModel(models.Model): + flags = BitField(flags=( + 'FLAG_0', + 'FLAG_1', + 'FLAG_2', + 'FLAG_3', + ), null=True, default=None, db_column='another_default_null_name') diff --git a/bitfield/tests/tests.py b/bitfield/tests/tests.py index 0d847fd..ec722c8 100644 --- a/bitfield/tests/tests.py +++ b/bitfield/tests/tests.py @@ -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, BitFieldNullDefaultModel class BitHandlerTest(TestCase): def test_defaults(self): @@ -289,3 +289,31 @@ def test_hasattr(self): self.assertEqual(hasattr(inst.flags, 'flag_4'), hasattr(inst.flags_2, 'flag_4')) +class NullDefaultBitfieldTest(TestCase): + """Null values for bitfields used to not work. This test checks to make sure they do work + now and don't break other non-null cases.""" + def test_create_default_null(self): + inst = BitFieldNullDefaultModel() + # flags should be None (null) by default + self.assertIsNone(inst.flags) + inst.save() + # make sure still None (null) after save + self.assertIsNone(inst.flags) + inst = BitFieldNullDefaultModel.objects.get(pk=inst.pk) + # make sure still None (null) after being loaded back in + self.assertIsNone(inst.flags) + # make sure we can still set the flags + inst.flags = 1 + self.assertEqual(type(inst.flags),BitHandler) + inst.save() + inst = BitFieldNullDefaultModel.objects.get(pk=inst.pk) + self.assertEqual(type(inst.flags),BitHandler) + self.assertTrue(inst.flags.FLAG_0.is_set) + # and that we haven't broken things + self.assertFalse(inst.flags.FLAG_1.is_set) + inst.save() + inst = BitFieldNullDefaultModel.objects.get(pk=inst.pk) + self.assertEqual(type(inst.flags),BitHandler) + self.assertTrue(inst.flags.FLAG_0.is_set) + self.assertFalse(inst.flags.FLAG_1.is_set) + diff --git a/setup.py b/setup.py index 8a7daf8..9144db1 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ setup( name='django-bitfield', - version='1.5.0', + version='1.5.0.ejs', author='DISQUS', author_email='opensource@disqus.com', url='http://github.com/disqus/django-bitfield',