From ad060aa360fa2ed33bd83cbb419d7b996a428726 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gregor=20M=C3=BCllegger?= Date: Sat, 15 Nov 2014 15:23:58 +0100 Subject: [PATCH] More helpful error message when default `.create` fails. Closes #2013. --- rest_framework/serializers.py | 14 +++++++++++++- tests/test_model_serializer.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index e7e93f380..8dafea4d4 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -34,6 +34,7 @@ from rest_framework.validators import ( ) import copy import inspect +import sys import warnings # Note: We do the following so that users of the framework can use this style: @@ -593,7 +594,18 @@ class ModelSerializer(Serializer): if relation_info.to_many and (field_name in validated_attrs): many_to_many[field_name] = validated_attrs.pop(field_name) - instance = ModelClass.objects.create(**validated_attrs) + try: + instance = ModelClass.objects.create(**validated_attrs) + except TypeError as exc: + msg = ( + 'The mentioned argument might be a field on the serializer ' + 'that is not part of the model. You need to override the ' + 'create() method in your ModelSerializer subclass to support ' + 'this.') + six.reraise( + type(exc), + type(exc)(str(exc) + '. ' + msg), + sys.exc_info()[2]) # Save many-to-many relationships after the instance is created. if many_to_many: diff --git a/tests/test_model_serializer.py b/tests/test_model_serializer.py index 3aec0da0c..90767dac1 100644 --- a/tests/test_model_serializer.py +++ b/tests/test_model_serializer.py @@ -10,6 +10,7 @@ from django.core.validators import MaxValueValidator, MinValueValidator, MinLeng from django.db import models from django.test import TestCase from rest_framework import serializers +import pytest def dedent(blocktext): @@ -26,6 +27,10 @@ class CustomField(models.Field): pass +class OneFieldModel(models.Model): + char_field = models.CharField(max_length=100) + + class RegularFieldsModel(models.Model): """ A model class for testing regular flat fields. @@ -68,6 +73,29 @@ class FieldOptionsModel(models.Model): choices_field = models.CharField(max_length=100, choices=COLOR_CHOICES) +class TestModelSerializer(TestCase): + def test_create_method(self): + class TestSerializer(serializers.ModelSerializer): + non_model_field = serializers.CharField() + + class Meta: + model = OneFieldModel + fields = ('char_field', 'non_model_field') + + serializer = TestSerializer(data={ + 'char_field': 'foo', + 'non_model_field': 'bar', + }) + serializer.is_valid() + with pytest.raises(TypeError): + serializer.save() + + try: + serializer.save() + except TypeError as exc: + assert 'ModelSerializer' in str(exc) + + class TestRegularFieldMappings(TestCase): def test_regular_fields(self): """