2010-01-27 80 views
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及其所有子项相关的Checkout的计数。我知道如何获得与OU相关的所有结帐的计数。

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

但是,我该如何计算这个OU的子女及其子女的结账?我是否使用某种迭代循环?


编辑:我想我还是不太满脑子都在同时命令来做到这一点。组织单位可以像用户想要嵌套它们那样深入,但现在它在数据库中的最大数量是5个。我写了这...

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() 

......这是完全废话。而且它需要一段时间才能运行,因为它几乎遍历了数据库的一大块。帮帮我! (我今天似乎觉得不太好)。

回答

3

我认为最有效的计算方法是写入时间。您应修改组织单位是这样的:

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) 

应该这样做......

0

我不确定SQL是如何执行的,但是你想要做的就是你所解释的。

获得所有的OU,它的父母与While循环,然后计数签出和他们。

ORM为您带来了SQL动态操作,但杀性能:)

+0

这使得感。我只是不确定Django的ORM是否具有内置的这种能力。我没有看到文档中的任何内容;想确保我没有失去任何东西。 这是我与Django的ORM遇到的唯一限制。我发现使用它真的很愉快,在我使用它的背景下,我并不关心最前沿的性能 - 它非常适合我们,而且效率很高。 – 2010-01-28 05:00:16

3

你需要的是穿越组织单位关系树,并得到相关的检出的数量为每个组织单位递归函数。所以,你的代码看起来就像这样:

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() 

insted的的:

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

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