summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Pyrathon <pirosb3@gmail.com>2015-01-02 16:14:23 +0100
committerTim Graham <timograham@gmail.com>2015-01-02 10:46:04 -0500
commit8958170755b37ce346ae5257c1000bd936faa3b0 (patch)
tree53eeaf3e736cb776b84a3bef940f545b753bb37e
parent1aa3e09c2043c88a760e8b73fb95dc8f1ffef50e (diff)
Fixed #9104 -- Moved FieldDoesNotExist to core.exceptions
-rw-r--r--django/contrib/admin/checks.py26
-rw-r--r--django/contrib/admin/options.py6
-rw-r--r--django/contrib/admin/utils.py7
-rw-r--r--django/contrib/admin/validation.py15
-rw-r--r--django/contrib/admin/views/main.py7
-rw-r--r--django/contrib/contenttypes/admin.py2
-rw-r--r--django/contrib/contenttypes/fields.py4
-rw-r--r--django/contrib/gis/db/models/lookups.py2
-rw-r--r--django/contrib/gis/sitemaps/views.py2
-rw-r--r--django/contrib/gis/utils/layermapping.py6
-rw-r--r--django/contrib/sites/managers.py2
-rw-r--r--django/core/exceptions.py5
-rw-r--r--django/db/models/base.py8
-rw-r--r--django/db/models/fields/__init__.py7
-rw-r--r--django/db/models/fields/related.py4
-rw-r--r--django/db/models/manager.py2
-rw-r--r--django/db/models/options.py3
-rw-r--r--django/db/models/query_utils.py2
-rw-r--r--django/db/models/sql/query.py3
-rw-r--r--docs/ref/exceptions.txt13
-rw-r--r--tests/annotations/tests.py3
-rw-r--r--tests/model_meta/test.py4
22 files changed, 73 insertions, 60 deletions
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