Django

Code

Changeset 7046

Show
Ignore:
Timestamp:
01/28/08 10:08:34 (7 months ago)
Author:
mtredinnick
Message:

queryset-refactor: Added some error checking for a potential crasher if model ordering is set up in a cycle somehow. The error reporting here isn't perfect (it doesn't give any hints about what the infinite loop might be), but it's better than nothing.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/branches/queryset-refactor/django/db/models/sql/query.py

    r7045 r7046  
    508508        return result 
    509509 
    510     def find_ordering_name(self, name, opts, alias=None, default_order='ASC'): 
     510    def find_ordering_name(self, name, opts, alias=None, default_order='ASC', 
     511            already_seen=None): 
    511512        """ 
    512513        Returns the table alias (the name might be ambiguous, the alias will 
     
    526527        # append the default ordering for that model. 
    527528        if len(joins) > 1 and opts.ordering: 
     529            # Firstly, avoid infinite loops. 
     530            if not already_seen: 
     531                already_seen = {} 
     532            join_tuple = tuple([tuple(j) for j in joins]) 
     533            if join_tuple in already_seen: 
     534                raise TypeError('Infinite loop caused by ordering.') 
     535            already_seen[join_tuple] = True 
     536 
    528537            results = [] 
    529538            for item in opts.ordering: 
    530539                results.extend(self.find_ordering_name(item, opts, alias, 
    531                         order)) 
     540                        order, already_seen)) 
    532541            return results 
    533542 
  • django/branches/queryset-refactor/tests/regressiontests/queries/models.py

    r7030 r7046  
    9797class Y(models.Model): 
    9898    x1 = models.ForeignKey(X, related_name='y1') 
     99 
     100# Some models with a cycle in the default ordering. This would be bad if we 
     101# didn't catch the infinite loop. 
     102class LoopX(models.Model): 
     103    y = models.ForeignKey('LoopY') 
     104 
     105    class Meta: 
     106        ordering = ['y'] 
     107 
     108class LoopY(models.Model): 
     109    x = models.ForeignKey(LoopX) 
     110 
     111    class Meta: 
     112        ordering = ['x'] 
    99113 
    100114__test__ = {'API_TESTS':""" 
     
    374388[<Cover: first>, <Cover: second>] 
    375389 
     390# If you're not careful, it's possible to introduce infinite loops via default 
     391# ordering on foreign keys in a cycle. We detect that. 
     392>>> LoopX.objects.all() 
     393Traceback (most recent call last): 
     394... 
     395TypeError: Infinite loop caused by ordering. 
     396 
    376397# If the remote model does not have a default ordering, we order by its 'id' 
    377398# field.