Changes between Version 3 and Version 4 of Ticket #32244


Ignore:
Timestamp:
Dec 4, 2020, 2:33:37 PM (4 years ago)
Author:
Lushen Wu
Comment:

Legend:

Unmodified
Added
Removed
Modified
  • Ticket #32244 – Description

    v3 v4  
    44My failed attempts to solve this:
    551. First I tried passing a queryset to the {{{BookFormSet}}}, i.e. {{{formset = BookFormSet(data=request.POST, queryset=Book.objects.filter(author=1))}}}, but the `ModelChoiceField` still does its single-object SELECT queries.
    6 2. Then I tried to see where the {{{ModelChoiceField}}} defines its queryset, which seems to be in {{{BaseModelFormSet.add_fields()}}}. I tried initiating the {{{ModelChoiceField}}} with the same queryset that I passed to the formset, e.g. {{{Book.objects.filter(author=1)}}} instead of the original code which would be {{{Book._default_manager.get_queryset()}}}. But this doesn't help because I guess the new queryset I defined isn't actually linked to what was passed to the formset (and we don't have a cache running). So the multiple SELECT queries still happen. (Note: I realize {{{_default_manager.get_queryset()}}} might be necessary in cases where the formset can be used to switch one Model instance to another instance which might not be in the original queryset passed to the {{{BaseModelFormset}}}, but this is not our use case)
     62. Then I tried to see where the {{{ModelChoiceField}}} defines its queryset, which seems to be in {{{BaseModelFormSet.add_fields()}}}. I tried initiating the {{{ModelChoiceField}}} with the same queryset that I passed to the formset, e.g. {{{Book.objects.filter(author=1)}}} instead of the original code which would be {{{Book._default_manager.get_queryset()}}}. But this doesn't help because I guess the new queryset I defined isn't actually linked to what was passed to the formset (and already evaluated). So the multiple SELECT queries still happen. (Note: I realize {{{_default_manager.get_queryset()}}} might be necessary in cases where the formset can be used to switch one Model instance to another instance which might not be in the original queryset passed to the {{{BaseModelFormset}}}, but this is not our use case)
    773. I noticed that {{{BaseModelFormSet._existing_object()}}} actually provides a way to check whether an object exists in the queryset that was giving to the formset constructor, which means that queryset is evaluated at most once and the results stored in {{{BaseModelFormSet._object_dict}}}. I thought there might be some way to have {{{ModelChoiceField.to_python()}}} do something similar before calling {{{self.queryset.get(id=123)}}}, but I don't think {{{ModelChoiceField}}} is aware of {{{BaseModelFormSet}}}, and it would seem an anti-pattern to reach up the hierarchy like this.
    88
    99The easiest solution seems to me to pass {{{BaseModelFormSet._object_dict}}} in some way to each {{{ModelForm}}} that's created, and then allow the {{{ModelChoiceField}}} to check this {{{_object_dict}}} before making another SELECT query.
     10
     11Even if this could be solved with some form of DB caching, it still seems inefficient application-layer logic.
Back to Top