Created
April 1, 2012 15:14
-
-
Save ivanjr0/2276233 to your computer and use it in GitHub Desktop.
Django - MultipleOptionsField - A set of boolean options stored in a positive integer field.
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.db.models import SubfieldBase | |
from django.db.models.fields import PositiveIntegerField | |
class MultipleOptions(object): | |
def __init__(self, options, value=None): | |
self.options = options | |
try: | |
self._value = int(value) | |
except (ValueError, TypeError): | |
self._value = 0 | |
def _get_flag_value(self, option): | |
return (1 << self.options.index(option)) | |
def __getattr__(self, name): | |
if name in self.options: | |
return bool(self._value & self._get_flag_value(name)) | |
raise AttributeError("'%s' isn't in '%s'." % (name, '\', '.join(self.options))) | |
def __setattr__(self, name, value): | |
if not name == 'options' and name in self.options: | |
try: | |
value = bool(value) | |
except (ValueError, TypeError): | |
value = False | |
current = getattr(self, name) | |
if not value == current: | |
self._value ^= self._get_flag_value(name) | |
else: return super(MultipleOptions, self).__setattr__(name, value) | |
class MultipleOptionsField(PositiveIntegerField): | |
__metaclass__ = SubfieldBase | |
description = "A set of boolean options stored in a positive integer field. " | |
def __init__(self, options=[], *args, **kwargs): | |
self.options = options | |
super(MultipleOptionsField, self).__init__(*args, **kwargs) | |
def to_python(self, value): | |
if isinstance(value, MultipleOptions): | |
return value | |
return MultipleOptions(value=value, options=self.options) | |
def get_prep_value(self, value): | |
return value._value |
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
import unittest | |
from main import MultipleOptions | |
class MultipleOptionsTest(unittest.TestCase): | |
def setUp(self): | |
self.options = ['foo', 'bar', 'baz'] | |
self.container = MultipleOptions(options=self.options) | |
def test_attrs(self): | |
for option in self.options: | |
self.assertTrue(hasattr(self.container, option)) | |
self.assertTrue(isinstance(getattr(self.container, option), bool)) | |
def test_get_set(self): | |
self.container.foo = True | |
self.assertTrue(self.container.foo) | |
self.assertEquals(2 ** self.options.index('foo'), self.container._value) | |
self.container.foo = False | |
self.assertEquals(0, self.container._value) | |
def test_get_set_multiple(self): | |
self.container.foo = True | |
self.assertTrue(self.container.foo) | |
self.container.baz = True | |
self.assertTrue(self.container.baz) | |
self.assertEquals(2 ** self.options.index('foo') \ | |
+ 2 ** self.options.index('baz'), self.container._value) | |
self.container.foo = False | |
self.assertEquals(2 ** self.options.index('baz'), self.container._value) | |
self.container.baz = False | |
self.assertEquals(0, self.container._value) | |
main = unittest.main | |
if __name__ == '__main__': main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
TODO: