5

基本の LoggedEvent モデルと、次のようないくつかのサブクラス モデルがあります。

class LoggedEvent(models.Model):
    user = models.ForeignKey(User, blank=True, null=True)
    timestamp = models.DateTimeField(auto_now_add=True)

class AuthEvent(LoggedEvent):
    good = models.BooleanField()
    username = models.CharField(max_length=12)

class LDAPSearchEvent(LoggedEvent):
    type = models.CharField(max_length=12)
    query = models.CharField(max_length=24)

class PRISearchEvent(LoggedEvent):
    type = models.CharField(max_length=12)
    query = models.CharField(max_length=24)

ユーザーが関連するアクションを実行すると、これらのイベントが生成されます。各ユーザーが先月発生した各イベント タイプの数の使用状況レポートを生成しようとしています。私は Django の ORM に苦労しており、近くにいる間に問題が発生しています。クエリコードは次のとおりです。

def usage(request):
    # Calculate date range
    today = datetime.date.today()
    month_start = datetime.date(year=today.year, month=today.month - 1, day=1)
    month_end = datetime.date(year=today.year, month=today.month, day=1) - datetime.timedelta(days=1)

    # Search for how many LDAP events were generated per user, last month
    baseusage = User.objects.filter(loggedevent__timestamp__gte=month_start, loggedevent__timestamp__lte=month_end)
    ldapusage = baseusage.exclude(loggedevent__ldapsearchevent__id__lt=1).annotate(count=Count('loggedevent__pk'))
    authusage = baseusage.exclude(loggedevent__authevent__id__lt=1).annotate(count=Count('loggedevent__pk'))

    return render_to_response('usage.html', {
        'ldapusage' : ldapusage,
        'authusage' : authusage,
    }, context_instance=RequestContext(request))

ldapusage と authusage はどちらもユーザーのリストであり、各ユーザーには、ユーザーが生成した特定のイベントの数を表す .count 属性で注釈が付けられています。ただし、両方のリストで、.count 属性は同じ値です。実際、注釈付きの「カウント」は、タイプに関係なく、ユーザーが生成したイベントの数と同じです。だから、私の特定の

authusage = baseusage.exclude(loggedevent__authevent__id__lt=1)

サブクラスで除外していません。id__lt=1、id__isnull=True などを試しました。半分。

4

1 に答える 1

4

Djangoモデルの継承の鍵は、抽象化されていない基本クラスでは、すべてが実際には基本クラスのインスタンスであり、別のテーブルの側に余分なデータがストラップされている可能性があることを覚えていることです。つまり、ベーステーブルで検索を行うと、ベースクラスのインスタンスが返され、サブクラステーブルでデータベースクエリを繰り返し実行して、一致するキーを持つレコードが含まれているかどうかを確認しない限り、どのサブクラスであるかを判断する方法はありません( 「イベントがあります。AuthEventにレコードがありますか?いいえ。LDAPイベントはどうですか?…」)。特に、これは、すべてのサブクラステーブルで結合を行わずに、基本クラスでの通常のクエリでそれらを簡単にフィルタリングできないことを意味します。

いくつかの選択肢があります。1つは、サブクラスに対してクエリを実行し、結果(ldap_event_count = LDAPEvent.objects.filter(user=foo).count()、…)を集計することです。これは、単一のレポートには十分な場合があります。通常、コンテンツタイプフィールドを基本クラスに追加することをお勧めします。これにより、別のクエリを実行しなくても、インスタンスがどの特定のサブクラスであるかを効率的に判断できます。

content_type = models.ForeignKey("contenttypes.ContentType")

event.autheventこれにより、2つの大きな改善が可能になります。最も一般的なものは、サブクラス固有のアクセサー(またはevent.ldapevent)をヒットしたり、を処理したりすることなく、一般的に多くのイベントを処理できることですDoesNotExist。この場合、レポート値を取得するようなことを行うことができるため、クエリを書き直すのも簡単にEvent.objects.aggregate(Count("content_type"))なります。これは、ロジックがより複雑になる場合に特に便利です(「イベントはAuthまたはLDAPで…」)。

于 2010-08-24T11:44:57.050 に答える