Django加入多个带注释的查询集

时间:2013-12-19 15:56:23

标签: python sql django

我有一个简单应用的以下模型:

class App(models.Model):
    name = models.CharField(max_length=60)

class TestCase(models.Model):
    title = models.CharField(max_length=500)
    app = models.ForeignKey('apps.App', blank=True)

class Run(models.Model):
    timestamp = models.DateTimeField()
    value = models.FloatField()
    test_case = models.ForeignKey(TestCase)

例如,我想计算特定运行中已执行和完整的案例:

>>> # r is instance of Run
>>> cases_ids = r.values('test_case').distinct()
>>> executed_cases = TestCase.objects.filter(pk__in=cases_ids)
>>> executed_cases_stat = executed_cases.values('app__name').annotate(dcound=Count('app__name'))
[{'executed_cases': 1, 'app__name': u'App1'}, {'executed_cases': 3, 'app__name': u'App2'}]
>>> all_cases_stat = TestCase.objects.all().values('app__name').annotate(total_cases='app__name')
[{'total_cases': 5, 'app__name': u'App1'}, {'total_cases': 7, 'app__name': u'App2'}, {'total_cases': 12, 'app__name': u'App3'}]
>>>
>>> # I want to get this result:
[{'executed_cases': 1, 'total_cases': 5, 'app__name': u'App1'}, {'executed_cases': 3, 'total_cases': 7, 'app__name': u'App2'}, {'executed_cases': 0, 'total_cases': 12, 'app__name': u'App3'}]

我知道这可能是通过SQL(它可能看起来很难看):

select 
    simple_app.name
    , tc.total_cases
    , ce.cases_executed
from apps_app
join (
   select count(id) as total_cases, app_id
   from simple_testcase
    group by app_id) tc 
    on simple_app.id = tc.app_id
join(
    select count(id) as cases_executed, app_id
    from simple_testcase
    where id in (select test_case_id
    from simple_run where run_id = 1)
    group by app_id) ce 
    on apps_app.id = ce.app_id

如果没有原始sql或在python中迭代,有没有办法呢?

1 个答案:

答案 0 :(得分:3)

我大多数时候都想用注释做一些看似不可能的事情,我使用extrahttps://docs.djangoproject.com/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.extra

例如,在你的情况下你可以做这样的事情:

apps_extra = App.objects.all().extra (select={
    'total_cases': """
      select count(id) 
      from simple_testcase
      where simple_app.id = simple_testcase.app_id
    """, 
    'executed_cases': """
      # the same with your second nested query
    """,
})

现在apps_extra将包含Apptotal_cases字段的executed_cases个对象!

这真的很棒,因为您可以apps_extra使用Column()作为django_tables2的{​​{1}}来源,在该列上启用排序