Fixed #10251 -- Fixed model inheritance when there's also an explicit pk field.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@9970 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Malcolm Tredinnick 2009-03-04 07:20:08 +00:00
parent 0e93f60c7f
commit dfd7a6c781
3 changed files with 38 additions and 4 deletions

View File

@ -435,6 +435,21 @@ class Options(object):
result.update(parent._meta.get_parent_list()) result.update(parent._meta.get_parent_list())
return result return result
def get_ancestor_link(self, ancestor):
"""
Returns the field on the current model which points to the given
"ancestor". This is possible an indirect link (a pointer to a parent
model, which points, eventually, to the ancestor). Used when
constructing table joins for model inheritance.
Returns None if the model isn't an ancestor of this one.
"""
if ancestor in self.parents:
return self.parents[ancestor]
for parent in self.parents:
if parent._meta.get_ancestor_link(ancestor):
return self.parents[parent]
def get_ordered_objects(self): def get_ordered_objects(self):
"Returns a list of Options objects that are ordered with respect to this object." "Returns a list of Options objects that are ordered with respect to this object."
if not hasattr(self, '_ordered_objects'): if not hasattr(self, '_ordered_objects'):

View File

@ -643,14 +643,14 @@ class BaseQuery(object):
aliases = set() aliases = set()
if start_alias: if start_alias:
seen = {None: start_alias} seen = {None: start_alias}
root_pk = opts.pk.column
for field, model in opts.get_fields_with_model(): for field, model in opts.get_fields_with_model():
if start_alias: if start_alias:
try: try:
alias = seen[model] alias = seen[model]
except KeyError: except KeyError:
link_field = opts.get_ancestor_link(model)
alias = self.join((start_alias, model._meta.db_table, alias = self.join((start_alias, model._meta.db_table,
root_pk, model._meta.pk.column)) link_field.column, model._meta.pk.column))
seen[model] = alias seen[model] = alias
else: else:
# If we're starting from the base model of the queryset, the # If we're starting from the base model of the queryset, the
@ -1156,13 +1156,13 @@ class BaseQuery(object):
as_sql()). as_sql()).
""" """
opts = self.model._meta opts = self.model._meta
root_pk = opts.pk.column
root_alias = self.tables[0] root_alias = self.tables[0]
seen = {None: root_alias} seen = {None: root_alias}
for field, model in opts.get_fields_with_model(): for field, model in opts.get_fields_with_model():
if model not in seen: if model not in seen:
link_field = opts.get_ancestor_link(model)
seen[model] = self.join((root_alias, model._meta.db_table, seen[model] = self.join((root_alias, model._meta.db_table,
root_pk, model._meta.pk.column)) link_field.column, model._meta.pk.column))
self.included_inherited_models = seen self.included_inherited_models = seen
def remove_inherited_models(self): def remove_inherited_models(self):

View File

@ -86,6 +86,19 @@ class Evaluation(Article):
class QualityControl(Evaluation): class QualityControl(Evaluation):
assignee = models.CharField(max_length=50) assignee = models.CharField(max_length=50)
class BaseM(models.Model):
base_name = models.CharField(max_length=100)
def __unicode__(self):
return self.base_name
class DerivedM(BaseM):
customPK = models.IntegerField(primary_key=True)
derived_name = models.CharField(max_length=100)
def __unicode__(self):
return "PK = %d, base_name = %s, derived_name = %s" \
% (self.customPK, self.base_name, self.derived_name)
__test__ = {'API_TESTS':""" __test__ = {'API_TESTS':"""
# Regression for #7350, #7202 # Regression for #7350, #7202
@ -275,4 +288,10 @@ True
>>> ArticleWithAuthor.objects.filter(pk=article.pk).update(headline="Oh, no!") >>> ArticleWithAuthor.objects.filter(pk=article.pk).update(headline="Oh, no!")
1 1
>>> DerivedM.objects.create(customPK=44, base_name="b1", derived_name="d1")
<DerivedM: PK = 44, base_name = b1, derived_name = d1>
>>> DerivedM.objects.all()
[<DerivedM: PK = 44, base_name = b1, derived_name = d1>]
"""} """}