Django 中的查询集优化

QuerySet Optimisations in Django

我只是想知道,我有以下两个伪相关的查询:

organisation = Organisation.objects.get(pk=org_id)
employees = Employee.objects.filter(organisation=organisation).filter(is_active=True)

每个 Employee 都与 Organisation 有 ForeignKey 关系。

我想知道在本机 Django ORM 的一个查询中是否可以利用任何东西来执行上述操作?

另外,会:

employees = Employee.objects.filter(organisation__id=organisation.id).filter(is_active=True)

是一种更快的获取方式employees?


Willem 的参考,employees 然后用作:

# Before constructing **parameters, it is neccessary to filter out any supurfluous key, value pair that do not correspond to model attributes:

if len(request.GET.getlist('gender[]')) > 0:
    parameters['gender__in'] = request.GET.getlist('gender[]')
    employees = employees.filter(**parameters)

if len(request.GET.getlist('age_group[]')) > 0:
    parameters['age_group__in'] = request.GET.getlist('age_group[]')
    employees = employees.filter(**parameters)

results = SurveyResult.objects.filter(
    user__in=employees,
    created_date__range=date_range,
).annotate(
    date=TruncDate('created_date'),
).values(
    'survey',
    'date',
).annotate(
    score=Sum('normalized_score'),
    participants=Count('user'),
).order_by(
    'survey',
    'date',
)

我省略了这个,因为它似乎对我最初的目标来说是不必要的并发症。

Also, would:

employees = Employee.objects.filter(organisation__id=organisation.id).filter(is_active=True)

Be a quicker way to fetch employees?

不,或者可能是勉强,因为本质上这就是 Django ORM 自己做的事情:它会简单地获取 organisation 的主键,然后像您描述的那样进行查询。

如果不需要organisation本身,可以查询:

employees = Employee.objects.filter(organisation_id=<b>org_pk</b>, is_active=True)

此外,例如,您可以在组织上执行 .select_related(..) [Django-doc],以在与员工相同的查询中加载 organisation 的数据,尽管减少了一个额外的查询,通常并没有太大的区别。如果 iut 导致 N+1 个查询,则性能更成问题。

例如,我们可以 "piggyback" 通过获取员工来获取 Organisation 详细信息,例如:

employees = list(
    Employee.objects.select_related('organization').filter(
        organisation_id=org_pk, is_active=True
    )
)
if employees:  # at least one employee
    organization = employees[0].organization

但是无论如何,如前所述,一两个查询之间的差异并不那么那么多。如果您有 N+1 个查询,这通常是一个更大的问题。有点可惜的是 Django/Python 似乎没有 Haxl [GitHub] 等价物,可以通过代数分析快速检索(远程)资源。

如果您对 Employee servey 结果感兴趣,您可以查询:

results = SurveyResult.objects.filter(
    <b>user__organization_id=org_pk,</b>
    created_date__range=date_range,
).annotate(
    date=TruncDate('created_date'),
).values(
    'survey',
    'date',
).annotate(
    score=Sum('normalized_score'),
    participants=Count('user'),
).order_by(
    'survey',
    'date',
)

因此,如果您不需要这些,您可以 省略 单独查询 Employee

您还可以将过滤器添加到您的查询中,例如:

<b>emp_filter = {}</b>
genders = request.GET.getlist('gender[]')
if genders:
    emp_filter['user__gender__in'] = genders

age_groups = request.GET.getlist('age_group[]')
if age_groups:
    emp_filter['user__age_group__in'] = age_groups

results = SurveyResult.objects.filter(
    user__organization_id=org_pk,
    created_date__range=date_range,
    <b>**emp_filter</b>
).annotate(
    date=TruncDate('created_date'),
).values(
    'survey',
    'date',
).annotate(
    score=Sum('normalized_score'),
    participants=Count('user'),
).order_by(
    'survey',
    'date',
)

如果您在组织和员工之间有外键关系,那么您可以像这样使用 select_related 获取员工:

employees = Employee.objects.selected_related('organisation').filter(is_active=True)

organisation = Organisation.objects.get(pk=org_id)
employees =organisation.employee_set.all() #your_employee_model_name_set.all