django的ORM中是否存在包含过滤器?

时间:2014-09-02 08:56:40

标签: django django-models django-orm

我可以按此类条件过滤查询吗?像

这样的东西
Model.objects.filter(department__is_contained=x).values_list('department')

其中

 x = 'AAA-BBB-CCC-DDD'

我的结果应该显示

之类的内容
 ['AAA', 'AAA-BBB-CCC', 'BBB-CCC', 'AAA-BBB-CCC-DDD', None]

2 个答案:

答案 0 :(得分:1)

不,没有。您想要执行的SQL看起来像这样:

SELECT *
FROM model
WHERE 'AAA-BBB-CCC-DDD' like '%' + model.department + '%'

Django目前不支持左侧的过滤条件。可以使用custom lookups使用django 1.7实现自己的reverse_contains查找。

class ReverseContains(Lookup):
    lookup_name = 'rcontains'

    def as_sql(self, qn, connection):
        # untested! you'll have to validate this
        lhs, lhs_params = self.process_lhs(qn, connection)
        rhs, rhs_params = self.process_rhs(qn, connection)
        # note we're putting the rhs sql and params on the lhs
        params = rhs_params + lhs_params
        return "%s LIKE '%%' + %s + '%%' " % (rhs, lhs), params

from django.db.models.fields import CharField
CharField.register_lookup(ReverseContains)

并像这样使用它:

x = 'AAA-BBB-CCC-DDD'
Model.objects.filter(department__rcontains=x).values_list('department')

或者您可以使用.extra(where=)直接在SQL中为该一个查询实现搜索。

答案 1 :(得分:0)

这是一个单线解决方案:

import operator
from django.db.models import Q

x = 'AAA-BBB-CCC-DDD'
User.objects.filter(reduce(operator.or_, (Q(department__contains=y) for y in x.split('-')))).values_list('department', flat=True)

# Result will be list of 'department' fields, that contains
# "AAA" or "BBB" or "CCC" or "DDD"

可能很难理解,所以这里有一个更详细的代码变体:

total_filter_q = Q()
for y in x.split("-"):
    total_filter_q |= Q(department__contains=y)

# total_filter_q now represent this:
# Q(department__contains="AAA") | Q(department__contains="BBB") | Q(department__contains="CCC") | Q(department__contains="DDD")

User.objects.filter(total_filter_q).values_list('department', flat=True)

结果与单行解决方案相同。

以下是一些有用的链接: