ModelFormSet with ForeignKey relations causes duplicate queries

When rendering a ModelFormset with foreign key relations and a queryset of existing data, I’m getting repeated SQL queries, one on each foreign key related table, and these then multiplied as many times as there are rows in the rendered formset.

There’s a model, call it Product if you like, with 3 ForeignKey relations on top of other fields:

class Product(models.Model):
    d = models.ForeignKey(ModelD, ...)
    c = models.ForeignKey(modelC, ...)
    p = models.ForeignKey(modelP, ...)
    # non-related fields truncated

When creating and/or editing these Product instances, these related models, C, D and P are selected from the available pool of these classes.

ModelForm used for this has nothing fancy, only the widgets defined as:

class ProductForm(forms.ModelForm):
    class Meta:
    model = Product
    fields = #...
    widgets = {
        'd': forms.Select(attrs={'class':'editable'}),
        #same for other fk-fields

This class is added there for template scripting purposes.

The view where the existing data is fetched involves a bit complex queryset, but it includes .select_related(‘d’, ‘c’, ‘p’) which gets the job done when just fetching the data and not rendering it in the formset, i.e. no duplicated queries.

Formset is created with factory:

ProductFormset = modelformset_factory(model=Product, form=ProductForm, can_delete=True, extra=n)
formset = ProductFormset(queryset=queryset_with_many_products.select_related('d', 'c', 'p')) #queryset contains a number of Product instances

Template renders the form like so (some table tags cut off in the snip):

<form method="post">
{% csrf_token %}
{{ formset.management_form }}
<tbody>
{% for form in formset %}
<tr> {{ form.d }} {{ form.c }} {{ form.p }} <!--etc--> </tr>
{% endfor %}

The logic works as expected, I’m getting the necessary data in and out, but rendering the form triggers the unwanted swarm of duplicate queries.

I tried customizing the formset as below, and providing this class as the formset argument for the factory, but the issue remained unchanged.

class ProductFormSet(forms.BaseModelFormSet):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        d_qs = D.objects.all()
        c_qs = C.objects.all()
        p_qs = P.objects.all()
        for form in self.forms:
            form.fields['d'].queryset = d_qs
            form.fields['c'].queryset = c_qs
            form.fields['p'].queryset = p_qs

Django version is 5.0.8 and database is PostgreSQL.