Django ORM 中多对多字段的复杂计数

发布于 2024-11-17 00:10:03 字数 1151 浏览 6 评论 0原文

因此,我有一组可以出现在多个类别中的任务:

class TaskGroup(models.Model):
    name = models.CharField(max_length=200)
    slug = models.SlugField(max_length=200)
    icon = models.CharField(max_length=200, blank=True, null=True)

    def __unicode__(self):
        return unicode(self.name)


class Task(models.Model):
    start_date = models.DateField()
    end_date = models.DateField()
    is_date_fuzzy = models.BooleanField()
    name = models.CharField(max_length=200)
    assignee = models.ForeignKey(User, verbose_name="users who is assigned the task", blank=True, null=True)
    task_groups = models.ManyToManyField(TaskGroup)

如您所见,每个任务可以出现在多个任务组中。

我希望我的查询满足以下条件:

  1. 所有任务组的列表应该是 回来了。
  2. 任务数量的计数 在特定群体内。 IE 家具 (3)、床上用品 (2)、地板 灯 (6)
  3. 如果没有任务 具体TaskGroup,表示组 应该有 0 个
  4. 每组内的任务是 仅限于当前用户。

到目前为止我想出的最好的办法是这样的:

TaskGroup.objects.filter(
    task__assignee=current_usr
).annotate(
    task_count=Count('task__id')
).order_by('name')

但它在进行计数之前过滤所有内容,所以我看不到任务为零的任务组。

也许我想得太多了,但多年来我一直在尝试这样做,而且在这个阶段我只是想自己循环计数。

我真的希望你能帮助挽救我仅存的一点理智!

So I have a set of tasks that can appear in many categories:

class TaskGroup(models.Model):
    name = models.CharField(max_length=200)
    slug = models.SlugField(max_length=200)
    icon = models.CharField(max_length=200, blank=True, null=True)

    def __unicode__(self):
        return unicode(self.name)


class Task(models.Model):
    start_date = models.DateField()
    end_date = models.DateField()
    is_date_fuzzy = models.BooleanField()
    name = models.CharField(max_length=200)
    assignee = models.ForeignKey(User, verbose_name="users who is assigned the task", blank=True, null=True)
    task_groups = models.ManyToManyField(TaskGroup)

As you can see, each task can appear in multiple task groups.

I would like the following conditions to be satisfied by my query:

  1. The list of all TaskGroups should be
    returned.
  2. A count of the number of Tasks
    within a specific group. I.e.
    Furniture (3), Bedding (2), Floor
    lamps (6)
  3. If there are no tasks for a
    specific TaskGroup, said group
    should have 0
  4. The tasks within each group are
    limited to by the current user.

The best I have come up with so far is something like this:

TaskGroup.objects.filter(
    task__assignee=current_usr
).annotate(
    task_count=Count('task__id')
).order_by('name')

But it filters everything before doing the count, so I don't see the task groups with zero tasks.

Maybe I'm being very think but I've been trying to do this for ages and I'm at this stage just tempted to loop through and do the count myself.

I really hope you can help save what little remains of my sanity!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

归属感 2024-11-24 00:10:03

我曾经遇到过完全相同的问题。一种解决方案是使用额外的子查询:

TaskGroup.objects.extra(
    select={"task_count": "SELECT COUNT(*) from app_task where app_task.id=app_taskgroup.task_id AND app_task.assignee = '?'"},
    select_params = [current_usr]
).order_by('name')

或类似的东西。可能是连接密钥错误。

但这太丑了。并打破了很多 DRY 和 DB 独立原则。

更好的选择可能是使用 2 个查询。第二个针对没有分配给该用户任何任务的特定组:

empty_groups = TaskGroup.objects.exclude(task__assignee=current_usr)

然后只需迭代两组而不是一组。

I had the exact same problem once. One solution would be to use an extra subquery:

TaskGroup.objects.extra(
    select={"task_count": "SELECT COUNT(*) from app_task where app_task.id=app_taskgroup.task_id AND app_task.assignee = '?'"},
    select_params = [current_usr]
).order_by('name')

Or something like that. Probably the joining key is wrong.

But this is just ugly. and breaks a lot of DRY and DB independance priciples.

A better option would probably be to use 2 queries. The second one for the particular Groups that don't have any tasks assigned to that user:

empty_groups = TaskGroup.objects.exclude(task__assignee=current_usr)

Then just iterate over the two sets instead of only one.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文