_Django 2.x
_と_Django REST Framework
_を使用しています。
私は2つのモデルがあります
_class Contact(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
user = models.ForeignKey(User, on_delete=models.PROTECT)
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100, blank=True, null=True)
modified = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
class AmountGiven(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
contact = models.ForeignKey(Contact, on_delete=models.PROTECT)
amount = models.FloatField(help_text='Amount given to the contact')
given_date = models.DateField(default=timezone.now)
created = models.DateTimeField(auto_now=True)
_
serializer.pyファイルには次のように定義されたシリアライザーがあります
_class ContactSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Contact
fields = ('id', 'first_name', 'last_name', 'created', 'modified')
class AmountGivenSerializer(serializers.ModelSerializer):
contact = ContactSerializer()
class Meta:
model = AmountGiven
depth = 1
fields = (
'id', 'contact', 'amount', 'given_date', 'created'
)
_
views.py
_class AmountGivenViewSet(viewsets.ModelViewSet):
serializer_class = AmountGivenSerializer
def perform_create(self, serializer):
save_data = {}
contact_pk = self.request.data.get('contact', None)
if not contact_pk:
raise ValidationError({'contact': ['Contact is required']})
contact = Contact.objects.filter(
user=self.request.user,
pk=contact_pk
).first()
if not contact:
raise ValidationError({'contact': ['Contact does not exists']})
save_data['contact'] = contact
serializer.save(**save_data)
_
しかし、AmountGivenモデルに新しいレコードを追加し、contact
フィールドにcontact
idを渡すと
それはエラーを与えています
_{"contact":{"non_field_errors":["Invalid data. Expected a dictionary, but got str."]}}
_
AmountGivenSerializerからcontact = ContactSerializer()
を削除すると、期待どおりに機能しますが、depth
がに設定されているため応答します1、連絡先データにはモデルフィールドのみが含まれ、他のプロパティフィールドは定義されていません。
私はこのリクエスト解析パターンの大ファンではありません。私の理解では、AmountGiven
オブジェクトを取得するときにすべての連絡先の詳細を表示できると同時に、連絡先IDを指定するだけでAmountGiven
を作成および更新できるようにする必要があります。 。
したがって、AmountGiven
シリアライザーを変更して、contact
モデルフィールド用に2つのフィールドを持つことができます。このような:
class AmountGivenSerializer(serializers.ModelSerializer):
contact_detail = ContactSerializer(source='contact', read_only=True)
class Meta:
model = AmountGiven
depth = 1
fields = (
'id', 'contact', 'contact_detail', 'amount', 'given_date', 'created'
)
contact_detail
フィールドにはsource
属性があることに注意してください。
これで、作成と更新のデフォルト機能がすぐに機能するはずです(検証とすべて)。
また、AmountGiven
オブジェクトを取得すると、連絡先のすべての詳細がcontact_detail
フィールドに表示されます。
Contact
がユーザーのものであるかどうかを確認する必要があることを見逃しました(ただし、user
モデルにContact
フィールドが表示されないため、投稿を見逃した可能性があります)。そのチェックを簡略化できます。
class AmountGivenViewSet(viewsets.ModelViewSet):
serializer_class = AmountGivenSerializer
def perform_create(self, serializer):
contact = serializer.validated_data.get('contact')
if contact.user != self.request.user:
raise ValidationError({'contact': ['Not a valid contact']})
serializer.save()
__init__()
メソッドのAmountGivenSerializer
を次のようにオーバーライドします。
_class AmountGivenSerializer(serializers.ModelSerializer):
def __init__(self, *args, **kwargs):
super(AmountGivenSerializer, self).__init__(*args, **kwargs)
if 'view' in self.context and self.context['view'].action != 'create':
self.fields.update({"contact": ContactSerializer()})
class Meta:
model = AmountGiven
depth = 1
fields = (
'id', 'contact', 'amount', 'given_date', 'created'
)
_
説明
問題は、定義されているため、DRFがcontact
フィールドからオブジェクトのようなdictを予期することでした_nested serializer
_。そこで、__init__()
メソッドをオーバーライドすることで、ネストされた関係を動的に削除しました