Django:如何确定某个对象是否被其他任何对象引用?

时间:2019-02-15 14:43:17

标签: python django foreign-keys

摘要

在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对象,或者通过OneToOneFieldForeignKeyManyToManyField

换句话说,我们要确定给定对象是否有任何reverse relations

对于Article很简单,我们可以得到例如reporter.article_set.count(),但以后可能会添加其他模型,这些模型也指向Reporter,并且这些模型也必须考虑在内。

用例示例

一个示例用例是,我们要在其他对象任何引用该对象后立即阻止修改。或者我们可以使用它来强制执行类似于on_delete=models.PROTECT机制的行为。

1 个答案:

答案 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

请注意,ForeignKeyManyToManyField的反向关系返回RelatedManager,因此我们可以检查例如count()。但是,OneToOneField的反向关系不会返回RelatedManager。如docs中所述,如果没有相关对象,它将引发DoesNotExist异常。 另请参见reverse_related的{​​{3}}。