默认情况下,.create()方法不支持可写的嵌套字段。 [英] The `.create()` method does not support writable nested fields by default.
问题描述
关于在DRF中与中间模型进行多对多关系的序列化,我遇到了一个大问题:如果请求方法是get,那么一切都将正常运行。但是,一旦我尝试将数据发布或放到API上,我就会收到以下错误消息:
Traceback(最近一次调用最近):
文件 /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/core/handlers/base.py,行149,在get_response $ b $中b响应= self.process_exception_by_middleware(e,请求)
文件 /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/core/handlers/base.py第147行,在get_response
response = wrapd_callback(request,* callback_args,** callback_kwargs)
File /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-包/django/views/decorators/csrf.py,第58行,在wrapped_view
中,返回view_func(* args,** kwargs)
文件 /Library/Frameworks/Python.framework/Versions/2.7 /lib/python2.7/site-packages/django/views/generic/base.py,第68行,在视图
中返回self.dispatch(request,* args,** kwargs)
文件 /图书馆/ Fr ameworks / Python.framework / Versions / 2.7 / lib / python2.7 / site-packages / djangorestframework-3.5.3-py2.7.egg / rest_framework / views.py,第477行,在分发中
response = self.handle_exception(exc)
文件 /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/djangorestframework-3.5.3-py2.7.egg/rest_framework/views .py,第437行,在handle_exception
self.raise_uncaught_exception(exc)
文件 /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/djangorestframework- 3.5.3-py2.7.egg / rest_framework / views.py,行474,在调度
response = handler(request,* args,** kwargs)
File / Library / Frameworks / Python.framework / Versions / 2.7 / lib / python2.7 / site-packages / djangorestframework-3.5.3-py2.7.egg / rest_framework / generics.py,第243行,在帖子
中返回self.create (请求,* args,** kwargs)
文件 /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/djangorestframework-3.5.3-p y2.7.egg / rest_framework / mixins.py,第21行,在创建
self.perform_create(serializer)
文件 /Library/Frameworks/Python.framework/Versions/2.7/lib/python2 .7 / site-packages / djangorestframework-3.5.3-py2.7.egg / rest_framework / mixins.py,第26行,在perform_create
serializer.save()
File / Library / Frameworks /Python.framework/Versions/2.7/lib/python2.7/site-packages/djangorestframework-3.5.3-py2.7.egg/rest_framework/serializers.py,第214行,保存
self.instance = self.create(validated_data)
文件 /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/djangorestframework-3.5.3-py2.7.egg/rest_framework/ serializers.py,第888行,位于create
raise_errors_on_nested_writes('create',self,validated_data)
文件 /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site -packages / djangorestframework-3.5.3-py2.7.egg / rest_framework / serializers.py,第780行,在raise_errors_on_nested_writes
类中_name = serializer .__ class __.__ name__
AssertionError:默认情况下,.create()方法不支持可写嵌套字段。
为序列化器 manager.serializers.EquipmentSerializer编写一个显式的 .create()方法,或在嵌套的序列化器字段上设置 read_only = True。
我不太确定如何编写适当的创建和更新函数,我也不是很了解,文档中的解释方式。
代码:
views.py:
<$来自django.shortcuts导入的p $ p>
从django.contrib.auth.models导入渲染
从manager.serializers导入用户,组
导入*从rest_framework导入泛型的
从rest_framework导入视图集
从rest_framework.decorators导入api_view
从rest_framework.response导入响应
从rest_framework.views导入APIView
从django.forms.models导入model_to_dict
类OrderSetDetails(generics.RetrieveUpdateDestroyAPIView):
queryset = Order.objects.all()
serializer_class = OrderSerializer
类OrderSetList(generics.ListCreateAPIView):
queryset = Order.objects.all()
serializer_class = OrderSerializer
class EquipmentSetDetails(generics.RetrieveUpdateDestroyAPIView):
queryset = Equipment.objects.all()
serializer_class = EquipmentSerializer
类EquipmentSetList(generics.ListCreateAPIView):
queryset = Equipment.objects.all()
serializer_class = EquipmentSerializer
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()。order_by('-date_joined')
serializer_class = UserSerializer
类GroupViewSet(viewsets.ModelViewSet) :
queryset = Group.objects.all()
serializer_class = GroupSerializer
类ClientList(generics.ListCreateAPIView):
queryset = client.objects .all()
serializer_class = ClientSerializer
serializers.py
来自rest_framework导入序列化器的
来自django.contrib.auth.models import用户,组
来自storage.models import *
类AssignmentSerializer(serializers.HyperlinkedModelSerializer):
id = serializers.ReadOnlyField(source ='Order.id')
name = serialize rs.ReadOnlyField(source ='Order.name')
class Meta:
model = Assignment
fields =('id','name','quantity')
类EquipmentSerializer(serializers.ModelSerializer):
event = AssignmentSerializer(source ='assignment_set',many = True)
class Meta:
model =设备
字段='__all__'
类ClientSerializer(serializers.ModelSerializer):
类Meta:
模型=客户
字段='__all__'
类UserSerializer(serializers.HyperlinkedModelSerializer):
类元数据:
模型=用户
字段=('url','用户名','电子邮件','组')
类GroupSerializer(serializers.HyperlinkedModelSerializer):
类元:
模型=组
字段= ('url','name')
class OrderSerializer(serializers.ModelSerializer):
class Meta:
模式l =订单
字段='__all__'
models.py:
从__future__导入unicode_literals
从django.db导入模型
从storage.choices导入*
#在此处创建模型。
class Equipment(models.Model):
名称= models.CharField(max_length = 30)
制造者= models.CharField(max_length = 30,默认='-')
storeplace = models.IntegerField()
labour = models.CharField(max_length = 1,choices = labor_choices)
event = models.ManyToManyField('Order',blank = True,through ='Assignment',through_fields =(''Equipment','Order'))
max_quantity = models.IntegerField(默认= 1,null = True)
status = models.CharField(max_length = 8,选择= STATUS_CHOICES,默认=' im Lager')
def __str __(self):
return self.name
类客户端(models.Model):
firstname = models.CharField(max_length = 30)
secondname = models.CharField(max_length = 30)
email = models.EmailField()
post_code = models.IntegerField()
city = models.CharField(max_length = 30)
street = models.CharField(max_length = 30)
def __str __(self):
返回%s%s%(self.firstname,self.secondname)
类Order(models.Model):
名称= models.CharField(max_length = 30)
Type = models.CharField(
max_length = 2,
options = TYPE_CHOICES,
default ='Rental',
)
city = models.CharField(max_length = 30)
street = models.CharField(max_length = 30)
date = models.DateField()
GuestNumber = models.IntegerField()
description = models.TextField()
client = models.ForeignKey( client,on_delete = models .CASCADE,空白= True,null = True)
状态=模型.CharField(max_length = 30,choices = order_choices,default ='glyphicon glyphicon-remove')
def __str __(self ):
返回self.name
class Assignment(models.Model):
设备= models.ForeignKey('Equipment',on_delete = models.CASCADE)
Order = models.ForeignKey('Order',on_delete = models.CASCADE)
数量= models.PositiveIntegerField(default = 1)
谢谢。
DRF不支持 create
嵌套序列化程序的方法。如果要以扩展布局显示相关字段,而不仅是使用pks,还可以覆盖 to_representation
方法,而不必重写默认的 mtm
字段。您还应该重写 create
方法,因为 mtm
链接中的第三个模型:
类EquipmentSerializer(serializers.ModelSerializer):
类元数据:
模型=设备
字段=' __all__'
def create(self,validated_data):
订单= Order.objects.get(pk = validated_data.pop('event'))
实例= Equipment.objects .create(** validated_data)
Assignment.objects.create(Order = order,Equipment = instance)
返回实例
def to_representation(self,instance):
表示=超级(EquipmentSerializer,自身).to_representation(实例)
表示['assigment'] = AssignmentSerializer(instance.assigment_set.all(),many = True).data
返回表示
现在它将保存正确传递pk列表的mtm字段,例如 [1、2 ,3]
并代表与该mtm相关的模型 EquipmentSerializer
将使用 AssignmentSerializer
。
I have a big problem regarding the serialization of a Many to Many relationship with intermediate model in DRF: If the request method is get everything works perfectly. But as soon as i try to POST or PUT Data to the API I get the following Error:
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/core/handlers/base.py", line 149, in get_response
response = self.process_exception_by_middleware(e, request)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/core/handlers/base.py", line 147, in get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/views/decorators/csrf.py", line 58, in wrapped_view
return view_func(*args, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/views/generic/base.py", line 68, in view
return self.dispatch(request, *args, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/djangorestframework-3.5.3-py2.7.egg/rest_framework/views.py", line 477, in dispatch
response = self.handle_exception(exc)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/djangorestframework-3.5.3-py2.7.egg/rest_framework/views.py", line 437, in handle_exception
self.raise_uncaught_exception(exc)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/djangorestframework-3.5.3-py2.7.egg/rest_framework/views.py", line 474, in dispatch
response = handler(request, *args, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/djangorestframework-3.5.3-py2.7.egg/rest_framework/generics.py", line 243, in post
return self.create(request, *args, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/djangorestframework-3.5.3-py2.7.egg/rest_framework/mixins.py", line 21, in create
self.perform_create(serializer)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/djangorestframework-3.5.3-py2.7.egg/rest_framework/mixins.py", line 26, in perform_create
serializer.save()
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/djangorestframework-3.5.3-py2.7.egg/rest_framework/serializers.py", line 214, in save
self.instance = self.create(validated_data)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/djangorestframework-3.5.3-py2.7.egg/rest_framework/serializers.py", line 888, in create
raise_errors_on_nested_writes('create', self, validated_data)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/djangorestframework-3.5.3-py2.7.egg/rest_framework/serializers.py", line 780, in raise_errors_on_nested_writes
class_name=serializer.__class__.__name__
AssertionError: The `.create()` method does not support writable nested fields by default.
Write an explicit `.create()` method for serializer `manager.serializers.EquipmentSerializer`, or set `read_only=True` on nested serializer fields.
I am not really sure how to write proper create and update functions and i don´t really understand it, how it is explained in the documentation.
Code:
views.py:
from django.shortcuts import render
from django.contrib.auth.models import User, Group
from manager.serializers import *
from rest_framework import generics
from rest_framework import viewsets
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework.views import APIView
from django.forms.models import model_to_dict
class OrderSetDetails(generics.RetrieveUpdateDestroyAPIView):
queryset = Order.objects.all()
serializer_class = OrderSerializer
class OrderSetList(generics.ListCreateAPIView):
queryset = Order.objects.all()
serializer_class = OrderSerializer
class EquipmentSetDetails(generics.RetrieveUpdateDestroyAPIView):
queryset = Equipment.objects.all()
serializer_class = EquipmentSerializer
class EquipmentSetList(generics.ListCreateAPIView):
queryset = Equipment.objects.all()
serializer_class = EquipmentSerializer
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all().order_by('-date_joined')
serializer_class = UserSerializer
class GroupViewSet(viewsets.ModelViewSet):
queryset = Group.objects.all()
serializer_class = GroupSerializer
class ClientList(generics.ListCreateAPIView):
queryset = client.objects.all()
serializer_class = ClientSerializer
serializers.py
from rest_framework import serializers
from django.contrib.auth.models import User, Group
from storage.models import *
class AssignmentSerializer(serializers.HyperlinkedModelSerializer):
id = serializers.ReadOnlyField(source = 'Order.id')
name = serializers.ReadOnlyField(source = 'Order.name')
class Meta:
model = Assignment
fields = ('id', 'name', 'quantity')
class EquipmentSerializer(serializers.ModelSerializer):
event = AssignmentSerializer(source= 'assignment_set', many = True)
class Meta:
model = Equipment
fields = '__all__'
class ClientSerializer(serializers.ModelSerializer):
class Meta:
model = client
fields = '__all__'
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = ('url', 'username', 'email', 'groups')
class GroupSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Group
fields = ('url', 'name')
class OrderSerializer(serializers.ModelSerializer):
class Meta:
model = Order
fields = '__all__'
models.py:
from __future__ import unicode_literals
from django.db import models
from storage.choices import *
# Create your models here.
class Equipment(models.Model):
name = models.CharField(max_length=30)
fabricator = models.CharField(max_length=30, default='-')
storeplace = models.IntegerField()
labor = models.CharField(max_length=1, choices=labor_choices)
event = models.ManyToManyField('Order', blank = True, through= 'Assignment', through_fields=('Equipment', 'Order'))
max_quantity = models.IntegerField(default=1, null = True)
status = models.CharField(max_length=8, choices = STATUS_CHOICES, default = 'im Lager')
def __str__(self):
return self.name
class client(models.Model):
firstname = models.CharField(max_length=30)
secondname = models.CharField(max_length=30)
email = models.EmailField()
post_code = models.IntegerField()
city = models.CharField(max_length=30)
street= models.CharField(max_length=30)
def __str__(self):
return "%s %s" % (self.firstname, self.secondname)
class Order(models.Model):
name = models.CharField(max_length=30)
Type = models.CharField(
max_length=2,
choices=TYPE_CHOICES,
default='Rental',
)
city = models.CharField(max_length=30)
street= models.CharField(max_length=30)
date = models.DateField()
GuestNumber = models.IntegerField()
description = models.TextField()
client = models.ForeignKey("client", on_delete=models.CASCADE, blank = True, null = True)
status = models.CharField(max_length=30, choices=order_choices, default='glyphicon glyphicon-remove')
def __str__(self):
return self.name
class Assignment(models.Model):
Equipment = models.ForeignKey('Equipment', on_delete=models.CASCADE)
Order = models.ForeignKey('Order', on_delete=models.CASCADE)
quantity = models.PositiveIntegerField(default=1)
Thanks in Advance.
DRF does not support create
method for nested serializers. If you want to show related fields in an extended layout and not only with pks then you can override the to_representation
method instead of rewriting default mtm
field. You should also override a create
method, because of the third model in mtm
link:
class EquipmentSerializer(serializers.ModelSerializer):
class Meta:
model = Equipment
fields = '__all__'
def create(self, validated_data):
order = Order.objects.get(pk=validated_data.pop('event'))
instance = Equipment.objects.create(**validated_data)
Assignment.objects.create(Order=order, Equipment=instance)
return instance
def to_representation(self, instance):
representation = super(EquipmentSerializer, self).to_representation(instance)
representation['assigment'] = AssignmentSerializer(instance.assigment_set.all(), many=True).data
return representation
Now it'll save mtm fields properly passing list of pks, like [1, 2, 3]
and for representation of that mtm related model, EquipmentSerializer
will use AssignmentSerializer
.
这篇关于默认情况下,.create()方法不支持可写的嵌套字段。的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!