views:

588

answers:

3

I have a model with field:

class Movie(models.Model):
    genre = models.CommaSeparatedIntegerField(max_length=100, choices=GENRE_CHOICES, blank=True, default=0)
    lang = models.CommaSeparatedIntegerField(max_length=100, choices=LANG_CHOICES, blank=True, default=0)

And I need to get multiple select fields (not checkboxes) from that.

One way, that i found, is to redefine form from ModelAdmin

class MyMovieAdminForm(forms.ModelForm):
    genre = forms.MultipleChoiceField(choices=GENRE_CHOICES)
    lang = forms.MultipleChoiceField(choices=LANG_CHOICES)

class MovieAdmin(admin.ModelAdmin):
    form = MyMovieAdminForm

admin.site.register(Movie, MovieAdmin)

But it need to redeclare 'label' and 'initial' for each field, that isn't good for DRY principle. And I doesn't understand, how can I set current value of object for initial value of each field?

And other way, that I found in manual is formfield-overrides. I use dev version from trunk and I try to use this code, but it didn't change my select fields to multiselect in admin interface:

class MovieAdmin(admin.ModelAdmin):
    formfield_overrides = {
        models.CommaSeparatedIntegerField: {'widget': forms.SelectMultiple},
    }

May be anyone know, what is the best way to define multiple select fields? Thanks!

A: 

I use the following for somewhat-DRYer form manipulation, and it works with 1.0. It's verbose, but it works.

class MyMovieAdminForm(forms.ModelForm):
    ## Meta, etc

    def __init__(self, *args, **kwargs):
        super(MyMovieAdminForm, self).__init__(*args, **kwargs)
        self.fields["genre"].widget = forms.SelectMultiple(choices=foo)
        self.fields["genre"].initial = self.instance.genre
        # Doesn't require redefining label, etc.
AdamKG
I try to use your code, but I have a several problems:* when I save object, form shows error: 'invalid_choice', that I select unaccepteble values, but I use right choices in the model and in the MyMovieAdminForm.__init__ too.
ramusus
second and the most important problem: when I edit existent objects, form doesn't show me values from DB in this mulitselect fields.
ramusus
+1  A: 

I don't find any working answer for making models.CommaSeparatedIntegerField as forms.SelectMultiple. So I changed models.CommaSeparatedIntegerField to models.ManyToManyField and form field becomes works very well! It is more suitable in cases, where you need to make queries on this field.

ramusus
+1 That's nice to know
Van Gale
A: 

1) Remove choices from models.CommaSeparatedIntegerField in models

2) Create CommaSeparatedCharField as replacement

class CommaSeparatedCharField(forms.CharField):
    def to_python(self, value):
        if value in validators.EMPTY_VALUES:
            return u''
        csv = smart_unicode(','.join(value) )
        return csv   

class CommaSeparatedSelectMultiple(forms.SelectMultiple):
    def render(self, *args, **kwargs):
        print args, kwargs
        args_=list(args)
        if type(args_[1])!=list:
            args_[1] = args_[1].split(',')
        return super(CommaSeparatedSelectMultiple, self).render(*args_, **kwargs)

3) Apply

class MyAdmin(admin.ModelAdmin):
    class form(forms.ModelForm):
        def __init__(self, *args, **kwargs):
            super(forms.ModelForm, self).__init__(*args, **kwargs)
            for field_name, choices in [
                ('minutes', [(i,str(i)) for i in range(60)]),
            ]:
                self.fields[field_name] = CommaSeparatedCharField(
                    label=self.fields[field_name].label,
                    initial=self.fields[field_name].initial,
                    widget=forms.CommaSeparatedSelectMultiple(choices=choices)
                )

Work nice on 1.2 trunk

Anonymous