2016-12-24 4 views
6

私はちょっとした問題に直面しています。Django Rest Framework私はそれに入れ子オブジェクトを持つオブジェクトを投稿しようとしています。Django Rest Framework POSTネストされたオブジェクト

def create(self, request): 
    serializer = self.serializer_class(data=request.data) 
    serializer.is_valid(raise_exception=True) 
    self.perform_create(serializer) 

    return Response(serializer.validated_data, status=status.HTTP_201_CREATED) 

そして、ここではポストマンからの応答である:

views.pyから
class ClassSerializer(serializers.ModelSerializer): 
    class Meta: 
     model = Class 
     fields = ('number', 'letter') 


class SubjectSerializer(serializers.ModelSerializer): 
    class Meta: 
     model = Subject 
     fields = ('title',) 


class ExamSerializer(serializers.ModelSerializer): 
    subject = SubjectSerializer() 
    clazz = ClassSerializer() 

    class Meta: 
     model = Exam 
     fields = ('id', 'subject', 'clazz', 'topic', 'date', 'details') 
     depth = 1 

    def create(self, validated_data): 
     return Exam.objects.create(**validated_data) 

    def update(self, instance, validated_data): 
     instance.__dict__.update(**validated_data) 
     instance.save() 

     return instance 

そしてcreate():ここ

は私serializers.pyある Postman response

私はいくつかを読みましたこの問題についてはここに投稿しますが、私はそれに固執するまで。私はいくつかの方法で修正しようとしましたが、それでもまだ"This field is required."を返しています。

+0

一般的な問題ですが、私の答えを見て、あなたはそれが便利だとわかります。 http://stackoverflow.com/questions/41308406/django-rest-framework-add-object-to-request-data-and-then-call-serializer-is-va –

答えて

15

nested serializationの問題に対処しています。続行する前に、リンクされたドキュメントをお読みください。

あなたの質問は、DRFの問題の複雑な領域に関連しているため、シリアライザとビューセットの仕組みを理解するための説明と議論が必要です。

これは、人々は、ネストされた形式でのデータを表現したい問題は、一般的なので、私は、別のHTTPメソッドのデータの異なる表現を使って、同じエンドポイントを経由してあなたのSubjectClassデータを表すの問題について説明します。彼らは、ユーザインターフェイスに、クリーン使用のための十分な情報を提供したいと考えています。ドロップダウンセレクタを使用します。デフォルトジャンゴとDjango RESTフレームワーク(DRF)によって

は彼らの主キーによって、関連するオブジェクト(あなたSubjectClass)を参照してください。デフォルトでは、Djangoで整数キーを自動インクリメントします。他の方法で参照する場合は、これを上書きする必要があります。いくつかのオプションがあります。他のいくつかの属性(複数可)を介して、あなたのクラスを参照して、手動で作成するためのルックアップを自分で書くか、としてを通じて参照されているキーを設定します。

  1. 最初のオプションは、あなたの作成と更新ロジックを専門にありますあなたのクラスのprimary keyユニークである限り、クラスの名前、UUID、またはその他の属性をプライマリデータベースのキーとして設定することができます(single field)。これはあなたが今のところあなたのClassモデルを見ているからです複合(数字、文字)検索語で構成された複合検索を使用します。たとえば、createのビューメソッド(POSTの場合)で関連するオブジェクトのルックアップをオーバーライドできますが、同様に(PUTおよびPATCHの場合は)updateビューメソッドで同様のルックアップを処理する必要があります。
  2. 第二には、私の意見では望ましい選択肢は、あなたのオブジェクト表現を専門にある:それを作成し、を更新するための対象と1を読み取るための1つのシリアライザを作成し、主キーとを経由して、通常は自分のクラスを参照してください。これは、シリアライザのクラスの継承と表現のオーバーライドによって簡単に実現できます。 POST、PUT、PATCHなどでプライマリキーを使用します。クラス参照と外部キーの更新要求

オプション1:クラスを見て、任意の作成における属性と更新をアップ件名:

class ExamSerializer(serializers.ModelSerializer): 
    subject = SubjectSerializer(read_only=True) 
    clazz = ClassSerializer(read_only=True) 

上書き:読み取り専用としてあなたのネストされたクラスのシリアライザを設定

自由形式の属性で関連するクラスを検索するためにビューを作成します。また、how DRF implements this with mixinsをチェックしてください。オプション2

def create(self, request): 
    # Look up objects by arbitrary attributes. 
    # You can check here if your students are participating 
    # the classes and have taken the subjects they sign up for. 
    subject = get_object_or_404(Subject, title=request.data.get('subject')) 
    clazz = get_object_or_404(
     Class, 
     number=request.data.get('clazz_number') 
     letter=request.data.get('clazz_letter') 
    ) 

    serializer = self.get_serializer(data=request.data) 
    serializer.is_valid(raise_exception=True) 
    serializer.save(clazz=clazz, subject=subject) 
    headers = self.get_success_headers(serializer.data) 

    return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) 

:あなたはまた、正しくこれらを処理するために、あなたのupdateメソッドをオーバーライドする必要があり、あなたはこのルートを取る場合は、アカウントにPUT(更新)に加えて、PATCH(部分更新)のサポートがかかります:読み書き用にシリアライザを特化し、主キーを使用する。これは慣用的なアプローチです:

まずModelSerializerはあなたが通常の操作(POST、PUT、PATCH)のために使用するデフォルト値を定義します。

class ExamSerializer(serializers.ModelSerializer) 
    class Meta: 
     model = Exam 
     fields = ('id', 'subject', 'clazz', 'topic', 'date', 'details') 

次に、あなたが望む表現の種類に必要なフィールドを上書き(GET)のデータを読み込むためにそれらに与える:

class ExamReadSerializer(ExamSerializer): 
    subject = SubjectSerializer(read_only=True) 
    clazz = ClassSerializer(read_only=True) 

その後specify the serializer you wish to use for different operationsあなたのビューセットのために。 (はるかに簡単)ここでは、読み取り操作のために、ネストされた件名とクラスのデータを返すが、唯一の更新操作のために彼らの主キーを使用します。

class ExamViewSet(viewsets.ModelViewSet): 
    queryset = Exam.objects.all() 

    def get_serializer_class(self): 
     # Define your HTTP method-to-serializer mapping freely. 
     # This also works with CoreAPI and Swagger documentation, 
     # which produces clean and readable API documentation, 
     # so I have chosen to believe this is the way the 
     # Django REST Framework author intended things to work: 
     if self.request.method in ('GET',) 
      # Since the ReadSerializer does nested lookups 
      # in multiple tables, only use it when necessary 
      return ExamReadSerializer 
     return ExamSerializer 

あなたが見ることができるように、オプション2はかなり少なく、複雑でエラーが発生しやすいと思われます、 DRF(get_serializer_class実装)の上に3行の手書きコードしか含まれていません。フレームワークのロジックがオブジェクトの表現と作成と更新を把握できるようにします。

私は多くの他のアプローチを見てきましたが、これまでのところ、これらは私のために維持し、クリーンな方法で、DRFの設計を利用する以上のコードを生成したものとなっています。

+0

ありがとう、男!それは私が今後のプロジェクトに使う良いアプローチです。 – wencakisa

+0

それがあなたを助けたらうれしいよ:)メリークリスマスを! –

+0

メリークリスマス! – wencakisa

0

DRF(ジャンゴ休憩フレームワーク)にネストされたJSONオブジェクトを投稿しようとしたとき、私は同じ問題を持っていました。

ネストされたシリアライザを正しく設定したら(writable nested serializersのドキュメントを参照)、browsable APIを使用してそこにデータを置いて動作することをテストできます。それが動作し、あなたはまだJSONオブジェクトを置く/投稿するときに、あなたのネストされたモデルにエラー「このフィールドはを必要とする」取得している場合、あなたはあなたの要求のコンテンツタイプを設定する必要があります。

This answerは、私は必要なソリューションを提供し、それは以下にまとめています。

$.ajax ({ 
    // Other parameters e.g. url, type 
    data: JSON.stringify(data), 
    dataType: "json", 
    contentType: "application/json; charset=utf-8", 
}); 

私のjsオブジェクトの "stringType"と "stringify"を設定する必要がありました。

関連する問題