Loading django/apps/registry.py +5 −0 Original line number Diff line number Diff line Loading @@ -337,7 +337,12 @@ class Apps(object): This is mostly used in tests. """ # Call expire cache on each model. This will purge # the relation tree and the fields cache. self.get_models.cache_clear() if self.ready: for model in self.get_models(include_auto_created=True): model._meta._expire_cache() ### DEPRECATED METHODS GO BELOW THIS LINE ### Loading django/contrib/admin/checks.py +1 −1 Original line number Diff line number Diff line Loading @@ -762,7 +762,7 @@ class ModelAdminChecks(BaseModelAdminChecks): def _check_list_editable_item(self, cls, model, field_name, label): try: field = model._meta.get_field_by_name(field_name)[0] field = model._meta.get_field(field_name) except FieldDoesNotExist: return refer_to_missing_field(field=field_name, option=label, model=model, obj=cls, id='admin.E121') Loading django/contrib/admin/options.py +8 −5 Original line number Diff line number Diff line Loading @@ -406,7 +406,7 @@ class BaseModelAdmin(six.with_metaclass(forms.MediaDefiningClass)): rel_name = None for part in parts[:-1]: try: field, _, _, _ = model._meta.get_field_by_name(part) field = model._meta.get_field(part) except FieldDoesNotExist: # Lookups on non-existent fields are ok, since they're ignored # later. Loading @@ -422,7 +422,7 @@ class BaseModelAdmin(six.with_metaclass(forms.MediaDefiningClass)): else: rel_name = None elif isinstance(field, ForeignObjectRel): model = field.model model = field.related_model rel_name = model._meta.pk.name else: rel_name = None Loading Loading @@ -473,9 +473,12 @@ class BaseModelAdmin(six.with_metaclass(forms.MediaDefiningClass)): for inline in admin.inlines: registered_models.add(inline.model) for related_object in (opts.get_all_related_objects(include_hidden=True) + opts.get_all_related_many_to_many_objects()): related_model = related_object.model related_objects = ( f for f in opts.get_fields(include_hidden=True) if (f.auto_created and not f.concrete) ) for related_object in related_objects: related_model = related_object.related_model if (any(issubclass(model, related_model) for model in registered_models) and related_object.field.rel.get_related_field() == field): return True Loading django/contrib/admin/templatetags/admin_list.py +1 −1 Original line number Diff line number Diff line Loading @@ -326,7 +326,7 @@ def date_hierarchy(cl): """ if cl.date_hierarchy: field_name = cl.date_hierarchy field = cl.opts.get_field_by_name(field_name)[0] field = cl.opts.get_field(field_name) dates_or_datetimes = 'datetimes' if isinstance(field, models.DateTimeField) else 'dates' year_field = '%s__year' % field_name month_field = '%s__month' % field_name Loading django/contrib/admin/utils.py +21 −9 Original line number Diff line number Diff line Loading @@ -25,7 +25,7 @@ def lookup_needs_distinct(opts, lookup_path): Returns True if 'distinct()' should be used to query the given lookup path. """ field_name = lookup_path.split('__', 1)[0] field = opts.get_field_by_name(field_name)[0] field = opts.get_field(field_name) if hasattr(field, 'get_path_info') and any(path.m2m for path in field.get_path_info()): return True return False Loading Loading @@ -265,7 +265,7 @@ def model_ngettext(obj, n=None): def lookup_field(name, obj, model_admin=None): opts = obj._meta try: f = opts.get_field(name) f = _get_non_gfk_field(opts, name) except FieldDoesNotExist: # For non-field values, the value is either a method, property or # returned via a callable. Loading @@ -291,6 +291,17 @@ def lookup_field(name, obj, model_admin=None): return f, attr, value def _get_non_gfk_field(opts, name): """ For historical reasons, the admin app relies on GenericForeignKeys as being "not found" by get_field(). This could likely be cleaned up. """ field = opts.get_field(name) if field.is_relation and field.one_to_many and not field.related_model: raise FieldDoesNotExist() return field def label_for_field(name, model, model_admin=None, return_attr=False): """ Returns a sensible label for a field name. The name can be a callable, Loading @@ -301,7 +312,7 @@ def label_for_field(name, model, model_admin=None, return_attr=False): """ attr = None try: field = model._meta.get_field_by_name(name)[0] field = _get_non_gfk_field(model._meta, name) try: label = field.verbose_name except AttributeError: Loading Loading @@ -349,11 +360,10 @@ def label_for_field(name, model, model_admin=None, return_attr=False): def help_text_for_field(name, model): help_text = "" try: field_data = model._meta.get_field_by_name(name) field = _get_non_gfk_field(model._meta, name) except FieldDoesNotExist: pass else: field = field_data[0] if hasattr(field, 'help_text'): help_text = field.help_text return smart_text(help_text) Loading Loading @@ -425,19 +435,21 @@ def reverse_field_path(model, path): parent = model pieces = path.split(LOOKUP_SEP) for piece in pieces: field, model, direct, m2m = parent._meta.get_field_by_name(piece) field = parent._meta.get_field(piece) # skip trailing data field if extant: if len(reversed_path) == len(pieces) - 1: # final iteration try: get_model_from_relation(field) except NotRelationField: break if direct: # Field should point to another model if field.is_relation and not (field.auto_created and not field.concrete): related_name = field.related_query_name() parent = field.rel.to else: related_name = field.field.name parent = field.model parent = field.related_model reversed_path.insert(0, related_name) return (parent, LOOKUP_SEP.join(reversed_path)) Loading @@ -458,7 +470,7 @@ def get_fields_from_path(model, path): parent = get_model_from_relation(fields[-1]) else: parent = model fields.append(parent._meta.get_field_by_name(piece)[0]) fields.append(parent._meta.get_field(piece)) return fields Loading Loading
django/apps/registry.py +5 −0 Original line number Diff line number Diff line Loading @@ -337,7 +337,12 @@ class Apps(object): This is mostly used in tests. """ # Call expire cache on each model. This will purge # the relation tree and the fields cache. self.get_models.cache_clear() if self.ready: for model in self.get_models(include_auto_created=True): model._meta._expire_cache() ### DEPRECATED METHODS GO BELOW THIS LINE ### Loading
django/contrib/admin/checks.py +1 −1 Original line number Diff line number Diff line Loading @@ -762,7 +762,7 @@ class ModelAdminChecks(BaseModelAdminChecks): def _check_list_editable_item(self, cls, model, field_name, label): try: field = model._meta.get_field_by_name(field_name)[0] field = model._meta.get_field(field_name) except FieldDoesNotExist: return refer_to_missing_field(field=field_name, option=label, model=model, obj=cls, id='admin.E121') Loading
django/contrib/admin/options.py +8 −5 Original line number Diff line number Diff line Loading @@ -406,7 +406,7 @@ class BaseModelAdmin(six.with_metaclass(forms.MediaDefiningClass)): rel_name = None for part in parts[:-1]: try: field, _, _, _ = model._meta.get_field_by_name(part) field = model._meta.get_field(part) except FieldDoesNotExist: # Lookups on non-existent fields are ok, since they're ignored # later. Loading @@ -422,7 +422,7 @@ class BaseModelAdmin(six.with_metaclass(forms.MediaDefiningClass)): else: rel_name = None elif isinstance(field, ForeignObjectRel): model = field.model model = field.related_model rel_name = model._meta.pk.name else: rel_name = None Loading Loading @@ -473,9 +473,12 @@ class BaseModelAdmin(six.with_metaclass(forms.MediaDefiningClass)): for inline in admin.inlines: registered_models.add(inline.model) for related_object in (opts.get_all_related_objects(include_hidden=True) + opts.get_all_related_many_to_many_objects()): related_model = related_object.model related_objects = ( f for f in opts.get_fields(include_hidden=True) if (f.auto_created and not f.concrete) ) for related_object in related_objects: related_model = related_object.related_model if (any(issubclass(model, related_model) for model in registered_models) and related_object.field.rel.get_related_field() == field): return True Loading
django/contrib/admin/templatetags/admin_list.py +1 −1 Original line number Diff line number Diff line Loading @@ -326,7 +326,7 @@ def date_hierarchy(cl): """ if cl.date_hierarchy: field_name = cl.date_hierarchy field = cl.opts.get_field_by_name(field_name)[0] field = cl.opts.get_field(field_name) dates_or_datetimes = 'datetimes' if isinstance(field, models.DateTimeField) else 'dates' year_field = '%s__year' % field_name month_field = '%s__month' % field_name Loading
django/contrib/admin/utils.py +21 −9 Original line number Diff line number Diff line Loading @@ -25,7 +25,7 @@ def lookup_needs_distinct(opts, lookup_path): Returns True if 'distinct()' should be used to query the given lookup path. """ field_name = lookup_path.split('__', 1)[0] field = opts.get_field_by_name(field_name)[0] field = opts.get_field(field_name) if hasattr(field, 'get_path_info') and any(path.m2m for path in field.get_path_info()): return True return False Loading Loading @@ -265,7 +265,7 @@ def model_ngettext(obj, n=None): def lookup_field(name, obj, model_admin=None): opts = obj._meta try: f = opts.get_field(name) f = _get_non_gfk_field(opts, name) except FieldDoesNotExist: # For non-field values, the value is either a method, property or # returned via a callable. Loading @@ -291,6 +291,17 @@ def lookup_field(name, obj, model_admin=None): return f, attr, value def _get_non_gfk_field(opts, name): """ For historical reasons, the admin app relies on GenericForeignKeys as being "not found" by get_field(). This could likely be cleaned up. """ field = opts.get_field(name) if field.is_relation and field.one_to_many and not field.related_model: raise FieldDoesNotExist() return field def label_for_field(name, model, model_admin=None, return_attr=False): """ Returns a sensible label for a field name. The name can be a callable, Loading @@ -301,7 +312,7 @@ def label_for_field(name, model, model_admin=None, return_attr=False): """ attr = None try: field = model._meta.get_field_by_name(name)[0] field = _get_non_gfk_field(model._meta, name) try: label = field.verbose_name except AttributeError: Loading Loading @@ -349,11 +360,10 @@ def label_for_field(name, model, model_admin=None, return_attr=False): def help_text_for_field(name, model): help_text = "" try: field_data = model._meta.get_field_by_name(name) field = _get_non_gfk_field(model._meta, name) except FieldDoesNotExist: pass else: field = field_data[0] if hasattr(field, 'help_text'): help_text = field.help_text return smart_text(help_text) Loading Loading @@ -425,19 +435,21 @@ def reverse_field_path(model, path): parent = model pieces = path.split(LOOKUP_SEP) for piece in pieces: field, model, direct, m2m = parent._meta.get_field_by_name(piece) field = parent._meta.get_field(piece) # skip trailing data field if extant: if len(reversed_path) == len(pieces) - 1: # final iteration try: get_model_from_relation(field) except NotRelationField: break if direct: # Field should point to another model if field.is_relation and not (field.auto_created and not field.concrete): related_name = field.related_query_name() parent = field.rel.to else: related_name = field.field.name parent = field.model parent = field.related_model reversed_path.insert(0, related_name) return (parent, LOOKUP_SEP.join(reversed_path)) Loading @@ -458,7 +470,7 @@ def get_fields_from_path(model, path): parent = get_model_from_relation(fields[-1]) else: parent = model fields.append(parent._meta.get_field_by_name(piece)[0]) fields.append(parent._meta.get_field(piece)) return fields Loading