Loading django/db/models/sql/compiler.py +1 −1 Original line number Diff line number Diff line Loading @@ -569,7 +569,7 @@ class SQLCompiler(object): if (len(self.query.get_meta().concrete_fields) == len(self.query.select) and self.connection.features.allows_group_by_pk): self.query.group_by = [ (self.query.get_meta().db_table, self.query.get_meta().pk.column) (self.query.get_initial_alias(), self.query.get_meta().pk.column) ] select_cols = [] seen = set() Loading django/db/models/sql/query.py +29 −0 Original line number Diff line number Diff line Loading @@ -1084,6 +1084,32 @@ class Query(object): (lookup, self.get_meta().model.__name__)) return lookup_parts, field_parts, False def check_query_object_type(self, value, opts): """ Checks whether the object passed while querying is of the correct type. If not, it raises a ValueError specifying the wrong object. """ if hasattr(value, '_meta'): if not (value._meta.concrete_model == opts.concrete_model or opts.concrete_model in value._meta.get_parent_list() or value._meta.concrete_model in opts.get_parent_list()): raise ValueError( 'Cannot query "%s": Must be "%s" instance.' % (value, opts.object_name)) def check_related_objects(self, field, value, opts): """ Checks the type of object passed to query relations. """ if field.rel: # testing for iterable of models if hasattr(value, '__iter__'): for v in value: self.check_query_object_type(v, opts) else: # expecting single model instance here self.check_query_object_type(value, opts) def build_lookup(self, lookups, lhs, rhs): lookups = lookups[:] while lookups: Loading Loading @@ -1159,6 +1185,9 @@ class Query(object): try: field, sources, opts, join_list, path = self.setup_joins( parts, opts, alias, can_reuse=can_reuse, allow_many=allow_many) self.check_related_objects(field, value, opts) # split_exclude() needs to know which joins were generated for the # lookup parts self._lookup_joins = join_list Loading docs/releases/1.8.txt +15 −0 Original line number Diff line number Diff line Loading @@ -350,6 +350,21 @@ The check also applies to the columns generated in an implicit and then specify :attr:`~django.db.models.Field.db_column` on its column(s) as needed. Query relation lookups now check object types ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Querying for model lookups now checks if the object passed is of correct type and raises a :exc:`ValueError` if not. Previously, Django didn't care if the object was of correct type; it just used the object's related field attribute (e.g. ``id``) for the lookup. Now, an error is raised to prevent incorrect lookups:: >>> book = Book.objects.create(name="Django") >>> book = Book.objects.filter(author=book) Traceback (most recent call last): ... ValueError: Cannot query "<Book: Django>": Must be "Author" instance. Miscellaneous ~~~~~~~~~~~~~ Loading tests/one_to_one/tests.py +0 −1 Original line number Diff line number Diff line Loading @@ -100,7 +100,6 @@ class OneToOneTests(TestCase): assert_filter_waiters(restaurant__place__exact=self.p1) assert_filter_waiters(restaurant__place__pk=self.p1.pk) assert_filter_waiters(restaurant__exact=self.p1.pk) assert_filter_waiters(restaurant__exact=self.p1) assert_filter_waiters(restaurant__pk=self.p1.pk) assert_filter_waiters(restaurant=self.p1.pk) assert_filter_waiters(restaurant=self.r) Loading tests/queries/models.py +15 −0 Original line number Diff line number Diff line Loading @@ -409,6 +409,15 @@ class ObjectA(models.Model): return self.name class ProxyObjectA(ObjectA): class Meta: proxy = True class ChildObjectA(ObjectA): pass @python_2_unicode_compatible class ObjectB(models.Model): name = models.CharField(max_length=50) Loading @@ -419,11 +428,17 @@ class ObjectB(models.Model): return self.name class ProxyObjectB(ObjectB): class Meta: proxy = True @python_2_unicode_compatible class ObjectC(models.Model): name = models.CharField(max_length=50) objecta = models.ForeignKey(ObjectA, null=True) objectb = models.ForeignKey(ObjectB, null=True) childobjecta = models.ForeignKey(ChildObjectA, null=True, related_name='ca_pk') def __str__(self): return self.name Loading Loading
django/db/models/sql/compiler.py +1 −1 Original line number Diff line number Diff line Loading @@ -569,7 +569,7 @@ class SQLCompiler(object): if (len(self.query.get_meta().concrete_fields) == len(self.query.select) and self.connection.features.allows_group_by_pk): self.query.group_by = [ (self.query.get_meta().db_table, self.query.get_meta().pk.column) (self.query.get_initial_alias(), self.query.get_meta().pk.column) ] select_cols = [] seen = set() Loading
django/db/models/sql/query.py +29 −0 Original line number Diff line number Diff line Loading @@ -1084,6 +1084,32 @@ class Query(object): (lookup, self.get_meta().model.__name__)) return lookup_parts, field_parts, False def check_query_object_type(self, value, opts): """ Checks whether the object passed while querying is of the correct type. If not, it raises a ValueError specifying the wrong object. """ if hasattr(value, '_meta'): if not (value._meta.concrete_model == opts.concrete_model or opts.concrete_model in value._meta.get_parent_list() or value._meta.concrete_model in opts.get_parent_list()): raise ValueError( 'Cannot query "%s": Must be "%s" instance.' % (value, opts.object_name)) def check_related_objects(self, field, value, opts): """ Checks the type of object passed to query relations. """ if field.rel: # testing for iterable of models if hasattr(value, '__iter__'): for v in value: self.check_query_object_type(v, opts) else: # expecting single model instance here self.check_query_object_type(value, opts) def build_lookup(self, lookups, lhs, rhs): lookups = lookups[:] while lookups: Loading Loading @@ -1159,6 +1185,9 @@ class Query(object): try: field, sources, opts, join_list, path = self.setup_joins( parts, opts, alias, can_reuse=can_reuse, allow_many=allow_many) self.check_related_objects(field, value, opts) # split_exclude() needs to know which joins were generated for the # lookup parts self._lookup_joins = join_list Loading
docs/releases/1.8.txt +15 −0 Original line number Diff line number Diff line Loading @@ -350,6 +350,21 @@ The check also applies to the columns generated in an implicit and then specify :attr:`~django.db.models.Field.db_column` on its column(s) as needed. Query relation lookups now check object types ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Querying for model lookups now checks if the object passed is of correct type and raises a :exc:`ValueError` if not. Previously, Django didn't care if the object was of correct type; it just used the object's related field attribute (e.g. ``id``) for the lookup. Now, an error is raised to prevent incorrect lookups:: >>> book = Book.objects.create(name="Django") >>> book = Book.objects.filter(author=book) Traceback (most recent call last): ... ValueError: Cannot query "<Book: Django>": Must be "Author" instance. Miscellaneous ~~~~~~~~~~~~~ Loading
tests/one_to_one/tests.py +0 −1 Original line number Diff line number Diff line Loading @@ -100,7 +100,6 @@ class OneToOneTests(TestCase): assert_filter_waiters(restaurant__place__exact=self.p1) assert_filter_waiters(restaurant__place__pk=self.p1.pk) assert_filter_waiters(restaurant__exact=self.p1.pk) assert_filter_waiters(restaurant__exact=self.p1) assert_filter_waiters(restaurant__pk=self.p1.pk) assert_filter_waiters(restaurant=self.p1.pk) assert_filter_waiters(restaurant=self.r) Loading
tests/queries/models.py +15 −0 Original line number Diff line number Diff line Loading @@ -409,6 +409,15 @@ class ObjectA(models.Model): return self.name class ProxyObjectA(ObjectA): class Meta: proxy = True class ChildObjectA(ObjectA): pass @python_2_unicode_compatible class ObjectB(models.Model): name = models.CharField(max_length=50) Loading @@ -419,11 +428,17 @@ class ObjectB(models.Model): return self.name class ProxyObjectB(ObjectB): class Meta: proxy = True @python_2_unicode_compatible class ObjectC(models.Model): name = models.CharField(max_length=50) objecta = models.ForeignKey(ObjectA, null=True) objectb = models.ForeignKey(ObjectB, null=True) childobjecta = models.ForeignKey(ChildObjectA, null=True, related_name='ca_pk') def __str__(self): return self.name Loading