From b47231ee3e164855590b231d6092e54938d6ae53 Mon Sep 17 00:00:00 2001 From: Malcolm Tredinnick Date: Sun, 14 Oct 2007 02:13:51 +0000 Subject: [PATCH] querset-refactor: Fixed a bunch of little things as a result of working on the tests. All of modeltests/ now pass. This includes a fix to modeltests/signals/ (in the post_delete signal testing), which I'm sure was incorrect previously. git-svn-id: http://code.djangoproject.com/svn/django/branches/queryset-refactor@6489 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/db/models/query.py | 4 ++-- django/db/models/sql/query.py | 30 +++++++++++++------------- django/db/models/sql/where.py | 14 ++++++------ tests/modeltests/many_to_one/models.py | 8 +++---- tests/modeltests/or_lookups/models.py | 8 +++---- tests/modeltests/signals/models.py | 4 ++-- 6 files changed, 33 insertions(+), 35 deletions(-) diff --git a/django/db/models/query.py b/django/db/models/query.py index ca85403f7e..f7371ad1da 100644 --- a/django/db/models/query.py +++ b/django/db/models/query.py @@ -300,7 +300,7 @@ class _QuerySet(object): if kwargs: clone.query.add_q(mapper(Q(**kwargs))) for arg in args: - clone.query.add_q(arg) + clone.query.add_q(mapper(arg)) return clone def complex_filter(self, filter_obj): @@ -515,7 +515,7 @@ def delete_objects(seen_objs): update_query = sql.UpdateQuery(cls, connection) for field in cls._meta.fields: if field.rel and field.null and field.rel.to in seen_objs: - update_query.clear_related(field.column, pk_list) + update_query.clear_related(field, pk_list) # Now delete the actual data for cls in ordered_classes: diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py index 9f5030cf93..7eb9d826bf 100644 --- a/django/db/models/sql/query.py +++ b/django/db/models/sql/query.py @@ -54,7 +54,6 @@ MULTI = 'multi' SINGLE = 'single' NONE = None -# FIXME: Add quote_name() calls around all the tables. class Query(object): """ A single SQL query. @@ -176,6 +175,7 @@ class Query(object): If 'with_limits' is False, any limit/offset information is not included in the query. """ + qn = self.connection.ops.quote_name self.pre_sql_setup() result = ['SELECT'] if self.distinct: @@ -192,10 +192,10 @@ class Query(object): alias_str = (alias != name and ' AS %s' % alias or '') if join_type: result.append('%s %s%s ON (%s.%s = %s.%s)' - % (join_type, name, alias_str, lhs, lhs_col, alias, - col)) + % (join_type, qn(name), alias_str, qn(lhs), + qn(lhs_col), qn(alias), qn(col))) else: - result.append('%s%s' % (name, alias_str)) + result.append('%s%s' % (qn(name), alias_str)) result.extend(self.extra_tables) where, params = self.where.as_sql() @@ -282,12 +282,12 @@ class Query(object): elif self.where: # rhs has an empty where clause. Make it match everything (see # above for reasoning). - w = WhereNode() + w = WhereNode(self) alias = self.join((None, self.model._meta.db_table, None, None)) pk = self.model._meta.pk w.add((alias, pk.column, pk, 'isnull', False), AND) else: - w = WhereNode() + w = WhereNode(self) self.where.add(w, connection) # Selection columns and extra extensions are those provided by 'rhs'. @@ -334,7 +334,7 @@ class Query(object): result.append(col.as_sql(quote_func=qn)) else: table_alias = self.tables[0] - result = ['%s.%s' % (table_alias, qn(f.column)) + result = ['%s.%s' % (qn(table_alias), qn(f.column)) for f in self.model._meta.fields] # We sort extra_select so that the result columns are in a well-defined @@ -388,10 +388,10 @@ class Query(object): order = 'ASC' if '.' in col: table, col = col.split('.', 1) - table = '%s.' % self.table_alias[table] + table = '%s.' % qn(self.table_alias(table)[0]) elif col not in self.extra_select: # Use the root model's database table as the referenced table. - table = '%s.' % self.tables[0] + table = '%s.' % qn(self.tables[0]) else: table = '' result.append('%s%s %s' % (table, @@ -685,9 +685,9 @@ class Query(object): if field.rel: # One-to-one or many-to-one field remote_opts = field.rel.to._meta + target = field.rel.get_related_field() alias = self.join((root_alias, remote_opts.db_table, field.column, - field.rel.field_name)) - target = remote_opts.get_field(field.rel.field_name) + target.column)) return [alias], remote_opts, field, target, target.column # Only remaining possibility is a normal (direct lookup) field. No @@ -838,8 +838,8 @@ class DeleteQuery(Query): if not isinstance(related.field, generic.GenericRelation): for offset in range(0, len(pk_list), GET_ITERATOR_CHUNK_SIZE): where = WhereNode(self) - where.add((None, related.field.m2m_reverse_name(), None, - 'in', + where.add((None, related.field.m2m_reverse_name(), + related.field, 'in', pk_list[offset : offset+GET_ITERATOR_CHUNK_SIZE]), AND) self.do_query(related.field.m2m_db_table(), where) @@ -913,9 +913,9 @@ class UpdateQuery(Query): This is used by the QuerySet.delete_objects() method. """ for offset in range(0, len(pk_list), GET_ITERATOR_CHUNK_SIZE): - where = WhereNode() + where = WhereNode(self) f = self.model._meta.pk - where.add((None, f, f.db_type(), 'in', + where.add((None, f.column, f, 'in', pk_list[offset : offset + GET_ITERATOR_CHUNK_SIZE]), AND) values = [(related_field.column, 'NULL')] diff --git a/django/db/models/sql/where.py b/django/db/models/sql/where.py index 71f192d7ba..4058752ed6 100644 --- a/django/db/models/sql/where.py +++ b/django/db/models/sql/where.py @@ -70,11 +70,10 @@ class WhereNode(tree.Node): params = child[2].get_db_prep_lookup(child[3], child[4]) format = '%s' except EmptyResultSet: - if node.negated: - # If this is a "not" atom, being empty means it has no - # effect on the result, so we can ignore it. - continue - raise + if self.connection == AND and not node.negated: + # We can bail out early in this particular case (only). + raise + sql = None if sql: result.append(format % sql) result_params.extend(params) @@ -92,10 +91,11 @@ class WhereNode(tree.Node): """ table_alias, name, field, lookup_type, value = child conn = self.query.connection + qn = conn.ops.quote_name if table_alias: - lhs = '%s.%s' % (table_alias, conn.ops.quote_name(name)) + lhs = '%s.%s' % (qn(table_alias), qn(name)) else: - lhs = conn.ops.quote_name(name) + lhs = qn(name) db_type = field and field.db_type() or None field_sql = conn.ops.field_cast_sql(db_type) % lhs diff --git a/tests/modeltests/many_to_one/models.py b/tests/modeltests/many_to_one/models.py index d5d07a1e21..85365e2bc3 100644 --- a/tests/modeltests/many_to_one/models.py +++ b/tests/modeltests/many_to_one/models.py @@ -145,18 +145,18 @@ False [, ] # The underlying query only makes one join when a related table is referenced twice. ->>> query = Article.objects.filter(reporter__first_name__exact='John', reporter__last_name__exact='Smith') ->>> null, sql, null = query._get_sql_clause() +>>> queryset = Article.objects.filter(reporter__first_name__exact='John', reporter__last_name__exact='Smith') +>>> sql = queryset.query.as_sql()[0] >>> sql.count('INNER JOIN') 1 # The automatically joined table has a predictable name. ->>> Article.objects.filter(reporter__first_name__exact='John').extra(where=["many_to_one_article__reporter.last_name='Smith'"]) +>>> Article.objects.filter(reporter__first_name__exact='John').extra(where=["many_to_one_reporter.last_name='Smith'"]) [, ] # And should work fine with the unicode that comes out of # newforms.Form.cleaned_data ->>> Article.objects.filter(reporter__first_name__exact='John').extra(where=["many_to_one_article__reporter.last_name='%s'" % u'Smith']) +>>> Article.objects.filter(reporter__first_name__exact='John').extra(where=["many_to_one_reporter.last_name='%s'" % u'Smith']) [, ] # Find all Articles for the Reporter whose ID is 1. diff --git a/tests/modeltests/or_lookups/models.py b/tests/modeltests/or_lookups/models.py index ee2cfd2b95..5dc8351054 100644 --- a/tests/modeltests/or_lookups/models.py +++ b/tests/modeltests/or_lookups/models.py @@ -4,11 +4,9 @@ To perform an OR lookup, or a lookup that combines ANDs and ORs, combine QuerySet objects using & and | operators. -Alternatively, use positional arguments, and pass one or more expressions -of clauses using the variable ``django.db.models.Q`` (or any object with -a get_sql method). - - +Alternatively, use positional arguments, and pass one or more expressions of +clauses using the variable ``django.db.models.Q`` (or any object with an +add_to_query method). """ from django.db import models diff --git a/tests/modeltests/signals/models.py b/tests/modeltests/signals/models.py index 1fb73828bb..d41142135e 100644 --- a/tests/modeltests/signals/models.py +++ b/tests/modeltests/signals/models.py @@ -54,7 +54,7 @@ Is updated pre_delete signal, Tom Smith instance.id is not None: True post_delete signal, Tom Smith -instance.id is None: False +instance.id is None: True >>> p2 = Person(first_name='James', last_name='Jones') >>> p2.id = 99999 @@ -73,7 +73,7 @@ Is created pre_delete signal, James Jones instance.id is not None: True post_delete signal, James Jones -instance.id is None: False +instance.id is None: True >>> Person.objects.all() []