Django Rest Framework에서 부모와 자식 관계가있는 테이블에 데이터 등록

소개



하나의 엔드포인트에서 부모-자식 관계가 있는 테이블 구조에 대해 어떻게 데이터를 등록할까.
업무중에 그런 일이 있었으므로, 기재합니다.

목차



1. 요건
2. 요청 API의 데이터 구조
3. 모델 정의
4. View 정의
5. Serializer의 정의
6. URL 디스패처 정의
7. 동작의 확인
8. 정리

1. 요건



이번에는, 「수주를 한다」라고 하는 요건을 상정해 작업을 해 보려고 생각합니다.
EC등에서 자주 있는 수주 기능이군요.
판매 주문 헤더 (orderhead), 주문 주문 (orderdetail)이라는 일대 다
부모 - 자식 관계를 가진 테이블 구조에 데이터를 등록하는 것을 목표로합니다.

2. 요청 API의 데이터 구조



우선 Django 측에서 받는 POST 데이터의 정의를 하려고 합니다.
다음과 같이 판매 주문 헤더의 기본 데이터 그룹 (부모)과 판매 주문 항목의 기본 데이터 그룹 (자식)
정의했습니다.

order.json
{
    "order_number"  : "9000000",
    "customer_id" : "customer001",
    "order_detail": [
        {
            "product_code":"A001",
            "quantity":2
        },
        {
            "product_code":"A002",
            "quantity":2
        }
    ]
}

3. 모델 정의



데이터를 저장하는 테이블 구조는 다음과 같습니다.
판매 오더 헤더(OrderHead)와 판매 오더 품목(OrderDetail)입니다.
판매 오더 품목 측에는 Foreign 키를 이용하여 판매 오더 헤더와 판매 오더 품목에 일대 다 관계를 구축합니다.

models.py
class OrderHead(models.Model):
    order_number = models.CharField(max_length=10)
    order_at = models.DateTimeField(auto_now_add = True)
    customer_id =  models.CharField(max_length=12)

class OrderDetail(models.Model):
    orderhead = models.ForeignKey(OrderHead, related_name='details', on_delete=models.CASCADE)
    product_code = models.CharField(max_length=10)
    quantity = models.PositiveSmallIntegerField()


4. View 정의



요청 데이터를 받은 후 어떻게 처리할지 설명합니다.
최대 Django Rest framework의 기능을 살리려고 ModelViewSets를 이용하고 있습니다.

view.py

class OrderViewSet(viewsets.ModelViewSet):

    queryset = OrderHead.objects.all()
    serializer_class = OrderSerializer

    def create(self, request):

            order_serializer = OrderSerializer(data=request.data)

            if not order_serializer.is_valid():
                print(order_serializer.errors)
                return Response("validation error........")

            result = order_serializer.save()
            return Response(result)


5. Serializer 정의



view측으로부터의 호출로, 리퀘스트 데이터에 대한 처리를 기술합니다.
ModelSerializer를 이용하여 요청 데이터와 모델 필드를 매핑합니다.
밸리데이션 체크나 데이터 등록 처리를 실시하도록 합니다.
※바리데이션은, 모델 필드에 근거해 실시

order_haed, order_detail에 데이터 등록했을 때의 사로 게이트 키(자동 번호 매기기 키)를 취득해
응답 데이터로 반환하는 구조로했습니다.

serializer.py


class OrderDetailSerializer(serializers.ModelSerializer):

    class Meta: 
        model = OrderDetail
        fields = ('product_code','quantity')


class OrderSerializer(serializers.ModelSerializer):

    order_detail = OrderDetailSerializer(many=True)

    class Meta:
        model = OrderHead
        fields = ('order_number','customer_id', 'order_detail')

    def create(self, validated_data):

        result_dict = {}
        detail_list = []

        order_detail = validated_data.pop('order_detail')

        created_orderhead = OrderHead.objects.create(**validated_data)
        result_dict['head_id'] = created_orderhead.id

        for order_detail_data in order_detail:

            created_orderdetail = OrderDetail.objects.create(orderhead=created_orderhead, **order_detail_data)
            detail_list.append(created_orderdetail.id)

        result_dict['detail_id'] = detail_list
        return result_dict

6. URL 디스패처 정의(URLConf)



애플리케이션별 urls.py 설정은 다음과 같습니다.
판매 오더를 조작 할 수있는 API이므로 orders를 정의하고이 URL에 대해
HTTP 메소드를 지정하여 동작을 수행합니다.

urls.py
# coding: utf-8

from rest_framework import routers
from .views import OrderViewSet


router = routers.DefaultRouter()
router.register(r'orders', OrderViewSet)

7. 동작 확인



Postman을 사용하여 확인합니다.
응답이 돌아왔다는 것을 알 수 있습니다.



그런 다음 DB에 등록되어 있는지 확인합니다.
oderhead 테이블의 id가 응답으로 반환된 값과 함께 있음을 알 수 있습니다.

・orderhead 테이블 확인


・orderdetail 테이블 확인


8. 정리



판매 오더 헤더와 판매 오더 품목에 데이터를 등록하는 API를 만들 수 있습니다.
작성해 생각한 것은, serializer는, OrderSerializer가 1개 있어, 그 안에서 OrderHeader,OrderDetail의 serializer를 읽는 형태가 생기면 보다 깨끗한 형태로
디자인 할 수 있었던 것이 아닐까 생각합니다.
오늘은 여기까지.
끝까지 읽어 주신 분 감사합니다.

좋은 웹페이지 즐겨찾기