Django查询 - 从一个IP

时间:2017-11-24 16:46:31

标签: django orm

让我们说我有一个简单的投票表格,有不同的答案。 人们可以从一个IP多次投票。我可以很容易地找到一个给定答案得到多少票 - a.vote_set.all().count()(不受1个IP的投票限制)我也可以找出有多少票,考虑到来自1个IP的限制1票 - {{1 (一个IP = 1的投票限制) 如果我想从1个IP(极限= 10)计算多达10票,如何获得给定答案的总票数?

澄清我的问题:我需要一个Django orm查询来获得给定答案的所有投票 - 但是有了这个条件,我想从一个IP计算多达10票。例: 答案A得到100票。 100票来自以下知识产权(一人投票或其中几人共享公共知识产权):

  

1)120.x.x.x - 20票2)121.x.x.x - 50票3)122.x.x.x - 10   票4)123.x.x.x - 5票5)124.x.x.x - 15票

我希望查询返回45票:来自IP 1的10票)(10,不是20,因为10是限制),10来自2),10来自3),5来自4)最后10来自5

我事先并不知道选民使用了多少IP。 请不要告诉我这个用例是不可能的 - 这是真的,我必须这样做并且卡住了:P

2 个答案:

答案 0 :(得分:1)

好吧,这不是一个简短的答案,但我在Django shell中验证了这一点,并且从我运行的几个测试中它似乎正在计数。

我假设你有一个可以简化的模型:

class Answer(models.Model):
    answertext = models.CharField(max_length=200)

class Vote(models.Model):
    answer = models.ForeignKey(Answer, on_delete=None)
    ip = models.CharField(max_length=15)

如果我理解你的问题,我们现在想要计算一个答案的投票数 - 限制一个IP投票的次数为10次。

我将分解各种组件并在最后给出完整的陈述。

首先,我们过滤掉一个特定的答案。你可能想要一些具体的东西 - 我只是拿了所有的“是”答案。我们用计数进行注释,以便我们得到所有的肯定答案,其中包含投票IP和这些IP投票的次数:

Vote.objects.filter(answer__answertext='Yes').values('ip').annotate(ipcount=Count('id'))

接下来,我们需要将计数大于10的IP限制为最多10票。我们使用Case和When表达式来完成此操作。基本上,这表示给我们一个新的字段,当计数小于或等于10时,等于来自IP的投票数,如果IP投票数大于10,则将新字段限制为10。

.annotate(limitedipcount = Case(
    When(ipcount__lte=10, then='ipcount'), 
    When(ipcount__gt=10, then=10), 
    output_field=IntegerField())
)

最后,我们需要总结一下这个新的'limitedipcount',我们用一个简单的聚合表达式做到这一点:

.aggregate(totallimitedipcount=Sum('limitedipcount'))

如果你把所有这些放在一起就会得到这样的东西:

Vote.objects.filter(answer__answertext='Yes')
    .values('ip')
    .annotate(ipcount=Count('id'))
    .annotate(limitedipcount = Case(
        When(ipcount__lte=10, then='ipcount'), 
        When(ipcount__gt=10, then=10),
        output_field=IntegerField())
    )
    .aggregate(totallimitedipcount=Sum('limitedipcount'))

答案 1 :(得分:0)

好的,所以我最终编写了一个带有限制作为参数的辅助函数(默认为None),它构建了字典{ip1:num_of_votes1,ip2:num_of_votes2}。为了构建这个字典,该函数遍历给定答案的所有投票,每次检查投票的ip,判断ip是否已经在字典中,是否已达到给定IP的限制,如果没有 - 增加给定键的值。最后,我总结了值 - sum(my_dict.values())并将其返回。

这可能是一个非常强力的解决方案,所以如果有人知道更好的事情,请发布。