nic*_*tec 8 python django django-rest-framework
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.
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
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__'
Run Code Online (Sandbox Code Playgroud)
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)
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
现在,它可以节省MTM领域正确传递PKS,喜欢的列表[1, 2, 3],并为相关的MTM模型的表示,EquipmentSerializer会用AssignmentSerializer。
| 归档时间: |
|
| 查看次数: |
10759 次 |
| 最近记录: |