2016-07-12 2 views
0

나는 길고 오랫동안 궁금해하는 경우가 있습니다. 내가 3 가지 모델을 가지고 있다고 가정 해보십시오 :중첩 된 관계를 처리하는 올바른 방법

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 및 클라이언트 응용 프로그램이 있습니다. 그래서 지금 그들 사이에 의사 소통을해야합니다!

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

/purchase/1/ 그래서 내가 products 필드가 차례로 중첩 사용 PurchasedProductSerializer를 사용하도록 지정하는 적절한 시리얼을 만들어 액세스 할 때 내가 DRF에서이 상황을 처리하는 방법을 확실하지 않다, 자연스럽게 나는 이런 식으로 뭔가를 얻을 기대 ProductSerializer . React에서 적절한 구성 요소를 사용하여 쇼핑하는 동안 어떤 특정 제품을 어디서 구입했는지 표시하는 데 필요한 정보를 얻는 데 필요한 모든 정보가 필요합니다.

그러나 문제는 내가 POSTPurchasedProduct 일 때입니다. 가장 편리한 형식은 다음과 같습니다.

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

이 정보는 필요한 모든 정보를 전달하며 가장 작은 크기입니다. 그러나 나는 id 대신 객체가되도록 product이 필요하므로 PurchasedProductSerializer을 사용하여 수행 할 수 없습니다.

여기 내 질문에이 좋은 접근 방식입니다 (나에게는 매우 자연스러운 것처럼 보입니다) GETPOST에 두 개의 별도의 직렬 변환기를 사용해야합니까? 이 작업을 다르게 수행해야합니까? API 및 클라이언트 응용 프로그램 작성 방법에 대한 우수 사례/서적을 가르쳐 주시겠습니까?

답변

1

나는 몇 달 전과 똑같은 문제가 있었는데 누군가 나에게 말하면 행복했을 것입니다. 구매에 제품을 추가하라는 제안과 정확히 일치했습니다. 귀하의 제안 된 POST 요청이 최소한의 필요한 점유 면적을 가진 가장 자연스러운 방법이라는 데 동의합니다.

정확히 POST 요청의 데이터를 올바르게 처리하기 위해 설명 된대로 두 개의 별도의 Serializer를 사용했다. DRF 뷰 세트를 사용하는 경우 GETPOST에서 올바른 serializer를 선택하는 한 가지 방법은 here과 같이 get_serializer_class 메서드를 재정의하는 것입니다. 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') 

(또는 그 양을 증가).

예, 당신의 뷰셋 내부 : 모범 사례로

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을 조사하고 싶을 수도 있습니다.

관련 문제