Added field.attname to Options.name_map
The change also removed allow_explicit_fk from sql/query.py.
This commit is contained in:
parent
31e6d58d46
commit
c21e86ab9e
|
@ -404,12 +404,13 @@ class Options(object):
|
||||||
for f, model in self.get_all_related_objects_with_model():
|
for f, model in self.get_all_related_objects_with_model():
|
||||||
cache[f.field.related_query_name()] = (f, model, False, False)
|
cache[f.field.related_query_name()] = (f, model, False, False)
|
||||||
for f, model in self.get_m2m_with_model():
|
for f, model in self.get_m2m_with_model():
|
||||||
cache[f.name] = (f, model, True, True)
|
cache[f.name] = cache[f.attname] = (f, model, True, True)
|
||||||
for f, model in self.get_fields_with_model():
|
for f, model in self.get_fields_with_model():
|
||||||
cache[f.name] = (f, model, True, False)
|
cache[f.name] = cache[f.attname] = (f, model, True, False)
|
||||||
for f in self.virtual_fields:
|
for f in self.virtual_fields:
|
||||||
if hasattr(f, 'related'):
|
if hasattr(f, 'related'):
|
||||||
cache[f.name] = (f.related, None if f.model == self.model else f.model, True, False)
|
cache[f.name] = cache[f.attname] = (
|
||||||
|
f.related, None if f.model == self.model else f.model, True, False)
|
||||||
if app_cache_ready():
|
if app_cache_ready():
|
||||||
self._name_map = cache
|
self._name_map = cache
|
||||||
return cache
|
return cache
|
||||||
|
|
|
@ -1091,8 +1091,7 @@ class Query(object):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
field, sources, opts, join_list, path = self.setup_joins(
|
field, sources, opts, join_list, path = self.setup_joins(
|
||||||
parts, opts, alias, can_reuse, allow_many,
|
parts, opts, alias, can_reuse, allow_many,)
|
||||||
allow_explicit_fk=True)
|
|
||||||
if can_reuse is not None:
|
if can_reuse is not None:
|
||||||
can_reuse.update(join_list)
|
can_reuse.update(join_list)
|
||||||
except MultiJoin as e:
|
except MultiJoin as e:
|
||||||
|
@ -1237,15 +1236,14 @@ class Query(object):
|
||||||
len(q_object.children))
|
len(q_object.children))
|
||||||
return target_clause
|
return target_clause
|
||||||
|
|
||||||
def names_to_path(self, names, opts, allow_many, allow_explicit_fk):
|
def names_to_path(self, names, opts, allow_many):
|
||||||
"""
|
"""
|
||||||
Walks the names path and turns them PathInfo tuples. Note that a
|
Walks the names path and turns them PathInfo tuples. Note that a
|
||||||
single name in 'names' can generate multiple PathInfos (m2m for
|
single name in 'names' can generate multiple PathInfos (m2m for
|
||||||
example).
|
example).
|
||||||
|
|
||||||
'names' is the path of names to travle, 'opts' is the model Options we
|
'names' is the path of names to travle, 'opts' is the model Options we
|
||||||
start the name resolving from, 'allow_many' and 'allow_explicit_fk'
|
start the name resolving from, 'allow_many' is as for setup_joins().
|
||||||
are as for setup_joins().
|
|
||||||
|
|
||||||
Returns a list of PathInfo tuples. In addition returns the final field
|
Returns a list of PathInfo tuples. In addition returns the final field
|
||||||
(the last used join field), and target (which is a field guaranteed to
|
(the last used join field), and target (which is a field guaranteed to
|
||||||
|
@ -1258,17 +1256,9 @@ class Query(object):
|
||||||
try:
|
try:
|
||||||
field, model, direct, m2m = opts.get_field_by_name(name)
|
field, model, direct, m2m = opts.get_field_by_name(name)
|
||||||
except FieldDoesNotExist:
|
except FieldDoesNotExist:
|
||||||
for f in opts.fields:
|
available = opts.get_all_field_names() + list(self.aggregate_select)
|
||||||
if allow_explicit_fk and name == f.attname:
|
raise FieldError("Cannot resolve keyword %r into field. "
|
||||||
# XXX: A hack to allow foo_id to work in values() for
|
"Choices are: %s" % (name, ", ".join(available)))
|
||||||
# backwards compatibility purposes. If we dropped that
|
|
||||||
# feature, this could be removed.
|
|
||||||
field, model, direct, m2m = opts.get_field_by_name(f.name)
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
available = opts.get_all_field_names() + list(self.aggregate_select)
|
|
||||||
raise FieldError("Cannot resolve keyword %r into field. "
|
|
||||||
"Choices are: %s" % (name, ", ".join(available)))
|
|
||||||
# Check if we need any joins for concrete inheritance cases (the
|
# Check if we need any joins for concrete inheritance cases (the
|
||||||
# field lives in parent, but we are currently in one of its
|
# field lives in parent, but we are currently in one of its
|
||||||
# children)
|
# children)
|
||||||
|
@ -1314,7 +1304,7 @@ class Query(object):
|
||||||
return path, final_field, targets
|
return path, final_field, targets
|
||||||
|
|
||||||
def setup_joins(self, names, opts, alias, can_reuse=None, allow_many=True,
|
def setup_joins(self, names, opts, alias, can_reuse=None, allow_many=True,
|
||||||
allow_explicit_fk=False, outer_if_first=False):
|
outer_if_first=False):
|
||||||
"""
|
"""
|
||||||
Compute the necessary table joins for the passage through the fields
|
Compute the necessary table joins for the passage through the fields
|
||||||
given in 'names'. 'opts' is the Options class for the current model
|
given in 'names'. 'opts' is the Options class for the current model
|
||||||
|
@ -1329,9 +1319,6 @@ class Query(object):
|
||||||
If 'allow_many' is False, then any reverse foreign key seen will
|
If 'allow_many' is False, then any reverse foreign key seen will
|
||||||
generate a MultiJoin exception.
|
generate a MultiJoin exception.
|
||||||
|
|
||||||
The 'allow_explicit_fk' controls if field.attname is allowed in the
|
|
||||||
lookups.
|
|
||||||
|
|
||||||
Returns the final field involved in the joins, the target field (used
|
Returns the final field involved in the joins, the target field (used
|
||||||
for any 'where' constraint), the final 'opts' value, the joins and the
|
for any 'where' constraint), the final 'opts' value, the joins and the
|
||||||
field path travelled to generate the joins.
|
field path travelled to generate the joins.
|
||||||
|
@ -1345,7 +1332,7 @@ class Query(object):
|
||||||
joins = [alias]
|
joins = [alias]
|
||||||
# First, generate the path for the names
|
# First, generate the path for the names
|
||||||
path, final_field, targets = self.names_to_path(
|
path, final_field, targets = self.names_to_path(
|
||||||
names, opts, allow_many, allow_explicit_fk)
|
names, opts, allow_many)
|
||||||
# Then, add the path to the query's joins. Note that we can't trim
|
# Then, add the path to the query's joins. Note that we can't trim
|
||||||
# joins at this stage - we will need the information about join type
|
# joins at this stage - we will need the information about join type
|
||||||
# of the trimmed joins.
|
# of the trimmed joins.
|
||||||
|
|
|
@ -470,7 +470,8 @@ class LookupTests(TestCase):
|
||||||
self.fail('FieldError not raised')
|
self.fail('FieldError not raised')
|
||||||
except FieldError as ex:
|
except FieldError as ex:
|
||||||
self.assertEqual(str(ex), "Cannot resolve keyword 'pub_date_year' "
|
self.assertEqual(str(ex), "Cannot resolve keyword 'pub_date_year' "
|
||||||
"into field. Choices are: author, headline, id, pub_date, tag")
|
"into field. Choices are: author, author_id, headline, "
|
||||||
|
"id, pub_date, tag")
|
||||||
try:
|
try:
|
||||||
Article.objects.filter(headline__starts='Article')
|
Article.objects.filter(headline__starts='Article')
|
||||||
self.fail('FieldError not raised')
|
self.fail('FieldError not raised')
|
||||||
|
|
Loading…
Reference in New Issue