Django如何动态选择__gt和__range

1 投票
2 回答
521 浏览
提问于 2025-04-18 03:53

我在我的一个Django模板里有一个HTML表单,用户可以选择一个对象的价格范围和它的实际价值范围,但这不是必选项。

<select name="minimum_price">
    <option value="1">1</option>
    <option value="2">2</option>
</select>

<select name="maximum_price">
    <option value="1">1</option>
    <option value="2">2</option>
</select>

<select name="min_real_value">
    <option value="1">1</option>
    <option value="2">2</option>
</select>

<select name="max_real_value">
    <option value="1">1</option>
    <option value="2">2</option>
</select>

为了这个问题,我看了大部分Django的文档,包括一篇很有启发性的文章:Q类。不过我还没弄明白如何根据用户从这四个选择框中选择的任意组合,动态构建一个查询。

真正的问题出现在,当Django的__range需要被替换成__gt__lt时,这种情况发生在每个“类别”的选择框中只选择了一个。

这是我到目前为止所做的:

myList = MyObjectsCost.objects.filter(price__range=(minimum_price, maximum_price),
                                   real_value__range=(min_real_value, max_real_value),
                                   **kwargs)

但是如果这四个变量中有一个缺失,这个方法就会失败……

提前谢谢你。

2 个回答

1

这里你可以用一些巧妙的方法来处理kwargs,但其实更简单的办法是直接理解range其实就是gtlt的组合。所以你可以动态地构建查询:

my_list = MyObjectsCost.objects.all()
if minimum_price:
    my_list.filter(price__gt=minimum_price)
if maximum_price:
    my_list.filter(price__lt=maximum_price)
if min_real_value:
    my_list.filter(real_value__gt=min_real_value)
if max_real_value:
    my_list.filter(real_value__lt=max_real_value)
1

丹尼尔·罗斯曼提到的“聪明”的方法,是通过字符串来构建过滤器,对吧?

大概是这样的:

method = MyObjectsCost.objects.filter
qs = method(**{'%s__%s' % (field_name, lookup_type): value})

根据你的具体情况提供合适的值,你可以构建出类似这样的东西:

field_name = 'real_value'
lookup_type = 'gt'
value = 'min_real_value'

这会生成一个像'real_value__gt=min_real_value'这样的字符串,然后把它传递给过滤方法。这样你就可以根据字符串来创建过滤器。这种方法可能会很有用,但也可能导致代码变得很丑陋和复杂。所以要谨慎使用,不过这个概念可以帮助你构建过滤器。

如果你喜欢使用第三方应用,可以看看 https://github.com/alex/django-filter,它也能让你的过滤器更灵活。

但永远不要忘记保持简单。

撰写回答