代码之家  ›  专栏  ›  技术社区  ›  djvg Carl Meyer

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

  •  0
  • djvg Carl Meyer  · 技术社区  · 6 年前

    总结

    在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 A ForeignKey ,或者 ManyToManyField ?

    换句话说,我们想确定是否有 reverse relations 到给定的对象。

    为了 文章 这很容易,我们可以得到。 reporter.article_set.count() ,但以后可能会添加其他模型,这些模型也指向 记者 ,这些也必须考虑在内。

    示例用例

    一个示例用例是我们希望在对象被 任何 其他物体。或者我们可以用它来强制一种类似于 on_delete=models.PROTECT 机制。

    1 回复  |  直到 6 年前
        1
  •  0
  •   djvg Carl Meyer    6 年前

    这是一个有效的解决方案,使用 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 返回A RelatedManager 所以我们可以检查 count() . 然而,与 OneToOneField 不返回 RelatedManager . 它提出了一个 DoesNotExist 如果没有相关对象,则出现异常,如 docs . 也看到 source 对于 reverse_related .