Hi all,
I am trying to implement a "FlagField" that can be used to store
binary flags in a single integer value in the DB. The approach that
looks most promising is subclassing Integer Field, pass in some
choices as possible flags (which will be internally converted into the
appropriate bitmasks) and use subclasses of MultipleChoiceField and
CheckboxSelectMultiple as form field and widget, respectively.
This all works nicely besides the fact that the formfield() method of
Field forces the Field to use TypedChoiceField as the form_class if
choices are present (django/db/models/fields/__init__.py:326). So
there is no way for me to use my own form_class unless I override this
whole (otherwise perfectly suitable) method. The workaround I have
taken is to use a different name instead of 'choices', but I would
prefer to stick with this name as it is intuitive in the django
context. (One could argue that choices should be reserved for cases
where a single item should be chosen form choices, but I doubt this
would be a worthwile distinction and there is nothing in the code/docs
that suggest this).
My proposal would be to change the formfields() method to check, if
choices are defined, if form_class is a subclass of ChoiceField an if
so, leave it alone. Otherwise the default (TypedChoiceField) can be
used as it is the case now. What do you people think?
I could open a ticket if feedback here suggests so. All other
suggenstions regarding my code are welcome!
All the best,
flo ledermann
Here is my (working) code:
----------------------------------------------------------------------------------
# fields.py
from django.db.models import IntegerField
from django.forms import BooleanField
import forms
class FlagField(IntegerField):
def __init__(self, flags, **kwargs):
# i would like to use 'choices' instead of flags, but this is
impossible
assert flags, "%ss must have flags argument set." %
self.__class__.__name__
self.flags = flags
super(FlagField, self).__init__(**kwargs)
def formfield(self, **kwargs):
defaults = {'form_class': forms.FlagField,
'choices': self.flags }
defaults.update(kwargs)
# this has to be done because admin assigns a widget to
IntegerFields,
# which we do not want here
defaults.pop('widget', None)
return super(FlagField, self).formfield(**defaults)
----------------------------------------------------------------------------------
# forms.py
from django.forms import MultipleChoiceField, CheckboxSelectMultiple,
SelectMultiple
from django.utils.encoding import force_unicode
class FlagWidget(CheckboxSelectMultiple):
def render(self, name, value, attrs=None, choices=()):
flags = []
for i, flag in enumerate(self.choices):
if value & 1<<i > 0: flags.append(flag[0])
return super(FlagWidget, self).render(name, flags, attrs,
choices)
def value_from_datadict(self, data, files, name):
raw = super(FlagWidget, self).value_from_datadict(data, files,
name)
if raw == None: return None
value = 0
for i, flag in enumerate(self.choices):
if flag[0] in raw: value += 1<<i
return value
# revert back to default implementation since we do not really
have multiple values
def _has_changed(self, initial, data):
return super(SelectMultiple, self)._has_changed(initial, data)
class FlagField(MultipleChoiceField):
widget = FlagWidget
def clean(self, value):
return value
----------------------------------------------------------------------------------
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"Django users" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/django-users?hl=en
-~----------~----~----~----~------~----~------~--~---