ネストされた「多対多」の関係でシリアライザを作成しようとしています。目標は、シリアル化された関連オブジェクトの配列を含むシリアル化されたJSONオブジェクトを取得することです。モデルは次のようになり、着信JSONは私の現在のシリアライザコードはそれがいるようです。このDRFのカスタム関連フィールドをシリアライズ
class ToppingRelatedField(RelatedField): def get_queryset(self): return Topping.objects.all() def to_representation(self, instance): return {'name': instance.name, 'inventor': instance.inventor.username} def to_internal_value(self, data): name = data.get('name', None) inventor = data.get('inventor', None) try: user = User.objects.get(username=inventor) except Setting.DoesNotExist: raise serializers.ValidationError('bad inventor') return Topping(name=name, inventor=user) class PizzaSerializer(ModelSerializer): toppings = ToppingRelatedField(many=True) class Meta: model = Pizza fields = ('name', 'toppings')
のように見えるこの
{ "name": "My Pizza", "toppings": [ {"name": "cheese", "inventor": "bob"}, {"name": "tomatoes", "inventor": "alice"} ] }
のように見えます
from django.contrib.auth.models import User PizzaTopping(models.Model): name = models.CharField(max_length=255) inventor = models.ForeignKey(User) Pizza(models.Model): name = models.CharField(max_length=255) toppings = models.ManyToManyField(PizzaTopping)
(名前は、構造が保存さ変更)以来カスタムフィールドのto_internal_value()を定義したので、多対多フィールドを自動的に作成/更新する必要があります。しかし、私がピザを作成しようとすると、「追加できません」というメッセージが表示されます。フィールド「pizzatopping」の値は「ValueError」ではありません。 Djangoはモデルの名前によって多対多のフィールドを呼び出す必要があると判断しました。そうでない場合はどうすればわかりますか?
編集#1:DjangoやDRFのどこかに本物のバグがあるようです。 DRFは正しいことをしていると思われ、ManyToManyフィールドを処理していることを検出し、カスタムフィールドを使用してデータからトッピングを作成し、ピザに追加しようとします。ピザインスタンスとフィールド名しか持たないので、setattr(pizza, 'toppings', toppings)
を使用します。 Djangoは正しいことをしているようです。 __set__
が定義されており、マネージャーでadd()メソッドを使用する必要があることが分かっているようです。しかし途中で、フィールド名の「トッピング」が失われ、デフォルトに置き換えられます。これは "小文字の関連モデル名"です。
編集#2:解決策を見つけました。私は許されたら答えにそれを記録します。 RelatedField
サブクラスのto_internal_value()
メソッドは、ManyToManyが正しく動作するために、保存されたToppingのインスタンスを返す必要があるようです。既存のドキュメントには反対のリンクがあります(http://www.django-rest-framework.org/api-guide/fields/#custom-fields)。この例では、保存されていないインスタンスが返されます。