Quick summary: If Django errors during a QuerySet evaluation with
DEBUG=True, the built-in 500 handler in views/debug.py causes the last
QuerySet (one filter shorter than the final version) to be executed, as
in the SQL statement hits the database.
This is very bad if there was only a single filter on a table, and that
table is very large. Here's an example to demonstrate:
class Test1(models.Model):
a = models.CharField(max_length=100)
class Test2(models.Model):
b = models.OneToOneField(Test1)
Say that Test1 is populated with an entry at id=1, but there is not a
matching entry at Test2:
t = Test1.objects.get(id=1)
print t.b
This throws the error you would expect, a "DoesNotExist" error. When
running from a shell, this is the end of it.
However, if you're running from a view, and have Debug=True, then it
runs the 500 error, goes up through the stack trace and shows all the
functions and their local vars. Unfortunately, one of the functions is
QuerySet.get(), in django.db.models.query:
def get(self, *args, **kwargs):
"Performs the SELECT and returns a single object matching the
given keyword arguments."
clone = self.filter(*args, **kwargs)
When the local variables are printed, it attempts to print both the self
and the clone. Since the clone is where the filter is applied, and not
the self, at the point when debugging happens, the self variable is
missing a filter. I know that this is expected behavior, but it is
important for the following piece.
Now, when the 500 template iterates through the local variables, this
"self" QuerySet gets printed, and by the act of printing, it gets
executed. Now, this causes the SQL to hit the database. In this case,
the SQL is the SELECT statement with *no* WHERE clause. If I were to
have used:
t = Test1.objects.filter(id=27).get(id=1)
print t
The end result would be a SELECT statement checking for only WHERE id =
27, instead of WHERE (id=27 AND id=1). (Yes, I know this example is
contrived, but it's the simplest case I can provide).
Picture this: Test1 has 5 million records in it. Suddenly, the
debugging is now destroying the Apache instance and/or MySQL with the
amount of data it has to process, because it's returning all 5 million
results due to a query error.
Something seems very wrong about this situation, that debugging could
cause another query to execute (especially an unintended query), but I
don't know what the correct way to go about fixing or preventing it.
I've tried a bunch of things to stop the QuerySets from evaluating when
the local vars are being printed, but haven't been able to come up with
anything much. Is there a good way to prevent this issue in the 500
template?
Thanks,
George
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"Django developers" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at
http://groups.google.com/group/django-developers?hl=en
-~----------~----~----~----~------~----~------~--~---