首页 > 解决方案 > Django:获取给定实例的所有子相关实例

问题描述

我想获取所有引用给定实例的类的所有子相关实例。我试过使用related_name,但它没有达到目的,因为它只获取一个特定类的所有实例,而不是所有相关类的所有实例。我怎么能做到这一点?

模型

class AlertTypeMaster():
    alert_type_name = models.CharField(max_length=255)
    description = models.CharField(max_length=255)
    active = models.BooleanField(default=True)

class MachineAlertZone():
    machine_id = models.ForeignKey(MachineMaster, on_delete=models.CASCADE)
    alert_type_id = models.ForeignKey(AlertTypeMaster, on_delete=models.CASCADE)
    radius_value = models.CharField(max_length=50)
    active = models.BooleanField(default=True)

class ActivityRecording():
    alert_type_id = models.ForeignKey(AlertTypeMaster, on_delete=models.CASCADE)
    working_area_id = models.ForeignKey(WorkingAreaMaster, on_delete=models.CASCADE)
    staff_id = models.ForeignKey(StaffMaster, on_delete=models.CASCADE)
    type_of_occur = models.CharField(max_length=255)
    active = models.BooleanField(default=True)

给定 的一个对象AlertTypeMaster,我应该能够从MachineAlertZone和中获取所有对象ActivityRecording

请提出任何合适的方法!

标签: pythondjango

解决方案


您不能在同一个查询集中混合来自不同模型的实例(当您记住模型和查询集只是关系数据库上的薄层时,原因似乎很明显)。

现在没有什么能阻止您提供自己的可迭代对象。在最简单的情况下,您只需在生成器中将两个查询集链接在一起,即:

import itertools

def iter_subs(self):
    yield from itertools.chain(self.machinealertzone_set.all(), self.activityrecording_set.all())

或更精细的东西(根据您的需要对“子”对象进行排序等)。

话虽这么说,我真的不明白这一点......鉴于您的模型定义(很少有公共字段并且没有公共操作),这将是一个非常异构的集合,您可能必须在迭代期间对每个项目进行类型检查才能知道什么与它有关,这破坏了一次检索它们的全部意义。

编辑

我需要一次全部检索它们,因为当一个 AlertTypeMaster 对象活动字段设置为 True 时,所有子对象活动字段也需要设置为 True。如果我的方法效率不高,您能提出更好的方法吗?

这是非规范化。你真的需要吗?如果 MachineAlertZone 和 ActivityRecordingstatus应该反映它们的 AlertTypeMaster,那么正确的设计(理论上,根据关系模型范式)是直接从 AlertTypeMaster 获取状态:

class StatusQueryset(models.Queryset):
    # allow to filter MachineAlertZone and ActivityRecording
    # by their parent AlertType active status
    def active(self):
        return self.filter(alert_type__active=True)

class MachineAlertZone():
    machine = models.ForeignKey(MachineMaster, on_delete=models.CASCADE)
on_delete=models.CASCADE)
    alert_type = models.ForeignKey(AlertTypeMaster, on_delete=models.CASCADE)
    radius_value = models.CharField(max_length=50)

    #active = models.BooleanField(default=True)
    @property
    def active(self):
        return self.alert_type.status

    objects = StatusQueryset.as_manager()

但是,如果您仍然想为您的“子模型”保留一个单独的标志,您仍然不需要“一次全部检索它们”来更新它们的状态 - 只需在您的AlertTypeMaster.save()方法中的事务中发出两个更新查询:

from django.db import transaction

class AlertTypeMaster(models.Model):
    def save(self, *args, **kw):
        with transaction.atomic():
            super(AlertTypeMaster, self).save(*args, **kw)
            self.machinealertzone_set.update(active=self.active)
            self.activityrecording_set.update(active=self.active)

推荐阅读