やりたいこと
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