Поле SerializerClass в Сериализаторе сохранить с первичного ключа

Я работаю над разработкой API с Django-rest-framework и потреблением его из веб-приложения. Он имеет модель врача с Fk из модели пользователя django.auth. Я хочу отправить сообщение из формы в модель врача, но сериализатор возвращает это сообщение:

{"user": {"non_field_errors": ["Недопустимые данные. Ожидаемый словарь, но получил unicode."]}}

Я посылаю первичный ключ объекта пользователя. Что является правильным (или только одним способом) для хранения внешнего ключа на DRF. Я попытался переопределить get_validation_exclusions в сериализаторе и переопределить метод perform_create в представлении.

Api и веб-приложение отделены друг от друга. API разработан с помощью django и веб-приложения с угловыми функциями.

Моя модель

class Physician(models.Model): medical_office_number = models.CharField(max_length = 15) fiscal_id_number = models.CharField(max_length = 20) user = models.OneToOneField(User) def __unicode__(self): return self.user.first_name +' '+ self.user.last_name 

Serializer:

 class PhysicianSerializer(serializers.ModelSerializer): user = AccountSerializer() class Meta: model = Physician fields = ('id', 'user', 'medical_office_number', 'fiscal_id_number') read_only_fields = ('id') depth = 1 def get_validation_exclusions(self, *args, **kwargs): exclusions = super(PhysicianSerializer, self).get_validation_exclusions() return exclusions + ['user'] 

* Редактировать Это мой сериализатор моей учетной записи, основанный на этой реализации и с предложением @Kevin Brown

 class PrimaryKeyNestedMixin(serializers.RelatedField, serializers.ModelSerializer): def to_internal_value(self, data): return serializers.PrimaryKeyRelatedField.to_internal_value(self, data) def to_representation(self, data): return serializers.ModelSerializer.to_representation(self, data) class AccountSerializer(PrimaryKeyNestedMixin): password = serializers.CharField(write_only=True, required=False) confirm_password = serializers.CharField(write_only=True, required=False) class Meta: model = Account fields = ('id', 'email', 'username', 'created_at', 'updated_at', 'first_name', 'last_name', 'password', 'confirm_password', 'is_admin',) read_only_fields = ('created_at', 'updated_at',) 

Viewset

 class AccountViewSet(viewsets.ModelViewSet): lookup_field = 'username' queryset = Account.objects.all() serializer_class = AccountSerializer 

Когда я пытаюсь сериализовать этот объект, он вызывает ошибку.

Поэтому я могу отправить любого пользователя из элемента <select> . Но я не могу проверить решение. Что-то мне не хватает?

Ошибка Stacktrace

 TypeError at /api/v1/accounts/ __init__() takes exactly 1 argument (5 given) Exception Location: /home/jlromeroc/workspace/asclepios/venv/local/lib/python2.7/site-packages/rest_framework/relations.py in many_init, line 68 Python Executable: /home/jlromeroc/workspace/asclepios/venv/bin/python Python Version: 2.7.3 File "/home/jlromeroc/workspace/asclepios/venv/local/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response 111. response = wrapped_callback(request, *callback_args, **callback_kwargs) File "/home/jlromeroc/workspace/asclepios/venv/local/lib/python2.7/site-packages/django/views/decorators/csrf.py" in wrapped_view 57. return view_func(*args, **kwargs) File "/home/jlromeroc/workspace/asclepios/venv/local/lib/python2.7/site-packages/rest_framework/viewsets.py" in view 85. return self.dispatch(request, *args, **kwargs) File "/home/jlromeroc/workspace/asclepios/venv/local/lib/python2.7/site-packages/rest_framework/views.py" in dispatch 407. response = self.handle_exception(exc) File "/home/jlromeroc/workspace/asclepios/venv/local/lib/python2.7/site-packages/rest_framework/views.py" in dispatch 404. response = handler(request, *args, **kwargs) File "/home/jlromeroc/workspace/asclepios/venv/local/lib/python2.7/site-packages/rest_framework/mixins.py" in list 45. serializer = self.get_serializer(instance, many=True) File "/home/jlromeroc/workspace/asclepios/venv/local/lib/python2.7/site-packages/rest_framework/generics.py" in get_serializer 90. instance, data=data, many=many, partial=partial, context=context File "/home/jlromeroc/workspace/asclepios/venv/local/lib/python2.7/site-packages/rest_framework/relations.py" in __new__ 48. return cls.many_init(*args, **kwargs) File "/home/jlromeroc/workspace/asclepios/venv/local/lib/python2.7/site-packages/rest_framework/relations.py" in many_init 68. list_kwargs = {'child_relation': cls(*args, **kwargs)} Exception Type: TypeError at /api/v1/accounts/ Exception Value: __init__() takes exactly 1 argument (5 given) 

Изменить ** Я решил переопределить функцию create в представлении и включить объект в запрос, чтобы он мог быть проверен, но затем сериализатор пытается вставить новый объект для модели учетной записи. Как я могу предотвратить это поведение? Я попытался установить сериализатор класса PhysicianSerializer как read_only, но затем django пытается сохранить модель с нулевым user_id. Как сохранить модель без попытки вставки связанного объекта?

  • <Объект Django> не является сериализуемым JSON
  • Редактирование объекта сериализатора django-rest-framework перед сохранением
  • Как получить строковые объекты вместо Unicode от JSON?
  • Django Rest Framework записываемые вложенные сериализаторы
  • django-rest-framework: как мне сериализовать поле, которое уже содержит JSON?
  • Динамически исключать или включать поле в сериализатор рамки Django REST
  • Создание файла XML из данных модели
  • datetime.date (2014, 4, 25) не является JSON-сериализуемым в Django
  • 4 Solutions collect form web for “Поле SerializerClass в Сериализаторе сохранить с первичного ключа”

    Проблема здесь в том, что с вложенными сериализаторами инфраструктура Django REST ожидает, что вход и выход будут вложенными представлениями. DRF автоматически проверит ввод, чтобы убедиться, что он соответствует вложенному сериализатору, что позволяет вам создать основной объект и любые отношения в одном запросе.

    Вы хотите иметь вложенный результат с входом PrimaryKeyRelatedField . Это очень распространено для тех, кому не нужно создавать отношения в одном запросе, но вместо этого всегда будет использовать существующие объекты в своих отношениях. То, как вы собираетесь это делать, в основном принимает первичный ключ (как и PrimaryKeyRelatedField ) в to_internal_value , но выводит сериализатор в to_representation . Что-то вроде этого (untested) должно работать

     class PrimaryKeyNestedMixin(serializers.PrimaryKeyRelatedField, serializers.ModelSerializer): def to_internal_value(self, data): return serializers.PrimaryKeyRelatedField.to_internal_value(self, data) def to_representation(self, data): return serializers.ModelSerializer.to_representation(self, data) 

    Вам нужно будет использовать это как mixin на вложенном сериализаторе AccountSerializer в вашем случае, и он должен делать то, что вы ищете.

    Я последовал за этим ответом от SO. Отключить создание вложенных объектов в django rest framework. Немного грязно, но работает. В любом случае, этому недостает DRF.

    Я работал над этой проблемой, имея разные взгляды, чтобы обрабатывать получение отдельного элемента и сообщения и получать вложенный список. Для получения отдельного элемента и получения списка используется вложенный сериализатор, а метод post использует не-вложенный сериализатор. При публикации для создания нового предупреждения о задании вы можете использовать первичные ключи для задания и пользователя, которые являются связанными объектами.

     class JobAlertList(APIView): """ List all job alerts or create a new job alert """ def get(self, request, format=None): job_alerts = JobAlert.objects.all() serializer = JobAlertNestedSerializer(job_alerts, many=True) return Response(serializer.data) def post(self, request, format=None): serializer = JobAlertSerializer(data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) class JobAlertDetail(APIView): """ Retrieve or delete a job alert instance. """ def get_object(self, pk): try: return JobAlert.objects.get(pk=pk) except JobAlert.DoesNotExist: raise Http404 def get(self, request, pk, format=None): job_alert = self.get_object(pk) serializer = JobAlertNestedSerializer(job_alert) return Response(serializer.data) def delete(self, request, pk, format=None): job_alert = self.get_object(pk) job_alert.delete() return Response(status=status.HTTP_204_NO_CONTENT) class JobAlertSerializer(serializers.ModelSerializer): class Meta: model = JobAlert fields = ('job', 'user') depth = 0 def create(self, validated_data): user = validated_data.pop('user') job = validated_data.pop('job') job_alert = JobAlert.objects.create(user=user, job=job) return job_alert class JobAlertNestedSerializer(serializers.ModelSerializer): class Meta: model = JobAlert fields = ('id', 'job', 'user') depth = 1 url(r'^job_alerts/$', views.JobAlertList.as_view(), name='job-alerts-list'), url(r'^job_alerts/(?P<pk>[0-9]+)/$', views.JobAlertDetail.as_view(), name='job-alerts-detail'), 

    Я столкнулся с аналогичной проблемой (желая POST id / FK объекта, но ожидая сериализованного объекта в GET). Я успешно реализовал решение Кевина Брауна по моему делу. Адаптируйте это к вашей проблеме (слишком поздно, но надеюсь, что кто-то другой, в том числе будущее меня, наткнется на это и сочтет это полезным).

     def get_primary_key_related_model(model_class, **kwargs): """ Nested serializers are a mess. https://stackoverflow.com/a/28016439/2689986 This lets us accept ids when saving / updating instead of nested objects. Representation would be into an object (depending on model_class). """ class PrimaryKeyNestedMixin(model_class): def to_internal_value(self, data): try: return model_class.Meta.model.objects.get(pk=data) except model_class.Meta.model.DoesNotExist: self.fail('does_not_exist', pk_value=data) except (TypeError, ValueError): self.fail('incorrect_type', data_type=type(data).__name__) def to_representation(self, data): return model_class.to_representation(self, data) return PrimaryKeyNestedMixin(**kwargs) class AccountSerializer(serializers.ModelSerializer): password = serializers.CharField(write_only=True, required=False) confirm_password = serializers.CharField(write_only=True, required=False) class Meta: model = Account # ... class PhysicianSerializer(serializers.ModelSerializer): user = get_primary_key_related_model(AccountSerializer) class Meta: model = Physician # ... 

    Генератор class очень удобен, когда у вас есть настраиваемые поля сериализатора (ограничение доступа на основе request.user).

    Interesting Posts

    Суммируйте второе значение каждого кортежа в списке

    Ошибка с объектом Beautifulsoup 'ResultSet' не имеет атрибута 'findAll'

    Классификация с использованием модуля просмотра фильма в NLTK / Python

    Использование перечислений в ctypes.Structure

    Почему моя анимация pylab замедляется при каждом обновлении?

    UnicodeEncodeError: кодек «latin-1» не может кодировать символ

    django – DetailView, как отображать две модели одновременно

    Экспоненциальное отключение: time.sleep с random.randint (0, 1000) / 1000

    Как я могу получить доступ к XML-элементам с именами, используя BeautifulSoup?

    Замена замены для `urllib2.urlopen`, которая проверяет сертификат

    KeyError при добавлении объектов в объект ассоциации SQLAlchemy

    Как правильно утверждать, что исключение возникает в pytest?

    Создание двумерного булева массива из кортежей

    Как построить температуру (напряжения) на прямоугольной полосе матплотлибом?

    Почему нет класса Timer в многопроцессорном модуле Python?

    Python - лучший язык программирования в мире.