2016-07-12 9 views
0

私は長い間、長い間興味があるケースがあります。ネストされた関係を処理するための適切な方法

class Product(models.Model): 
    manufacturer = models.CharField(max_length=100) 
    description = models.TextField(blank=True) 

class PurchasedProduct(models.Model): 
    product = models.ForeignKey(Product) 
    purchase = models.ForeignKey('Purchase') 
    quantity = models.PositiveIntegerField() 

class Purchase(models.Model): 
    customer = models.ForeignKey('customers.Customer') 
    products = models.ManyToManyField(Product, through=PurchasedProduct) 
    comment = models.CharField(max_length=200) 

私はいくつかのJavaScriptフレームワークで書かれたAPIおよびクライアントアプリケーションを持っている:私は3つのモデルを持っていると言います。だから私はそれらの間で通信する必要があります!

{ 
    "id": 1, 
    "customer": 1, 
    "comment": "Foobar", 
    "products": [ 
     { 
      "id": 1, 
      "product": { 
       "id": 1, 
       .... 
      }, 
      .... 
     }, 
     .... 
    ] 
} 

/purchase/1/は、だから私はproductsフィールドが順番にネストされた使用PurchasedProductSerializerを使用する必要があることを指定し、適切なシリアライザを作成してアクセスするとき、私は私がDRFでこの状況をどのように処理するかわからない、自然に私はこのような何かを得ることを期待するProductSerializer 。 Reactなどの適切なコンポーネントを使って買い物をしている間に、購入した特定の商品と購入した商品の数量を表示するのに必要なすべての情報を得ることができます。

しかし、私にとって問題は、POST新しいPurchasedProductが必要なときです。それはすべての必要な情報を保持し、最小のフットプリントを持っていたよう

{ 
    "quantity": 10, 
    "purchase": 1, 
    "product": 1 
} 

:私が最も便利なフォームがあることを期待します。しかしidの代わりにproductが必要なので、私はPurchasedProductSerializerを使って達成することはできません。

GETPOSTの2つの別々のシリアライザを使用する必要がありますので、これは良いアプローチです(これは私にとって非常に自然なことです)。私はこれを別の方法で行うべきですか?いくつかのベストプラクティス/書籍でAPIやクライアントアプリケーションの作成方法を教えてください。

答えて

1

私は数ヶ月前とまったく同じ問題を抱えていました。誰かが私に語ったことがあれば、それ以上に満足していました。私はあなたが購入に商品を追加することを提案した正確な解決策に終わった。私はあなたの提案したPOSTリクエストが、必要最低限​​のフットプリントで最も自然な方法であることに同意します。

POSTリクエストのデータを正しく処理するには、説明したとおり、2つの別々のシリアライザを使用してしまいました。 DRFビューセットを使用している場合、GETPOSTで正しいシリアライザを選択する方法の1つは、get_serializer_classメソッドをhereのようにオーバーライドすることです。 POSTリクエストのため

デシリアライザは、次のようになります。デシリアライザは、入力の検証のために使用することができ、最終的に購入する製品を追加すること

class PurchasedProductDeserializer(serializers.ModelSerializer): 
    product = serializers.PrimaryKeyRelatedField(queryset=Product.objects.all()) 
    purchase = serializers.PrimaryKeyRelatedField(queryset=Purchase.objects.all()) 

    class Meta: 
    model = PurchasedProduct 
    fields = ('id', 'product', 'purchase', 'quantity') 
    write_only_fields = ('product', 'purchase', 'quantity') 

(またはその量を増やします)。

Egは、あなたのビューセット内:ベストプラクティスについては

def create(self, request, *args, **kwargs): 
    # ... 
    # init your serializer here 
    serializer = self.get_serializer(data=request.data) 
    if serializer.is_valid(raise_exception=True): 
    # now check if the same item is already in the cart 
    try: 
     # try to find the product in the list of purchased products 
     purchased_product = serializer.validated_data['purchase'].purchasedproduct_set.get(product=serializer.validated_data['product']) 
     # if so, simply increase its quantity, else add the product as a new item to the cart (see except case) 
     purchased_product.quantity += serializer.validated_data['quantity'] 
     purchased_product.save() 
     # update the serializer so it knows the id of the existing instance 
     serializer.instance = purchased_product 
    except PurchasedProduct.DoesNotExist: 
     # product is not yet part of the purchase cart, add it now 
     self.perform_create(serializer) 
    # ... 
    # do other stuff here 

、インターネット上で利用可能なドキュメントのトンがありますが、あなたが本を探している場合は、掲載のもののいくつかを見てみたいかもしれませんhere。あなたがRESTに飽きると、あなたはGraphQLを調べたいかもしれません。

関連する問題