war*_*iuc 10 python django postgresql psycopg2
我有这个代码:
try:
principal = cls.objects.create(
user_id=user.id,
email=user.email,
path='something'
)
except IntegrityError:
principal = cls.objects.get(
user_id=user.id,
email=user.email
)
Run Code Online (Sandbox Code Playgroud)
它尝试使用给定的id和电子邮件创建用户,如果已存在,则尝试获取现有记录.
我知道这是一个糟糕的结构,无论如何它都会被重构.但我的问题是:
我如何确定IntegrityError发生了什么类型:与unique约束违规相关的一个((user_id,email)上有唯一键)或者与not null约束相关的那个(path不能为空)?
psycopg2提供了SQLSTATE作为pgcode成员的异常,它为您提供了相当细粒度的错误信息.
python3
>>> import psycopg2
>>> conn = psycopg2.connect("dbname=regress")
>>> curs = conn.cursor()
>>> try:
... curs.execute("INVALID;")
... except Exception as ex:
... xx = ex
>>> xx.pgcode
'42601'
Run Code Online (Sandbox Code Playgroud)
有关代码含义,请参阅PostgreSQL手册中的附录A:错误代码.请注意,对于大类,您可以粗略匹配前两个字符.在这种情况下,我可以看到SQLSTATE 42601属于syntax_error该Syntax Error or Access Rule Violation类别.
你想要的代码是:
23505 unique_violation
23502 not_null_violation
Run Code Online (Sandbox Code Playgroud)
所以你可以写:
try:
principal = cls.objects.create(
user_id=user.id,
email=user.email,
path='something'
)
except IntegrityError as ex:
if ex.pgcode == '23505':
principal = cls.objects.get(
user_id=user.id,
email=user.email
)
else:
raise
Run Code Online (Sandbox Code Playgroud)
也就是说,这是一个糟糕的方式做一个upsert或merge.@ pr0gg3d可能正确地建议用Django做正确的方法; 我不做Django所以我不能评论那一点.有关upsert/merge的一般信息,请参阅depesz关于该主题的文章.
小智 8
2017 年 9 月 6 日更新:
一个非常优雅的方法是使用try/ except IntegrityError as exc,然后在exc.__cause__and上使用一些有用的属性exc.__cause__.diag(一个诊断类,它为您提供有关手头错误的一些其他超级相关信息 - 您可以使用 自己探索它dir(exc.__cause__.diag))。
上面描述了您可以使用的第一个。为了使您的代码更具前瞻性,您可以直接引用 psycopg2 代码,您甚至可以使用我上面提到的诊断类检查违反的约束:
except IntegrityError as exc:
from psycopg2 import errorcodes as pg_errorcodes
assert exc.__cause__.pgcode == pg_errorcodes.UNIQUE_VIOLATION
assert exc.__cause__.diag.constraint_name == 'tablename_colA_colB_unique_constraint'
Run Code Online (Sandbox Code Playgroud)
编辑澄清:我必须使用__cause__访问器,因为我使用的是 Django,所以要访问我必须调用的 psycopg2 IntegrityError 类exc.__cause__
| 归档时间: |
|
| 查看次数: |
10099 次 |
| 最近记录: |