Django Rest Frameworkを使用して関連モデルフィールドを含めるにはどうすればよいですか?


153

次のモデルがあるとします。

class Classroom(models.Model):
    room_number = [....]

class Teacher(models.Model):
    name = [...]
    tenure = [...]
    classroom = models.ForeignKey(Classroom)

ManyRelatedPrimaryKeyField関数ごとに次のような結果を得る代わりに、

{
    "room_number": "42", 
    "teachers": [
        27, 
        24, 
        7
    ]
},

次のような完全な関連モデル表現を含む何かを返すようにします。

{
    "room_number": "42", 
    "teachers": [
        {
           'id':'27,
           'name':'John',
           'tenure':True
        }, 
        {
           'id':'24,
           'name':'Sally',
           'tenure':False
        }, 
    ]
},

これは可能ですか?もしそうなら、どうですか?そして、これは悪い考えですか?

回答:


242

最も簡単な方法は、depth引数を使用することです

class ClassroomSerializer(serializers.ModelSerializer):
    class Meta:
        model = Classroom
        depth = 1

ただし、これにはフォワード関係の関係のみが含まれます。教師フィールドはリバース関係であるため、この場合はそれほど必要ではありません。

より複雑な要件がある場合(例:逆の関係を含める、一部のフィールドをネストするが他のフィールドをネストしない、またはフィールドの特定のサブセットのみをネストする)シリアライザネストできます。

class TeacherSerializer(serializers.ModelSerializer):
    class Meta:
        model = Teacher
        fields = ('id', 'name', 'tenure')

class ClassroomSerializer(serializers.ModelSerializer):
    teachers = TeacherSerializer(source='teacher_set')

    class Meta:
        model = Classroom

シリアライザフィールドのsource引数を使用して、フィールドのソースとして使用する属性を指定することに注意してください。source代わりに、モデルでrelated_nameオプションteachersを使用して属性が存在することを確認することで、引数を削除できます。Teacherclassroom = models.ForeignKey(Classroom, related_name='teachers')

留意すべきことの1つは、ネストされたシリアライザーは現在書き込み操作をサポートしていないことです。書き込み可能な表現の場合、pkやハイパーリンクなどの通常のフラット表現を使用する必要があります。


最初の解決策を試したとき、教師を受け取りませんでしたが、教室の親のインスタンスを受け取りました(この例には表示されていません)。2番目の解決策では、「 'Classroom'オブジェクトには 'teachers'属性がありません」というエラーを受け取りました。何か不足していますか?
Chaz

1
@Chaz回答を更新してdepth、この場合に必要なことを実行できない理由を説明し、発生している例外とその対処方法を説明しました。
トムクリスティ

1
私はばかで、間違ったサーバーを攻撃していました。それは間違いなく多対多の関係にわたって機能します。
yellottyellott 2013年

15
シリアライザの入れ子は素晴らしいです!私はこれを行わなければならず、DRF 3.1.0を使用していました。私はmany=Trueそのように含めなければなりませんでした...TeacherSerializer(source='teacher_set', many=True)。それ以外の場合、次のエラーが発生しました:The serializer field might be named incorrectly and not match any attribute or key on the 'RelatedManager' instance. Original exception text was: 'RelatedManager' object has no attribute 'type'.
Karthic Raghupathi

2
外部キーの反対側は..._setデフォルトで名前が付けられます。詳細は、Djangoのドキュメントを参照してください。docs.djangoproject.com/en/1.10/ref/models/relations/...
トム・クリスティー

36

@TomChristieありがとうございます!!! あなたは私をたくさん助けてくれました!私はそれを少し更新したいと思います(私が遭遇した間違いのため)

class TeacherSerializer(serializers.ModelSerializer):
    class Meta:
        model = Teacher
        fields = ('id', 'name', 'tenure')

class ClassroomSerializer(serializers.ModelSerializer):
    teachers = TeacherSerializer(source='teacher_set', many=True)

    class Meta:
        model = Classroom
        field = ("teachers",)

2

これは、drf-flex-fieldsと呼ばれる非常に便利なdandy djangoパッケージを使用して行うこともできます。私たちはそれを使用しており、それはかなり素晴らしいです。あなたはそれをインストールしpip install drf-flex-fields、シリアライザに渡し、追加しexpandable_fields、ビンゴします(下の例)。また、ドット表記を使用して、ネストされた深い関係を指定することもできます。

from rest_flex_fields import FlexFieldsModelSerializer

class ClassroomSerializer(FlexFieldsModelSerializer):
    class Meta:
        model = Model
        fields = ("teacher_set",)
        expandable_fields = {"teacher_set": (TeacherSerializer, {"source": "teacher_set"})}

次に?expand=teacher_set、URLに追加すると、拡張された応答が返されます。これがいつか誰かを助けることを願っています。乾杯!

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.