From b1b58762a3d84ac4cdc6553e8ed06983fd3502ca Mon Sep 17 00:00:00 2001 From: Dustin Farris Date: Mon, 13 Jan 2014 11:47:44 -0500 Subject: [PATCH] Move models.resolve_model to serializers._resolve_model --- rest_framework/models.py | 23 +-------------- rest_framework/serializers.py | 29 +++++++++++++++++-- .../{test_models.py => test_serializers.py} | 14 ++++----- 3 files changed, 35 insertions(+), 31 deletions(-) rename rest_framework/tests/{test_models.py => test_serializers.py} (62%) diff --git a/rest_framework/models.py b/rest_framework/models.py index 249cdd828..5b53a5264 100644 --- a/rest_framework/models.py +++ b/rest_framework/models.py @@ -1,22 +1 @@ -import inspect - -from django.db import models - - -def resolve_model(obj): - """ - Resolve supplied `obj` to a Django model class. - - `obj` must be a Django model class, or a string representation - of one. - - String representations should have the format: - 'appname.ModelName' - """ - if type(obj) == str and len(obj.split('.')) == 2: - app_name, model_name = obj.split('.') - return models.get_model(app_name, model_name) - elif inspect.isclass(obj) and issubclass(obj, models.Model): - return obj - else: - raise ValueError("{0} is not a valid Django model".format(obj)) +# Just to keep things like ./manage.py test happy diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index 6b31c3043..0ea2cadbf 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -13,14 +13,15 @@ response content is handled by parsers and renderers. from __future__ import unicode_literals import copy import datetime +import inspect import types from decimal import Decimal +from django.core.exceptions import ImproperlyConfigured from django.core.paginator import Page from django.db import models from django.forms import widgets from django.utils.datastructures import SortedDict from rest_framework.compat import get_concrete_model, six -from rest_framework.models import resolve_model # Note: We do the following so that users of the framework can use this style: # @@ -33,6 +34,27 @@ from rest_framework.relations import * from rest_framework.fields import * +def _resolve_model(obj): + """ + Resolve supplied `obj` to a Django model class. + + `obj` must be a Django model class itself, or a string + representation of one. Useful in situtations like GH #1225 where + Django may not have resolved a string-based reference to a model in + another model's foreign key definition. + + String representations should have the format: + 'appname.ModelName' + """ + if type(obj) == str and len(obj.split('.')) == 2: + app_name, model_name = obj.split('.') + return models.get_model(app_name, model_name) + elif inspect.isclass(obj) and issubclass(obj, models.Model): + return obj + else: + raise ValueError("{0} is not a Django model".format(obj)) + + def pretty_name(name): """Converts 'first_name' to 'First name'""" if not name: @@ -657,7 +679,10 @@ class ModelSerializer(Serializer): if model_field.rel: to_many = isinstance(model_field, models.fields.related.ManyToManyField) - related_model = resolve_model(model_field.rel.to) + try: + related_model = _resolve_model(model_field.rel.to) + except ValueError as error_message: + raise ImproperlyConfigured(error_message) if to_many and not model_field.rel.through._meta.auto_created: has_through_model = True diff --git a/rest_framework/tests/test_models.py b/rest_framework/tests/test_serializers.py similarity index 62% rename from rest_framework/tests/test_models.py rename to rest_framework/tests/test_serializers.py index 5e92d48ae..082a400ca 100644 --- a/rest_framework/tests/test_models.py +++ b/rest_framework/tests/test_serializers.py @@ -1,28 +1,28 @@ from django.db import models from django.test import TestCase -from rest_framework.models import resolve_model +from rest_framework.serializers import _resolve_model from rest_framework.tests.models import BasicModel class ResolveModelTests(TestCase): """ - `resolve_model` should return a Django model class given the + `_resolve_model` should return a Django model class given the provided argument is a Django model class itself, or a properly formatted string representation of one. """ def test_resolve_django_model(self): - resolved_model = resolve_model(BasicModel) + resolved_model = _resolve_model(BasicModel) self.assertEqual(resolved_model, BasicModel) def test_resolve_string_representation(self): - resolved_model = resolve_model('tests.BasicModel') + resolved_model = _resolve_model('tests.BasicModel') self.assertEqual(resolved_model, BasicModel) def test_resolve_non_django_model(self): with self.assertRaises(ValueError): - resolve_model(TestCase) + _resolve_model(TestCase) - def test_resolve_with_improper_string_representation(self): + def test_resolve_improper_string_representation(self): with self.assertRaises(ValueError): - resolve_model('BasicModel') + _resolve_model('BasicModel')