1

I have a model with an integer field and would like to have an alternative form input render other than the default textbox, so that I have the following:

models.py: myfield = models.IntegerField(default=7, blank=True)

Would like to have the following:

[x] Choice A (value 0)

[ ] Choice B (value 1)

[x] Choice C (value 2)

So that upon save the choices would be calculated like the the following: (since choice A and C are selected and 2 is not selected).

myfield = sum(choice selected multiplied by the 2 to the value of the selected choice)

so that:

my field = (1 * 2^0) + (0 * 2^1) + (1 * 2^2)

my field = 1 + 0 + 4

my field = 5 #final value

If this was anything outside of Django, it would be more straight-forward via standard Checkbox grouping that does not map directly to a database field in the model, but with Django, i'm currently at a loss.

I have referenced the following materials, but still am unable to figure out what to do:

widgets

modelforms

Thanks for your help and input.

Community
  • 1
  • 1
antoniuslin
  • 249
  • 2
  • 10

2 Answers2

4

You can use custom widget like this:

from django import forms

class BinaryWidget(forms.CheckboxSelectMultiple):
    def value_from_datadict(self, data, files, name):
        value = super(BinaryWidget, self).value_from_datadict(data, files, name)
        if name == 'myfield':
            value = sum([2**(int(x)-1) for x in value])
        return value

and override myfield in your modelform as follows:

class MyModelForm(forms.ModelForm):
    ...
    myfield = forms.IntegerField(widget=BinaryWidget(choices=(
        ('1', '2^0',), ('2', '2^1',), ('3', '2^2',)
        )))

this will give you the expected result, although you probably will need a reverse feature - set initial values when editing for example, if so please let me know, so we can figure editing as well.

mariodev
  • 13,928
  • 3
  • 49
  • 61
  • Thank you very much. I actually tried and used a different method that seems to also work, although it's not as straight-forward as yours. like so mychoices_cb = forms.MultipleChoiceField(label='Checkbox For', required=False, widget = forms.CheckboxSelectMultiple, choices=CHOICES), problem is now, I don't know how to default them to all checked. I really wish Django documentation is a bit more helpful so that I don't have to do trial and errors on acceptable attributes. Do you know? – antoniuslin Oct 30 '13 at 00:31
  • Found it. initial = (c[0] for c in CHOICES). – antoniuslin Oct 30 '13 at 00:40
  • @mariodev I'm using your custom widget in combination with: http://stackoverflow.com/a/8152717/3849359. Therefore I had to change it a little, because my values are given back already as bitchoices, and I only need to sum them. Now I would like get the inverse, because I would like to edit the choice also. Could you please help? Here is my question: http://stackoverflow.com/q/25575951/3849359 – gabn88 Sep 08 '14 at 11:02
-1

Try Select2. It's a much better option.

Imran S.
  • 935
  • 3
  • 15
  • 32