Ticket #16187: 16187.lookup-refactor.diff
File 16187.lookup-refactor.diff, 6.5 KB (added by , 13 years ago) |
---|
-
django/db/models/sql/query.py
diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py index 61fd2be..2863a50 100644
a b class Query(object): 1045 1045 if not parts: 1046 1046 raise FieldError("Cannot parse keyword query %r" % arg) 1047 1047 1048 # Work out the lookup type and remove it from 'parts', if necessary. 1049 if len(parts) == 1 or parts[-1] not in self.query_terms: 1050 lookup_type = 'exact' 1051 else: 1052 lookup_type = parts.pop() 1048 lookup_type = "exact" 1049 model = self.model 1050 # walk the relations and figure out the lookup type 1051 if len(parts) > 1 and arg not in self.aggregates: 1052 for idx, part in enumerate(parts): 1053 try: 1054 if part == "pk": 1055 field = model._meta.pk 1056 else: 1057 # Try to retrieve one of the model's fields from the 1058 # given part. 1059 try: 1060 field, _, _, _ = model._meta.get_field_by_name(part) 1061 except FieldDoesNotExist: 1062 # The first attempt failed. Let's check if it's 1063 # a foreignkey. 1064 if len(part) > 3 and part[-3:] == '_id': 1065 field, _, _, _ = model._meta.get_field_by_name(part[:-3]) 1066 else: 1067 # OK, so the field really doesn't exist 1068 raise 1069 if hasattr(field, "model") and field.model != model: 1070 model = field.model 1071 continue 1072 if hasattr(field, "field"): 1073 # RelatedObjects 1074 field = field.field 1075 if field.rel is not None: 1076 model = field.rel.to 1077 continue 1078 # If we reach here we are no longer traversing relations 1079 if idx < len(parts) - 1 and parts[-1] in self.query_terms: 1080 lookup_type = parts.pop() 1081 break 1082 except FieldDoesNotExist: 1083 if part in self.aggregates and parts[-1] in self.query_terms: 1084 lookup_type = parts.pop() 1085 break 1086 # if we're not on the last part something is wrong 1087 if idx != len(parts) - 1: 1088 # We can't handle this - fall through 1089 if parts[-1] in self.query_terms: 1090 lookup_type = parts.pop() 1091 break 1092 lookup_type = parts.pop() 1093 break 1053 1094 1054 1095 # By default, this is a WHERE clause. If an aggregate is referenced 1055 1096 # in the value, the filter will be promoted to a HAVING -
new file tests/modeltests/lookup_collision/models.py
diff --git a/tests/modeltests/lookup_collision/__init__.py b/tests/modeltests/lookup_collision/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/modeltests/lookup_collision/models.py b/tests/modeltests/lookup_collision/models.py new file mode 100644 index 0000000..e8ed05a
- + 1 from django.db import models, DEFAULT_DB_ALIAS, connection 2 from django.conf import settings 3 4 class RepeatingEvent(models.Model): 5 name = models.CharField(max_length=100) 6 week_day = models.IntegerField() 7 class Meta: 8 ordering = ('week_day', 'name', ) 9 10 class Appointment(models.Model): 11 name = models.CharField(max_length=100) 12 day = models.DateField() 13 repeating = models.ForeignKey(RepeatingEvent) 14 class Meta: 15 ordering = ('day', 'name', ) 16 17 class Calendar(models.Model): 18 name = models.CharField(max_length=100) 19 appointments = models.ManyToManyField(Appointment) 20 class Meta: 21 ordering = ('name',) 22 23 def __unicode__(self): 24 return self.name -
new file tests/modeltests/lookup_collision/tests.py
diff --git a/tests/modeltests/lookup_collision/tests.py b/tests/modeltests/lookup_collision/tests.py new file mode 100644 index 0000000..0a87730
- + 1 from datetime import datetime 2 from django.test import TestCase 3 from models import RepeatingEvent, Appointment, Calendar 4 5 6 class LookupCollisionTests(TestCase): 7 """Test for collisions between lookup type names and field names""" 8 9 def setUp(self): 10 # Create a RepeatingEvent 11 self.rep1 = RepeatingEvent(name="Every Thursday", week_day=5) 12 self.rep1.save() 13 # Create an Appointment 14 self.ap1 = Appointment(name="Today and every thursday", day=datetime(2011, 6, 9), repeating=self.rep1) 15 self.ap1.save() 16 # Create a Calendar 17 self.cal = Calendar(name="My Calendar") 18 self.cal.save() 19 self.cal.appointments = [self.ap1, ] 20 self.cal.save() 21 22 def test_query_simple(self): 23 """Test simple queries with colliding names without traversing relations""" 24 self.assertTrue(RepeatingEvent.objects.filter(week_day=5).exists()) 25 self.assertTrue(Appointment.objects.filter(day=datetime(2011, 6, 9)).exists()) 26 27 def test_query_related(self): 28 """Test queries through related fields with colliding field names""" 29 self.assertTrue(Appointment.objects.filter(repeating__week_day=5).exists()) 30 31 self.assertTrue(Calendar.objects.filter(appointments__day=datetime(2011, 6, 9)).exists()) 32 self.assertTrue(Calendar.objects.filter(appointments__repeating__week_day=5).exists()) 33 34 def test_query_related_with_lookup(self): 35 """Test queries through related fields with colliding names with explicit lookup types""" 36 self.assertTrue(RepeatingEvent.objects.filter(week_day__exact=5).exists()) 37 38 self.assertTrue(Appointment.objects.filter(day__exact=datetime(2011, 6, 9)).exists()) 39 self.assertTrue(Appointment.objects.filter(day__week_day=5).exists()) 40 self.assertTrue(Appointment.objects.filter(repeating__week_day__exact=5).exists()) 41 42 self.assertTrue(Calendar.objects.filter(appointments__day__exact=datetime(2011, 6, 9)).exists()) 43 self.assertTrue(Calendar.objects.filter(appointments__day__week_day=5).exists()) 44 self.assertTrue(Calendar.objects.filter(appointments__repeating__week_day__exact=5).exists())