LoginSignup
3
2

More than 1 year has passed since last update.

DRFのModelSerializerを通して新規登録、更新(create / update)

Posted at

以下のような構成のTable、ModelSerializerで新規登録、更新する実現するための実装サンプル
Table.png
ModelSerializer.png

  • Table_A_Serilaizer で create、updateをオーバーライドする
    • オーバーライドした create、update で validated_data から table_b を抜き出す
    • create() では先にTable_A へvalidated_data で createを行い、id を生成してから Table_Bへの save を行う
    • update() はTable_A へvalidated_data で update、抜き出した data で Table_Bへの save を行う
  • view で Table_A_Serilaizer を生成する際、partial=True を付ける
    • 新規登録時に validation で エラーになることを避けるため
view
# 登録するデータ
data = {
    'value_1': 100
    'table_b': {
        'value_2': 200
    } 
}
# 新規登録時
serializer = Table_A_Serilaizer(data=data, partial=True)
# 更新時
before = Table_A.objects.get(id=id)
serializer = Table_A_Serilaizer(instance=before, data=data, partial=True)
# 登録処理
serializer.is_valid()
serializer.save()
serializer
class Table_B_Serilaizer(ModelSerializer):
    class Meta:
        model = Table_B
        fields = '__all__'

class Table_A_Serilaizer(ModelSerializer):
    table_b = Table_B_Serilaizer()
    class Meta:
        model = Table_A
        fields = '__all__'

    def create(self, validated_data):
        # validated_data から table_b を抜き出す
        data = validated_data.pop('table_b')
        # Table_Aのcreate
        table_a = super().create(validated_data)
        # Table_Bのsave
        table_a.table_b = self.__save_table_b(table_a, data)
        return table_a

    def update(self, instance, validated_data):
        # validated_data から table_b を抜き出す
        data = validated_data.pop('table_b')
        # Table_Bのsave
        self.__save_table_b(instance, data)
        # Table_Aのupdate
        return super().update(instance, validated_data)

    def __save_table_b(self, instance, data):
        data['id'] = instance.id
        if hasattr(instance, 'table_b'):
            table_b = Table_B_Serilaizer(instance=instance.table_b, data=data)
        else:
            table_b = Table_B_Serilaizer(data=data)
        table_b.is_valid()
        table_b.save()
model
class Table_A(models.Model):
    id = models.AutoField(primary_key=True)
    value_1 = models.IntegerField()

class Table_B(models.Model):
    id = models.AutoField(primary_key=True)
    table_a_id = models.OneToOneField(Table_A, on_delete=models.CASCADE)
    value_2 = models.IntegerField()
3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2