mirror of
https://github.com/django/django.git
synced 2025-07-07 11:19:12 +00:00
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
This commit is contained in:
parent
e9f1f50461
commit
b47231ee3e
@ -300,7 +300,7 @@ class _QuerySet(object):
|
|||||||
if kwargs:
|
if kwargs:
|
||||||
clone.query.add_q(mapper(Q(**kwargs)))
|
clone.query.add_q(mapper(Q(**kwargs)))
|
||||||
for arg in args:
|
for arg in args:
|
||||||
clone.query.add_q(arg)
|
clone.query.add_q(mapper(arg))
|
||||||
return clone
|
return clone
|
||||||
|
|
||||||
def complex_filter(self, filter_obj):
|
def complex_filter(self, filter_obj):
|
||||||
@ -515,7 +515,7 @@ def delete_objects(seen_objs):
|
|||||||
update_query = sql.UpdateQuery(cls, connection)
|
update_query = sql.UpdateQuery(cls, connection)
|
||||||
for field in cls._meta.fields:
|
for field in cls._meta.fields:
|
||||||
if field.rel and field.null and field.rel.to in seen_objs:
|
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
|
# Now delete the actual data
|
||||||
for cls in ordered_classes:
|
for cls in ordered_classes:
|
||||||
|
@ -54,7 +54,6 @@ MULTI = 'multi'
|
|||||||
SINGLE = 'single'
|
SINGLE = 'single'
|
||||||
NONE = None
|
NONE = None
|
||||||
|
|
||||||
# FIXME: Add quote_name() calls around all the tables.
|
|
||||||
class Query(object):
|
class Query(object):
|
||||||
"""
|
"""
|
||||||
A single SQL query.
|
A single SQL query.
|
||||||
@ -176,6 +175,7 @@ class Query(object):
|
|||||||
If 'with_limits' is False, any limit/offset information is not included
|
If 'with_limits' is False, any limit/offset information is not included
|
||||||
in the query.
|
in the query.
|
||||||
"""
|
"""
|
||||||
|
qn = self.connection.ops.quote_name
|
||||||
self.pre_sql_setup()
|
self.pre_sql_setup()
|
||||||
result = ['SELECT']
|
result = ['SELECT']
|
||||||
if self.distinct:
|
if self.distinct:
|
||||||
@ -192,10 +192,10 @@ class Query(object):
|
|||||||
alias_str = (alias != name and ' AS %s' % alias or '')
|
alias_str = (alias != name and ' AS %s' % alias or '')
|
||||||
if join_type:
|
if join_type:
|
||||||
result.append('%s %s%s ON (%s.%s = %s.%s)'
|
result.append('%s %s%s ON (%s.%s = %s.%s)'
|
||||||
% (join_type, name, alias_str, lhs, lhs_col, alias,
|
% (join_type, qn(name), alias_str, qn(lhs),
|
||||||
col))
|
qn(lhs_col), qn(alias), qn(col)))
|
||||||
else:
|
else:
|
||||||
result.append('%s%s' % (name, alias_str))
|
result.append('%s%s' % (qn(name), alias_str))
|
||||||
result.extend(self.extra_tables)
|
result.extend(self.extra_tables)
|
||||||
|
|
||||||
where, params = self.where.as_sql()
|
where, params = self.where.as_sql()
|
||||||
@ -282,12 +282,12 @@ class Query(object):
|
|||||||
elif self.where:
|
elif self.where:
|
||||||
# rhs has an empty where clause. Make it match everything (see
|
# rhs has an empty where clause. Make it match everything (see
|
||||||
# above for reasoning).
|
# above for reasoning).
|
||||||
w = WhereNode()
|
w = WhereNode(self)
|
||||||
alias = self.join((None, self.model._meta.db_table, None, None))
|
alias = self.join((None, self.model._meta.db_table, None, None))
|
||||||
pk = self.model._meta.pk
|
pk = self.model._meta.pk
|
||||||
w.add((alias, pk.column, pk, 'isnull', False), AND)
|
w.add((alias, pk.column, pk, 'isnull', False), AND)
|
||||||
else:
|
else:
|
||||||
w = WhereNode()
|
w = WhereNode(self)
|
||||||
self.where.add(w, connection)
|
self.where.add(w, connection)
|
||||||
|
|
||||||
# Selection columns and extra extensions are those provided by 'rhs'.
|
# 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))
|
result.append(col.as_sql(quote_func=qn))
|
||||||
else:
|
else:
|
||||||
table_alias = self.tables[0]
|
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]
|
for f in self.model._meta.fields]
|
||||||
|
|
||||||
# We sort extra_select so that the result columns are in a well-defined
|
# We sort extra_select so that the result columns are in a well-defined
|
||||||
@ -388,10 +388,10 @@ class Query(object):
|
|||||||
order = 'ASC'
|
order = 'ASC'
|
||||||
if '.' in col:
|
if '.' in col:
|
||||||
table, col = col.split('.', 1)
|
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:
|
elif col not in self.extra_select:
|
||||||
# Use the root model's database table as the referenced table.
|
# Use the root model's database table as the referenced table.
|
||||||
table = '%s.' % self.tables[0]
|
table = '%s.' % qn(self.tables[0])
|
||||||
else:
|
else:
|
||||||
table = ''
|
table = ''
|
||||||
result.append('%s%s %s' % (table,
|
result.append('%s%s %s' % (table,
|
||||||
@ -685,9 +685,9 @@ class Query(object):
|
|||||||
if field.rel:
|
if field.rel:
|
||||||
# One-to-one or many-to-one field
|
# One-to-one or many-to-one field
|
||||||
remote_opts = field.rel.to._meta
|
remote_opts = field.rel.to._meta
|
||||||
|
target = field.rel.get_related_field()
|
||||||
alias = self.join((root_alias, remote_opts.db_table, field.column,
|
alias = self.join((root_alias, remote_opts.db_table, field.column,
|
||||||
field.rel.field_name))
|
target.column))
|
||||||
target = remote_opts.get_field(field.rel.field_name)
|
|
||||||
return [alias], remote_opts, field, target, target.column
|
return [alias], remote_opts, field, target, target.column
|
||||||
|
|
||||||
# Only remaining possibility is a normal (direct lookup) field. No
|
# Only remaining possibility is a normal (direct lookup) field. No
|
||||||
@ -838,8 +838,8 @@ class DeleteQuery(Query):
|
|||||||
if not isinstance(related.field, generic.GenericRelation):
|
if not isinstance(related.field, generic.GenericRelation):
|
||||||
for offset in range(0, len(pk_list), GET_ITERATOR_CHUNK_SIZE):
|
for offset in range(0, len(pk_list), GET_ITERATOR_CHUNK_SIZE):
|
||||||
where = WhereNode(self)
|
where = WhereNode(self)
|
||||||
where.add((None, related.field.m2m_reverse_name(), None,
|
where.add((None, related.field.m2m_reverse_name(),
|
||||||
'in',
|
related.field, 'in',
|
||||||
pk_list[offset : offset+GET_ITERATOR_CHUNK_SIZE]),
|
pk_list[offset : offset+GET_ITERATOR_CHUNK_SIZE]),
|
||||||
AND)
|
AND)
|
||||||
self.do_query(related.field.m2m_db_table(), where)
|
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.
|
This is used by the QuerySet.delete_objects() method.
|
||||||
"""
|
"""
|
||||||
for offset in range(0, len(pk_list), GET_ITERATOR_CHUNK_SIZE):
|
for offset in range(0, len(pk_list), GET_ITERATOR_CHUNK_SIZE):
|
||||||
where = WhereNode()
|
where = WhereNode(self)
|
||||||
f = self.model._meta.pk
|
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]),
|
pk_list[offset : offset + GET_ITERATOR_CHUNK_SIZE]),
|
||||||
AND)
|
AND)
|
||||||
values = [(related_field.column, 'NULL')]
|
values = [(related_field.column, 'NULL')]
|
||||||
|
@ -70,11 +70,10 @@ class WhereNode(tree.Node):
|
|||||||
params = child[2].get_db_prep_lookup(child[3], child[4])
|
params = child[2].get_db_prep_lookup(child[3], child[4])
|
||||||
format = '%s'
|
format = '%s'
|
||||||
except EmptyResultSet:
|
except EmptyResultSet:
|
||||||
if node.negated:
|
if self.connection == AND and not node.negated:
|
||||||
# If this is a "not" atom, being empty means it has no
|
# We can bail out early in this particular case (only).
|
||||||
# effect on the result, so we can ignore it.
|
|
||||||
continue
|
|
||||||
raise
|
raise
|
||||||
|
sql = None
|
||||||
if sql:
|
if sql:
|
||||||
result.append(format % sql)
|
result.append(format % sql)
|
||||||
result_params.extend(params)
|
result_params.extend(params)
|
||||||
@ -92,10 +91,11 @@ class WhereNode(tree.Node):
|
|||||||
"""
|
"""
|
||||||
table_alias, name, field, lookup_type, value = child
|
table_alias, name, field, lookup_type, value = child
|
||||||
conn = self.query.connection
|
conn = self.query.connection
|
||||||
|
qn = conn.ops.quote_name
|
||||||
if table_alias:
|
if table_alias:
|
||||||
lhs = '%s.%s' % (table_alias, conn.ops.quote_name(name))
|
lhs = '%s.%s' % (qn(table_alias), qn(name))
|
||||||
else:
|
else:
|
||||||
lhs = conn.ops.quote_name(name)
|
lhs = qn(name)
|
||||||
db_type = field and field.db_type() or None
|
db_type = field and field.db_type() or None
|
||||||
field_sql = conn.ops.field_cast_sql(db_type) % lhs
|
field_sql = conn.ops.field_cast_sql(db_type) % lhs
|
||||||
|
|
||||||
|
@ -145,18 +145,18 @@ False
|
|||||||
[<Article: John's second story>, <Article: This is a test>]
|
[<Article: John's second story>, <Article: This is a test>]
|
||||||
|
|
||||||
# The underlying query only makes one join when a related table is referenced twice.
|
# 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')
|
>>> queryset = Article.objects.filter(reporter__first_name__exact='John', reporter__last_name__exact='Smith')
|
||||||
>>> null, sql, null = query._get_sql_clause()
|
>>> sql = queryset.query.as_sql()[0]
|
||||||
>>> sql.count('INNER JOIN')
|
>>> sql.count('INNER JOIN')
|
||||||
1
|
1
|
||||||
|
|
||||||
# The automatically joined table has a predictable name.
|
# 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'"])
|
||||||
[<Article: John's second story>, <Article: This is a test>]
|
[<Article: John's second story>, <Article: This is a test>]
|
||||||
|
|
||||||
# And should work fine with the unicode that comes out of
|
# And should work fine with the unicode that comes out of
|
||||||
# newforms.Form.cleaned_data
|
# 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'])
|
||||||
[<Article: John's second story>, <Article: This is a test>]
|
[<Article: John's second story>, <Article: This is a test>]
|
||||||
|
|
||||||
# Find all Articles for the Reporter whose ID is 1.
|
# Find all Articles for the Reporter whose ID is 1.
|
||||||
|
@ -4,11 +4,9 @@
|
|||||||
To perform an OR lookup, or a lookup that combines ANDs and ORs,
|
To perform an OR lookup, or a lookup that combines ANDs and ORs,
|
||||||
combine QuerySet objects using & and | operators.
|
combine QuerySet objects using & and | operators.
|
||||||
|
|
||||||
Alternatively, use positional arguments, and pass one or more expressions
|
Alternatively, use positional arguments, and pass one or more expressions of
|
||||||
of clauses using the variable ``django.db.models.Q`` (or any object with
|
clauses using the variable ``django.db.models.Q`` (or any object with an
|
||||||
a get_sql method).
|
add_to_query method).
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
@ -54,7 +54,7 @@ Is updated
|
|||||||
pre_delete signal, Tom Smith
|
pre_delete signal, Tom Smith
|
||||||
instance.id is not None: True
|
instance.id is not None: True
|
||||||
post_delete signal, Tom Smith
|
post_delete signal, Tom Smith
|
||||||
instance.id is None: False
|
instance.id is None: True
|
||||||
|
|
||||||
>>> p2 = Person(first_name='James', last_name='Jones')
|
>>> p2 = Person(first_name='James', last_name='Jones')
|
||||||
>>> p2.id = 99999
|
>>> p2.id = 99999
|
||||||
@ -73,7 +73,7 @@ Is created
|
|||||||
pre_delete signal, James Jones
|
pre_delete signal, James Jones
|
||||||
instance.id is not None: True
|
instance.id is not None: True
|
||||||
post_delete signal, James Jones
|
post_delete signal, James Jones
|
||||||
instance.id is None: False
|
instance.id is None: True
|
||||||
|
|
||||||
>>> Person.objects.all()
|
>>> Person.objects.all()
|
||||||
[<Person: James Jones>]
|
[<Person: James Jones>]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user