Skip to content

Instantly share code, notes, and snippets.

@un1t
Last active September 23, 2016 09:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save un1t/5f7ea38329e8efe4678cc4848d7bf2f6 to your computer and use it in GitHub Desktop.
Save un1t/5f7ea38329e8efe4678cc4848d7bf2f6 to your computer and use it in GitHub Desktop.
from django import forms
from django.db import models
class BitFieldWrapper:
def __init__(self, instance, field, value):
self.instance = instance
self.field = field
self.value = value
def has(self, bit):
return self.value & 1 << (bit - 1)
def set(self, bit):
self.value = self.value | 1 << (bit - 1)
def all(self):
return [choice[0] for choice in self.field.bit_choices if self.has(choice[0])]
def __int__(self):
return self.value
def __str__(self):
return str(self.value)
class BitDescriptor:
def __init__(self, field):
self.field = field
def __get__(self, instance, cls=None):
if instance is None:
return self
value = instance.__dict__[self.field.name]
if value is None:
value = self.field.default
if isinstance(value, int) and not isinstance(value, BitFieldWrapper):
return self.field.attr_class(instance, self.field, value)
return instance.__dict__[self.field.name]
def __set__(self, instance, value):
instance.__dict__[self.field.name] = value
class BitField(models.IntegerField):
attr_class = BitFieldWrapper
descriptor_class = BitDescriptor
# https://github.com/kelvinwong-ca/django-select-multiple-field
# https://github.com/goinnn/django-multiselectfield
# https://djangosnippets.org/snippets/2753/
# https://docs.djangoproject.com/en/1.10/ref/forms/fields/
# https://docs.djangoproject.com/en/1.10/ref/models/fields/#commaseparatedintegerfield
def __init__(self, bit_choices=None, *args, **kwargs):
self.bit_choices = bit_choices
super().__init__(*args, **kwargs)
def contribute_to_class(self, cls, name, **kwargs):
super().contribute_to_class(cls, name, **kwargs)
setattr(cls, self.name, self.descriptor_class(self))
def test_bitfieldwrapper():
choices = (
(1, 'a'),
(2, 'b'),
(3, 'c'),
(4, 'd'),
)
wrapper = BitFieldWrapper(None, BitField(bit_choices=choices), 0)
assert int(wrapper) == 0
wrapper.set(1)
assert int(wrapper) == 1
wrapper = BitFieldWrapper(None, BitField(bit_choices=choices), 0)
wrapper.set(2)
assert int(wrapper) == 2
wrapper.set(1)
assert int(wrapper) == 3
wrapper.set(3)
assert int(wrapper) == 7
set(wrapper.all()) == {1, 2}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment