Opened 16 months ago

Last modified 6 months ago

#22492 assigned New feature

provide a way to prevent database queries on model objects

Reported by: cjerdonek Owned by: raulcd
Component: Database layer (models, ORM) Version: master
Severity: Normal Keywords: model, queryset, defer, only
Cc: chris.jerdonek@…, raulcumplido@… Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

This is a feature request to provide a way to prevent database queries from happening in a block of code, especially on model objects (e.g. using a context manager, or an internal flag on model objects).

The motivation is for use with the QuerySet method `only()`, for example. (The only() method is used to prevent unnecessary fields from being loaded from a database when querying.) Consider the case of using only() to retrieve a list of many model objects, and then subsequently displaying them. If one executes some Django code after obtaining this list (e.g. by looping through the list of objects), it would be bad if this later code accidentally accessed some other field on each object. This could trigger the unintentional execution of many individual database queries (e.g. on a production database), with potentially bad consequences. I don't currently know an easy way to prevent this.

It would be good to have such a way. For example, Django could provide some sort of noQuery() context manager which would raise an exception if the database were queried inside it. Code after the only() line could be included in such a context manager. This could prevent accidentally hammering a database.

Alternatively, the QuerySet API could expose a way to return objects with some sort of no_query flag set. If attribute access on such a model object required a database query, objects with such a flag set could instead raise an exception. This would also suffice to prevent accidental queries.

Change History (4)

comment:1 Changed 16 months ago by cjerdonek

  • Cc chris.jerdonek@… added
  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset

comment:2 Changed 15 months ago by timo

  • Triage Stage changed from Unreviewed to Accepted
  • Version changed from 1.6 to master

Seems like an interesting idea to at least explore.

comment:3 Changed 6 months ago by raulcd

  • Cc raulcumplido@… added
  • Owner changed from nobody to raulcd
  • Status changed from new to assigned

comment:4 Changed 6 months ago by raulcd

Is something like this a possible solution. I am thinking on the API, or do we prefer a solution where we have a context manager?

In [1]: from polls.models import Choice

In [2]: p = Choice.objects.defer('body_yes', 'id')

In [3]: choice = p[0]

In [4]: choice.no_query_deferred = True

In [5]: choice.body_yes

Traceback (most recent call last):
  File "<....>", line xxx, in <module>
QueryException: no_query flag is set to True and a query has been attempted.

In [6]: choice.no_query_deferred = False

In [7]: choice.body_yes
Out[7]: u'yes'

Note: See TracTickets for help on using tickets.
Back to Top