#32244: ORM inefficiency: ModelFormSet executes a single-object SELECT query per
formset instance when saving/validating
-------------------------------------+-------------------------------------
     Reporter:  Lushen Wu            |                    Owner:  nobody
         Type:                       |                   Status:  closed
  Cleanup/optimization               |
    Component:  Database layer       |                  Version:  3.1
  (models, ORM)                      |
     Severity:  Normal               |               Resolution:  wontfix
     Keywords:  formsets             |             Triage Stage:
                                     |  Unreviewed
    Has patch:  0                    |      Needs documentation:  0
  Needs tests:  0                    |  Patch needs improvement:  0
Easy pickings:  0                    |                    UI/UX:  0
-------------------------------------+-------------------------------------

Comment (by Lushen Wu):

 Thanks for taking a look!  I understand that the issue is probably not a
 performance bottle neck in most projects, but if it truly is an extra SQL
 query translating to millions of unnecessary roundtrips across all Django
 deployments (and the fix would be relatively straightforward), I feel like
 it still deserves some consideration. I'd be willing to contribute to a
 patch if helpful.

 Conceptually I'm not exactly sure why ModelChoiceField needs a Python
 representation of the value to validate. I understand why this would be
 needed for e.g. a CharField with a max_length requirement. But if the
 ModelChoiceField value passed from the form is a PK, can it be validated
 without loading the entire instance into memory? (If fetching the full
 Python object is required for custom validators, the to_python() call and
 SELECT query could be deferred until such a case is encountered.)

 Currently the validation callstack goes BaseForm.full_clean() ->
 BaseForm._clean_fields(value) -> Field.clean(value) ->
 ModelChoiceField.to_python(value).

 From what I can see, ModelChoiceField does not override Field.validate()
 or Field.run_validators(). So the only validation step performed by
 ModelChoiceField basically checks whether the Book instance generated by
 Field.to_python() belongs to ModelChoiceField._get_choices() <-- which by
 default is a ModelChoiceIterator for all Book objects.

 Is there a "lighter" way of doing this that simply checks whether the
 ModelChoiceField value (as a PK) exists in the corresponding model table?
 If the SELECT query is simply a side effect of ModelChoiceField inheriting
 Field.clean(), then I think it would be cleaner design to have
 ModelChoiceField.clean() override Field.clean() and avoid calling
 to_python() in the default validation loop. And as mentioned fetch the
 object only if needed for custom validators.

 Thanks again!

 ------------------------------

 P.S. The kw_args workaround you suggested seems to be the cleanest in the
 meantime if this stays a wontfix.

-- 
Ticket URL: <https://code.djangoproject.com/ticket/32244#comment:8>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/066.f3fa61785bcea64af4b465bab9597192%40djangoproject.com.

Reply via email to