起初我认为尽可能具体是最好的方法:
from django.db import IntegrityError
from psycopg2.errorcodes import UNIQUE_VIOLATION
try:
m = Model.objects.create(value=m2.old_value)
except IntegrityError as e:
if e.__cause__.pgcode != UNIQUE_VIOLATION:
raise
m = Model.objects.get(value=m2.old_value)
然而,后来我遇到了这样的答案:
SQLAlchemy是一个抽象库,如果它引发特定于底层dpapi适配器的异常,它将显著降低在其中编写的代码的可移植性。。。。然而,除非您的错误处理非常特定于dbapi层引发的类型,否则我建议检查底层类型可能是不必要的,因为引发的SQLAlchemy异常将提供足够的运行时信息来执行您必须执行的操作。
django.db.IntegrityError
应该在以下情况下引发:
INTEGRITY_CONSTRAINT_VIOLATION = '23000'
RESTRICT_VIOLATION = '23001'
NOT_NULL_VIOLATION = '23502'
FOREIGN_KEY_VIOLATION = '23503'
UNIQUE_VIOLATION = '23505'
CHECK_VIOLATION = '23514'
EXCLUSION_VIOLATION = '23P01'
我不确定这些特定错误是在什么情况下发生的,但一般规则是;不要忽视例外情况"如果我选择:
try:
m = Model.objects.create(value=m2.old_value)
except IntegrityError as e:
m = Model.objects.get(value=m2.old_value)
听起来我可能会忽略一个我本不想忽略的例外。你有什么建议?
我认为做你正在做的事情没有任何问题。当然,没有理由不添加代码来更清楚地了解在各种条件下会抛出哪些类型的错误以及哪些错误是可以捕获的。如果你不确定这个代码是否正确,那么最好过于具体,而不是不够具体。在您运行并测试代码一段时间后,您将了解更多关于";正确性";你在这里做什么。也许你稍后会决定做出改变。也许你会决定,你可以用类似的方式处理更大的异常组。
不过有一个重要的想法。。。你不会忽视这里的任何错误。忽略错误(这意味着当一个错误发生时和没有发生时不做任何不同的事情(和捕捉错误然后因为错误发生而做一些不同的事情是有区别的。这根本不是忽略错误,这就是你在这里所做的。所以这里的问题是";在create
抛出IntegrityError
异常的所有情况下执行get
是否正确&";。如果答案是"否";否";,那么这就是您必须测试特定错误条件的地方,并决定正确的做法是执行get
还是因为确实出了问题而让错误传播。这正是你正在做的。如果您提供的代码做得正确,那么它可能正是您想要的。
底线。。。做任何你必须做的事情,让代码在所有情况下都能正确运行。如果这样做意味着以你现在的方式挖掘异常,那就顺其自然吧
我很好奇。。。你对根本不允许抛出异常有什么想法?也就是说,在尝试create
之前,检查记录的预存在性如何?你不能这样做有什么原因吗?另外,将这两种操作颠倒过来怎么样?先做get
,如果失败了再做create
,这有意义吗?我介绍这些其他选项只是为了探索这里的所有选项,既有利于您,也有利于问题本身。