【问题标题】:how to calculate frequency of pairs in queryset如何计算查询集中对的频率
【发布时间】:2020-10-10 21:02:19
【问题描述】:

我在 Django 中有两个模型:

class Pair(models.Model):
   pass

class Person(models.Model):
    pair = models.ForeignKey(to=Pair, related_name='mates')
    city = models.ForeignKey(to=City)

所以我需要计算来自不同城市的配对频率:

city_a<->city_b: 100
city_a<->city_a: 80
city_b<->city_c: 200
...

对于每个人,我可以通过以下方式获得另一个人的城市: person.pair.mates.exclude(id=person.id).first() 或类似的东西,所以理论上我可以遍历 Person 的所有实例,然后计算频率,但显然这将是超级低效的。

但我不知道如何通过标准查询集获取此信息(如果有办法)。欢迎任何提示

【问题讨论】:

  • 右边的数字是多少?你是怎么计算的?
  • 一个来自城市 I 和另一个来自城市 J 的对数

标签: sql django django-models django-queryset


【解决方案1】:

您可以注释这些对,例如:

from django.db.models import Count, F, Q

Person.objects.filter(
    Q(pair__mates__lt=F('pk')) | Q(pair__mates__gt=F('pk'))
).values(
    city1=F('city__name'),
    city2=F('pair__mates__city__name')
).annotate(
    number=Count('pk')
).order_by('city1', 'city2')

__name 应该是您要使用的城市的字段。例如__pk 也可能是一个选项。

查询的工作方式如下:Q(pair__mates__lt=F('pk')) | Q(pair__mates__gt=F('pk')) 通常应排除引用同一 Person 的“伙伴”。然后我们使用.values(..) 从城市和pair__mates__city__names 获取name(或其他文件)。现在我们有了这两个值,我们Count(..)city1city2 的每组记录数。 .order_by(..) 是避免下标所必需的,例如 qs[1] 会从原始 Person 查询返回一条记录。

查询因此看起来像:

SELECT app_name_city.name AS city1,
       T5.name AS city2,
       COUNT(app_name_person.id) AS number
FROM app_name_person
INNER JOIN app_name_pair ON app_name_person.pair_id = app_name_pair.id
INNER JOIN app_name_person T3 ON app_name_pair.id = T3.pair_id
INNER JOIN app_name_city ON app_name_person.city_id = app_name_city.id
INNER JOIN app_name_city T5 ON T3.city_id = T5.id
WHERE T3.id < app_name_person.id OR T3.id > app_name_person.id
GROUP BY app_name_city.name, T5.name
ORDER BY city1 ASC, city2 ASC

这将返回一个QuerySet 的字典:

<QuerySet [
    {'city1': 'city_a', 'city2': 'city_a', 'number': 80},
    {'city1': 'city_a', 'city2': 'city_b', 'number': 100},
    {'city1': 'city_b', 'city2': 'city_c', 'number': 200}
]>

【讨论】:

  • @PhilippChapkovski:~Q(pair__mates=F('pk')) 通常应该排除引用相同Person 的“伙伴”。然后我们使用.values(..) 从城市和pair__mates__city__names 获取name(或其他文件)。现在我们有了这两个值,我们Count(..)city1city2 的每组记录数。 .order_by(..) 是避免下标所必需的,例如 qs[1] 会从原始 Person 查询返回一条记录。
  • @PhilippChapkovski:对于查询集qs,您可以使用print(qs.query) 打印它将在数据库端执行的查询。因此,您可以验证它是否使您打算在数据库端执行查询。
  • 知道了!非常感谢!我没有得到的唯一部分是“.order_by(..) 是避免下标所必需的,例如 qs[1] 将从原始 Person 查询返回一条记录。”
  • @PhilippChapkovski: 好吧,不幸的是没有.order_by(),如果你使用qs[1],它会删除GROUP BY,这确实很“奇怪”,这是Django ORM的一个特点(我希望有一天他们会消除这种特殊性),但就目前而言,有必要避免这种情况。
  • 不幸的是,这部分:Person.objects.filter( ~Q(pair__mates=F('pk')) 导致django.db.utils.OperationalError: no such column: U1.id。相反的,没有否定(Person.objects.filter( Q(pair__mates=F('pk')))工作正常,返回(不出所料)所有Person对象
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-05-18
  • 1970-01-01
  • 2017-04-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-29
相关资源
最近更新 更多