【问题标题】:TypeError and AssertionError after upgrade to Django 2升级到 Django 2 后的 TypeError 和 AssertionError
【发布时间】:2020-05-25 07:59:10
【问题描述】:

我的任务是将 Django REST 框架项目从 Django 1.8 升级到 Django 2.x。我已经将整个代码从 python 2.7 移植到 python 3.7 和从 Django 1.8 移植到 2.0.13。我正在使用虚拟环境。

我让它在 python 3.7 和 Django 2.0.13 以及 RESTframework 3.11 上运行,尽管我在尝试创建新对象时遇到了问题。

这是我的问题的追溯:

Traceback (most recent call last):
  File "C:\Users\user1\Envs\projpy3\lib\site-packages\django\core\handlers\exception.py", line 35, in inner
    response = get_response(request)
  File "C:\Users\user1\Envs\projpy3\lib\site-packages\django\core\handlers\base.py", line 128, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "C:\Users\user1\Envs\projpy3\lib\site-packages\django\core\handlers\base.py", line 126, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "C:\Users\user1\Envs\projpy3\lib\site-packages\django\views\decorators\csrf.py", line 54, in wrapped_view
    return view_func(*args, **kwargs)
  File "C:\Users\user1\projects\proj_py3\rest_framework\viewsets.py", line 114, in view
    return self.dispatch(request, *args, **kwargs)
  File "C:\Users\user1\projects\proj_py3\rest_framework\views.py", line 505, in dispatch
    response = self.handle_exception(exc)
  File "C:\Users\user1\projects\proj_py3\rest_framework\views.py", line 465, in handle_exception
    self.raise_uncaught_exception(exc)
  File "C:\Users\user1\projects\proj_py3\rest_framework\views.py", line 476, in raise_uncaught_exception
    raise exc
  File "C:\Users\user1\projects\proj_py3\rest_framework\views.py", line 502, in dispatch
    response = handler(request, *args, **kwargs)
  File "C:\Users\user1\projects\proj_py3\rest_framework\mixins.py", line 18, in create
    serializer.is_valid(raise_exception=True)
  File "C:\Users\user1\projects\proj_py3\rest_framework\serializers.py", line 219, in is_valid
    self._validated_data = self.run_validation(self.initial_data)
  File "C:\Users\user1\projects\proj_py3\rest_framework\serializers.py", line 418, in run_validation
    value = self.to_internal_value(data)
  File "C:\Users\user1\projects\proj_py3\rest_framework\serializers.py", line 471, in to_internal_value
    for field in fields:
  File "C:\Users\user1\projects\proj_py3\rest_framework\serializers.py", line 354, in _writable_fields
    for field in self.fields.values():
  File "C:\Users\user1\Envs\projpy3\lib\site-packages\django\utils\functional.py", line 36, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
  File "C:\Users\user1\projects\proj_py3\rest_framework\serializers.py", line 348, in fields
    for key, value in self.get_fields().items():
  File "C:\Users\user1\projects\proj_py3\rest_framework\serializers.py", line 1027, in get_fields
    field_names = self.get_field_names(declared_fields, info)
  File "C:\Users\user1\projects\proj_py3\rest_framework\serializers.py", line 1128, in get_field_names
    serializer_class=self.__class__.__name__
AssertionError: The field 'participantIDs' was declared on serializer OrderSerializer, but has not been included in the 'fields' option.

我不明白为什么该异常只发生在新版本的代码中,因为除了版本更新之外,我没有更改 modelsserializersviews

这就是有问题的serializer 的样子:

class OrderSerializer(serializers.ModelSerializer):
    created_by = ShortPersonSerializer(read_only=True, required=False)
    modified_by = ShortPersonSerializer(read_only=True, required=False)
    customer = OrderPersonSerializer(required=False, allow_null=True, partial=True)
    ...
    ...
    participantIDs = serializers.SlugRelatedField(many=True, required=False, allow_null=True, slug_field='id', source='participants', queryset=Person.objects.all())
    ...
    ...
    
    class Meta:
        model = Order
        fields = ('id', 'title','customer', 
                    'customer_copy_id', 'customer_copy_salutation', 'customer_copy_first_name', 'customer_copy_last_name', 'created_at', 'created_by', 'modified_at', 'modified_by')

     def create(self, validated_data):
        customer_data = validated_data.pop('customer', None)
        participants_data = validated_data.pop('participants', None)

        if customer_data and customer_data is not None:
            validated_data['customer'] = Person(pk=customer_data['id'])

        order = Order.objects.create(**validated_data)

        if participants_data and participants_data is not None:
            setattr(order, 'participants', participants_data)      # line 1
            order.save()                                           # line 2
...           

其他信息: 在检测到这个错误之前,我得到了一个不同的错误,带有以下回溯:

Traceback (most recent call last):
  ...
  ...
  File "C:\Users\user1\projects\proj_py3\rest_framework\serializers.py", line 204, in save
    self.instance = self.create(validated_data)
  File "C:\Users\user1\projects\proj_py3\orders\serializers.py", line 90, in create
    setattr(order, 'participants', participants_data)
  File "C:\Users\user1\Envs\projpy3\lib\site-packages\django\db\models\fields\related_descriptors.py", line 509, in __set__
    % self._get_set_deprecation_msg_params(),
TypeError: Direct assignment to the forward side of a many-to-many set is prohibited. Use participants.set() instead.

所以我像这样更改了serializer

...
...
        if participants_data and participants_data is not None:
            #setattr(order, 'participants', participants_data)      # line 1
            order.save()                                           # line 2
            order.participants.set(participants_data)
...

自从我这样做后,我得到了AssertionError 而不是TypeError,我不知道如何解决这个问题。当然我把代码改回来了,但我也删除了项目目录中所有编译的文件,我删除了虚拟环境并创建了一个新环境,我在 Windows 上运行了磁盘清理,我什至卸载了 Python37 以安装它再次。总是在中间重新启动。一切都无济于事。


更新:

我将项目的serializers.py 文件中的updatecreate 方法与我正在使用的rest_framework 版本中的方法进行了比较:rest_framework/serializers.py on GitHub

我根据较新版本的 Django REST framework 更改了它们(代码是为旧版本开发的)。

我还检查了项目中其他应用程序的所有serializers,我发现,除了相关应用程序orders 之外,所有应用程序的participantsID 都在其Serializer 的@987654342 中具有attribute participantsID @class,以防它应该通过其他的Serializer访问其他App。

在这种情况下,就像 cmets 中建议的那样:AssertionError 一直存在。

除了将attribute 添加到fields 之外别无他法。

【问题讨论】:

    标签: django python-3.x django-models django-rest-framework django-serializer


    【解决方案1】:

    participantIDs 添加到 OrderSerializerMeta 类的 fields 属性

    class OrderSerializer(serializers.ModelSerializer):
        # other code snippets
        class Meta:
            model = Order
            fields = (other-fields, 'participantIDs')
        # other code snippets

    【讨论】:

    • 我认为这不是正确的做法,因为 python 2 版本的代码在没有额外字段的情况下工作。我还有一个连接到项目的大型数据库,我想避免对其表进行不必要的更改。无论如何,非常感谢!
    • 此解决方案基于您给定的错误回溯。我认为这与版本升级无关。
    • 什么错误?将错误回溯添加到问题
    • 对不起,不是“错误”。让我们称之为问题,这样更容易区分。我暂时可以简单地添加该字段来“症状地”解决这个问题,但我宁愿找到我所描述的不一致的根本原因。如果有什么值得一提的,我会尝试不同的事情并会更新。太棒了!
    • 您升级了主要语言版本主要框架版本。预计会有这样的变化(django 错误)。关于fields= vs 声明字段的DRF 检查已经存在了很长一段时间。如果您真的好奇,请克隆 repo 并检查 serializers.py 的完整历史记录。经过这么多次升级,这里看起来没有什么不寻常的地方。
    猜你喜欢
    • 2017-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-01
    相关资源
    最近更新 更多