Struggling with multiselect form. Help please!

Maybe I am being completely dumb, but I cannot figure this out.

I have built a test scenario for my situation.

I wanted to store multiple pizzas and the corresponding ingredients. The list of ingredients are stored in a reference table.

test_table_pizza = name of pizza
test_table_ingredients = linked to table above with a link to ingredients in below table
test_table_ingredient = list of ingredients I want user to select from for each pizza.

When the form is loaded, the ingredients are not marked selected, and when you save the form I get a validation error
Select a valid choice. That choice is not one of the available choices

Like I said above I may being dumb, but I cannot figure this out :frowning:

Models.py

class test_table_ingredient(models.Model):
    name            = models.CharField(max_length=200) 
    def __str__(self):
        return self.name
    
class test_table_pizza(models.Model):
    name            = models.CharField(max_length=200) 
    ingredients     = models.ManyToManyField(test_table_ingredient, through='test_table_ingredients')
    def __str__(self):
        return self.name

class test_table_ingredients(models.Model):
    pizza               = models.ForeignKey(test_table_pizza, on_delete=models.CASCADE)
    ingredient          = models.ForeignKey(test_table_ingredient, on_delete=models.CASCADE)
    def __int__(self):
        return self.id

Forms.py

class form_pizza(forms.ModelForm):
        name = forms.CharField(
            label='Pizza Name'
            , max_length=100
            , required=True
            , widget=forms.TextInput(attrs={'class': 'form-control form-label', 'for':'basic-form-name'})
        )
        ingredients = forms.ModelChoiceField(
                    label='Ingredients'
                    , queryset=test_table_ingredient.objects.all()
                    , empty_label=None
                    , widget=forms.SelectMultiple(attrs={'class': 'form-select'}) 
                )
        class Meta:
            model = test_table_pizza
            #exclude = ('',)
            fields = '__all__'

views.py

def test_pizza(request, pid):
    if request.method == 'POST':
        form = form_pizza(request.POST)
        if form.is_valid():
            if int(pid)==0:
                f = form.save( commit=False )
                f.save()
            else:
                form = form_pizza(request.POST, instance=test_table_pizza.objects.get(id = pid))
                f = form.save( commit=False )
                f.save()                    
        else:
            form = form_pizza(request.POST)
    else:
        if int(pid) == 0:
            form = form_pizza()
        else:
            form = form_pizza(instance=test_table_pizza.objects.get(id = pid))
    print(form)
    return render(request, 'home/view_person/form_pizza.html', {'form':form})

Template

    <form id="fAddressType" action="" method="POST" enctype="multipart/form-data" >
        {% csrf_token %}
        {{ form }}
        <br />
        <button class="btn btn-primary btn-value" id="master" name="form" type="submit">Save</button>
    </form>

Read the docs for The save method, specifically the area with using commit=False and many-to-many fields.

(Also, why are you using the commit=False parameter at all? You’re not doing anything with the object between the time you’re saving the form and when you save the object.)

In my example im clearly not doing that.

But in the application I am building, I add change_user=logged in user. and that is ignored from the form and applied before save.

I will look at that, I spent a decent amount of time trying to figure this out. Thanks for the tip I will investigate that documentation.

thanks

Actually… Its failing to validate the data back and returning an error on screen.
So its not getting to the commit=False step.

It seems to be returning false to if form.is_valid(): and then form = form_pizza(request.POST)
So its never getting to that save step.

def test_pizza(request, pid):
    if request.method == 'POST':
        form = form_pizza(request.POST)
        if form.is_valid():
            if int(pid)==0:
                f = form.save( commit=False )
                f.save()
            else:
                form = form_pizza(request.POST, instance=test_table_pizza.objects.get(id = pid))
                f = form.save( commit=False )
                f.save()                    
        else:
            form = form_pizza(request.POST)
    else:
        if int(pid) == 0:
            form = form_pizza()
        else:
            form = form_pizza(instance=test_table_pizza.objects.get(id = pid))
    print(form)
    return render(request, 'home/view_person/form_pizza.html', {'form':form})

So what errors are being shown in the form?

Select a valid choice. That choice is not one of the available choices

Here is a print of request.POST… so its returning ingredients back

<QueryDict: {'csrfmiddlewaretoken': ['xxx'], 'name': ['Cheese Pizza'], 'ingredients': ['1', '2', '3'], 'form': ['']}>

Ahhh, I believe you should be using a ModelMultipleChoiceField instead of a ModelChoiceField in this situation.

Thanks heaps that has helped loading form, but saving I don’t get an error but ingredients table is not being written too.

What is wrong here?

This comes back to my earlier reply - Struggling with multiselect form. Help please! - #2 by KenWhitesell

Thanks heaps that all worked!!!