Ticket #11670: 11670.diff

File 11670.diff, 5.4 KB (added by Joel Watts, 14 years ago)
  • django/db/models/sql/constants.py

    diff --git a/django/db/models/sql/constants.py b/django/db/models/sql/constants.py
    index 63c704f..1a2cc72 100644
    a b QUERY_TERMS = dict([(x, None) for x in (  
    77    'month', 'day', 'week_day', 'isnull', 'search', 'regex', 'iregex',
    88    )])
    99
     10# Valid query types for related fields.
     11# See `django.db.models.fields.related.RelatedField.get_db_prep_lookup`.
     12RELATED_QUERY_TERMS = dict([(x, None) for x in (
     13    'exact', 'gt', 'lt', 'gte', 'lte', 'range', 'in', 'isnull'
     14    )])
     15
    1016# Size of each "chunk" for get_iterator calls.
    1117# Larger values are slightly faster at the expense of more storage space.
    1218GET_ITERATOR_CHUNK_SIZE = 100
  • django/db/models/sql/query.py

    diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py
    index 9a19a9e..d9f357b 100644
    a b class Query(object):  
    7777
    7878    alias_prefix = 'T'
    7979    query_terms = QUERY_TERMS
     80    related_query_terms = RELATED_QUERY_TERMS
    8081    aggregates_module = base_aggregates_module
    8182
    8283    compiler = 'SQLCompiler'
    class Query(object):  
    953954            raise FieldError("Cannot parse keyword query %r" % arg)
    954955
    955956        # Work out the lookup type and remove it from 'parts', if necessary.
    956         if len(parts) == 1 or parts[-1] not in self.query_terms:
     957        if len(parts) == 1:
    957958            lookup_type = 'exact'
    958959        else:
    959             lookup_type = parts.pop()
     960            # Find the last field in the lookup and determine if it's a
     961            # related field. By restricting the query terms used for lookups
     962            # that span relations, we prevent valid field names like "year"
     963            # from being misinterpreted as lookup types.
     964            try:
     965                lookup_model = self.model
     966                for field_name in parts[:-1]:
     967                    lookup_field = lookup_model._meta.get_field(field_name)
     968                    if lookup_field.rel:
     969                        lookup_model = lookup_field.rel.to
     970            except FieldDoesNotExist:
     971                query_terms = self.query_terms
     972            else:
     973                if lookup_field.rel:
     974                    query_terms = self.related_query_terms
     975                else:
     976                    query_terms = self.query_terms
     977            if parts[-1] in query_terms:
     978                lookup_type = parts.pop()
     979            else:
     980                lookup_type = 'exact'
    960981
    961982        # By default, this is a WHERE clause. If an aggregate is referenced
    962983        # in the value, the filter will be promoted to a HAVING
  • new file tests/regressiontests/model_related_lookups_regress/models.py

    diff --git a/tests/regressiontests/model_related_lookups_regress/__init__.py b/tests/regressiontests/model_related_lookups_regress/__init__.py
    new file mode 100644
    index 0000000..e69de29
    diff --git a/tests/regressiontests/model_related_lookups_regress/models.py b/tests/regressiontests/model_related_lookups_regress/models.py
    new file mode 100644
    index 0000000..97d12cf
    - +  
     1from django.db import models
     2
     3
     4class Season(models.Model):
     5    year = models.PositiveSmallIntegerField()
     6    world_series_winner = models.CharField(max_length=100)
     7
     8    def __unicode__(self):
     9        return unicode(self.year)
     10
     11
     12class Game(models.Model):
     13    season = models.ForeignKey(Season, related_name='games')
     14    home = models.CharField(max_length=100)
     15    away = models.CharField(max_length=100)
     16
     17    def __unicode__(self):
     18        return u"%s at %s" % (self.away, self.home)
     19
     20
     21class Player(models.Model):
     22    name = models.CharField(max_length=100)
     23    games = models.ManyToManyField(Game, related_name='players')
     24
     25    def __unicode__(self):
     26        return self.name
     27
     28
     29__test__ = {'API_TESTS':"""
     30Regression test for #11670
     31
     32>>> season_2009 = Season.objects.create(year=2009, world_series_winner="New York Yankees")
     33>>> cardinals_at_astros = season_2009.games.create(home="Houston Astros", away="St. Louis Cardinals")
     34
     35>>> season_2010 = Season.objects.create(year=2010, world_series_winner="Houston Astros")
     36>>> cubs_at_astros = season_2010.games.create(home="Houston Astros", away="Chicago Cubs")
     37>>> brewers_at_astros = season_2010.games.create(home="Houston Astros", away="Milwaukee Brewers")
     38
     39>>> Game.objects.count()
     403
     41
     42>>> Game.objects.filter(season__year=2010).count()
     432
     44
     45>>> Game.objects.get(season__year=2009)
     46<Game: St. Louis Cardinals at Houston Astros>
     47
     48>>> hunter_pence = Player.objects.create(name="Hunter Pence")
     49>>> hunter_pence.games = Game.objects.filter(season__year__in=[2009, 2010])
     50
     51>>> hunter_pence.games.count()
     523
     53
     54>>> hunter_pence.games.filter(season__year=2009).count()
     551
     56
     57>>> hunter_pence.games.filter(season__year__exact=2010).count()
     582
     59
     60>>> pudge = Player.objects.create(name="Ivan Rodriquez")
     61>>> pudge.games = Game.objects.filter(season__year=2009)
     62
     63>>> pedro_feliz = Player.objects.create(name="Pedro Feliz")
     64>>> pedro_feliz.games = Game.objects.filter(season__year=2010)
     65
     66>>> Player.objects.count()
     673
     68
     69>>> Player.objects.filter(games__season__year=2009).distinct().count()
     702
     71
     72>>> Player.objects.filter(games__season__year__exact=2010).distinct().count()
     732
     74
     75>>> Player.objects.filter(games__season__world_series_winner__icontains="Yankees").distinct().count()
     762
     77
     78>>> Player.objects.filter(games__season__world_series_winner__iexact="Houston Astros").distinct().count()
     792
     80
     81"""}
Back to Top