Loading django/db/models/sql/compiler.py +2 −1 Original line number Diff line number Diff line Loading @@ -56,7 +56,8 @@ class SQLCompiler(object): if name in self.quote_cache: return self.quote_cache[name] if ((name in self.query.alias_map and name not in self.query.table_map) or name in self.query.extra_select or name in self.query.external_aliases): name in self.query.extra_select or ( name in self.query.external_aliases and name not in self.query.table_map)): self.quote_cache[name] = name return name r = self.connection.ops.quote_name(name) Loading docs/releases/1.7.8.txt +6 −2 Original line number Diff line number Diff line Loading @@ -4,5 +4,9 @@ Django 1.7.8 release notes *Under development* Django 1.7.8 fixes database introspection with SQLite 3.8.9 (released April 8, 2015) (:ticket:`24637`). Django 1.7.8 fixes: * Database introspection with SQLite 3.8.9 (released April 8, 2015) (:ticket:`24637`). * A database table name quoting regression in 1.7.2 (:ticket:`24605`). tests/queries/models.py +15 −0 Original line number Diff line number Diff line Loading @@ -690,3 +690,18 @@ class Ticket23605B(models.Model): class Ticket23605C(models.Model): field_c0 = models.FloatField() # db_table names have capital letters to ensure they are quoted in queries. class Individual(models.Model): alive = models.BooleanField(default=False) class Meta: db_table = 'Individual' class RelatedIndividual(models.Model): related = models.ForeignKey(Individual, related_name='related_individual') class Meta: db_table = 'RelatedIndividual' tests/queries/tests.py +44 −18 Original line number Diff line number Diff line from __future__ import unicode_literals from collections import OrderedDict import datetime from operator import attrgetter import pickle import unittest import warnings from collections import OrderedDict from operator import attrgetter from django.core.exceptions import FieldError from django.db import connection, DEFAULT_DB_ALIAS from django.db.models import Count, F, Q from django.db.models.sql.where import WhereNode, EverythingNode, NothingNode from django.db import DEFAULT_DB_ALIAS, connection from django.db.models import F, Q, Count from django.db.models.sql.datastructures import EmptyResultSet from django.db.models.sql.where import EverythingNode, NothingNode, WhereNode from django.test import TestCase, skipUnlessDBFeature from django.test.utils import str_prefix, CaptureQueriesContext from django.test.utils import CaptureQueriesContext, str_prefix from django.utils import six from django.utils.six.moves import range from .models import ( Annotation, Article, Author, Celebrity, Child, Cover, Detail, DumbCategory, ExtraInfo, Fan, Item, LeafA, Join, LeafB, LoopX, LoopZ, ManagedModel, Member, NamedCategory, Note, Number, Plaything, PointerA, Ranking, Related, Report, ReservedName, Tag, TvChef, Valid, X, Food, Eaten, Node, ObjectA, ObjectB, ObjectC, CategoryItem, SimpleCategory, SpecialCategory, OneToOneCategory, NullableName, ProxyCategory, SingleObject, RelatedObject, ModelA, ModelB, ModelC, ModelD, Responsibility, Job, JobResponsibilities, BaseA, FK1, Identifier, Program, Channel, Page, Paragraph, Chapter, Book, MyObject, Order, OrderItem, SharedConnection, Task, Staff, StaffUser, CategoryRelationship, Ticket21203Parent, Ticket21203Child, Person, Company, Employment, CustomPk, CustomPkTag, Classroom, School, Student, Ticket23605A, Ticket23605B, Ticket23605C) FK1, X, Annotation, Article, Author, BaseA, Book, CategoryItem, CategoryRelationship, Celebrity, Channel, Chapter, Child, Classroom, Company, Cover, CustomPk, CustomPkTag, Detail, DumbCategory, Eaten, Employment, ExtraInfo, Fan, Food, Identifier, Individual, Item, Job, JobResponsibilities, Join, LeafA, LeafB, LoopX, LoopZ, ManagedModel, Member, ModelA, ModelB, ModelC, ModelD, MyObject, NamedCategory, Node, Note, NullableName, Number, ObjectA, ObjectB, ObjectC, OneToOneCategory, Order, OrderItem, Page, Paragraph, Person, Plaything, PointerA, Program, ProxyCategory, Ranking, Related, RelatedIndividual, RelatedObject, Report, ReservedName, Responsibility, School, SharedConnection, SimpleCategory, SingleObject, SpecialCategory, Staff, StaffUser, Student, Tag, Task, Ticket21203Child, Ticket21203Parent, Ticket23605A, Ticket23605B, Ticket23605C, TvChef, Valid, ) class BaseQuerysetTest(TestCase): Loading Loading @@ -3448,3 +3450,27 @@ class Ticket23605Tests(TestCase): self.assertQuerysetEqual(qs1, [a1], lambda x: x) qs2 = Ticket23605A.objects.exclude(complex_q) self.assertQuerysetEqual(qs2, [a2], lambda x: x) class TestTicket24605(TestCase): def test_ticket_24605(self): """ Subquery table names should be quoted. """ i1 = Individual.objects.create(alive=True) RelatedIndividual.objects.create(related=i1) i2 = Individual.objects.create(alive=False) RelatedIndividual.objects.create(related=i2) i3 = Individual.objects.create(alive=True) i4 = Individual.objects.create(alive=False) self.assertQuerysetEqual( Individual.objects.filter(Q(alive=False), Q(related_individual__isnull=True)), [i4], lambda x: x ) self.assertQuerysetEqual( Individual.objects.exclude( Q(alive=False), Q(related_individual__isnull=True) ).order_by('pk'), [i1, i2, i3], lambda x: x ) Loading
django/db/models/sql/compiler.py +2 −1 Original line number Diff line number Diff line Loading @@ -56,7 +56,8 @@ class SQLCompiler(object): if name in self.quote_cache: return self.quote_cache[name] if ((name in self.query.alias_map and name not in self.query.table_map) or name in self.query.extra_select or name in self.query.external_aliases): name in self.query.extra_select or ( name in self.query.external_aliases and name not in self.query.table_map)): self.quote_cache[name] = name return name r = self.connection.ops.quote_name(name) Loading
docs/releases/1.7.8.txt +6 −2 Original line number Diff line number Diff line Loading @@ -4,5 +4,9 @@ Django 1.7.8 release notes *Under development* Django 1.7.8 fixes database introspection with SQLite 3.8.9 (released April 8, 2015) (:ticket:`24637`). Django 1.7.8 fixes: * Database introspection with SQLite 3.8.9 (released April 8, 2015) (:ticket:`24637`). * A database table name quoting regression in 1.7.2 (:ticket:`24605`).
tests/queries/models.py +15 −0 Original line number Diff line number Diff line Loading @@ -690,3 +690,18 @@ class Ticket23605B(models.Model): class Ticket23605C(models.Model): field_c0 = models.FloatField() # db_table names have capital letters to ensure they are quoted in queries. class Individual(models.Model): alive = models.BooleanField(default=False) class Meta: db_table = 'Individual' class RelatedIndividual(models.Model): related = models.ForeignKey(Individual, related_name='related_individual') class Meta: db_table = 'RelatedIndividual'
tests/queries/tests.py +44 −18 Original line number Diff line number Diff line from __future__ import unicode_literals from collections import OrderedDict import datetime from operator import attrgetter import pickle import unittest import warnings from collections import OrderedDict from operator import attrgetter from django.core.exceptions import FieldError from django.db import connection, DEFAULT_DB_ALIAS from django.db.models import Count, F, Q from django.db.models.sql.where import WhereNode, EverythingNode, NothingNode from django.db import DEFAULT_DB_ALIAS, connection from django.db.models import F, Q, Count from django.db.models.sql.datastructures import EmptyResultSet from django.db.models.sql.where import EverythingNode, NothingNode, WhereNode from django.test import TestCase, skipUnlessDBFeature from django.test.utils import str_prefix, CaptureQueriesContext from django.test.utils import CaptureQueriesContext, str_prefix from django.utils import six from django.utils.six.moves import range from .models import ( Annotation, Article, Author, Celebrity, Child, Cover, Detail, DumbCategory, ExtraInfo, Fan, Item, LeafA, Join, LeafB, LoopX, LoopZ, ManagedModel, Member, NamedCategory, Note, Number, Plaything, PointerA, Ranking, Related, Report, ReservedName, Tag, TvChef, Valid, X, Food, Eaten, Node, ObjectA, ObjectB, ObjectC, CategoryItem, SimpleCategory, SpecialCategory, OneToOneCategory, NullableName, ProxyCategory, SingleObject, RelatedObject, ModelA, ModelB, ModelC, ModelD, Responsibility, Job, JobResponsibilities, BaseA, FK1, Identifier, Program, Channel, Page, Paragraph, Chapter, Book, MyObject, Order, OrderItem, SharedConnection, Task, Staff, StaffUser, CategoryRelationship, Ticket21203Parent, Ticket21203Child, Person, Company, Employment, CustomPk, CustomPkTag, Classroom, School, Student, Ticket23605A, Ticket23605B, Ticket23605C) FK1, X, Annotation, Article, Author, BaseA, Book, CategoryItem, CategoryRelationship, Celebrity, Channel, Chapter, Child, Classroom, Company, Cover, CustomPk, CustomPkTag, Detail, DumbCategory, Eaten, Employment, ExtraInfo, Fan, Food, Identifier, Individual, Item, Job, JobResponsibilities, Join, LeafA, LeafB, LoopX, LoopZ, ManagedModel, Member, ModelA, ModelB, ModelC, ModelD, MyObject, NamedCategory, Node, Note, NullableName, Number, ObjectA, ObjectB, ObjectC, OneToOneCategory, Order, OrderItem, Page, Paragraph, Person, Plaything, PointerA, Program, ProxyCategory, Ranking, Related, RelatedIndividual, RelatedObject, Report, ReservedName, Responsibility, School, SharedConnection, SimpleCategory, SingleObject, SpecialCategory, Staff, StaffUser, Student, Tag, Task, Ticket21203Child, Ticket21203Parent, Ticket23605A, Ticket23605B, Ticket23605C, TvChef, Valid, ) class BaseQuerysetTest(TestCase): Loading Loading @@ -3448,3 +3450,27 @@ class Ticket23605Tests(TestCase): self.assertQuerysetEqual(qs1, [a1], lambda x: x) qs2 = Ticket23605A.objects.exclude(complex_q) self.assertQuerysetEqual(qs2, [a2], lambda x: x) class TestTicket24605(TestCase): def test_ticket_24605(self): """ Subquery table names should be quoted. """ i1 = Individual.objects.create(alive=True) RelatedIndividual.objects.create(related=i1) i2 = Individual.objects.create(alive=False) RelatedIndividual.objects.create(related=i2) i3 = Individual.objects.create(alive=True) i4 = Individual.objects.create(alive=False) self.assertQuerysetEqual( Individual.objects.filter(Q(alive=False), Q(related_individual__isnull=True)), [i4], lambda x: x ) self.assertQuerysetEqual( Individual.objects.exclude( Q(alive=False), Q(related_individual__isnull=True) ).order_by('pk'), [i1, i2, i3], lambda x: x )