TypeError и AssertionError после обновления до Django 2 - PullRequest
0 голосов
/ 10 февраля 2020

Мне поручено обновить проект Django REST Framework с Django 1.8 до Django 2.x. Я уже портировал весь код с python 2.7 на python 3.7 и с Django 1.8 на 2.0.13. Я использую виртуальные envs.

Я запустил его на 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.

Я не понимаю, почему это исключение возникает только в новой версии кода, поскольку я не изменил models, serializers или views, кроме обновлений версии.

так выглядит проблематика c 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, и я не знаю, как решить эту проблему. Конечно, я изменил код обратно, но я также удалил все скомпилированные файлы в каталоге проекта, я удалил виртуальный env и создал новый, я запустил очистку диска на Windows, я даже удалил Python37, чтобы установите его снова. Всегда перезагрузка между ними. Все безрезультатно.


ОБНОВЛЕНИЕ:

Я сравнил методы update и create в файлах serializers.py моего проекта с методами в rest_framework версии I ' используя: rest_framework / serializers.py на GitHub

Я изменил их в соответствии с более новой версией Django REST framework (код был разработан для более старой версии).

Я также проверил все serializers других приложений в проекте и обнаружил, что все приложения, кроме соответствующего orders, имеют attribute participantsID в их Serializer * Класс 1048 *, на случай, если он должен получить доступ к другому приложению через Serializer.

. В этом случае это похоже на то, что предлагается в комментариях: AssertionError был там все время.

Больше ничего не остается, кроме как добавить attribute к fields.

1 Ответ

1 голос
/ 10 февраля 2020

Добавьте participantIDs к вашему fields атрибуту OrderSerializer Meta класс

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