#26481: Add a "strict mode" for defer()/only()
----------------------------------------------+-------------------------
     Reporter:  adamchainz                    |      Owner:  nobody
         Type:  New feature                   |     Status:  new
    Component:  Database layer (models, ORM)  |    Version:  master
     Severity:  Normal                        |   Keywords:  only, defer
 Triage Stage:  Unreviewed                    |  Has patch:  0
Easy pickings:  0                             |      UI/UX:  0
----------------------------------------------+-------------------------
 In our project at YPlan we had some highly optimized queries using
 `only()` to restrict the fields being fetched.

 Some time later the downstream code of these queries was changed to access
 extra fields not in the `only()` list. This triggered the
 `DeferredAttribute` implicit queries to go fill in those fields with
 single queries, a classic N+1 queries problem.

 Whilst better testing on the queries would have revealed this, I can't
 help but feel that it's a somewhat surprising behaviour that `only()` (and
 by extension, `defer()`) can bite back this badly.

 I'd like some way of making `only()` and `defer()` strict, and to raise an
 exception on deferred fields.

 Currently we've implemented this with a `patchy.patch` to insert a `raise`
 into `DeferredAttribute`:

 {{{
 from django.db.models.query_utils import DeferredAttribute

 patchy.patch(DeferredAttribute.__get__, """\
     @@ -20,6 +20,7 @@ def __get__(self, instance, owner):
              # might be able to reuse the already loaded value. Refs
 #18343.
              val = self._check_parent_chain(instance, name)
              if val is None:
     +            raise AttributeError("Deferred field '{}' fetched from
 database!".format(self.field_name))
                  instance.refresh_from_db(fields=[self.field_name])
                  val = getattr(instance, self.field_name)
              data[self.field_name] = val
 """)
 }}}

 I can imagine this being a Django-wide setting, or maybe per-model so it
 wouldn't affect third party apps so badly.

--
Ticket URL: <https://code.djangoproject.com/ticket/26481>
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 django-updates+unsubscr...@googlegroups.com.
To post to this group, send email to django-updates@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/053.0650e54970c3855983af1ba2de5f2bb7%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to