Django:如何在Q()语句中使用字符串作为关键字?

15 投票
2 回答
13222 浏览
提问于 2025-04-17 06:24

我正在为一个特定的模型写一个简单的搜索表单。我们把这个模型叫做 Orchard,它有一些属性,比如 apples(苹果)、oranges(橙子)和 pears(梨子),这样方便演示。

这个表单不要求所有字段都必须填写。也就是说,你可以只搜索 applesoranges,而不填 pears。我需要这样来过滤数据:

Orchard.objects.filter(apples=request.GET.get('apples'), oranges=request.GET.get('oranges'), pears=request.GET.get('pears'))

但是如果 pears 这个字段是空的,就永远不会有结果返回。

我最初的想法是使用 Q 对象,类似这样:

from django.db.models import Q

options = {}
options['apples'] = request.GET.get('apples')
options['oranges'] = request.GET.get('oranges')
options['pears'] = request.GET.get('pears')

queries = None

for key in options:
    if options[key] != u'':
        if queries:
            queries &= Q(key=options[key]) # <=== problem here
        else:
            queries = Q(key=options[key])  # <=== same problem here

results = Orchard.objects.filter(queries)

问题出现在那些标记的行上。我显然不能直接用“key”作为属性的关键词,因为它不接受字符串,而是需要一个变量。

那么……我该怎么解决这个问题呢?

除非有其他已知的解决方案,不涉及 Q 的方法,那样也会很有帮助。

2 个回答

4

@second的回答是对的,可以用**这个操作符来解包字典,从而提供关键字参数。

不过,如果你只是用AND来组合Q对象,而不是OR,那么在你的例子中其实不需要使用Q对象。你只需要构建一个包含查找条件的字典,然后把这个字典作为filter的关键字参数使用就可以了。

options = {}
for key in ('apples', 'oranges', 'pears'):
    value = request.GET.get(key)
    if value:
        options[key] = value
results = Orchard.objects.filter(**options)
28

这是一个常见的问题,当你在使用变量作为关键字参数的键时。解决这个问题的方法是把内容放在一个字典里,然后再展开它:

queries &= Q(**{key: options[key]})

或者在你的情况下

for option in options:
    if options[option] is None:
        del(options[option])
# or otherwise only add the ones you actually want to filter on
# then
results = Orchard.objects.filter(**options)

撰写回答