Django排除了过去的一对多关系?

时间:2012-03-07 23:16:32

标签: django

我在使用Django时遇到了一些麻烦,并且在多次查询后运行了排除。

以下四个表格很重要:

Status - name, id
TestcaseCategory - category, id
Testcase - category (Foreign key to TestcaseCategory), id, name...
TestcaseRun - testcase (Foreign key to Testcase), id, status (Foreign key to Status), start_date, end_date, ...

显然每个TestCase都可以存在大量运行中,每个Run可以有一个Status,每个Testcase可以有一个Category,尽管每个类别可能有大量的testcases。

目标是在一个时间范围内,但在没有“开发”失败的情况下,获得每个类别失败的测试用例数量。这些是结构良好的名称:

PASS-DEV
FAIL
FAIL-DEV
...

我曾经有很多疑问要做,但我们最终遇到了性能问题。因此,我们试图将其简化为单个查询:

excludeArgs = {"testcase__testcaserun__status__name__icontains": "dev"}
filterArgs = {"testcase__testcaserun__status__name__icontains": "fail",
              'testcase__testcaserun__end_date__gte': start,
              'testcase__testcaserun__end_date__lte': end}
categoryData = models.TestCaseCategory.objects.all()
categoryData = categoryData.filter(**filterArgs)
# Data exists here fine
categoryData = categoryData.exclude(**excludeArgs)
# Huh? Exclude has removed all of our results, when we expect there to be results!
# This happens even if I move exclude before the filter.
# if we did have anything left, we would do the following to get only the values we want:
categoryData = categoryData.annotate(fail=Count('testcase__testcaserun'))
categoryData = categoryData.values('category', 'fail')

这表明我正在点击一个Django错误,或者为django做一些不正确的事情。这是什么?

以下答案是错误的,但请引导我找到正确答案:

categoryData = models.TestCaseRun.objects.\
exclude(status__name__icontains='dev').\
filter(status__name__icontains='fail', end_date__range=(start, end)).\ 
values('testcase__category').annotate(fail=Count('id')).order_by()

1 个答案:

答案 0 :(得分:1)

由于您在TestCaseCategory上运行查询,因此只要匹配,排除就会排除类别,而不是个别相关项目。换句话说,如果类别中至少有一个TestCaseRun状态包含“dev”,则整个类别将从您的结果中消失。

然而,无论如何,这是错误的做法。你需要从你实际工作的角度思考。您希望按类别划分测试用例的数量,但这意味着我们正在讨论测试用例,而不是类别。

尝试:

TestCase.objects.\
    exclude(testcaserun__status__icontains='dev').\
    filter(testcaserun__status__icontains='fail', testcaserun__end_date__range=(start, end)).\
    values(category).annotate(Count('id')).order_by()

重要的部分是values(category).annotate(Count('id')).order_by()位。这将按类别对测试用例进行分组,然后计算每组中有多少个测试用例。结果是ValuesQuerySet,而不是实际的QuerySet,所以你不能将它用于其他任何事情,但你会得到你的数量。