2016-12-20 17 views
1

DRFを使用して、ネストされたデータのread_onlyバージョンと、ただ1つのシリアライザのリスト内のIDの書き込み可能バージョンを提供することはできません。それは私のバグのように感じますが、通常は、フレームワークを十分に理解できず、エラーメッセージに惑わされているだけです。Django Rest Frameworkがネストされたデータのread_onlyに応答しない

class Individual(models.Model): 
    household = models.ForeignKey(
     'household.Household', 
     null=True, 
     related_name="individuals") 
    name = models.CharField(
     max_length=100, default='') 

class Household(models.Model): 
    address_line1 = models.CharField(max_length=64, default='') 

class IndividualListSerializer(serializers.ModelSerializer): 
    class Meta: 
     model = Individual 
     depth = 0 
     fields = ('url', 'id', 'name', 'household') 
     read_only_fields = fields 

class HouseholdUpdateSerializer(serializers.ModelSerializer): 
    individuals_details = IndividualListSerializer(many=True, source='individuals', read_only=True) 
    class Meta: 
     model = Household 
     fields = ('id', 'address_line1', 'individuals', 'individuals_details') 
     read_only_fields = ('id', 'individuals_details') 

エラーは、私が(更新に応じて、必要とされている)、ネストされたフィールド上でread_onlyが使用している

AssertionError: The `.update()` method does not support writable nested fields by default. Write an explicit `.update()` method for serializer `household.serializers.HouseholdUpdateSerializer`, or set `read_only=True` on nested serializer fields. // Werkzeug Debugger</title> 

として戻ってきます。しかし、エラーはまだ私がそうしていないことを示しています。フィールドを完全に削除した場合、individuals_detailsはエラーなしで読み取り可能なデータを返しますが、送信中のデータは無視されているため、そのリストは更新されていません。

individuals_detailsフィールドを削除すると、DRFはindividualsリストを受け入れ、モデルの更新を実行します。しかし、必要なリターンデータは存在しません。

したがって、読み込みネストされたリストまたは書き込みリストのいずれかが単独で機能している間に、もう一方が追加されるとシリアライザは機能しません。

これは非常に一般的な領域の人々が立ち往生していると思われます。答えはthis SO questionパターンのベストプラクティスになっているようです。しかし、私のコードで何らかの理由で動作しません。多分私のモデルのManyToOneのために。

私はおそらく、更新のためにPUTを実行し、応答を無視して別のGETを実行するようクライアントを変更することで対処できますが、DRFの更新を行うことができない期待どおりに動作します。

私はこれで何が欠けていますか?

+0

'read_only_fields'は、明示的に定義されたフィールドで動作することを意味していません。 'read_only_fields'からindivid_detailsを削除するのはどうですか?それは修正されますか? – Linovia

+0

これは、同じモデルに対してリレーショナルフィールドとネストされたシリアライザの両方を使用するための反パターンです。 – Linovia

+0

リレーショナルとネストの両方を使用することは私の目標ではありません。しかし、DRFではネストされたデータのIDだけを更新することはできません。どのIDが関連しているかを変更した後、子レコードの詳細を取得するための良いパターンは何ですか? – shanemgrey

答えて

1

いくつかの質問がありますので、私はその表現から始めます。実際にはto_representationメソッドを表示することができますフルIndividualビューのための別のフィールドを必要としません。

class HouseholdUpdateSerializer(serializers.ModelSerializer): 

    class Meta: 
     model = Household 
     fields = ('id', 'address_line1', 'individuals') 

    def to_representation(self, instance): 
     representation = super(HouseholdUpdateSerializer, self).to_representation(instance) 
     representation['individuals'] = IndividualListSerializer(instance.individuals.all(), many=True).data 
     return representation 

あなたは、モデルの更新に関連する分野をしたい時に通常あなたがcreateupdateシリアライザメソッドをオーバーライドする必要があります。

class HouseholdUpdateSerializer(serializers.ModelSerializer): 
    .... 
    def update(instance, validated_data): 
     # get and remove individuals from validated_data 
     individuals = validated_data.pop('individuals') 
     # delete all related links to individuals 
     # You could provide some validation before clear, check if provided pks exists in db table 
     instance.individuals.clear() 
     # update related links with new individuals 
     instance.individuals.add(*individuals) 
     # call super to provide update for other fields 
     return super(HouseholdUpdateSerializer, self).update(validated_data) 

createおそらく上書きせずに、あなたのケースでうまく動作します。それがupdateに似ているだけであればそれを書いてください。

+0

to_representationをオーバーライドすることは、私が必要としていたことに役立ちました。更新メソッドをオーバーライドする第2の部分が何をしているのかは不明です。私の推測では、個人用のカスタムバリデータも必要になると思いますか? – shanemgrey

+0

@shanemgreyあなたがそれらの間のリンクをクリアする前に、 '個体 'キーがdbに存在するかどうかを確認することができます。いくつかのキーが間違っている場合、例外をスローし、 'ifシリアライザを使ってビューレイヤーにキャッチします。is_valid():..'式か 'serializer.save(raise_exception = True)'を指定します。各キーの 'queryset.exists()'でキーを検証したり、 'len(個)== Individuals.objects.filter(pk__in) =個).count() '。 –

関連する問題