Django 原子事务处理唯一约束

我有模型


class Order(models.Model):

  order_id = models.CharField(max_length=30, default='', unique = True)

  amount = models.FloatField()

我有这个循环将对象从 json 保存到我的数据库并验证唯一字段order_id


for 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 但没有得到任何真正的性能提升,所以不能使用它


梵蒂冈之花
浏览 210回答 2
2回答

慕村9548890

引用Django 文档:捕获数据库错误的正确方法是围绕一个原子块这是您的代码的改编:from django.db import IntegrityError, transactionfor 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)

浮云间

首先,transaction.atomic装饰器将数据库提交推迟到装饰函数的末尾。因此,您的异常处理现在将不起作用,因为异常会在您的 try-except 块之外抛出。文档还建议您不要在原子块内捕获异常。或许这也会给你带来一个麻烦TransactionManagementError。如果在原子块内发生异常,则不允许执行任何数据库查询。您应该将 try-except 移到您的函数之外并检查是否可以解决您的问题。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python