3

Djangoには、誰かが機器をチェックアウトするためのチケットであるCheckoutモデルがあります。チェックアウトの担当者はキャンパスのOrganizationalUnitに属しているため、Checkoutモデルが(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とそのすべての子に関連するチェックアウトの数を取得したいと思います。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を変更する必要があります。

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 に答える
3

必要なのは、OrganizationalUnit リレーション ツリーをトラバースし、OrganizationalUnit ごとに関連するチェックアウトの数を取得する再帰関数です。したがって、コードは次のようになります。

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 に答える
0

これでSQLがどのように機能するかはわかりませんが、やりたいことはまさにあなたが説明したことです。

すべての OU とその親を While ループで取得し、チェックアウトをカウントして合計します。

ORM は SQL を介した動的操作を提供しますが、パフォーマンスは低下します :)

于 2010-01-28T03:09:46.027 に答える