Fixed #12663 -- Formalized the Model._meta API for retrieving fields.

Thanks to Russell Keith-Magee for mentoring this Google Summer of
Code 2014 project and everyone else who helped with the patch!
This commit is contained in:
Daniel Pyrathon 2015-01-06 19:16:35 -05:00 committed by Tim Graham
parent 749d23251b
commit fb48eb0581
58 changed files with 2851 additions and 1195 deletions

View file

@ -252,9 +252,8 @@ class QuerySet(object):
# If only/defer clauses have been specified,
# build the list of fields that are to be loaded.
if only_load:
for field, model in self.model._meta.get_concrete_fields_with_model():
if model is None:
model = self.model
for field in self.model._meta.concrete_fields:
model = field.model._meta.model
try:
if field.name in only_load[model]:
# Add a field that has been explicitly included
@ -818,7 +817,7 @@ class QuerySet(object):
obj = self._clone()
names = getattr(self, '_fields', None)
if names is None:
names = set(self.model._meta.get_all_field_names())
names = {f.name for f in self.model._meta.get_fields()}
# Add the annotations to the query
for alias, annotation in annotations.items():
@ -1329,7 +1328,8 @@ def get_klass_info(klass, max_depth=0, cur_depth=0, requested=None,
skip = set()
init_list = []
# Build the list of fields that *haven't* been requested
for field, model in klass._meta.get_concrete_fields_with_model():
for field in klass._meta.concrete_fields:
model = field.model._meta.concrete_model
if from_parent and model and issubclass(from_parent, model):
# Avoid loading fields already loaded for parent model for
# child models.
@ -1381,18 +1381,19 @@ def get_klass_info(klass, max_depth=0, cur_depth=0, requested=None,
reverse_related_fields = []
if restricted:
for o in klass._meta.get_all_related_objects():
for o in klass._meta.related_objects:
if o.field.unique and select_related_descend(o.field, restricted, requested,
only_load.get(o.model), reverse=True):
only_load.get(o.related_model), reverse=True):
next = requested[o.field.related_query_name()]
parent = klass if issubclass(o.model, klass) else None
klass_info = get_klass_info(o.model, max_depth=max_depth, cur_depth=cur_depth + 1,
parent = klass if issubclass(o.related_model, klass) else None
klass_info = get_klass_info(o.related_model, max_depth=max_depth, cur_depth=cur_depth + 1,
requested=next, only_load=only_load, from_parent=parent)
reverse_related_fields.append((o.field, klass_info))
if field_names:
pk_idx = field_names.index(klass._meta.pk.attname)
else:
pk_idx = klass._meta.pk_index()
meta = klass._meta
pk_idx = meta.concrete_fields.index(meta.pk)
return klass, field_names, field_count, related_fields, reverse_related_fields, pk_idx
@ -1485,7 +1486,10 @@ def get_cached_row(row, index_start, using, klass_info, offset=0,
for f, klass_info in reverse_related_fields:
# Transfer data from this object to childs.
parent_data = []
for rel_field, rel_model in klass_info[0]._meta.get_fields_with_model():
for rel_field in klass_info[0]._meta.fields:
rel_model = rel_field.model._meta.concrete_model
if rel_model == klass_info[0]._meta.model:
rel_model = None
if rel_model is not None and isinstance(obj, rel_model):
parent_data.append((rel_field, getattr(obj, rel_field.attname)))
# Recursively retrieve the data for the related object