2016-12-30 3 views
2

Ich habe ein großes Problem in Bezug auf die Serialisierung einer Viele-zu-viele-Beziehung mit Zwischenmodell in DRF: Wenn die Anfrage-Methode ist, funktioniert alles perfekt. Aber sobald ich versuche, Daten POST oder PUT an dem API ich die folgende Fehlermeldung erhalten:Die Methode `.create()` unterstützt standardmäßig schreibgeschützte Felder nicht.

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. 

Ich bin nicht wirklich sicher, wie die richtige schreiben Erstellen und Aktualisieren von Funktionen, und ich verstehe nicht wirklich, wie es wird in der Dokumentation erklärt.

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) 

Vielen Dank im Voraus.

Antwort

1

In Ihrem serializers.py ersetzen:

class EquipmentSerializer(serializers.ModelSerializer): 
    event = AssignmentSerializer(source= 'assignment_set', many = True) 
    class Meta: 
     model = Equipment 
     fields = '__all__' 

mit

class EquipmentSerializer(serializers.ModelSerializer): 
    # this is where the changes comes - read_only = True 
    event = AssignmentSerializer(source= 'assignment_set', many = True, read_only=True) 
    class Meta: 
     model = Equipment 
     fields = '__all__' 
+0

Auch wenn dies den Fehler verhindert, kann der Benutzer keine Instanz des verschachtelten obj erstellen, wenn es fehlt. – pravin

1

DRF unterstützt keine create Methode für verschachtelte Serializer. Wenn Sie verknüpfte Felder in einem erweiterten Layout anzeigen möchten, nicht nur mit pks. Sie können die Methode to_representation überschreiben, anstatt das Standardfeld mtm neu zu schreiben. Und Sie shoulld eine create Methode überschreiben, da der dritte Modell 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=Equipment) 
     return insance 

    def to_representation(self, instance): 
     representation = super(EquipmentSerializer, self).to_representation(instance) 
     representation['assigment'] = AssignmentSerializer(instance.assigment_set.all(), many=True).data 
     return representation 

Jetzt wird es mtm Felder richtig vorbei Liste von pks, wie [1, 2, 3] und zur Darstellung, dass mtm bezogene Modelle sparen, EquipmentSerializer wird verwenden AssignmentSerializer.

+0

Dies löst den AssertionError, aber jetzt bekomme ich eine 400 schlechte Anfrage Details: "JSON Parse Fehler - Kein JSON Objekt könnte decodiert werden" – nictec

+0

@nictec ah Ich habe nicht gesehen Sie verwendet drittes Modell für mtm Link –

+0

@nictec aktualisierte Antwort. Ihr Code ist nicht so klar, es ist wirklich schwierig, von SO zu debuggen. Wenn Sie einen Fehler haben, verknüpfen Sie ihn hier und aktualisieren Sie Ihre Antwort mit dem Post-Anfragetext –

Verwandte Themen