【问题标题】:how do catch A 'UNIQUE constraint failed' 404 in django如何在 django 中捕获“唯一约束失败”404
【发布时间】:2015-01-01 08:59:08
【问题描述】:

如何在以下代码中专门捕获 UNIQUE 约束失败 404,我知道我必须在 (here?) 部分添加一些内容

try:
    q = AnswerModel(user=user, yes_question=question_model)
    q.save()
except ( here? ):
    return HttpResponseRedirect('/user/already_exists')

【问题讨论】:

  • 您是否尝试过捕捉它以便知道它实际上是什么?
  • errrrr 当然,现在我想捕捉唯一约束错误,这样我就可以告诉用户已经回答了
  • 好的,既然你知道它是什么,就把它放在except 子句中。
  • 如果你不能帮我解决那个 except 子句是什么,那你为什么还要麻烦呢?
  • 我试过帮你。你声称你已经按照我说的做了。

标签: python django


【解决方案1】:
from django.db import IntegrityError

except IntegrityError:

这就是你需要的。

已编辑为@mbrochh:

from django.db import IntegrityError

except IntegrityError as e: 
    if 'unique constraint' in e.message: # or e.args[0] from Django 1.10
        #do something

是的,您可以更精确,但在有问题的情况下UNIQUE failed 很有可能。

【讨论】:

  • 这还不够,因为它捕获的不仅仅是 UNIQUE 约束。
  • 这仍然是一个糟糕的解决方案,因为我们不知道这些消息是否会改变。检查错误代码将是更好的方法。
  • 这就是错误代码的全部意义所在!它们记录在 Postgres 官方文档中,并且永远不会改变。将某些内容与消息字符串进行比较是非常糟糕的做法。
  • 从 Django 1.10 开始,您需要使用:if 'unique constraint' in e.args[0]
  • 如果 e.args[0] 中的“唯一约束失败”
【解决方案2】:

恕我直言,我建议通过 get_or_create() 解决这种情况。

new_obj, created = AnswerModel.objects.get_or_create(user=user, yes_question=question_model)
if created:
    do_something_for_new_object(new_obj)
else:
    logging.error("Duplicated item.")
    return

【讨论】:

  • 这是一个很好的答案
  • 这对我有用,直到我尝试使用新数据库,现在我仍然再次收到错误:django.db.utils.IntegrityError: UNIQUE constraint failed
  • 这在两个并发请求同时命中此代码的情况下不起作用。
  • @nickswiss 它会工作的。根据documentation,如果参数具有唯一性约束,get_or_create 是原子的。
【解决方案3】:

对于 Python > 3.5

你需要:

except IntegrityError as e: 
                if 'unique constraint' in e.args:

例子:

from django.db import IntegrityError

 for column in csv.reader(io_string, delimiter=',', quotechar="|"):
     try:
         _, created = Brand.objects.update_or_create(
            system_id=column[0],
            name=column[1],
            slug=column[2],
            description=column[3],
            image=column[4]
           )
     except IntegrityError as e: 
           if 'unique constraint' in e.args:
               continue 

【讨论】:

  • e.args 在我的情况下是一个列表,所以需要: if 'unique constraint' in str(e.args) instead
【解决方案4】:

发现于django.db.models.query.QuerySet._create_object_from_params。还有一些变化:

from typing import Any, Dict, Type  
from django.db import transaction, IntegrityError, Model


def get_or_create_obj(model: Type[Model], defaults: Dict[str, Any] = None, **kwargs: Any):
    defaults = defaults or {}
    try:
        with transaction.atomic():
            return model.objects.create(**kwargs, **defaults), True
    except IntegrityError as e:
        try:
            return model.objects.using("default").get(**kwargs), False
        except model.DoesNotExist:
            pass
        raise e

【讨论】:

    【解决方案5】:

    通常“请求原谅”原则在编程中是一种很好的做法,但在这种特殊情况下,我不会推荐它。

    您正在寻找的例外是IntegrityError。您可以通过简单地删除 try-catch 块并强制该异常来轻松地自己弄清楚这一点。回溯显示异常类。

    问题是,有几种不同类型的完整性错误,因此在您的 try-catch 块中,您必须检查类似 if ex.pgcode == 23505 的内容,以查看这是否实际上是一个 UNIQUE 约束错误。之前已经回答过这里:IntegrityError: distinguish between unique constraint and not null violations

    更糟的是:每个 ORM 都有不同的错误代码,字段名称不会是 pgcode 而是其他东西,并且一些 ORM 根本不会抛出 UNIQUE 约束。因此,如果您正在构建一个可重用的应用程序,或者您正在使用糟糕的 ORM(例如 MySQL),或者您不确定将来是否会更改项目的数据库,那么您不应该这样做!

    更好的方法是简单地删除 try-catch 块并在保存之前检查对象是否已经在数据库中。

    我不知道在你的情况下哪个字段是唯一的,所以我假设它是 user 字段。您的代码将如下所示:

    answers = AnswerModel.objects.filter(user=user)
    if answers:
       return HttpResponseRedirect('/user/already_exists')
    obj = AnswerModel.objects.create(user=user, yes_question=question_model)
    ...
    

    如果您正在处理组合唯一约束,则第一行将是:

    answers = AnswerModel.objects.filter(user=user, yes_question=question_model)
    

    【讨论】:

      【解决方案6】:

      唯一约束失败返回:“('UNIQUE约束失败:notepad_notepadform.title')”基本上是一个元组,所以我们可以使用下面的代码来捕捉它并做任何需要的事情:

      from django.db import IntegrityError
      try:
              if form.is_valid():
                  form.save()
      
          except IntegrityError as e:
              if 'UNIQUE constraint' in str(e.args):
                  #your code here
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-03-18
        • 1970-01-01
        • 2013-07-04
        • 2021-07-15
        • 1970-01-01
        • 2019-04-28
        • 2020-10-22
        • 1970-01-01
        相关资源
        最近更新 更多