#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.