简体   繁体   English

如果相关外键不存在,如何禁止创建对象?

[英]How to disallow creation of object if related foreign key doesn't exists?

Here is the setup 这是设置

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

DB is PostgreSQL. DB是PostgreSQL。 There are no A objects yet (at least with id=1 ). 尚无A对象(至少id=1 )。

I try to create object B using the id of some hypothetical object A fetched from the 3rd party. 我尝试使用从第三方获取的某些假设对象A的ID创建对象B

Expectation 期望

If there is no object A -> IntegrityError is thrown -> deal with it (eg create object A with id=1 and rerun). 如果没有对象A >引发IntegrityError->处理它(例如,创建id=1对象A并重新运行)。

Reality 现实

Object B is created anyway despite having a foreign key constraint, IntegrityError ( Key (a_id)=(1) is not present in table "app_a" ) is thrown but is not fetched by try/except. 尽管具有外键约束,还是创建了对象B ,但抛出了IntegrityError( Key (a_id)=(1) is not present in table "app_a" ),但是try / except并未获取它。 Everything is messed up. 一切都搞砸了。


I don't what to get_or_create object A beforehand because I will end up with 2 queries every time I want to create B (and I need to create it many times while most of the time needed object A is already in DB) 我没有什么get_or_create对象A因为每次我要创建B时都会以2个查询结束(而且我需要多次创建它,而大多数时候所需的对象A已经在数据库中)


EDIT 1 编辑1

As it turns out, the problem is with pytest. 事实证明,问题出在pytest上。 Only inside test I can't catch IntegrityError . 仅在测试中,我无法捕获IntegrityError

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

Code above didn't raise IntegrityError despite the absence of A object with id=1 . 尽管缺少id=1A对象,但是上面的代码并未引发IntegrityError Nonetheless IntegrityError 's traceback is printed out in the console. 尽管如此, IntegrityError的回溯还是在控制台中打印出来。 And object b is created. 并创建对象b

The problem was with trying to catch IntegrityError inside an atomic transaction. 问题在于试图在原子事务中捕获IntegrityError

Guys from pytest helped to fix it @pytest.mark.django_db(transaction=True) instead of just @pytest.mark.django_db . pytest家伙帮助修复了@pytest.mark.django_db(transaction=True)而不仅仅是@pytest.mark.django_db

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM