Django按条件过滤

时间:2018-06-02 21:51:26

标签: python django django-queryset django-orm django-filter

我有一个我想按字母顺序分页的查询集。

employees = Employee.nodes.order_by('name')

我想将员工姓名name[0]的第一个字母与我正在迭代的字母进行比较。 - 但我不知道如何根据应用于我的属性的条件进行过滤。

employees_by_letter = []      

for letter in alphabet: 
    employees_by_this_letter = employees.filter(name[0].lower()=letter)
    employees_by_letter.append(employees_by_this_letter)

  """error -- SyntaxError: keyword can't be an expression"""

我想我可以遍历每个员工对象并为他们的第一个字母添加一个值......但必须有更好的方法。

1 个答案:

答案 0 :(得分:4)

这是Python,在Python中,参数名称是标识符。你不能在其中删除某种表达。

然而,Django有一些方法可以进行高级过滤。在您的情况下,您想使用__istartswith过滤器:

employees_by_letter = [
    employees.filter(name__istartswith=letter)
    for letter in alphabet
]

这是一个列表推导,它将生成每个letter in alphabet,相应的查询集在列表中。

但请注意,由于您最终将获取每个元素,因此我实际上建议迭代(或执行groupby)。

像:

from django.db.models.functions import Lower
fromiteratools import groupby

employees_by_letter = {
    k: list(v)
    for k, v in groupby(
        Employee.annotate(lowname=Lower('name')).nodes.order_by('lowname'),
        lambda x: x.lowname[:1]
    )
}

这将构造一个字典,其中包含小写字母作为键(或者如果存在具有空名称的字符串,则为空字符串),这些都映射到Employee个实例的列表:Employee名称以该字母开头的名称。这意味着我们只对数据库执行一次查询。但是Django查询集是懒惰的,所以如果你打算只提取一些查询集,那么前者可以更高效。