我正在尝试使用嵌套的“多对多”关系创建一个序列化程序 . 目标是获取序列化的JSON对象包含序列化相关对象的数组 . 模型看起来像这样(名称已更改,结构已保留)
from django.contrib.auth.models import User
PizzaTopping(models.Model):
name = models.CharField(max_length=255)
inventor = models.ForeignKey(User)
Pizza(models.Model):
name = models.CharField(max_length=255)
toppings = models.ManyToManyField(PizzaTopping)
传入的JSON看起来像这样
{
"name": "My Pizza",
"toppings": [
{"name": "cheese", "inventor": "bob"},
{"name": "tomatoes", "inventor": "alice"}
]
}
我当前的序列化程序代码如下所示
class ToppingRelatedField(RelatedField):
def get_queryset(self):
return Topping.objects.all()
def to_representation(self, instance):
return {'name': instance.name, 'inventor': instance.inventor.username}
def to_internal_value(self, data):
name = data.get('name', None)
inventor = data.get('inventor', None)
try:
user = User.objects.get(username=inventor)
except Setting.DoesNotExist:
raise serializers.ValidationError('bad inventor')
return Topping(name=name, inventor=user)
class PizzaSerializer(ModelSerializer):
toppings = ToppingRelatedField(many=True)
class Meta:
model = Pizza
fields = ('name', 'toppings')
似乎自从我为自定义字段定义了to_internal_value()后,它应该自动创建/更新多对多字段 . 但是当我尝试创建比萨时,我得到“无法添加”“:字段”pizzatopping“的值为”无错误“ . 它看起来像是在某个内部深处,Django决定应该通过模型名称来调用多对多的字段 . 我该怎么说服呢?
编辑#1:似乎这可能是Django或DRF中的某个真正的错误 . DRF似乎正在做正确的事情,它检测到它正在处理ManyToMany字段并尝试使用自定义字段从数据创建配件并将它们添加到披萨中 . 由于它只有一个披萨实例和一个字段名称,因此它使用 setattr(pizza, 'toppings', toppings)
来完成它 . Django似乎正在做正确的事情 . __set__
已定义,并且似乎发现它需要在管理器中使用add()方法 . 但是在某个地方,字段名称'toppings'会丢失并被默认值替换 . 这是"related model name in lower case" .
编辑#2:我找到了解决方案 . 一旦我被允许,我会在答案中记录它 . 似乎 RelatedField
子类中的 to_internal_value()
方法需要返回一个保存的Topping实例,以使ManyToMany事物正常工作 . 现有文档显示相反的情况,此链接(http://www.django-rest-framework.org/api-guide/fields/#custom-fields)示例清楚地返回未保存的实例 .
1 回答
似乎有一个无证的要求 . 对于使用自定义ManyToMany字段的写操作,自定义字段类
to_internal_value()
方法需要在返回实例之前保存该实例 . DRF文档省略了这一点,并且创建自定义字段(在http://www.django-rest-framework.org/api-guide/fields/#custom-fields)的示例显示了返回未保存实例的方法 . 我将更新我与DRF团队开设的问题 .