2

我正在使用django-hitcount来统计对我的数据库对象的命中。我想按对象计算点击次数,以确定在给定时间范围内哪个对象的点击次数最多。该应用程序在这里有两个感兴趣的模型:

class Hit(models.Model):
    created         = models.DateTimeField(editable=False)
    ip              = models.CharField(max_length=40, editable=False)
    session         = models.CharField(max_length=40, editable=False)
    user_agent      = models.CharField(max_length=255, editable=False)
    user            = models.ForeignKey(User,null=True, editable=False)
    hitcount        = models.ForeignKey(HitCount, editable=False)

class HitCount(models.Model):
    hits            = models.PositiveIntegerField(default=0)
    modified        = models.DateTimeField(default=datetime.datetime.utcnow)
    content_type    = models.ForeignKey(ContentType,
                        verbose_name="content cype",
                        related_name="content_type_set_for_%(class)s",)
    object_pk       = models.TextField('object ID')
    content_object  = generic.GenericForeignKey('content_type', 'object_pk')

“命中”记录每个命中的时间戳,而 HitCount 存储命中的总数。要在某个时间范围内按对象获取命中,我需要执行以下操作:

按创建日期过滤命中计数每个 content_object 的命中数(在上面过滤的时间范围内)按上面计算的计数排序返回 content_object 和计数

这可能非常昂贵,所以我计划每天计算/缓存一次。

作为第一步,我想计算每个 content_object 的点击次数,而不考虑时间范围。

limited_hc = Hit.objects.all().values('hitcount__content_object').annotate(count = Count('hitcount__object_pk'))

我立即遇到了一个问题:

无法将关键字“hitcount__content_object”解析为字段。选项有:created、hitcount、id、ip、session、user、user_agent

经过一番挖掘,我发现注释和泛型关系不能很好地协同工作。如果我使用 object_pk 而不是 content_object,它可以正常工作,但是我没有对象的名称。

所以我的问题是:实现相同结果的替代方法是什么?如何按对象分组但还保留名称?

我确实有模型 (content_type) 和 id (object_pk),所以我总是可以单独提取它们,但这似乎不优雅。. .

4

1 回答 1

1

为了您的目的,将通用关系添加到Hit模型可能会更有效:

class Hit(models.Model):
    ...
    object_id = models.PositiveIntegerField()
    content_type = models.ForeignKey(ContentType)
    content_object = generic.GenericForeignKey('content_type', 'object_id')

然后直接在 Hit 上运行 count() 查询:

t = ContentType.objects.get_for_model(the_object_being_hit)
id = the_object_being_hit.id
count = Hit.objects.filter(
                   created__range=(from_timestamp, to_timestamp),
                   content_type = t,
                   object_id = id
                 ).count()

您可以使用 Django South 迁移系统来修改命中计数的模型。您还可以尝试在对其 Meta 类进行猴子修补后将 Hit 子类化,或者仅定义您自己的模型以更好地满足您的需求。

编辑如果要计算整个对象类或几个类的命中,则可以:

count = Hit.objects.filter(
                     created__range = myrange,
                     content_type__in = set_of_types
                   ).count()

其中set_of_types可以是get_for_model调用构造的列表,也可以是通过直接过滤ContentType表获得的查询集。

count() 方法的优点在于它可以在数据库中进行计数,这要快得多。

要按 content_type 进行细分,请尝试以下操作:

counts = Hit.objects.filter(
                   created__range = myrange
                ).values(
                   'content_type'
                ).annotate(
                   Count('content_type')
                )

这应该返回一个计数字典与内容类型 ID,非常接近你想要的。

于 2010-11-19T04:53:30.197 回答