The form does not work with more than 10 choices using CommaSeparatedIntegerField in Django

advertisements

After following the rather useful blog post, I am having issues with the widget (forms.SelectMultiple or forms.CheckboxSelectMultiple) not correctly showing which choices have previously been selected, if the number of choices is > 9.

Model:

from django.db import models

class Flower(models.Model):
  '''Flowers'''

  flowers = models.CommaSeparatedIntegerField(max_length=100, default="1,2", blank=True)

Form:

from django import forms

class FlowerForm(forms.ModelForm):

    FLOWERS = (
    ('0', 'Daisies'),
    ('1', 'Petunias'),
    ('2', 'Roses'),
    ('3', 'Forget-me-nots'),
    ('4', 'Choice 4'),
    ('5', 'Choice 5'),
    ('6', 'Choice 6'),
    ('7', 'Choice 7'),
    ('8', 'Choice 8'),
    ('9', 'Choice 9'),
    ('10', 'Choice 10'),
    ('11', 'Choice 11'),
    ('12', 'Choice 12'),
    ('13', 'Choice 13'),
    )

  flowers = forms.MultipleChoiceField(
    widget=forms.CheckboxSelectMultiple, choices=FLOWERS, initial="1")

  def clean_flowers(self):
      field = ""
      for data in self.cleaned_data['flowers']:
        field += str(data)+","
      return field.lstrip(",")

If you select any choices in the list, it does correctly save to the database (via the cleaning function), but when you go back to the form choices above 9 are no longer selected. Other choices are marked as selected instead - choice 1 and the value-10; e.g. if you choose choice 13, choices 1 & 3 will be selected when going back to the form

Please help!?!

Edit: FYI, I'm using Django 1.8.3 with Python 3.4.0.


I think the problem is when you convert the list to a comma separated string in your clean method... it looks like this value is then used by Django when displaying the form.

It seems Django is expecting a list and iterating over the field value, so when you pass it say '13' Django will select '1' and '3' (because strings are iterable as lists of characters)

So there's a problem matching what the form expects (list of values) with what the db field expects (comma separated string)

I don't think there is a straightforward solution.

Maybe try something like this snippet with custom db field as a starting point:
https://djangosnippets.org/snippets/2753/