默认情况下,.create()方法不支持可写的嵌套字段。 [英] The `.create()` method does not support writable nested fields by default.

查看:747
本文介绍了默认情况下,.create()方法不支持可写的嵌套字段。的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

关于在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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆