亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Django 原子事務處理唯一約束

Django 原子事務處理唯一約束

梵蒂岡之花 2023-06-06 15:03:55
我有模型class Order(models.Model):  order_id = models.CharField(max_length=30, default='', unique = True)  amount = models.FloatField()我有這個循環將對象從 json 保存到我的數據庫并驗證唯一字段order_idfor json_obj in json_data:   order = Order(symbol=json_obj['order_id'], amount= json_obj['amnount'])   try:     order.save()   except IntegrityError as exception:     if 'UNIQUE constraint failed' in exception.args[0]:        print('duplicate order id => skip this')        continue一切正常,但是當我將 @transaction.atomic 裝飾器添加到我的函數時,一切都會中斷。我得到一個錯誤: "An error occurred in the current transaction. You can't "    django.db.transaction.TransactionManagementError: An error occurred in the current transaction. You can't execute queries until the end of the 'atomic' block.處理這種情況的推薦方法是什么?UPD:我使用事務原子裝飾器來加速我的代碼,因為我有大量的訂單要保存,而且這是一個在后臺運行的相當昂貴的操作。UPD2:我嘗試使用get_or_create method 但沒有得到任何真正的性能提升,所以不能使用它
查看完整描述

2 回答

?
慕村9548890

TA貢獻1884條經驗 獲得超4個贊

引用Django 文檔:

捕獲數據庫錯誤的正確方法是圍繞一個原子塊

這是您的代碼的改編:

from django.db import IntegrityError, transaction


for json_obj in json_data:

? ? order = Order(symbol=json_obj['order_id'], amount=json_obj['amnount'])

? ? try:

? ? ? ? with transaction.atomic():

? ? ? ? ? ? order.save()

? ? except IntegrityError as exception:

? ? ? ? if 'UNIQUE constraint failed' in exception.args[0]:

? ? ? ? ? ? print('duplicate order id => skip this')

? ? ? ? ? ? continue

您還可以使用get_or_create來實現您想要的:


for json_obj in json_data:

? ? obj, created = Order.objects.get_or_create(

? ? ? ? symbol=json_obj['order_id'],

? ? ? ? defaults={'amount': json_obj['amnount'])},

? ? )

? ? if not created:

? ? ? ? print('order id already existing => skip this')

如果你想要一個快速的代碼(根據你的評論),你可以使用bulk_create。


orders_to_create = []


for json_obj in json_data:

? ? orders_to_create.append(Order(symbol=json_obj['order_id'], amount=json_obj['amnount']))


Order.objects.bulk_create(orders_to_create, ignore_conflicts=True)

請注意


在支持它的數據庫上(除 Oracle 之外的所有數據庫),將 ignore_conflicts 參數設置為 True 告訴數據庫忽略無法插入任何未通過約束(例如重復唯一值)的行


在不使用ignore_conflicts設置的情況下,您可以執行以下操作:


orders_to_create = []


order_ids = [json_obj['order_id'] for json_obj in json_data]


existing_order_ids = Order.objects.filter(symbol__in=order_ids).values_list('symbol', flat=True)


for json_obj in json_data:

? ? # this condition prevents any IntegrityError du to an existing order_id

? ? if json_obj['order_id'] not in existing_order_ids:

? ? ? ? orders_to_create.append(Order(symbol=json_obj['order_id'], amount=json_obj['amnount']))


Order.objects.bulk_create(orders_to_create)


查看完整回答
反對 回復 2023-06-06
?
浮云間

TA貢獻1829條經驗 獲得超4個贊

首先,transaction.atomic裝飾器將數據庫提交推遲到裝飾函數的末尾。因此,您的異常處理現在將不起作用,因為異常會在您的 try-except 塊之外拋出。文檔還建議您不要在原子塊內捕獲異常。

或許這也會給你帶來一個麻煩TransactionManagementError。如果在原子塊內發生異常,則不允許執行任何數據庫查詢。

您應該將 try-except 移到您的函數之外并檢查是否可以解決您的問題。


查看完整回答
反對 回復 2023-06-06
  • 2 回答
  • 0 關注
  • 256 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號