#はじめに
1つのエンドポイントで、親子関係があるテーブル構造に対してどうやってデータを登録するんだろうか。
業務中にそんな事があったので、記載します。
#目次
1. 要件
2. リクエストAPIのデータ構造
3. モデルの定義
4. Viewの定義
5. Serializerの定義
6. URLディスパッチャの定義
7. 動作の確認
8. まとめ
#1. 要件
今回は、「受注をする」という要件を想定して作業をしてみようと思います。
ECなどでよくある受注機能ですね。
受注ヘッダ(orderhead)、受注明細(orderdetail)という1対多の
親子関係を持ったテーブル構造に対してデータを登録することをゴールにします。
#2. リクエストAPIのデータ構造
まずDjango側で受けるPOSTデータの定義をしようと思います。
以下のように、受注ヘッダの基となるデータ群(親)と、受注明細の基となるデータ群(子)を
定義しました。
{
"order_number" : "9000000",
"customer_id" : "customer001",
"order_detail": [
{
"product_code":"A001",
"quantity":2
},
{
"product_code":"A002",
"quantity":2
}
]
}
#3. モデルの定義
データを格納するテーブル構造を以下に記載します。
受注ヘッダ(OrderHead)と受注明細(OrderDetail)です。
受注明細側には、Foreignキーを利用して受注ヘッダと受注明細に1対多の関係を築きます。
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を利用してます。
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を利用することでリクエストデータと、モデルフィールドのマッピングをして
バリデーションチェックやデータ登録処理を行うようにします。
※バリデーションは、modelフィールドに基づいて実施
order_haed、order_detailへデータ登録した際のサロゲートキー(自動採番キー)を取得して
レスポンスデータとして返却する仕組みにしました。
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メソッドを指定することで、動作を行うようにします。
# 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がレスポンスで返ってきた値と一緒であることが分かります。
#8. まとめ
受注ヘッダと受注明細にデータを登録するAPIを作成することができました。
作成して思ったことは、serializerは、OrderSerializerが1つあって、その中でOrderHeader,OrderDetailのserializerを読む形ができればもっと綺麗な形で
デザインできたんじゃないかと思います。
今日はここまで。
最後まで読んでくださった方 ありがとうございました。