Django ORM:强制外部连接到未使用的选项卡

2024-06-28 14:38:02 发布

您现在位置:Python中文网/ 问答频道 /正文

对于下面的所有内容,我使用的是django1.9。你知道吗

我有一个Django模型,看起来像这样:

class Project(models.Model):
  name = models.CharField()
  task_count = models.FloatField()
  requesters = models.ManyToManyField('Requester', through='ProjectRequester')

class ProjectRequester(models.Model):
  project = models.ForeignKey('Project')
  requester = models.ForeignKey('Requester')

class Requester(models.Model):
  username = models.CharField()

我有一个表单,允许用户获取所有项目的总任务数,或者按名称或请求者对任务数进行分组。如果你按名字分组的话,这完全可以。你会得到一个类似这样的查询集:

qs = Project.objects.select_related().values('name')
qs = qs.annotate(task_count=models.Sum('task_count'))

生成的SQL与您预期的完全一样,类似于:

SELECT SUM(Project.task_count) FROM Project GROUP BY Project.Name;

然而,由于多对多与请求者连接,当您按请求者透视时,任何有1个以上请求者的项目都会重复计算其任务。这是:

qs = Project.objects.select_related().values('requesters__username')
qs = qs.annotate(task_count=models.Sum('task_count'))

结果是:

SELECT SUM(Project.task_count) FROM Project
LEFT OUTER JOIN ProjectRequester ON ProjectRequester.ProjectId=Project.Id
LEFT OUTER JOIN Requester ON Requester.Id=ProjectRequester.RequesterId
GROUP BY Requester.Username;

我绝对不想放弃使用原始sql,原因有很多。因此,我最初的想法是将请求者的数量存储为项目模型(requester_count = models.FloatField())上的一个字段,当项目加载到表中时,该字段将自动填充。这样,我可以将上面创建的查询集的第二行更改为:

task_count = models.Sum(models.ExpressionWrapper(
    models.F('task_count') / models.F('requester_count')
qs = qs.annotate(task_count=task_count)

这将产生所需的结果:

SELECT SUM(Project.task_count / Project.requester_count) FROM Project
LEFT OUTER JOIN ProjectRequester ON ProjectRequester.ProjectId=Project.Id
LEFT OUTER JOIN Requester ON Requester.Id=ProjectRequester.RequesterId
GROUP BY Requester.Username;

耶!然而,这里实际上还有很多其他的东西(大约20种其他方法可以实际透视,加上通过这些字段的任意组合进行过滤的能力),所以这并不像简单地添加if pivot == 'name', use regular sum annotation, else use sum divided by requester count那么简单(因为如果左外连接没有发生,使用第二个注释将不会产生正确数量的任务)。你知道吗

这就引出了我的问题:有没有什么方法可以强制Django总是将左外连接添加到ProjectRequester表中,即使该表中没有filter或groupby?这样,我就可以简单地除以请求者的计数,而不必考虑数据透视或过滤器,这样就可以算出结果。你知道吗

提前谢谢。你知道吗


Tags: 项目projectidtaskonmodelscountrequester