How to save Many To Many field with Multiple Checkboxes in Django Form

10,698

Solution 1

Are you not getting the checkboxes to show, or is it the error you're trying to get rid of? If the latter, try removing the commit=False when saving the form.

Update: The Color model is not specifying any fields. Give it one, e.g. color = IntegerField(choices=COLOR_CHOICES).

In AddCar form, giving choices=Color.COLOR_CHOICES if wrong - you must give it a tuple of objects that actually exists (Color.COLOR_CHOICES are just code constants). Also you probably should use ModelMultipleChoiceField, which takes a queryset parameter, e.g.:

colors = forms.ModelMultipleChoiceField(queryset=Color.objects, widget=forms.CheckboxSelectMultiple(), required=False)

https://docs.djangoproject.com/en/dev/ref/forms/fields/#modelmultiplechoicefield

Solution 2

You are doing form.save(commit=False) in which does not actually creates record in DB and due to which it cannot store M2M fields. Do form.save_m2m() after you save form.

Or from your code, you can move car.color.add() after you have saved the car. And also you don't need to have form.save(commit=False).

Solution 3

This error is because, you are trying to save related objects to an object that isnt saved, you are two options:

put commit=True

or before:

for c in request.POST.getlist('color'):
                car.color.add(c)

put: car.save()

If you use commit=False, that objects is not beign saved.

But, you dont need save manually the "colors", doing form.save_m2m() will do it for you, well, only if your form has a manytomany field to choise.

EDIT:

Your color field within form, isnt well formed, must be a ModelMultipleChoiceField

color = forms.ModelMultipleChoiceField(queryset=Color.objects.all())

see docs: https://docs.djangoproject.com/en/1.3/topics/forms/modelforms/#inline-formsets

Share:
10,698
howtodothis
Author by

howtodothis

Updated on June 04, 2022

Comments

  • howtodothis
    howtodothis almost 2 years

    I would like to know how in the following form color (many-to-many field) can be populated by values from CheckboxSelectMultiple widget.

    #models.py

    class Color(models.Model):
        RED = 1
        BLACK = 2
    
        COLOR_CHOICES = (
            (RED, _('Red')),
            (BLACK, _('Black')),
        )
    
        name = models.CharField(_('Color'), max_length=512,
                            choices=COLOR_CHOICES, blank=True)
    class Car(models.Model):
        color = models.ManyToManyField(Color, blank=True, null=True)
    
        def save(self):
            self.slug = slugify(self.name)
            super(Car, self).save()
    

    #forms.py

    class AddCar(forms.ModelForm):
        color = forms.MultipleChoiceField(
            choices=Color.COLOR_CHOICES,
            widget=forms.CheckboxSelectMultiple(),
            required=False
        )
    

    #view.py

    def add(request):
        if request.method == 'POST':
            form = AddCar(request.POST)
            ...
            if form.is_valid():
                car = form.save(commit=False)
    
                for c in request.POST.getlist('color'):
                    car.color.add(c)
    
                car.save()
                form.save_m2m()
    
                return redirect('/')
    

    #error

    'Car' instance needs to have a primary key value before a many-to-many relationship can be used.