Python Django REST框架:读写自定义关系字段

Python Django REST框架:读写自定义关系字段,python,django,api,rest,django-rest-framework,Python,Django,Api,Rest,Django Rest Framework,在DRF文档中,可以定义要读写的关系字段。然而,文档没有给出这方面的示例,我在这样做时遇到了错误 以下是相关模型: class Survey(models.Model): name = models.CharField(max_length=128) subjects = models.ManyToManyField(Subject, blank=True, null=True) ... class Subject(models.Model): number =

在DRF文档中,可以定义要读写的关系字段。然而,文档没有给出这方面的示例,我在这样做时遇到了错误

以下是相关模型:

class Survey(models.Model):
    name = models.CharField(max_length=128)
    subjects = models.ManyToManyField(Subject, blank=True, null=True)
    ...

class Subject(models.Model):
    number = models.CharField(max_length=24)
    ...
以下是序列化程序:

class SurveyRecipientField(serializers.RelatedField):
    many_widget = forms.TextInput()

    def to_native(self, value):
        return value.number

    def from_native(self, data):
        return Subject.objects.filter(number__in=data)


class SurveySerializer(serializers.HyperlinkedModelSerializer):
    ...
    recipients = SurveyRecipientField(source='subjects', many=True, read_only=False)
    ...

    class Meta:
        model = Survey
        fields = ('url', 'recipients', ...)
        lookup_field= 'pk'
我正在使用标准ModelViewSet进行调查,没有任何内容被覆盖。当我尝试使用以下内容创建测量对象时:

{
    ...
    "recipients": ['8880008888', '9990009090']
    ...
}
我得到:

Environment:


Request Method: POST
Request URL: http://localhost:8000/AO/2/api/survey/

Django Version: 1.6
Python Version: 2.7.1
Installed Applications:
('longerusername',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.sites',
 ...
)

Traceback:
File "/Library/Python/2.7/site-packages/django/core/handlers/base.py" in get_response
  139.                 response = response.render()
File "/Library/Python/2.7/site-packages/django/template/response.py" in render
  105.             self.content = self.rendered_content
File "/Library/Python/2.7/site-packages/rest_framework/response.py" in rendered_content
  59.         ret = renderer.render(self.data, media_type, context)
File "/Library/Python/2.7/site-packages/rest_framework/renderers.py" in render
  577.         context = self.get_context(data, accepted_media_type, renderer_context)
File "/Library/Python/2.7/site-packages/rest_framework/renderers.py" in get_context
  554.             'post_form': self.get_rendered_html_form(view, 'POST', request),
File "/Library/Python/2.7/site-packages/rest_framework/renderers.py" in get_rendered_html_form
  443.             data = serializer.data
File "/Library/Python/2.7/site-packages/rest_framework/serializers.py" in data
  537.                 self._data = self.to_native(obj)
File "/Library/Python/2.7/site-packages/rest_framework/serializers.py" in to_native
  325.             value = field.field_to_native(obj, field_name)
File "/Library/Python/2.7/site-packages/rest_framework/relations.py" in field_to_native
  139.                 value = get_component(value, component)
File "/Library/Python/2.7/site-packages/rest_framework/fields.py" in get_component
  56.         val = getattr(obj, attr_name)
File "/Library/Python/2.7/site-packages/django/db/models/fields/related.py" in __get__
  815.             through=self.field.rel.through,
File "/Library/Python/2.7/site-packages/django/db/models/fields/related.py" in __init__
  512.                                  (instance, source_field_name))

Exception Type: ValueError at /AO/2/api/survey/
Exception Value: "<Survey: None>" needs to have a value for field "survey" before this many-to-many relationship can be used.

我不理解值列表是如何序列化、反序列化和保存的。例如,我不确定如何在
SurveyRecipientField
中正确实施
from_native
。我希望它是一个单独的数字,但它是一个数字列表。但是,返回对象列表似乎是不可接受的。

您已经非常接近了,
data
arg for
from_native
方法是一个字符串值(它表示来自有效负载的每个
收件人
键的值),因此基于此,您需要检索相关对象或创建一个(如果不存在):

class SurveyRecipientField(serializers.RelatedField):
    ...

    def from_native(self, data):
        return Subject.objects.get_or_create(number=data)
class SurveyRecipientField(serializers.RelatedField):
    ...

    def from_native(self, data):
        return Subject.objects.get_or_create(number=data)