16

Ich arbeite an der Entwicklung einer API mit Django-Rest-Framework und konsumieren es aus einer Web-App. Es hat ein Arztmodell mit einem Fk aus dem django.auth Benutzermodell. Ich möchte aus einem Formular an den Arzt Modell schreiben, aber die Serializer gibt diese Nachricht:SerializerClass Feld auf Serializer von Primärschlüssel

{ „user“: { „non_field_errors“: [ „. Ungültige Daten Erwartet ein Wörterbuch, bekam aber Unicode“]} }

ich schicke den Primärschlüssel des Benutzerobjekts. Welches ist das Recht (oder nur eine Möglichkeit), einen Fremdschlüssel in DRF zu speichern. Ich habe versucht, get_validation_exclusions auf dem Serializer zu überschreiben und die Methode perform_create im Viewset zu überschreiben.

Die API und die Web-App sind entkoppelbar. Die API wird mit django und der Web-App mit angularjs entwickelt.

Mein Modell

class Physician(models.Model): 
    medical_office_number = models.CharField(max_length = 15) 
    fiscal_id_number = models.CharField(max_length = 20) 
    user = models.OneToOneField(User) 

    def __unicode__(self): 
     return self.user.first_name +' '+ self.user.last_name 

Serializer:

class PhysicianSerializer(serializers.ModelSerializer): 
    user = AccountSerializer() 
    class Meta: 
     model = Physician 
     fields = ('id', 'user', 'medical_office_number', 'fiscal_id_number') 
     read_only_fields = ('id') 
     depth = 1 
    def get_validation_exclusions(self, *args, **kwargs): 
     exclusions = super(PhysicianSerializer, self).get_validation_exclusions() 
     return exclusions + ['user'] 

* Edit Das ist mein Konto Serializer, die auf dieser Implementierung und mit dem @ Kevin Brown Vorschlag

class PrimaryKeyNestedMixin(serializers.RelatedField, serializers.ModelSerializer): 

    def to_internal_value(self, data): 
     return serializers.PrimaryKeyRelatedField.to_internal_value(self, data) 
    def to_representation(self, data): 
     return serializers.ModelSerializer.to_representation(self, data) 

class AccountSerializer(PrimaryKeyNestedMixin): 
    password = serializers.CharField(write_only=True, required=False) 
    confirm_password = serializers.CharField(write_only=True, required=False) 

    class Meta: 
     model = Account 
     fields = ('id', 'email', 'username', 'created_at', 'updated_at', 
        'first_name', 'last_name', 'password', 
        'confirm_password', 'is_admin',) 
     read_only_fields = ('created_at', 'updated_at',) 
basiert

Viewset

Wenn ich versuche, dieses Objekt zu serialisieren, wird ein Fehler ausgelöst.

So kann ich einen beliebigen Benutzer aus dem <select> Element buchen. Aber ich kann die Lösung nicht überprüfen. Etwas, das ich vermisse?

Fehler Stacktrace

TypeError at /api/v1/accounts/ 

__init__() takes exactly 1 argument (5 given) 

Exception Location:  /home/jlromeroc/workspace/asclepios/venv/local/lib/python2.7/site-packages/rest_framework/relations.py in many_init, line 68 
Python Executable: /home/jlromeroc/workspace/asclepios/venv/bin/python 
Python Version:  2.7.3 

File "/home/jlromeroc/workspace/asclepios/venv/local/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response 111. response = wrapped_callback(request, *callback_args, **callback_kwargs) File "/home/jlromeroc/workspace/asclepios/venv/local/lib/python2.7/site-packages/django/views/decorators/csrf.py" in wrapped_view 57. return view_func(*args, **kwargs) 
File "/home/jlromeroc/workspace/asclepios/venv/local/lib/python2.7/site-packages/rest_framework/viewsets.py" in view 85. return self.dispatch(request, *args, **kwargs) 
File "/home/jlromeroc/workspace/asclepios/venv/local/lib/python2.7/site-packages/rest_framework/views.py" in dispatch 407. response = self.handle_exception(exc) File "/home/jlromeroc/workspace/asclepios/venv/local/lib/python2.7/site-packages/rest_framework/views.py" in dispatch 404. response = handler(request, *args, **kwargs) 
File "/home/jlromeroc/workspace/asclepios/venv/local/lib/python2.7/site-packages/rest_framework/mixins.py" in list 45. serializer = self.get_serializer(instance, many=True) 
File "/home/jlromeroc/workspace/asclepios/venv/local/lib/python2.7/site-packages/rest_framework/generics.py" in get_serializer 90. instance, data=data, many=many, partial=partial, context=context File "/home/jlromeroc/workspace/asclepios/venv/local/lib/python2.7/site-packages/rest_framework/relations.py" in __new__ 48. return cls.many_init(*args, **kwargs) 
File "/home/jlromeroc/workspace/asclepios/venv/local/lib/python2.7/site-packages/rest_framework/relations.py" in many_init 68. list_kwargs = {'child_relation': cls(*args, **kwargs)} 

Exception Type: TypeError at /api/v1/accounts/ 
Exception Value: __init__() takes exactly 1 argument (5 given) 

bearbeiten ** Ich habe entschieden, die Funktion erstellen auf der Viewset und schließen Sie das Objekt in der Anforderung außer Kraft zu setzen, so kann es bestätigt werden, aber dann versucht die Serializer einfügen ein neues Objekt für das Account-Modell. Wie kann ich dieses Verhalten verhindern? Ich habe versucht, den Serializer in der PhysicianSerializer-Klasse als read_only zu setzen, aber dann versucht django, das Modell mit einer null user_id zu speichern. Wie kann ich ein Modell speichern, ohne ein verwandtes Objekt einzufügen?

Antwort

3

Das Problem hierbei ist, dass das Django-REST-Framework bei verschachtelten Serialisierern sowohl die Eingabe als auch die Ausgabe als verschachtelte Darstellung erwartet. DRF überprüft die Eingabe automatisch, um sicherzustellen, dass sie mit dem verschachtelten Serializer übereinstimmt. Dadurch können Sie das Hauptobjekt und alle Beziehungen in einer einzigen Anfrage erstellen.

Sie suchen einen verschachtelten Ausgang mit einem PrimaryKeyRelatedField Eingang haben. Dies ist sehr häufig für diejenigen, die keine Beziehungen in derselben Anfrage erstellen müssen, sondern immer vorhandene Objekte in ihren Beziehungen verwenden. Die Art und Weise, wie Sie es tun müssen, besteht darin, einen Primärschlüssel (genau wie PrimaryKeyRelatedField) in to_internal_value aufzunehmen, aber einen Serializer in to_representation auszugeben.So etwas wie diese (nicht getestet) sollte

class PrimaryKeyNestedMixin(serializers.PrimaryKeyRelatedField, serializers.ModelSerializer): 

    def to_internal_value(self, data): 
     return serializers.PrimaryKeyRelatedField.to_internal_value(self, data) 

    def to_representation(self, data): 
     return serializers.ModelSerializer.to_representation(self, data) 

Sie arbeiten müßten verwenden, um dies als mixin auf dem verschachtelten Serializer AccountSerializer in Ihrem Fall, und es sollte tun, was Sie suchen.

+0

und das gilt für alle Serialisierer, die ein fk auf einem anderen Serializer sind? Es scheint ein seltsamer Ansatz für eine ganz normale Situation. Wenn Sie eine