按字段获取Queryset的不同值

66

我有这个模型:

class Visit(models.Model):
    timestamp  = models.DateTimeField(editable=False)
    ip_address = models.IPAddressField(editable=False)
如果一个用户在一天内多次访问,我该如何根据IP字段过滤唯一的行?(我想要今天的独特访问量)
today = datetime.datetime.today()
yesterday = datetime.datetime.today() - datetime.timedelta(days=1)

visits = Visit.objects.filter(timestamp__range=(yesterday, today)) #.something?

编辑:

我看到我可以使用:

Visit.objects.filter(timestamp__range=(yesterday, today)).values('ip_address')

我想要得到一个仅包含ip字段的ValuesQuerySet。现在我的QuerySet如下:

[{'ip_address': u'127.0.0.1'}, {'ip_address': u'127.0.0.1'}, {'ip_address':
 u'127.0.0.1'}, {'ip_address': u'127.0.0.1'}, {'ip_address': u'127.0.0.1'}]

如何在不执行查询并避免数据库负担的情况下筛选出唯一值?

# Hope it's something like this...
values.distinct().count()

可能是重复的问题: 从表字段中选择不同的值 - Mark Mikofski
@MarkMikofski 不是重复的问题,这里的问题是关于 Django 而不是纯 SQL。 - Adrian B
3个回答

50

您需要的是:

Visit.objects.filter(stuff).values("ip_address").annotate(n=models.Count("pk"))

这段代码的作用是获取所有ip地址,然后获取每个ip地址的主键(即行数)数量。


2
我不认为我完全理解annotate。就你所写的而言,我的ValuesQuerySet现在每个条目都附加了“n”:1。我不确定这告诉我什么? - Scott
10
问题可能出在 Meta.ordering 上 - 尝试这样做:Visit.objects.filter(stuff).order_by().values("ip_address").annotate(n=models.Count("pk")) - Greg
2
@Greg 谢谢!我知道 orderingorder_by() 会导致 distinct 出现问题,但我不知道该如何解决 - 尽管在 QuerySet API 文档中有说明,即在 order_by() 中 "如果您不想对查询应用任何排序,甚至不是默认排序,请调用没有参数的 order_by()" - Mark Mikofski
在这种情况下,pk是什么? - User
pk - 主键。每个记录的唯一标识符。 - arudzinska

36

使用Alex的答案后,我每个项目也有n:1。即使使用distinct()子句。

奇怪的是,这仍然返回正确数量的项目:

Visit.objects.filter(stuff).values("ip_address").distinct().count()

但是,当我迭代“Visit.objects.filter(stuff).values("ip_address").distinct()”时,我得到了更多的项目和一些重复的...

编辑:

筛选条款导致我麻烦。我正在使用另一个表字段进行过滤,并且进行了SQL JOIN,这破坏了不同的内容。 我使用了这个提示来查看实际使用的查询:

q=Visit.objects.filter(myothertable__field=x).values("ip_address").distinct().count()
print q.query

然后我恢复了我正在进行查询和过滤的类,以获得一个不依赖于任何“Visit”id的连接。

希望这可以帮助。


这是一个问题还是一个答案? - User
这是对Alex答案的一种补充。我尝试了它,遇到了与vfxcode相同的问题,然后我找到了原因。所以我想分享我的发现。三年后,我承认我的回答有点混乱,我明白你为什么会问这个问题 ;) - Guillaume Gendre

7

这个问题与标题所示的不同。如果你想从数据库获取类似集合的行为,你需要像这样做。

x = Visit.objects.all().values_list('ip_address', flat=True).distinct()

这应该会为x给你类似于这样的东西。

[1.2.3.4, 2.3.4.5, ...]

在哪里

len(x) == len(set(x))

返回 True

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接