3

在 Django 中,我有一个 Checkout 模型,它是某人检查设备的票。我还有一个与 Checkout 模型相关的 OrganizationalUnit 模型(通过 ForeignKey),因为结账的人属于我们校园的一个 OrganizationalUnit。

OrganizationalUnit 有一个自我关系,所以几个 OU 可以是某个 OU 的孩子,而这些孩子可以有孩子,以此类推。这是模型,有些简化。

class OrganizationalUnit(models.Model):
    name = models.CharField(max_length=100)
    parent = models.ForeignKey(
        'self',
        blank=True, null=True,
        related_name='children',
)

class Checkout(models.Model):
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)
    department = models.ForeignKey(
        OrganizationalUnit,
        null=True,
        blank=True,
        related_name='checkouts',
)

我想计算与某个 OrganizationalUnit 及其所有子级相关的 Checkouts。我知道如何获取与 OU 相关的所有结帐的计数。

ou = OrganizationalUnit.objects.get(pk=1)
count = ou.checkouts.all().count()

但是我如何让这个计数反映这个 OU 的孩子和他们的孩子的结帐?我是否使用某种迭代循环?


编辑:我想我仍然无法完全理解 while 命令来执行此操作。组织单元可以嵌套到用户想要嵌套的深度,但现在它在 DB 中的深度最多为 5 层。这是我写的……</p>

for kid in ou.children.all():
    child_checkout_count += kid.checkouts.all().count()
    for kid2 in kid.children.all():
        child_checkout_count += kid2.checkouts.all().count()
        for kid3 in kid2.children.all():
            child_checkout_count += kid3.checkouts.all().count()
            for kid4 in kid3.children.all():
                child_checkout_count += kid4.checkouts.all().count()
                for kid5 in kid4.children.all():
                    child_checkout_count += kid5.checkouts.all().count()

......这完全是废话。而且它需要一段时间才能运行,因为它几乎遍历了数据库的主要部分。帮助!(我今天似乎不能很好地思考。)

4

3 回答 3

3

您需要的是一个递归函数,它遍历 OrganizationalUnit 关系树并获取每个 OrganizationalUnit 的相关 Checkout 数量。因此,您的代码将如下所示:

def count_checkouts(ou):
   checkout_count = ou.checkouts.count()
   for kid in ou.children.all():
       checkout_count += count_checkouts(kid)
   return checkout_count

另请注意,为了获得一些相关的结帐,我使用:

checkout_count = ou.checkouts.count()

安装:

count = ou.checkouts.all().count()

我的变体更有效(参见http://docs.djangoproject.com/en/1.1/ref/models/querysets/#count)。

于 2010-01-29T18:03:16.700 回答
3

我认为计算这一点的最有效方法是在写入时。您应该像这样修改 OrganizationalUnit:

class OrganizationalUnit(models.Model):
    name = models.CharField(max_length=100)
    parent = models.ForeignKey(
        'self',
        blank=True, null=True,
        related_name='children',
    )
    checkout_number = models.IntegerField(default=0)

创建将在写入时更新 OrganizationalUnit 及其父级的函数:

def pre_save_checkout(sender, instance, **kwargs):
    if isinstance(instance,Checkout) and instance.id and instance.department:
         substract_checkout(instance.department)

def post_save_checkout(sender, instance, **kwargs):
    if isinstance(instance,Checkout) and instance.department:
         add_checkout(instance.department)

def  substract_checkout(organizational_unit):
    organizational_unit.checkout_number-=1
    organizational_unit.save()
    if organizational_unit.parent:
        substract_checkout(organizational_unit.parent)

def  add_checkout(organizational_unit):
    organizational_unit.checkout_number+=1
    organizational_unit.save()
    if organizational_unit.parent:
        add_checkout(organizational_unit.parent)

现在您只需将这些函数连接到 pre_save、post_save 和 pre_delete 信号:

from django.db.models.signals import post_save, pre_save, pre_delete

pre_save.connect(pre_save_checkout, Checkout)
pre_delete.connect(pre_save_checkout, Checkout)
post_save.connect(post_save_checkout, Checkout)

应该这样做...

于 2010-02-06T07:54:57.743 回答
0

我不确定 SQL 如何在此执行,但您想要做的正是您所解释的。

使用 While 循环获取所有 OU 及其父级,然后计算 Checkouts 并将它们相加。

ORM 为您带来对 SQL 的动态操作,但会扼杀性能:)

于 2010-01-28T03:09:46.027 回答