我想找出一个棘手的Django查询,希望你能帮忙。我有这个模型:
class ActiveVenue(models.Model):
event = models.ForeignKey(Event)
venue = models.ForeignKey(Venue)
class Venue(models.Model):
name = models.CharField(max_length=200)
class Event(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=200)
在我的应用程序中有很多事件,每个事件可以有多个活动场所,因此我目前的数据结构。我希望你的解决方案不是“将你的模型改为foo”,因为这已经是一个已部署的网站,我想保留当前的模型结构。
我想编写一个返回最受欢迎场所的查询,但其中每个用户只计算一次场地。举个例子,如果我有一个用户有四个活动并且他们每次都使用相同的场地,我只想在确定最受欢迎的场地时计算一次这个场地。
为了说明这一点,想象一下这是我的数据:
event: A user: bob venue: The Hill
event: B user: bob venue: The Hill
event: C user: bob venue: The Hill
event: D user: jane venue: The Oaks
event: E user: sarah venue: The Pound
event: F user: david venue: The Pound
event: G user: ron venue: The Oaks
event: H user: erica venue: The Oaks
这里的热门订单是:
1. The Oaks
2. The Pound
3. The Hill
我是如何编写查询来执行此操作同时适用于postgres和sqlite(换句话说,不依赖distinct()
(sqlite不支持))?
谢谢!
答案 0 :(得分:1)
这有用吗?
from collections import Counter
results = Counter([vid for vid, eid in ActiveVenue.objects.values_list("venue_id", "event_id").distinct()]
答案 1 :(得分:0)
看看这样的东西是否有效
ActiveVenue.objects.all().annotate(score=Count('event__user', distinct=True)).order_by('-score')
答案 2 :(得分:0)
这是我的版本(完成测试):
<强> models.py 强>
class Venue(models.Model):
name = models.CharField(max_length=200)
def __unicode__(self):
return self.name
def ranking(self):
count=0
actives = ActiveVenue.objects.filter(
venue__name=self.name).values(
'event__user__username', 'venue__name').distinct()
for active in actives:
count += 1
return count
<强> views.py 强>
def getRanking( anObject ):
return anObject.ranking()
def myview(request):
venues = list(Venue.objects.filter())
venues.sort(key=getRanking, reverse=True)
return render(request,'page.html',{'venues': venues})
<强>模板强>
{% for venue in venues %}
{{forloop.counter}}. {{venue}}<br/>
{% endfor %}
<强>输出:强>
答案 3 :(得分:0)
这是我对这个问题的看法。首先,这是一个查询,它将获取Venue ID以及与相关用户相对应的分数。
testquery = ActiveVenue.objects.values("venue").annotate(score=Count("event__user", distinct=True)).order_by("-score")
结果
[{'score': 3, 'venue': 2}, {'score': 2, 'venue': 3}, {'score': 1, 'venue': 1}]
接下来,场地ID将被放入一个新列表中。
query_ids = [item["venue"] for item in testquery]
[2, 3, 1]
接下来,必须获得相应的Venue对象。
tempresult = Venue.objects.filter(id__in=query_ids)
[<Venue: The Hill>, <Venue: The Oaks>, <Venue: The Pound>
最后,将执行列表推导以根据之前获得的分数重新排序Venue对象。
result = [venue for venue_id in query_ids for venue in tempresult if venue_id == venue.id]
[<Venue: The Oaks>, <Venue: The Pound>, <Venue: The Hill>]
根据测试数据给出正确的结果。