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
-~----------~----~----~----~------~----~------~--~---

Reply via email to