0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Django の ORM でユニークキー制約がある場合のオブジェクトの複製

Last updated at Posted at 2025-10-05

やりたいこと

Django の ORM でユニークキー制約がある場合に、オブジェクトを複製する

Django のプログラム例

プログラム構成

├── app1
│?? └── models.py     # モデルを定義
├── db_test3
│?? └── settings.py   # 設定を記述
└── test               # 動作確認用スクリプト
    ├── setup1.py
    ├── test1.py
    └── test2.py

モデル

app1/models.py に Item モデルを定義する。
Item は (code, name, price) のフィールドを持ち、code にユニークキー制約を設定する。

app1/models.py
from django.db import models

class Item(models.Model):
    code = models.CharField(max_length=64)
    name = models.CharField(max_length=64)
    price = models.IntegerField()

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=["code"],
                name='unique_key_code',
            ),
        ]

データ登録

プログラム例

test/setup1.py で ('001', 'aaa', 100) を登録する。

test/setup1.py
import os
import sys
import django

sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../')
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'db_test3.settings')
django.setup()

from app1.models import Item

def setup():
    item1 = Item.objects.create(
        code='001',
        name='aaa',
        price=100,
    )

def main():
    setup()
    return 0

if __name__ == '__main__':
    exit(main())

実行

$ python test/test1.py

DB の登録内容は以下の通り。

db_test3=# select * from app1_item;
 id | code | name | price
----+------+------+-------
  1 | 001  | aaa  |   100

データ複製(1)

code の一致によってユニークキー制約のエラーとなる例。

プログラム例

複製元のオブジェクトの id を None にして save() を実行する。

test/test1.py
import os
import sys
import django

sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../')
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'db_test3.settings')
django.setup()

from app1.models import Item

def duplicate1():
    try:
        item1 = Item.objects.get(code='001')

        item2 = item1
        item2.id = None
        item2.save()

    except Exception as e:
        print(e)
        return

    print("success")

def main():
    duplicate1()
    return 0

if __name__ == '__main__':
    exit(main())

実行例

ユニークキー制約のエラーメッセージが出力される。

$ python test/test1.py
duplicate key value violates unique constraint "unique_key_code"
DETAIL:  Key (code)=(001) already exists.

db には複製されたレコードが登録されていない。

db_test3=# select * from app1_item;
 id | code | name | price
----+------+------+-------
  1 | 001  | aaa  |   100

データ複製(2)

code を変更することで、ユニークキー制約のエラーとならない例。

プログラム例

複製元のオブジェクトの id を None にし、code を変更して save() を実行する。

import os
import sys
import django

sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../')
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'db_test3.settings')
django.setup()

from app1.models import Item

def duplicate2():
    try:
        item1 = Item.objects.get(code='001')

        item2 = item1
        item2.id = None
        item2.code = '002'
        item2.save()

    except Exception as e:
        print(e)
        return

    print("success")

def main():
    duplicate2()
    return 0

if __name__ == '__main__':
    exit(main())

実行例

$ python test/test2.py
success

DB には複製されたレコードが登録されていることが確認できる。

db_test3=# select * from app1_item;
 id | code | name | price
----+------+------+-------
  1 | 001  | aaa  |   100
  3 | 002  | aaa  |   100
0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?