diff --git a/django/contrib/admin/checks.py b/django/contrib/admin/checks.py index 5cb9d1e462..ee47f911b1 100644 --- a/django/contrib/admin/checks.py +++ b/django/contrib/admin/checks.py @@ -5,8 +5,8 @@ from itertools import chain from django.contrib.admin.utils import get_fields_from_path, NotRelationField, flatten from django.core import checks +from django.core.exceptions import FieldDoesNotExist from django.db import models -from django.db.models.fields import FieldDoesNotExist from django.forms.models import BaseModelForm, _get_foreign_key, BaseModelFormSet @@ -53,7 +53,7 @@ class BaseModelAdminChecks(object): try: field = model._meta.get_field(field_name) - except models.FieldDoesNotExist: + except FieldDoesNotExist: return refer_to_missing_field(field=field_name, option=label, model=model, obj=cls, id='admin.E002') else: @@ -168,7 +168,7 @@ class BaseModelAdminChecks(object): else: try: field = model._meta.get_field(field_name) - except models.FieldDoesNotExist: + except FieldDoesNotExist: # If we can't find a field on the model that matches, it could # be an extra field on the form. return [] @@ -248,7 +248,7 @@ class BaseModelAdminChecks(object): try: field = model._meta.get_field(field_name) - except models.FieldDoesNotExist: + except FieldDoesNotExist: return refer_to_missing_field(field=field_name, option=label, model=model, obj=cls, id='admin.E019') else: @@ -277,7 +277,7 @@ class BaseModelAdminChecks(object): try: field = model._meta.get_field(field_name) - except models.FieldDoesNotExist: + except FieldDoesNotExist: return refer_to_missing_field(field=field_name, option=label, model=model, obj=cls, id='admin.E022') else: @@ -357,7 +357,7 @@ class BaseModelAdminChecks(object): try: field = model._meta.get_field(field_name) - except models.FieldDoesNotExist: + except FieldDoesNotExist: return refer_to_missing_field(field=field_name, option=label, model=model, obj=cls, id='admin.E027') else: @@ -394,7 +394,7 @@ class BaseModelAdminChecks(object): try: model._meta.get_field(field_name) - except models.FieldDoesNotExist: + except FieldDoesNotExist: return refer_to_missing_field(field=field_name, option=label, model=model, obj=cls, id='admin.E030') else: @@ -439,7 +439,7 @@ class BaseModelAdminChecks(object): try: model._meta.get_field(field_name) - except models.FieldDoesNotExist: + except FieldDoesNotExist: return refer_to_missing_field(field=field_name, option=label, model=model, obj=cls, id='admin.E033') else: @@ -468,7 +468,7 @@ class BaseModelAdminChecks(object): else: try: model._meta.get_field(field_name) - except models.FieldDoesNotExist: + except FieldDoesNotExist: return [ checks.Error( "The value of '%s' is not a callable, an attribute of '%s', or an attribute of '%s.%s'." % ( @@ -581,7 +581,7 @@ class ModelAdminChecks(BaseModelAdminChecks): # getattr(model, item) could be an X_RelatedObjectsDescriptor try: field = model._meta.get_field(item) - except models.FieldDoesNotExist: + except FieldDoesNotExist: try: field = getattr(model, item) except AttributeError: @@ -613,7 +613,7 @@ class ModelAdminChecks(BaseModelAdminChecks): else: try: model._meta.get_field(item) - except models.FieldDoesNotExist: + except FieldDoesNotExist: return [ # This is a deliberate repeat of E108; there's more than one path # required to test this condition. @@ -763,7 +763,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] - except models.FieldDoesNotExist: + except FieldDoesNotExist: return refer_to_missing_field(field=field_name, option=label, model=model, obj=cls, id='admin.E121') else: @@ -833,7 +833,7 @@ class ModelAdminChecks(BaseModelAdminChecks): else: try: field = model._meta.get_field(cls.date_hierarchy) - except models.FieldDoesNotExist: + except FieldDoesNotExist: return refer_to_missing_field(option='date_hierarchy', field=cls.date_hierarchy, model=model, obj=cls, id='admin.E127') diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py index d950de7ffd..35758cfdaf 100644 --- a/django/contrib/admin/options.py +++ b/django/contrib/admin/options.py @@ -20,12 +20,12 @@ from django.contrib.admin.templatetags.admin_urls import add_preserved_filters from django.contrib.auth import get_permission_codename from django.core import checks from django.core.exceptions import (PermissionDenied, ValidationError, - FieldError, ImproperlyConfigured) + FieldDoesNotExist, FieldError, ImproperlyConfigured) from django.core.paginator import Paginator from django.core.urlresolvers import reverse from django.db import models, transaction, router from django.db.models.constants import LOOKUP_SEP -from django.db.models.fields import BLANK_CHOICE_DASH, FieldDoesNotExist +from django.db.models.fields import BLANK_CHOICE_DASH from django.db.models.fields.related import ForeignObjectRel from django.db.models.sql.constants import QUERY_TERMS from django.forms.formsets import all_valid, DELETION_FIELD_NAME @@ -1381,7 +1381,7 @@ class ModelAdmin(BaseModelAdmin): for k in initial: try: f = self.model._meta.get_field(k) - except models.FieldDoesNotExist: + except FieldDoesNotExist: continue # We have to special-case M2Ms as a list of comma-separated PKs. if isinstance(f, models.ManyToManyField): diff --git a/django/contrib/admin/utils.py b/django/contrib/admin/utils.py index 41b03a81c1..5da461351a 100644 --- a/django/contrib/admin/utils.py +++ b/django/contrib/admin/utils.py @@ -5,6 +5,7 @@ import datetime import decimal from django.contrib.auth import get_permission_codename +from django.core.exceptions import FieldDoesNotExist from django.db import models from django.db.models.constants import LOOKUP_SEP from django.db.models.deletion import Collector @@ -265,7 +266,7 @@ def lookup_field(name, obj, model_admin=None): opts = obj._meta try: f = opts.get_field(name) - except models.FieldDoesNotExist: + except FieldDoesNotExist: # For non-field values, the value is either a method, property or # returned via a callable. if callable(name): @@ -306,7 +307,7 @@ def label_for_field(name, model, model_admin=None, return_attr=False): except AttributeError: # field is likely a ForeignObjectRel label = field.opts.verbose_name - except models.FieldDoesNotExist: + except FieldDoesNotExist: if name == "__unicode__": label = force_text(model._meta.verbose_name) attr = six.text_type @@ -349,7 +350,7 @@ def help_text_for_field(name, model): help_text = "" try: field_data = model._meta.get_field_by_name(name) - except models.FieldDoesNotExist: + except FieldDoesNotExist: pass else: field = field_data[0] diff --git a/django/contrib/admin/validation.py b/django/contrib/admin/validation.py index a561265455..92ede613ec 100644 --- a/django/contrib/admin/validation.py +++ b/django/contrib/admin/validation.py @@ -1,6 +1,5 @@ -from django.core.exceptions import ImproperlyConfigured +from django.core.exceptions import FieldDoesNotExist, ImproperlyConfigured from django.db import models -from django.db.models.fields import FieldDoesNotExist from django.forms.models import BaseModelForm, BaseModelFormSet, _get_foreign_key from django.contrib.admin.utils import get_fields_from_path, NotRelationField @@ -42,7 +41,7 @@ class BaseValidator(object): continue try: f = model._meta.get_field(field) - except models.FieldDoesNotExist: + except FieldDoesNotExist: # If we can't find a field on the model that matches, it could be an # extra field on the form; nothing to check so move on to the next field. continue @@ -196,7 +195,7 @@ class BaseValidator(object): if not hasattr(model, field): try: model._meta.get_field(field) - except models.FieldDoesNotExist: + except FieldDoesNotExist: raise ImproperlyConfigured( "%s.readonly_fields[%d], %r is not a callable or " "an attribute of %r or found in the model %r." @@ -250,7 +249,7 @@ class ModelAdminValidator(BaseValidator): if not hasattr(model, field): try: model._meta.get_field(field) - except models.FieldDoesNotExist: + except FieldDoesNotExist: raise ImproperlyConfigured( "%s.list_display[%d], %r is not a callable or " "an attribute of %r or found in the model %r." @@ -348,7 +347,7 @@ class ModelAdminValidator(BaseValidator): for idx, field_name in enumerate(cls.list_editable): try: field = model._meta.get_field_by_name(field_name)[0] - except models.FieldDoesNotExist: + except FieldDoesNotExist: raise ImproperlyConfigured("'%s.list_editable[%d]' refers to a " "field, '%s', not defined on %s.%s." % (cls.__name__, idx, field_name, model._meta.app_label, model.__name__)) @@ -429,7 +428,7 @@ def check_isdict(cls, label, obj): def get_field(cls, model, label, field): try: return model._meta.get_field(field) - except models.FieldDoesNotExist: + except FieldDoesNotExist: raise ImproperlyConfigured("'%s.%s' refers to field '%s' that is missing from model '%s.%s'." % (cls.__name__, label, field, model._meta.app_label, model.__name__)) @@ -437,7 +436,7 @@ def get_field(cls, model, label, field): def fetch_attr(cls, model, label, field): try: return model._meta.get_field(field) - except models.FieldDoesNotExist: + except FieldDoesNotExist: pass try: return getattr(model, field) diff --git a/django/contrib/admin/views/main.py b/django/contrib/admin/views/main.py index 8f90585c68..07457a87fc 100644 --- a/django/contrib/admin/views/main.py +++ b/django/contrib/admin/views/main.py @@ -1,11 +1,10 @@ from collections import OrderedDict import sys -from django.core.exceptions import SuspiciousOperation, ImproperlyConfigured +from django.core.exceptions import FieldDoesNotExist, SuspiciousOperation, ImproperlyConfigured from django.core.paginator import InvalidPage from django.core.urlresolvers import reverse from django.db import models -from django.db.models.fields import FieldDoesNotExist from django.utils import six from django.utils.encoding import force_text from django.utils.translation import ugettext, ugettext_lazy @@ -226,7 +225,7 @@ class ChangeList(object): try: field = self.lookup_opts.get_field(field_name) return field.name - except models.FieldDoesNotExist: + except FieldDoesNotExist: # See whether field_name is a name of a non-field # that allows sorting. if callable(field_name): @@ -377,7 +376,7 @@ class ChangeList(object): for field_name in self.list_display: try: field = self.lookup_opts.get_field(field_name) - except models.FieldDoesNotExist: + except FieldDoesNotExist: pass else: if isinstance(field.rel, models.ManyToOneRel): diff --git a/django/contrib/contenttypes/admin.py b/django/contrib/contenttypes/admin.py index 3ad4c86ee8..3db9d2d612 100644 --- a/django/contrib/contenttypes/admin.py +++ b/django/contrib/contenttypes/admin.py @@ -9,7 +9,7 @@ from django.contrib.contenttypes.forms import ( BaseGenericInlineFormSet, generic_inlineformset_factory ) from django.core import checks -from django.db.models.fields import FieldDoesNotExist +from django.core.exceptions import FieldDoesNotExist from django.forms import ALL_FIELDS from django.forms.models import modelform_defines_fields diff --git a/django/contrib/contenttypes/fields.py b/django/contrib/contenttypes/fields.py index 6a883a8550..2297ad63a9 100644 --- a/django/contrib/contenttypes/fields.py +++ b/django/contrib/contenttypes/fields.py @@ -3,10 +3,10 @@ from __future__ import unicode_literals from collections import defaultdict from django.core import checks -from django.core.exceptions import ObjectDoesNotExist +from django.core.exceptions import FieldDoesNotExist, ObjectDoesNotExist from django.db import connection from django.db import models, router, transaction, DEFAULT_DB_ALIAS -from django.db.models import signals, FieldDoesNotExist, DO_NOTHING +from django.db.models import signals, DO_NOTHING from django.db.models.base import ModelBase from django.db.models.fields.related import ForeignObject, ForeignObjectRel from django.db.models.query_utils import PathInfo diff --git a/django/contrib/gis/db/models/lookups.py b/django/contrib/gis/db/models/lookups.py index 434e6fe6ab..17ed1a95c8 100644 --- a/django/contrib/gis/db/models/lookups.py +++ b/django/contrib/gis/db/models/lookups.py @@ -1,8 +1,8 @@ from __future__ import unicode_literals import re +from django.core.exceptions import FieldDoesNotExist from django.db.models.constants import LOOKUP_SEP -from django.db.models.fields import FieldDoesNotExist from django.db.models.lookups import Lookup from django.db.models.expressions import ExpressionNode, Col from django.utils import six diff --git a/django/contrib/gis/sitemaps/views.py b/django/contrib/gis/sitemaps/views.py index 13c24d5bf0..c0c2f83598 100644 --- a/django/contrib/gis/sitemaps/views.py +++ b/django/contrib/gis/sitemaps/views.py @@ -4,8 +4,8 @@ from django.apps import apps from django.http import Http404 from django.contrib.gis.db.models.fields import GeometryField from django.contrib.gis.shortcuts import render_to_kml, render_to_kmz +from django.core.exceptions import FieldDoesNotExist from django.db import connections, DEFAULT_DB_ALIAS -from django.db.models.fields import FieldDoesNotExist def kml(request, label, model, field_name=None, compress=False, using=DEFAULT_DB_ALIAS): diff --git a/django/contrib/gis/utils/layermapping.py b/django/contrib/gis/utils/layermapping.py index aef5a6e4ec..1c848f105e 100644 --- a/django/contrib/gis/utils/layermapping.py +++ b/django/contrib/gis/utils/layermapping.py @@ -8,7 +8,7 @@ """ import sys from decimal import Decimal, InvalidOperation as DecimalInvalidOperation -from django.core.exceptions import ObjectDoesNotExist +from django.core.exceptions import FieldDoesNotExist, ObjectDoesNotExist from django.db import connections, router from django.contrib.gis.db.models import GeometryField from django.contrib.gis.gdal import (CoordTransform, DataSource, @@ -189,7 +189,7 @@ class LayerMapping(object): # for the given field name in the mapping. try: model_field = self.model._meta.get_field(field_name) - except models.fields.FieldDoesNotExist: + except FieldDoesNotExist: raise LayerMapError('Given mapping field "%s" not in given Model fields.' % field_name) # Getting the string name for the Django field class (e.g., 'PointField'). @@ -231,7 +231,7 @@ class LayerMapping(object): idx = check_ogr_fld(ogr_field) try: rel_model._meta.get_field(rel_name) - except models.fields.FieldDoesNotExist: + except FieldDoesNotExist: raise LayerMapError('ForeignKey mapping field "%s" not in %s fields.' % (rel_name, rel_model.__class__.__name__)) fields_val = rel_model diff --git a/django/contrib/sites/managers.py b/django/contrib/sites/managers.py index 45dddd9273..6c2b6d8ad6 100644 --- a/django/contrib/sites/managers.py +++ b/django/contrib/sites/managers.py @@ -3,8 +3,8 @@ from __future__ import unicode_literals from django.conf import settings from django.core import checks +from django.core.exceptions import FieldDoesNotExist from django.db import models -from django.db.models.fields import FieldDoesNotExist class CurrentSiteManager(models.Manager): diff --git a/django/core/exceptions.py b/django/core/exceptions.py index a33fb36ea5..c92e8d4f2a 100644 --- a/django/core/exceptions.py +++ b/django/core/exceptions.py @@ -5,6 +5,11 @@ from django.utils import six from django.utils.encoding import force_text +class FieldDoesNotExist(Exception): + """The requested model field does not exist""" + pass + + class DjangoRuntimeWarning(RuntimeWarning): pass diff --git a/django/db/models/base.py b/django/db/models/base.py index d0c1b7ad16..ec5d4c7c1c 100644 --- a/django/db/models/base.py +++ b/django/db/models/base.py @@ -9,14 +9,14 @@ from django.apps import apps from django.apps.config import MODELS_MODULE_NAME from django.conf import settings from django.core import checks -from django.core.exceptions import (ObjectDoesNotExist, +from django.core.exceptions import (FieldDoesNotExist, ObjectDoesNotExist, MultipleObjectsReturned, FieldError, ValidationError, NON_FIELD_ERRORS) from django.db import (router, connections, transaction, DatabaseError, DEFAULT_DB_ALIAS, DJANGO_VERSION_PICKLE_KEY) from django.db.models import signals from django.db.models.constants import LOOKUP_SEP from django.db.models.deletion import Collector -from django.db.models.fields import AutoField, FieldDoesNotExist +from django.db.models.fields import AutoField from django.db.models.fields.related import (ForeignObjectRel, ManyToOneRel, OneToOneField, add_lazy_relation) from django.db.models.manager import ensure_default_manager @@ -1443,7 +1443,7 @@ class Model(six.with_metaclass(ModelBase)): try: field = cls._meta.get_field(field_name, many_to_many=True) - except models.FieldDoesNotExist: + except FieldDoesNotExist: errors.append( checks.Error( "'%s' refers to the non-existent field '%s'." % (option, field_name), @@ -1485,8 +1485,6 @@ class Model(six.with_metaclass(ModelBase)): """ Check "ordering" option -- is it a list of strings and do all fields exist? """ - from django.db.models import FieldDoesNotExist - if not cls._meta.ordering: return [] diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py index 0b6d4cd929..8afdca4fe0 100644 --- a/django/db/models/fields/__init__.py +++ b/django/db/models/fields/__init__.py @@ -31,6 +31,9 @@ from django.utils.ipv6 import clean_ipv6_address from django.utils import six from django.utils.itercompat import is_iterable +# imported for backwards compatibility +from django.core.exceptions import FieldDoesNotExist # NOQA + # Avoid "TypeError: Item in ``from list'' not a string" -- unicode_literals # makes these strings unicode __all__ = [str(x) for x in ( @@ -61,10 +64,6 @@ def _load_field(app_label, model_name, field_name): return apps.get_model(app_label, model_name)._meta.get_field_by_name(field_name)[0] -class FieldDoesNotExist(Exception): - pass - - # A guide to Field parameters: # # * name: The name of the field specified in the model. diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py index debc73e24c..2e05e57e51 100644 --- a/django/db/models/fields/related.py +++ b/django/db/models/fields/related.py @@ -5,13 +5,13 @@ import warnings from django.apps import apps from django.core import checks +from django.core.exceptions import FieldDoesNotExist from django.db import connection, connections, router, transaction from django.db.backends import utils from django.db.models import signals, Q from django.db.models.deletion import SET_NULL, SET_DEFAULT, CASCADE from django.db.models.fields import (AutoField, Field, IntegerField, - PositiveIntegerField, PositiveSmallIntegerField, FieldDoesNotExist, - BLANK_CHOICE_DASH) + PositiveIntegerField, PositiveSmallIntegerField, BLANK_CHOICE_DASH) from django.db.models.lookups import IsNull from django.db.models.query import QuerySet from django.db.models.query_utils import PathInfo diff --git a/django/db/models/manager.py b/django/db/models/manager.py index 6944a7a2b4..5ae173a1f6 100644 --- a/django/db/models/manager.py +++ b/django/db/models/manager.py @@ -2,9 +2,9 @@ import copy from importlib import import_module import inspect +from django.core.exceptions import FieldDoesNotExist from django.db import router from django.db.models.query import QuerySet -from django.db.models.fields import FieldDoesNotExist from django.utils import six from django.utils.encoding import python_2_unicode_compatible diff --git a/django/db/models/options.py b/django/db/models/options.py index ffec2653bd..79954a87e6 100644 --- a/django/db/models/options.py +++ b/django/db/models/options.py @@ -5,8 +5,9 @@ from collections import OrderedDict from django.apps import apps from django.conf import settings +from django.core.exceptions import FieldDoesNotExist from django.db.models.fields.related import ManyToManyRel -from django.db.models.fields import AutoField, FieldDoesNotExist +from django.db.models.fields import AutoField from django.db.models.fields.proxy import OrderWrt from django.utils import six from django.utils.encoding import force_text, smart_text, python_2_unicode_compatible diff --git a/django/db/models/query_utils.py b/django/db/models/query_utils.py index 60fa0421d7..69bc878caa 100644 --- a/django/db/models/query_utils.py +++ b/django/db/models/query_utils.py @@ -10,6 +10,7 @@ from __future__ import unicode_literals from collections import namedtuple from django.apps import apps +from django.core.exceptions import FieldDoesNotExist from django.db.backends import utils from django.db.models.constants import LOOKUP_SEP from django.utils import six @@ -99,7 +100,6 @@ class DeferredAttribute(object): Retrieves and caches the value from the datastore on the first lookup. Returns the cached value. """ - from django.db.models.fields import FieldDoesNotExist non_deferred_model = instance._meta.proxy_for_model opts = non_deferred_model._meta diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py index d1e6d2b819..eb16419091 100644 --- a/django/db/models/sql/query.py +++ b/django/db/models/sql/query.py @@ -13,12 +13,11 @@ from collections import Mapping, OrderedDict import copy import warnings -from django.core.exceptions import FieldError +from django.core.exceptions import FieldDoesNotExist, FieldError from django.db import connections, DEFAULT_DB_ALIAS from django.db.models.aggregates import Count from django.db.models.constants import LOOKUP_SEP from django.db.models.expressions import Col, Ref -from django.db.models.fields import FieldDoesNotExist from django.db.models.query_utils import PathInfo, Q, refs_aggregate from django.db.models.sql.constants import (QUERY_TERMS, ORDER_DIR, SINGLE, ORDER_PATTERN, SelectInfo, INNER, LOUTER) diff --git a/docs/ref/exceptions.txt b/docs/ref/exceptions.txt index bbd0229610..f12a32df25 100644 --- a/docs/ref/exceptions.txt +++ b/docs/ref/exceptions.txt @@ -33,6 +33,19 @@ ObjectDoesNotExist and DoesNotExist See :meth:`~django.db.models.query.QuerySet.get()` for further information on :exc:`ObjectDoesNotExist` and :exc:`DoesNotExist`. +FieldDoesNotExist +----------------- +.. exception:: FieldDoesNotExist + + The ``FieldDoesNotExist`` exception is raised by a model's + ``_meta.get_field()`` method when the requested field does not exist on the + model or on the model's parents. + + .. versionchanged:: 1.8 + + This exception was previously defined only in + ``django.db.models.fields`` and wasn't part of the public API. + MultipleObjectsReturned ----------------------- .. exception:: MultipleObjectsReturned diff --git a/tests/annotations/tests.py b/tests/annotations/tests.py index a2a1c8f852..570ef4d52c 100644 --- a/tests/annotations/tests.py +++ b/tests/annotations/tests.py @@ -2,12 +2,11 @@ from __future__ import unicode_literals import datetime from decimal import Decimal -from django.core.exceptions import FieldError +from django.core.exceptions import FieldDoesNotExist, FieldError from django.db.models import ( Sum, Count, F, Value, Func, IntegerField, BooleanField, CharField) -from django.db.models.fields import FieldDoesNotExist from django.test import TestCase from django.utils import six diff --git a/tests/model_meta/test.py b/tests/model_meta/test.py index 835ce9c6d5..ea861d5ad5 100644 --- a/tests/model_meta/test.py +++ b/tests/model_meta/test.py @@ -1,7 +1,7 @@ from django import test - -from django.db.models.fields import related, CharField, Field, FieldDoesNotExist from django.contrib.contenttypes.fields import GenericRelation +from django.core.exceptions import FieldDoesNotExist +from django.db.models.fields import related, CharField, Field from .models import ( AbstractPerson, BasePerson, Person, Relating, Relation