What is the best way to use `ModelChoiceField` in `NestedTabularInline`

Recently, I've noticed that the detail screen in my web has been performing very slowly. After analyzing the issue, I found that it's caused by an inline containing a ModelChoiceField when number of instances too large. This field repeatedly executes SELECT * queries to the database, significantly slowing down the screen's loading time.

Eg: That inline have 50 instances, now it has 50 ModelChoiceField that's ramping 50 SELECT *

I tried various solutions, including setting the queryset to objects.none()

However, this approach led to a new problem: when editing, the data doesn't auto-select as expected. I attempted to address this by setting the initial value dynamically in the __init__ method, but it didn't work due to the lack of a queryset.

class ProductOptionForm(CustomDuplicateItemInlineForm):
    class Meta:
        model = ProductOption
        fields = '__all__'

    # override option để hiển thị autocomplete với size option
    option = forms.ModelChoiceField(
        queryset=PodOption.objects.none(),
        required=True,
        widget=CustomOptionSelect2(
            url='product-size-options-auto-complete',
        ),
        label='Size Option'
    )

    def __init__(self, *args, **kwargs):
        super(ProductOptionForm, self).__init__(*args, **kwargs)

        # Use the preloaded data to set the initial dynamically
        if self.instance and self.instance.pk and hasattr(self, 'product_size_options'):
            self.fields['option'].initial = self.product_size_options[self.instance.option_id]  # Manually set the result cache

It's all empty as you can see

enter image description here

If anyone knows the solution, please let me know. Thanks in advance!

After some debugging, it seems filter_choices_to_render of autocomplete.Select2 is the one causing trouble, so I override it with pre-loaded value. This method doesn't look good but it's worked for now

class CustomOptionSelect2(autocomplete.Select2):

    def filter_choices_to_render(self, selected_choices):
        """Override filter_choices_to_render to prevent access database on initial."""
        if hasattr(self, 'initial'):
            value = ModelChoiceIteratorValue(
                self.initial.pk, self.initial
            )
            self.choices = [
                (value, f"{self.initial.type}: {self.initial.value}")
            ]
        else:
            super().filter_choices_to_render(selected_choices)
Back to Top