我使用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的点击次数(在上面过滤的时间范围内) 按上面计算的计数顺序 return content_object and count
这可能非常昂贵,所以我计划每天进行一次calcing / caching。
作为第一步,我想计算每个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
经过一番挖掘后,我发现annotation and generic relations do not work well together。如果我使用object_pk而不是content_object,它可以正常工作,但是我没有对象的名称。
所以我的问题:获得相同结果的替代方案是什么?如何按对象分组但也保留名称?
我有模型(content_type)和id(object_pk),所以我总是可以单独拉出这些,但这看起来不够优雅。 。 。
答案 0 :(得分: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的字典,非常接近你想要的。