【问题标题】:django: Assertion Error `create()` did not return an object instancedjango:断言错误`create()`没有返回对象实例
【发布时间】:2019-08-09 09:47:18
【问题描述】:

我正在使用 Django Rest 框架。我有一个现有的数据库(无法对其进行任何更改)。我已经定义了一个序列化程序 - 没有模型的 ReceiptLog,当对 ReceiptLog api 端点发出 post() 请求时,它应该在 TestCaseCommandRun 和 TestCaseCommandRunResults 中创建条目。数据库中不存在收据日志,我将其用作端点来接受组合有效负载并在基础表中创建条目。 Post() 到 TestCaseCommandRunResults 和 TestCaseCommandRun 独立工作,但是,当我尝试通过 ReceiptLog 发布时,它会抛出以下错误

错误回溯:

File "/usr/local/lib/python3.6/dist-packages/django/core/handlers/exception.py" in inner
  35.             response = get_response(request)

File "/usr/local/lib/python3.6/dist-packages/django/core/handlers/base.py" in _get_response
  128.                 response = self.process_exception_by_middleware(e, request)

File "/usr/local/lib/python3.6/dist-packages/django/core/handlers/base.py" in _get_response
  126.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "/usr/lib/python3.6/contextlib.py" in inner
  52.                 return func(*args, **kwds)

File "/usr/local/lib/python3.6/dist-packages/django/views/decorators/csrf.py" in wrapped_view
  54.         return view_func(*args, **kwargs)

File "/usr/local/lib/python3.6/dist-packages/django/views/generic/base.py" in view
  69.             return self.dispatch(request, *args, **kwargs)

File "/usr/local/lib/python3.6/dist-packages/rest_framework/views.py" in dispatch
  495.             response = self.handle_exception(exc)

File "/usr/local/lib/python3.6/dist-packages/rest_framework/views.py" in handle_exception
  455.             self.raise_uncaught_exception(exc)

File "/usr/local/lib/python3.6/dist-packages/rest_framework/views.py" in dispatch
  492.             response = handler(request, *args, **kwargs)

File "/usr/local/lib/python3.6/dist-packages/rest_framework/generics.py" in post
  192.         return self.create(request, *args, **kwargs)

File "/usr/local/lib/python3.6/dist-packages/rest_framework/mixins.py" in create
  21.         self.perform_create(serializer)

File "/usr/local/lib/python3.6/dist-packages/rest_framework/mixins.py" in perform_create
  26.         serializer.save()

File "/usr/local/lib/python3.6/dist-packages/rest_framework/serializers.py" in save
  216.                 '`create()` did not return an object instance.'

Exception Type: AssertionError at /dqf_api/ReceiptLog/
Exception Value: `create()` did not return an object instance.

models.py

class TestCaseCommandRun(models.Model):
   # fields ..Doesn't have id field as the database doesn't have it
   class Meta:
      managed = False
      db_table = 'test_case_command_run'
      unique_together = (('team_name', 'suite_name', 'suite_run_id', 'case_name', 'command_name'),)


class TestCaseCommandRunResults(models.Model):
    # fields ..Doesn't have id field as the database doesn't have it
    class Meta:
        managed = False
        db_table = 'test_case_command_run_results'
        unique_together = (('suite_run_id', 'command_run_id', 'rule_name', 'result_id'),)

views.py

class TestCaseCommandRunViewSet(viewsets.ModelViewSet):
    queryset = models.TestCaseCommandRunViewSet.objects.values('team_name','suite_name','suite_run_id', 'case_name','command_name','command_run_id','run_start','run_end','result','run_status')
    serializer_class = serializers.TestCaseCommandRunViewSet

class TestCaseCommandRunResultsViewSet(viewsets.ModelViewSet):
    queryset = models.TestCaseCommandRunResultsViewSet.objects.values('suite_run_id','command_run_id','rule_name', 'result_id',
                                                           'result','expected_values','actual_values','report_values','extended_values')
    serializer_class = serializers.TestCaseCommandRunResultsViewSet

class ReceiptLogViewSet(CreateAPIView):
    serializer_class = serializers.ReceiptLogSerializer.ReceiptLogSerializerClass

序列化器.py

class TestCaseCommandRunResultsViewSet(serializers.ModelSerializer):
    class Meta:
        model = models.TestCaseCommandRunResultsViewSet
        fields = ['suite_run_id','command_run_id','rule_name', 'result_id','result','expected_values','actual_values','report_values','extended_values']

class TestCaseCommandRunSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.TestCaseCommandRunSerializer
        fields = ['team_name','suite_name','suite_run_id', 'case_name','command_name','command_run_id','run_start','run_end','result','run_status']

class ReceiptLogSerializerClass(serializers.Serializer):
    team_name = serializers.CharField(max_length=30)
    suite_name = serializers.CharField(max_length=100)
    suite_run_id = serializers.CharField(max_length=50,required=False, allow_blank=True, default=datetime.now().strftime('%Y%m%d%H%M%S'))
    case_name = serializers.CharField(max_length=50)
    command_name = serializers.CharField(max_length=50)
    command_run_id = serializers.CharField(max_length=50,required=False, allow_blank=True, default='Not Applicable')
    run_start = serializers.DateTimeField(default=datetime.now, required=False)
    run_end = serializers.DateTimeField(default=datetime.now, required=False)
    result = serializers.CharField(max_length=10, default='Not Applicable')
    run_status = serializers.CharField(max_length=10)
    rule_name = serializers.CharField( max_length=50, required=False, allow_blank=True,  default='Not Applicable')
    expected_values = serializers.CharField(max_length=200, allow_blank=True)
    actual_values = serializers.CharField(max_length=200, allow_blank=True)
    report_values = serializers.CharField(max_length=200, allow_blank=True)
    extended_values = serializers.CharField(max_length=200, allow_blank=True)

    def create(self, validated_data):
    # command_run_data_list = []
    command_run_results_data_list = []
    raw_data_list = []
    many = isinstance(validated_data, list)
    if many:
        raw_data_list = validated_data
    else:
        raw_data_list.append(validated_data)
    result_id = 1
    for data_row in raw_data_list:
        new_command_run_entry = {
            'team_name': data_row.get('team_name'),
            'suite_name': data_row.get('suite_name'),
            'suite_run_id': data_row.get('suite_run_id'),
            'case_name': data_row.get('case_name'),
            'command_name': data_row.get('command_name'),
            'command_run_id': data_row.get('command_run_id'),
            'run_start': data_row.get('run_start'),
            'run_end': data_row.get('run_end'),
            'result': data_row.get('result'),
            'run_status': data_row.get('run_status')
        }
        command_run_data_list.append(new_command_run_entry)
        new_command_run_result_entry = {
            'suite_run_id': data_row.get('suite_run_id'),
            'command_run_id': data_row.get('command_run_id'),
            'rule_name': data_row.get('rule_name'),
            'result_id': result_id,
            'result': data_row.get('result'),  # PASS or FAIL
            'expected_values': data_row.get('expected_values'),
            'actual_values': data_row.get('actual_values'),
            'report_values': data_row.get('report_values'),
            'extended_values': data_row.get('extended_values'),
        }
        command_run_results_data_list.append(new_command_run_result_entry)
        result_id += 1

    for item in command_run_results_data_list:
        response_run_results = models.TestCaseCommandRunResults.objects.create(**item)

    for item in command_run_data_list:
        response_run = models.TestCaseCommandRun.objects.create(**item)

urls.py

router = routers.DefaultRouter()
router.register(r'test_case_command_runs', views.TestCaseCommandRunViewSet)
router.register(r'test_case_command_run_results', views.TestCaseCommandRunResultsViewSet)
urlpatterns = [
    url(r'^buildInfo', views.build_info),
    url(r'^isActive', views.is_active),
    url(r'^dqf_api/', include(router.urls)),
    url(r'^dqf_api/ReceiptLog/', views.ReceiptLogView.ReceiptLogViewSet.as_view(), name='ReceiptLog')]

非常感谢任何帮助。我是 Django 和 DRF 的新手

【问题讨论】:

    标签: django django-rest-framework serialization


    【解决方案1】:

    您的序列化程序的create 方法必须返回它所代表的对象的实例。此外,您不应该在序列化程序内部迭代以创建实例,这应该在视图上完成:您遍历数据,每次迭代调用序列化程序。

    【讨论】:

    • 另外,一个提示:你的代码可读性很差。强制执行 pep8 风格指南,那些长行很难阅读。
    • 感谢您的反馈。我将尝试执行 pep8 指南。另外,您能否帮助理解为什么我们不应该迭代序列化程序并使用视图?对于我当前的代码,由于我使用一个 API 端点 (ReceiptLog) 在两个表中创建数据,我应该使用 ReceiptLogViews 中的 CreateAPIView 来迭代两个表的序列化程序,我希望将数据 post() 到?这种理解正确吗?
    • 哦,现在我知道你在那里做了什么。您在同一个序列化程序上使用两个不同的模型。否则,只需设置标志 many=True 就可以了。为什么不写第二个序列化程序?
    • 是的,我在同一个序列化程序上使用了两个模型。这两个模型也有自己的序列化器。但如前所述,我需要一个 API 端点来将数据 post() 到这两个模型。因此,这个设计。
    • 更新了我的代码 - ReceiptLogSerializers.py 以包含以下行 response = models.TestCaseCommandRunResultsModel.objects.create(**new_command_run_result_entry)
    【解决方案2】:

    更新了 serializers.py 文件以包含以下代码

    class ReceiptLogSerializerClass(serializers.Serializer):
        #Fields
        def create(self, validated_data):
            raw_data_list = []
            many = isinstance(validated_data, list)
            if many:
                raw_data_list = validated_data
            else:
                raw_data_list.append(validated_data)
            result_id = 1
            for data_row in raw_data_list:
                new_command_run_entry = {
                'team_name': data_row.get('team_name'),
                'suite_name': data_row.get('suite_name'),
                'suite_run_id': data_row.get('suite_run_id'),
                'case_name': data_row.get('case_name'),
                'command_name': data_row.get('command_name'),
                'command_run_id': data_row.get('command_run_id'),
                'run_start': data_row.get('run_start'),
                'run_end': data_row.get('run_end'),
                'result': data_row.get('result'),
                'run_status': data_row.get('run_status')
            }
           response = TestCaseCommandRunSerializer.create(TestCaseCommandRunSerializer(),validated_data= new_command_run_entry)
           new_command_run_result_entry = {
                'suite_run_id': data_row.get('suite_run_id'),
                'command_run_id': data_row.get('command_run_id'),
                'rule_name': data_row.get('rule_name'),
                'result_id': result_id,
                'result': data_row.get('result'),  # PASS or FAIL
                'expected_values': data_row.get('expected_values'),
                'actual_values': data_row.get('actual_values'),
                'report_values': data_row.get('report_values'),
                'extended_values': data_row.get('extended_values'),
            }
            response = TestCaseCommandRunResultsSerializer.create(TestCaseCommandRunResultsSerializer(),validated_data= new_command_run_result_entry)
            logger.info(" new_command_run_result_entry response %s" % response)
            result_id += 1
        return validated_data
    

    我没有正确反序列化数据,因此遇到了多个问题。 返回已验证数据 纠正了所有错误,现在我可以通过单个 API 将数据 post() 到多个模型。

    用于在 ReceiptLogViewSet 中添加的单个 API 调用中发布多个有效负载

        def get_serializer(self, *args, **kwargs):
            if "data" in kwargs:
                data = kwargs["data"]
            if isinstance(data, list):
                kwargs["many"] = True
        return super(ReceiptLogViewSet, self).get_serializer(*args, **kwargs)
    

    参考:Django rest framework cannot deal with multple objects in model viewset

    【讨论】:

      【解决方案3】:

      序列化器 ReceiptLogSerializerClass 必须是 ModelSerializer,而不是序列化器

      【讨论】:

        猜你喜欢
        • 2021-04-28
        • 1970-01-01
        • 2020-04-17
        • 1970-01-01
        • 2021-04-22
        • 2021-10-15
        • 1970-01-01
        • 1970-01-01
        • 2018-08-31
        相关资源
        最近更新 更多