How do I exclude 'self' instance from a ManyToMany field which references the 'self' model?

I have a ‘Pizza’ model that can inherit ‘Toppings’ from another instance of ‘Pizza’.
When I go to update the Pizza, to add new toppings, I need to prevent the user from selecting the ‘self’ instance of Pizza in the parent list.

For Example: I create Margarita pizza with cheese and tomato toppings. I then create another Pizza (Pepperoni) and inherit all toppings form the Margarita. I need to stop Pepperoni from appearing in the ‘parents’ list to stop a circular reference.

models.py

class Topping(models.Model):
    name = models.CharField(max_length=100)


class Pizza(models.Model):
    name = models.CharField(max_length=100)
    parents = models.ManyToManyField("self", symmetrical=False)
    toppings = models.ManyToManyField(Topping)

forms.py

class PizzaForm(ModelForm):

    toppings = forms.ModelMultipleChoiceField(
        queryset=Topping.objects.all(),
        widget=forms.CheckboxSelectMultiple,
        required=False
    )

    parents = forms.ModelMultipleChoiceField(
        queryset=Pizza.objects.all(),
        widget=forms.CheckboxSelectMultiple,
        required=False
    )

    class Meta:
        model = Pizza
        fields = '__all__'

views.py

class PizzaUpdateView(UpdateView):
    model = Pizza
    form_class = PizzaForm

I suspect I need to amend the parent queryset in PizzaForm to exclude a PK, but I’m unsure of how to hand this through to the form from my view.

>Solution :

You can override the init method of PizzaForm:

class PizzaForm(ModelForm):

    toppings = forms.ModelMultipleChoiceField(
        queryset=Topping.objects.all(),
        widget=forms.CheckboxSelectMultiple,
        required=False
    )

    parents = forms.ModelMultipleChoiceField(
        queryset=Pizza.objects.all(),
        widget=forms.CheckboxSelectMultiple,
        required=False
    )

    class Meta:
        model = Pizza
        fields = '__all__'

    def __init__(*args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['parents'].queryset = Pizza.objects.exclude(id=self.instance.id)

Leave a Reply