【问题标题】:How to disallow creation of object if related foreign key doesn't exists?如果相关外键不存在,如何禁止创建对象?
【发布时间】:2019-07-31 13:32:52
【问题描述】:

这里是设置

class A(Model):
    pass

class B(Model):
    a = ForeignKey(A, on_delete=CASCADE)


assert A.objects.all().count() == 0
try:
    B.object.create(a_id=1)
except IntegrityError:
    print('error')
    # ... another logic to deal with situation

数据库是 PostgreSQL。目前还没有A 对象(至少有id=1)。

我尝试使用从第 3 方获取的某个假设对象 A 的 ID 创建对象 B

期待

如果没有对象A -> IntegrityError 被抛出 -> 处理它(例如用id=1 创建对象A 并重新运行)。

现实

尽管有外键约束,对象B 仍被创建,但抛出了 IntegrityError (Key (a_id)=(1) is not present in table "app_a"),但 try/except 不会获取。一切都搞砸了。


我没有事先对get_or_create 对象A 做什么,因为每次我想创建B 时都会得到2 个查询(而且我需要多次创建它,而大部分时间都需要对象A 已经在数据库中)


编辑 1

事实证明,问题出在 pytest 上。只有内部测试我无法捕捉到IntegrityError

with pytest.raises(IntegrityError):
  b = B.objects.create(a_id=1)

尽管没有A 对象和id=1,但上面的代码没有引发IntegrityError。尽管如此,IntegrityError 的回溯会在控制台中打印出来。并创建了对象b

【问题讨论】:

  • 创建了B 对象,但没有创建B 记录。当你打算插入它时,它会出错。
  • 我刚刚检查过,新创建的对象B 上已经存在 id,所以它被插入了。我也可以使用B.objects.get()从数据库中获取它。
  • 你没有some_b.save(),或者使用B.objects.create(..),所以你没有在数据库端用上述逻辑做任何事情。
  • 哦,有问题
  • 你没有禁用外键约束,对吧?

标签: python django postgresql pytest django-orm


【解决方案1】:

问题在于试图在原子事务中捕获 IntegrityError

来自pytesthelped 的人来修复它@pytest.mark.django_db(transaction=True) 而不仅仅是@pytest.mark.django_db

【讨论】:

    猜你喜欢
    • 2022-09-25
    • 2022-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-02
    • 1970-01-01
    相关资源
    最近更新 更多