2016-08-17 5 views
0

コンテンツタイプを格納する "content_type"フィールドと、オブジェクトIDを格納する "object_id"フィールドを使用する汎用外部キーを使用するモデルがあります。このモデルはCRUD APIで操作する必要があり、DRFを使用しています。私はモデルのシリアライザを持っていますが、少し問題があります。私はちょうどこのDRFでGenericForeignKeyをシリアル化する方法は?

 
class MySerializer(ModelSerializer): 
    class Meta: 
     fields = ('name', 'state', 'content_type', 'object_id') 

のようなフィールドのリストにCONTENT_TYPEを追加した場合、シリアライザは、ContentTypeをモデルインスタンスのIDにJSON表現を設定します。 APIのユーザーはこれらのIDを認識しないため、さらに別のAPIを使用してContentTypeモデルを公開したくありません。 APIユーザーはリンクしたいオブジェクトの種類を知っているので、コンテンツタイプ名を送信できます。そこで、私はこのようなシリアライザを定義しました。

モデルをシリアライズするだけで問題ありません。一般的な関係を使用してUserインスタンスをリンクすると、{'name': 'test', 'state': 'NY', 'content_type': 'user', 'object_id': 123}のようなものが得られます。しかし、JSON構造体でPUTまたはPOSTリクエストを送信すると、DRFはこれを{'name': 'test', 'state': 'NY', 'content_type': {'name': {'name': 'user'}}, 'object_id': 123}のようなものに変換します。私は何かを書くことができる

 
    def create(self, validated_data): 
     ct_model = validated_data['content_type']['name']['name'] 
     validated_data['content_type'] = ContentType.objects.get(model=ct_model) 
     return MyModel.objects.create(**validated_data) 

しかし、それは任意かつ壊れやすいようです。この状況に対処する正しい方法は何ですか?

更新#1:瞬間のために、私は(to_internal_valueをオーバーライドすることによって、問題を解決している)このコードの

 
def to_internal_value(self, data): 
    content_type = data.get('content_type', None) 
    validated_data = super().to_internal_value(data) 
    try: 
     validated_data['content_type'] = ContentType.objects.get(model=content_type) 
    except ContentType.DoesNotExist: 
     raise serializers.ValidationError("invalid content type %s" % content_type) 
    return validated_data 

表示するようにしなければならないために醜いハックのようなもののように思えます関連するオブジェクト。

+0

ドキュメントhttp://www.django-rest-framework.org/api-guide/relations/#generic-relationshipsから解決策を試しましたか? – mateuszb

+0

解決策はカスタム関連のフィールドクラスを定義することにあるようです。私はそれを調べるだろうが、それは畳み込まれているようだ。 –

+0

あなた自身の質問に答えた場合は、それを回答として投稿し、更新として投稿しないでください。 –

答えて

0

このような関係をシリアル化するには、to_representationto_internal_valueという独自のフィールドクラスを用意する必要があります。複雑ではありません。試してみてください。

あなたのシリアライズフォーマットとしてuri表記/api/resource/object_idを使用することを検討してください。

コンテンツタイプをリソースのurisとbackに変換するのはちょっと難しいかもしれませんが(可能なタイプがいくつかあります)、簡単な方法があるはずです。

+0

コンテンツタイプとしてURIを使用する場合は、APIを使用してコンテンツタイプを公開する必要があります(また、djangoはシステム内のすべてのモデルのコンテンツタイプを作成するため、権限とフィルタリングの問題を処理します)。 APIユーザーは、1つのデータを取得するために複数の要求を行うことができます。 –

+0

私はあなたの1.が真実ではないと思いますが、どうしても許可とフィルタリングを避けることができませんが、あなたのAPIを入れ子にして遅くしたい場合は、前述のシリアライザメソッドをカスタマイズする必要があります。 –

+0

ネストしたリソースにurisを使用する場合は、uriを使用してリソースを取得する必要があります。この場合、コンテンツタイプにurisを使用することを提案しました。これは、コンテンツタイプにアクセスするためのAPIを用意する必要があることを意味します。これは、djangoが絶対にすべてのコンテンツタイプを作成し、アプリケーションの内部構造をAPIユーザーに公開したくないため、非公開の方法でアクセスを制限する必要が生じることにつながります。 2番目の部分については、APIをネストしていません。しかし、私がしたとしても、あなたがその業績を判断する立場にいるかどうかはわかりません。 –

関連する問題