在Django中使用泛型关系进行注释

在Django中使用泛型关系进行注释,django,annotations,count,generic-relations,Django,Annotations,Count,Generic Relations,我正在使用统计数据库对象的点击次数。我想按对象计算点击次数,以确定在给定的时间范围内哪个对象的点击次数最多。该应用程序有两种有趣的模式: class Hit(models.Model): created = models.DateTimeField(editable=False) ip = models.CharField(max_length=40, editable=False) session = model

我正在使用统计数据库对象的点击次数。我想按对象计算点击次数,以确定在给定的时间范围内哪个对象的点击次数最多。该应用程序有两种有趣的模式:

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')
“命中”用时间戳记录每个命中,而命中计数存储总命中数。要按对象在一定时间范围内获取命中率,我需要执行以下操作:

按创建日期筛选 计算每个内容对象的点击数(在上面筛选的时间范围内) 按上面计算的计数订购 返回内容\u对象和计数

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

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

limited_hc = Hit.objects.all().values('hitcount__content_object').annotate(count = Count('hitcount__object_pk'))
我立即遇到了一个问题:

无法将关键字“命中计数内容对象”解析到字段中。选项包括:已创建、命中率、id、ip、会话、用户、用户和代理

经过一些挖掘,我发现了。如果我使用object_pk而不是content_object,它可以正常工作,但是我没有对象的名称

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


我确实有模型(content_type)和id(object_pk),所以我总是可以分别拉它们,但这似乎不雅观

Hit
模型添加通用关系可能会更有效:

class Hit(models.Model):
    ...
    object_id = models.PositiveIntegerField()
    content_type = models.ForeignKey(ContentType)
    content_object = generic.GenericForeignKey('content_type', 'object_id')
然后直接对命中的对象运行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迁移系统修改命中率的模型。您还可以尝试将Hit-after-monkey修补它的元类作为子类,或者只定义自己的模型来更好地满足您的需要

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

count = Hit.objects.filter(
                     created__range = myrange,
                     content_type__in = set_of_types
                   ).count()
其中,类型的
set\u
可以是使用
get\u for\u model
调用构造的列表,也可以是通过直接过滤
ContentType
表获得的查询集

count()方法的优点在于它使计数在数据库中发生,这要快得多

要按内容类型获得细分,请尝试以下操作:

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

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

现在不可能尝试,但是您是否尝试过
limited\u hc=Hit.objects.all().value('hitcount\uu content\u type','hitcount\uu object\u pk')。注释(count=count('hitcount\uu object\u pk'))
,有效,但我没有得到实际对象的链接。所以我没有名字,只有pk。然后,我必须再次ping数据库,以从我处理此解决方案的相应表中提取名称数据。但我不确定它是否给了我想要的。我想要的不是一个对象(给定时间范围、内容类型和对象id)的命中计数,而是所有对象(给定时间范围和内容类型)的命中计数,以便对它们进行排序。看起来,即使我像你描述的那样重新构造models.py,我也不能同时使用annotate和content_对象。在这种情况下,我不想使用annotate,因为您的查询会做太多的工作,而且我认为对于大型集合来说会非常慢。在这种情况下,我认为懒惰的计数方法可能会更好。谢谢你的跟进。这还没有完全达到我的目标。有了这个,我还是得到了一个号码。我希望能有一份合适的清单。比如说,在您的最后一段代码中,如果我们忽略.count(),我们将得到5个对象:3个为A类型,2个为B类型。我希望查询为我提供2个对象和每个对象的计数:类型A(计数=3)和类型B(计数=2)。不仅仅是5(这是我从上面的代码中得到的)。在你的问题中不是很清楚,但我已经尝试提出了一个选项。对于任何混淆,我深表歉意。谢谢你的帮助。我想我会按照我们在这个解决方案中达到的数量,简单地让数据库一个接一个地获取对象信息。我本想使用annotate(Count('content_object')),但正如我在问题中所说的,这在Django中似乎被打破了。