Python 如何返回表中最常用的项目,但每个项目在哪里是唯一的?
我正试图找出一个棘手的Django查询,希望您能提供帮助。我有这个模型:Python 如何返回表中最常用的项目,但每个项目在哪里是唯一的?,python,django,Python,Django,我正试图找出一个棘手的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): us
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中不支持))
谢谢 这有用吗
from collections import Counter
results = Counter([vid for vid, eid in ActiveVenue.objects.values_list("venue_id", "event_id").distinct()]
看看这样能不能奏效
ActiveVenue.objects.all().annotate(score=Count('event__user', distinct=True)).order_by('-score')
这是我的版本(完成测试):
型号.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
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})
视图.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
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 %}
{%用于场馆中的场馆%}
{{forloop.counter}。{{地点}}
{%endfor%}
输出:
这是我对这个问题的看法。首先,这里是一个查询,它将获取场馆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]
接下来,必须获得相应的场馆对象
tempresult = Venue.objects.filter(id__in=query_ids)
[<Venue: The Hill>, <Venue: The Oaks>, <Venue: The Pound>
tempresult=vention.objects.filter(id\uuu-in=query\u-id)
[,
最后,将执行列表理解,根据先前获得的分数重新排列场馆对象
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>]
result=[如果场馆id==场馆.id,则查询tempresult中场馆id中的场馆id中的场馆id]
[, ]
这会根据测试数据给出正确的结果。我非常确定
disctinct
应该在sqlite中工作。根据,您不能在sqlite中指定参数,但函数一般应该可以工作。考虑到用户限制,我认为您不能使用Django ORM来完成此操作。因此,您似乎必须编写一些手动SQL。@miki725我同意,如果它被抽象成一个返回集合的函数,那么在支持distinct()的情况下,它可以遵从ORM,而在不支持distinct()的情况下,它可以遵从手动SQL。+1,collections.Counter是非常高质量的,并且正是为了这个目的而设计的。在完成上述代码之后,类似于results.most_common(3)的内容
应该会给出您要寻找的答案,并进行了很好的排序。虽然这样做有效,但我认为我们应该避免在Python中迭代整个查询集。只在获取一个片段后进行迭代(分页)。如果我们迭代原始查询集而不首先对其进行切片,则查询集可能会非常大,视图可能需要很长时间才能响应。同样,这会将所有内容加载到内存中,并在内存中对整个表进行排序。这不是一个好的做法。如果SQL查询无法实现某些功能,则应稍微对架构进行反规范化,以使n不要在框架代码中加载所有内容和排序/筛选。@OwaisLone这只会按他要求的年份对活动场地进行排序,但我没有将其放入筛选器。我不是说它对Jono有效。这取决于他将拥有多少活动场地。只需指出一个好的做法。@OwaisLone好的,我知道这不是一个更好的方法回答。但这就是我为解决他的问题所做的工作。也许有一种方法可以重构这段代码。我在前一段时间发布我的答案之前,在这里尝试了其他答案,但我得到了一个错误。