Django:从查询集中删除过滤条件
Posted
技术标签:
【中文标题】Django:从查询集中删除过滤条件【英文标题】:Django: remove a filter condition from a queryset 【发布时间】:2011-06-09 00:59:54 【问题描述】:我有一个第三方函数,它给我一个过滤的查询集(例如,'valid'=True 的记录),但我想删除一个特定条件(例如,让所有记录,包括有效和无效)。
有没有办法将过滤条件删除到已过滤的查询集中?
例如
only_valid = MyModel.objects.filter(valid=True)
all_records = only_valid.**remove_filter**('valid')
(我知道在'only_valid'之前定义'all_records'会更好,但这只是一个例子......)
【问题讨论】:
你能展示一下代码示例吗? 【参考方案1】:虽然没有使用过滤器符号的官方方法来做到这一点,但您可以使用Q-notation 轻松做到这一点。 例如,如果您确保第三方函数返回的是 Q 对象,而不是过滤后的 QuerySet,则可以执行以下操作:
q = ThirdParty()
q = q | Q(valid=False)
生成的 SQL 条件将使用 OR 运算符连接。
【讨论】:
您将需要访问第三方代码,但是是的,这是一个很好的解决方案。 +1【参考方案2】:使用此功能
from django.db.models import Q
def remove_filter(lookup, queryset):
"""
Remove filter lookup in queryset
```
>>> queryset = User.objects.filter(email='user@gmail.com')
>>> queryset.count()
1
>>> remove_filter('email', queryset)
>>> queryset.count()
1000
```
"""
query = queryset.query
q = Q(**lookup: None)
clause, _ = self._add_q(q, self.used_aliases)
def filter_lookups(child):
return child.lhs.target != clause.children[0].lhs.target
query.where.children = list(filter(filter_lookups, query.where.children))
【讨论】:
自己应该被查询【参考方案3】:来自the docs:
每次优化 QuerySet 时,都会得到一个全新的 QuerySet,它绝不会绑定到之前的 QuerySet。每个细化都会创建一个单独且不同的 QuerySet,可以存储、使用和重用。
因此,我怀疑是否有一种标准的方法可以做到这一点。你可以dig into the code,看看filter()
做了什么,然后尝试一下。如果这没有帮助,我的假设是,你运气不好,需要自己重新构建查询。
【讨论】:
【参考方案4】:这是我在类似案例中所做的。
all_records = MyModel.objects.all()
only_valid = MyModel.objects.filter(valid=True)
only_valid.original = all_records
...
all_records = only_valid.original
显然,这也会清除任何其他过滤器,因此并非适用于所有情况。
【讨论】:
【参考方案5】:original_query_set = MyModel.objects.filter(**conditions)
model_class = orginal_query_set.model
new_query_set = model_class.objects.filter(**new_conditions)
您可以使用 QuerySet 上的 .model 属性来获取模型类,然后使用模型类创建一个全新的 QuerySet。
【讨论】:
请考虑解释为什么您的代码解决了操作的问题【参考方案6】:感谢您让我检查 Boldewyn 的源代码。因此,似乎在 filter() 下方有一个具有相同参数的新方法...称为 exclude() (从提交 mini-hash ef6c680 开始,当它丢失行号时)
返回一个新的 QuerySet 实例,用 NOT (args) ANDed 到现有集合。
所以,回答原来的问题:
only_valid = MyModel.objects.filter(valid=True)
filtered_results = only_valid.exclude(the_condition_to_remove=True)
【讨论】:
exclude
只是添加另一个过滤器,保留现有的过滤器。它不会恢复完整的查询集。
哦,我明白了!我当时误解了这个问题。感谢您清除它:)以上是关于Django:从查询集中删除过滤条件的主要内容,如果未能解决你的问题,请参考以下文章
Django:在查询集中过滤 get_foo_display