【Django】リレーション関係を持ったモデルにて登録・更新処理のAPIを作成する方法

 

初めに

リレーションの関係を持ったDBにて新規登録、更新処理を実現するための方法を紹介します。

現在、DRF(Django Rest Framework)を使用してAPIを作成しており、ManyToManyの関係を持ったDBへの新規・更新処理を実現しようとしています。

DRFのドキュメントを基に実装を進めたものの、リレーションを持ったDBの処理に関しての記事がなかったため今回まとめました。

同じように困っている方の助けとなれれば幸いです。

ちなみに単一のDB更新に関してはこちらから

環境

  • Python 3.8
  • Django 3.1.3
  • DRF 3.12.2

実装

前提条件

今回テストとして使用するモデルは以下の通りです。

「飲み物マスタ」と「自販機一覧」はM2Mの関係と言えます。

その理由として、

自販機から見れば飲み物は1個以上登録が必要であり、

飲み物マスタから見れば0個以上の自販機に登録されているからです。

本当はこれらの中間テーブルが存在しているのですが、DRFでは勝手に作成してくれるので、何も記載していません。

ソースコード

さて、前提条件にて記載したテーブルへ自販機を登録するAPIを作成していきます。

今回はmodel, serializerのみのソースとなります。

URLの設定などは以下をご参照いただけると幸いです。

models.py

from django.db import models

# Create your models here.
class Drinking(models.Model):
    name = models.CharField(max_length=50)
    temperature_flg = models.CharField(max_length=1)

    def __str__(self):
        return self.name

class VendorInfo(models.Model):
    address = models.CharField(max_length=200)
    longitude = models.DecimalField(max_digits=17, decimal_places=14)
    latitude = models.DecimalField(max_digits=17, decimal_places=14)
    created_at = models.DateField(auto_now=True)
    Drinkings = models.ManyToManyField(Drinking)
    
    def __str__(self):
        return self.address

serializer.py

from ctypes import addressof
from multiprocessing import context
from rest_framework import serializers
from jobs.models import Drinking, VendorInfo

class VendorInfoSerializer(serializers.ModelSerializer):
    Drinkings = DrinksSerializer(many=True)
    class Meta:
        model = VendorInfo
        fields = '__all__'

    def create(self, validated_data):
        newVendor = VendorInfo.objects.create(
            address = validated_data["address"],
            latitude = validated_data["latitude"],
            longitude = validated_data["longitude"],
            # Drinkings = validated_data["Drinkings"],
        )
        newVendor.save()

        for drink in validated_data["Drinkings"]:
            drinkObj = Drinking.objects.get(
                name = drink["name"], 
                temperature_flg = drink["temperature_flg"])
            newVendor.Drinkings.add(drinkObj)

        return newVendor

    def update(self, instance, validated_data):
        instance.address = validated_data["address"]
        instance.latitude = validated_data["latitude"]
        instance.longitude = validated_data["longitude"]
        instance.save()

        vendor = VendorInfo.objects.get(id=instance.id)
        vendor.Drinkings.clear()

        for drink in validated_data["Drinkings"]:
            drinkObj = Drinking.objects.get(
                name = drink["name"], 
                temperature_flg = drink["temperature_flg"])
            instance.Drinkings.add(drinkObj)
            
        return instance

           

基本的にはINSERTとUPDATEメソッドをオーバーライドするのですが、

M2Mの関係を持っているVendorInfoのDrinkingsへの登録や更新はfor文を使用して一つずつ、中間テーブルを作っているイメージです。

終わり

コメント

タイトルとURLをコピーしました