【问题标题】:How to translate this raw query to Django ORM如何将此原始查询转换为 Django ORM
【发布时间】:2015-08-23 21:56:58
【问题描述】:

我有一个模型,其中我们有候选人、语言和语言级别实体:

class Candidate(models.Model):
  user = models.ForeignKey(MyUser)
  telephone = models.CharField(max_length=20, unique=True)
  postcode = models.CharField(max_length=10)

class Language(models.Model):
  name = models.CharField(max_length=50)

class LanguageLevel(models.Model):
  candidate = models.ForeignKey(Candidate)
  language = models.ForeignKey(Language)
  level = models.IntegerField(max_length=1, choices=LANGUAGE_LEVEL, default=0)

我的原始查询是:

SELECT c.id, COUNT(c.id) as total
FROM candidates as c
  JOIN language_level as ll ON ll.candidate_id=c.id
  JOIN languages as l ON ll.language_id=l.id
WHERE ((ll.level >=1 AND l.id = 1 ) OR
       (ll.level >=1 AND l.id = 2 ) OR
       (ll.level >=1 AND l.id = 3 ) OR
       (ll.level >=3 AND l.id = 4 ) OR
       (ll.level >=3 AND l.id = 5 ) OR
       (ll.level >=2 AND l.id = 6 ))
GROUP By c.id

我需要能够按总计字段对结果进行排序,并且我还需要能够在模板中显示该总计。不知何故,我需要创建一个结合这 3 个实体 + 分组依据的更大对象的列表。

知道什么是最好的方法吗?我尝试获取候选人的 id 并仅执行 Candidates.objects.find(id__in = ids) 但以后无法对其进行排序。

提前致谢

【问题讨论】:

  • 不要尝试翻译原始 SQL。根据您拥有的对象描述您需要的结果。
  • A 基本上需要列出所有会说英语和西班牙语的候选人(例如),他们的水平等于或大于中级。然后将它们按具有更好水平给予百分比的那些进行排序......例如,如果你说两个都在要求的水平上 100%,如果你说一个 50%。所以这很容易用 SQL 来做......但我发现它在不使用原始查询的情况下与 Django 有点混淆。

标签: sql django django-models django-templates


【解决方案1】:
Candidate.objects.filter(
    Q(Q(languagelevel__language__id__in=(1, 2, 3)) & Q(languagelevel__language__level__gte=1)) |
    Q(Q(languagelevel__language__id__in=(4, 5)) & Q(languagelevel__language__level__gte=3)) |
    Q(Q(languagelevel__language__id=6) & Q(languagelevel__language__level__gte=2))
)).values('id').annotate(total=Count('id'))

values 只会返回每个候选人的id,计算出的总数为total

如果你想获取所有的字段(不仅仅是id),你可以删除.values('id')为:

Candidate.objects.filter(
    Q(Q(languagelevel__language__id__in=(1, 2, 3)) & Q(languagelevel__language__level__gte=1)) |
    Q(Q(languagelevel__language__id__in=(4, 5)) & Q(languagelevel__language__level__gte=3)) |
    Q(Q(languagelevel__language__id=6) & Q(languagelevel__language__level__gte=2))
)).annotate(total=Count('id'))

【讨论】:

  • 实际上前面的响应更有意义,因为我需要访问整个 Candidate 对象才能在模板中显示它。我会尽快试一试……但对我来说它看起来不错。 ——
  • 我的代码基于这个答案。真正有用的 .values('id') 不需要,因为我想要整个实体。不错。
【解决方案2】:

我真的不明白您的 SQL 如何执行您在评论中描述的内容。但是,此代码的作用与该描述相似。

from django.db.models import Max
Candidate.objects.filter(
    languagelevel__language__name__in=['English', 'Spanish'],
    languagelevel__level__gte=2
).annotate(max_level=Max('languagelevel__level')).order_by('max_level')

【讨论】:

  • 如果你运行我的查询,你会得到类似 c.id 5 => 总语言 2,c.id 3 => 总语言 3 它基本上告诉你候选 ID,以及来自的语言数量候选人的查询。您的代码的问题在于,当每种语言可能有不同的过滤器时,它对所有语言应用相同的过滤器。但这是一个起点……我会检查这种方法,看看是否可以扩展它。
猜你喜欢
  • 2022-08-18
  • 2019-07-19
  • 2019-06-11
  • 2020-07-13
  • 2019-12-10
  • 1970-01-01
  • 2018-07-19
  • 2014-12-26
  • 2019-10-31
相关资源
最近更新 更多