Django Admin, filter inline ForeignKey field based on main fields

Hi,

Can I apply filter so that in Route Step, it shows only route steps related to the declared product ?

My models:

class Route(models.Model):
    product = models.ForeignKey('inventory.Product', on_delete=models.RESTRICT)
    description = models.TextField(null=True, blank=True)

class RouteStep(models.Model):
    route = models.ForeignKey(Route, on_delete=models.CASCADE)
    operation = models.ForeignKey(Operation, on_delete=models.RESTRICT)
    sequence_number = models.IntegerField(default=1)

class BillOfMaterial(models.Model):
    product = models.ForeignKey('inventory.Product', on_delete=models.RESTRICT, limit_choices_to={'is_active': True},)
    quantity = models.DecimalField(max_digits=10, decimal_places=2, default=1)

class BillOfMaterialItem(models.Model):
    bill_of_material = models.ForeignKey(BillOfMaterial, on_delete=models.CASCADE)
    material = models.ForeignKey('inventory.Material', on_delete=models.RESTRICT)
    quantity = models.DecimalField(max_digits=10, decimal_places=2, default=1)
    route_step = models.ForeignKey(RouteStep, on_delete=models.RESTRICT)

Thank you!

Yes, this can be done. I’m not sure how far down the rabbit hole you’ll need to go.

<conjecture>
You’ll probably need to do something like creating a custom formset for the InlineModelAdmin class, so that it is defined to use a custom form. This custom form will need to define the Route Step field with a custom queryset, based upon the product field of the BillOfMaterial model assigned as the instance attribute of the formset.
</conjecture>

(This is an off-the-cuff idea that I hope points you in the right direction. Otherwise, you’re getting into areas where I don’t think it’s appropriate to be using the admin. You’re likely going to find it easier and cleaner to be doing this in your own view.)

I tried below code but it doesn’t work.
My expectation is that route step field shows only Assembling and QC which are included in the Laptop’s route.


Please help me if I made a mistake!

class BillOfMaterialItemFormset(BaseInlineFormSet):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        if self.forms:
            instance = kwargs['instance']

            if instance.pk:
                product = instance.product
                self.forms[0].base_fields['route_step'].queryset = RouteStep.objects.filter(
                    route__product=product
                )
        print(self.forms[0].base_fields['route_step'].queryset)


class BillOfMaterialItemInline(TabularInline):
    model = BillOfMaterialItem
    formset = BillOfMaterialItemFormset
    extra = 0

Thank you!!