Skip to content

Commit 6773568

Browse files
committed
Ensure _resolve_model does not return None
1 parent 0f508c5 commit 6773568

File tree

2 files changed

+38
-1
lines changed

2 files changed

+38
-1
lines changed

rest_framework/utils/model_meta.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,11 @@ def _resolve_model(obj):
4343
"""
4444
if isinstance(obj, six.string_types) and len(obj.split('.')) == 2:
4545
app_name, model_name = obj.split('.')
46-
return models.get_model(app_name, model_name)
46+
resolved_model = models.get_model(app_name, model_name)
47+
if not resolved_model:
48+
raise ValueError("Django did not return a model for "
49+
"{0}.{1}".format(app_name, model_name))
50+
return resolved_model
4751
elif inspect.isclass(obj) and issubclass(obj, models.Model):
4852
return obj
4953
raise ValueError("{0} is not a Django model".format(obj))

tests/test_utils.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
from rest_framework.views import APIView
88
from tests.models import BasicModel
99

10+
import rest_framework.utils.model_meta
11+
1012

1113
class Root(APIView):
1214
pass
@@ -130,3 +132,34 @@ def test_resolve_non_django_model(self):
130132
def test_resolve_improper_string_representation(self):
131133
with self.assertRaises(ValueError):
132134
_resolve_model('BasicModel')
135+
136+
137+
class ResolveModelWithPatchedDjangoTests(TestCase):
138+
"""
139+
Test coverage for when Django's `get_model` returns `None`.
140+
141+
Under certain circumstances Django may return `None` with `get_model`:
142+
http://git.io/get-model-source
143+
144+
It usually happens with circular imports so it is important that DRF
145+
excepts early, otherwise fault happens downstream and is much more
146+
difficult to debug.
147+
148+
"""
149+
150+
def setUp(self):
151+
"""Monkeypatch get_model."""
152+
self.get_model = rest_framework.utils.model_meta.models.get_model
153+
154+
def get_model(app_label, model_name):
155+
return None
156+
157+
rest_framework.utils.model_meta.models.get_model = get_model
158+
159+
def tearDown(self):
160+
"""Revert monkeypatching."""
161+
rest_framework.utils.model_meta.models.get_model = self.get_model
162+
163+
def test_blows_up_if_model_does_not_resolve(self):
164+
with self.assertRaises(ValueError):
165+
_resolve_model('tests.BasicModel')

0 commit comments

Comments
 (0)