在Django中,确定数据库中是否存在引用给定对象的对象的最简单方法是什么?
考虑Django Related objects reference中的这个最小示例:
from django.db import models
class Reporter(models.Model):
pass
class Article(models.Model):
reporter = models.ForeignKey(Reporter, on_delete=models.CASCADE)
我们如何确定是否有任何个对象,所以不仅 Article
个对象,而且指向一个给定的Reporter
对象,或者通过OneToOneField
,ForeignKey
或ManyToManyField
?
换句话说,我们要确定给定对象是否有任何reverse relations。
对于Article
很简单,我们可以得到例如reporter.article_set.count()
,但以后可能会添加其他模型,这些模型也指向Reporter
,并且这些模型也必须考虑在内。
一个示例用例是,我们要在其他对象任何引用该对象后立即阻止修改。或者我们可以使用它来强制执行类似于on_delete=models.PROTECT
机制的行为。
答案 0 :(得分:0)
这是使用Model._meta
API的有效解决方案,但是我不确定这是否是最佳方法。希望有更好的答案。
基本上,给定一个对象,我们将获得其反向关系的列表,然后针对每个关系,检查关系中是否存在任何对象。
# just any given reporter object
obj = Reporter.objects.first()
# assume no references to obj
obj_has_reverse = False
# skip for new objects (i.e. those not yet saved to database)
if obj.id is not None:
# reverse relation "fields" on the Reporter model are auto-created and
# not concrete
for reverse in [f for f in obj._meta.get_fields()
if f.auto_created and not f.concrete]:
# in case the related name has been customized
name = reverse.get_accessor_name()
# one-to-one requires a special approach
has_reverse_one_to_one = reverse.one_to_one and hasattr(obj, name)
has_reverse_other = not reverse.one_to_one and getattr(obj, name).count()
if has_reverse_one_to_one or has_reverse_other:
obj_has_reverse = True
请注意,ForeignKey
和ManyToManyField
的反向关系返回RelatedManager,因此我们可以检查例如count()
。但是,OneToOneField
的反向关系不会返回RelatedManager
。如docs中所述,如果没有相关对象,它将引发DoesNotExist
异常。
另请参见reverse_related
的{{3}}。