【问题标题】:How to refer to all child objects with existing queries in self-referencing foreign key?如何在自引用外键中引用所有具有现有查询的子对象?
【发布时间】:2021-11-13 22:47:13
【问题描述】:

我有一个代表所有者的模型。这个模型上有一个外键来表示一个父实体。还有另一种称为资产的模型,具有所有者的外键。父外键的目的是模拟公司结构,这样母公司“拥有”其外键是其自身或子公司的资产:

Class Owner(models.Model):
    parent = models.ForeignKey(
                 “self”,
             )

Class Asset(models.Model):
    owner = models.ForeignKey(
                 Owner,
             )

有没有办法通过简单地引用父级来返回父级及其所有子公司拥有的所有资产(例如 Asset.object.filter(owner=parent))?我知道我可以创建一个方法来返回父级所有子公司的查询集,然后过滤到该所有者查询集中的所有资产,但我希望避免大型重构,因为现有代码库没有概念父所有者。

我的第一个想法是自定义管理器,但我认为这不会改变现有查询的行为,这些查询都脱离了默认管理器。我可以在这个模型上重载过滤器吗?如果我需要重新考虑设计,那很好,但我认为这种方法更干净,可以捕捉我们想要的行为。谢谢!

【问题讨论】:

  • Owner.parent 关系可能嵌套得非常深,无论嵌套多深,您是否想要所有者是父级嵌套子级中的任何一个的所有资产?
  • 没错。在实践中,我认为不会超过 6-7 层。
  • 您使用的是哪个数据库?
  • PostgreSQL 与 postgis 扩展

标签: django django-models


【解决方案1】:

可能不是一个令人满意或完整的答案,但我有一个原始的 postgres 查询,它在单个查询中返回父级的所有子级。它使用recursive query

class Owner(models.Model):
    parent = models.ForeignKey('self', on_delete=models.SET_NULL, null=True, blank=True)

    def get_all_children(self):
        return Owner.objects.raw(f"""
            with recursive t(id, parent_id) as
            (
                select id, parent_id
                from app_owner where id={self.id}
                union all
                select b.id, b.parent_id
                from app_owner b
                join t on b.parent_id=t.id
            )
            select * from t
        """)

这也可以用来过滤资产

Asset.objects.filter(owner__in=Owner.objects.get(id=1).get_all_children())

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-17
    • 1970-01-01
    • 2010-10-22
    • 2012-08-07
    相关资源
    最近更新 更多