【问题标题】:Aggregating Django Queries for Many-to-Many related models为多对多相关模型聚合 Django 查询
【发布时间】:2017-04-21 09:59:33
【问题描述】:

我有下面列出的三个相关模型,我想运行一个聚合查询来给出每个人完成的任务总数,但只有那些位于特定文件夹中的任务。

class Person(models.Model):
    firstName = models.CharField(max_length=100, null=True, blank=True)
    lastName = models.CharField(max_length=100, null=True, blank=True)

class Folder(models.Model):
    title = models.CharField(max_length=254, null=True, blank=True)
    assignees = models.ManyToManyField(Person, related_name="projects")
    completedDate = models.DateTimeField(blank=True, null=True)

class Task(models.Model):
    title = models.CharField(max_length=254, null=True, blank=True)
    assignees = models.ManyToManyField(Person, related_name="tasks")
    folders = models.ManyToManyField(Folder, related_name="tasks")

这是我尝试的查询:

tasks = Contact.objects.filter(tasks__folders__id='I58343DS89ASDF').distinct().filter(tasks__completedDate__gte='2016-10-01 00:00:00').annotate(total=Count('tasks'), name=F('firstName')).values('total', 'name')

这给了我一个错误的计数。所以我检查了这个 Django 查询生成的 SQL 语句。 SQL 语句为:

SELECT DISTINCT COUNT(`wrike_task_assignees`.`task_id`) AS `total`, `wrike_contact`.`firstName` AS `name` FROM `wrike_contact` INNER JOIN `wrike_task_assignees` ON (`wrike_contact`.`id` = `wrike_task_assignees`.`contact_id`) INNER JOIN `wrike_task` ON (`wrike_task_assignees`.`task_id` = `wrike_task`.`id`) INNER JOIN `wrike_task_folders` ON (`wrike_task`.`id` = `wrike_task_folders`.`task_id`) INNER JOIN `wrike_task_assignees` T6 ON (`wrike_contact`.`id` = T6.`contact_id`) INNER JOIN `wrike_task` T7 ON (T6.`task_id` = T7.`id`) WHERE (`wrike_task_folders`.`folder_id` = I58343DS89ASDF AND T7.`completedDate` >= 2016-10-01 00:00:00) GROUP BY `wrike_contact`.`id` ORDER BY NULL

一个格式很好的版本是:

SELECT DISTINCT COUNT(ta.task_id) AS `total`, c.firstName AS `name` 
    FROM wrike_contact c INNER JOIN wrike_task_assignees ta ON (c.id = ta.contact_id)
    INNER JOIN wrike_task t ON (ta.task_id = t.id)
    INNER JOIN wrike_task_folders tf ON (t.id = tf.task_id)
    INNER JOIN wrike_task_assignees T6 ON (c.id = T6.contact_id)
    INNER JOIN wrike_task T7 ON (ta.task_id = T7.id) 
    WHERE (tf.folder_id = 'I58343DS89ASDF' 
        AND t.completedDate >= '2016-10-01 00:00:00') 
    GROUP BY c.id
    ORDER BY NULL

请注意,一对 INNER JOIN 重复了两次——不知道为什么。

如果我删除那些重复的 INNER JOIN 然后运行查询,结果是正确的。这是我删除重复的 INNER JOIN 段的 SQL 语句版本:

SELECT DISTINCT c.firstName AS name, COUNT(ta.task_id) AS `total` 
    FROM wrike_contact c 
    INNER JOIN wrike_task_assignees ta ON (c.id = ta.contact_id) 
    INNER JOIN wrike_task t ON (ta.task_id = t.id) 
    INNER JOIN wrike_task_folders tf ON (t.id = tf.task_id) 
    WHERE (tf.folder_id = 'I58343DS89ASDF' 
        AND t.completedDate >= '2016-10-01 00:00:00') 
    GROUP BY c.id 
    ORDER BY name;

有人可以解释一下为什么 Django 的查询会生成这样一个有问题的 SQL 语句以及如何解决它?

【问题讨论】:

    标签: django django-models


    【解决方案1】:

    线索在Django Documentation

    以下查询对我有用:

    fitlers = {'tasks__completedDate__gte': '2016-10-01 00:00:00', 'tasks__completedDate__lte': '2017-10-01 00:00:00'}
    filtering = {'tasks__folders__id': settings.FOLDER_ID }
    filtering.update(filters)
    
    # Get number of general_tech_support_requests by person
    gen_tasks = Contact.objects.filter(**filtering)\
                .distinct()\
                .annotate(total=Count('tasks'), assignee=F('firstName'))\
                .values('total', 'assignee')
    

    【讨论】:

      猜你喜欢
      • 2011-02-19
      • 1970-01-01
      • 2018-04-24
      • 2018-02-23
      • 2021-10-19
      • 2016-09-06
      • 2014-05-27
      • 1970-01-01
      • 2017-11-04
      相关资源
      最近更新 更多