Django:从查询集中删除过滤条件

发布于 2024-10-11 16:26:54 字数 308 浏览 4 评论 0原文

我有一个第三方函数,它为我提供了一个过滤查询集(例如“valid”=True 的记录),但我想删除特定条件(例如,拥有所有记录,包括有效的和无效的)。

有没有办法删除已过滤查询集的过滤条件?

例如

only_valid = MyModel.objects.filter(valid=True)
all_records = only_valid.**remove_filter**('valid')

(我知道最好在“only_valid”之前定义“all_records”,但这只是一个例子......)

I have a third-party function which gives me a filtered queryset (e.g. records with 'valid'=True) but I want to remove a particular condition (e.g. to have all records, both valid and invalid).

Is there a way to remove a filter condition to an already-filtered queryset?

E.g.

only_valid = MyModel.objects.filter(valid=True)
all_records = only_valid.**remove_filter**('valid')

(I know that it would be better to define 'all_records' before 'only_valid', but this is just an example...)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

揪着可爱 2024-10-18 16:26:54

尽管没有官方方法可以使用过滤器表示法来执行此操作,但您可以使用 Q - 表示法。
例如,如果您确保第三方函数返回 Q 对象,而不是过滤后的 QuerySet,您可以执行以下操作:

q = ThirdParty()
q = q | Q(valid=False)

并且生成的 SQL 条件将使用 OR 运算符连接。

Although there is no official way to do this using filter notation, you may easily do it with Q-notation.
For example, if you ensure that third-part function returns a Q object, not a filtered QuerySet, you may do the following:

q = ThirdParty()
q = q | Q(valid=False)

And the resulting SQL conditions will be joined using OR operator.

最终幸福 2024-10-18 16:26:54

来自文档

每次优化 QuerySet 时,您都会获得一个全新的 QuerySet,它与之前的 QuerySet 没有任何关系。每个细化都会创建一个单独且不同的查询集,可以存储、使用和重用。

因此,我怀疑是否有一种标准方法可以做到这一点。您可以深入研究代码,看看 filter() 做了什么并尝试一下。如果这没有帮助,我的假设是,你运气不好,需要自己重新构建查询。

From the docs:

Each time you refine a QuerySet, you get a brand-new QuerySet that is in no way bound to the previous QuerySet. Each refinement creates a separate and distinct QuerySet that can be stored, used and reused.

I doubt therefore, that there is a standard way to do it. You could dig into the code, see, what filter() does and try a bit. If that doesn't help, my assumption is, you're out of luck and need to re-build the query yourself.

仅此而已 2024-10-18 16:26:54

使用此功能

from django.db.models import Q

def remove_filter(lookup, queryset):
    """
    Remove filter lookup in queryset
    ```
    >>> queryset = User.objects.filter(email='[email protected]')
    >>> queryset.count()
    1
    >>> remove_filter('email', queryset)
    >>> queryset.count()
    1000
    ```
    """
    query = queryset.query
    q = Q(**{lookup: None})
    clause, _ = query._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))

Use this function

from django.db.models import Q

def remove_filter(lookup, queryset):
    """
    Remove filter lookup in queryset
    ```
    >>> queryset = User.objects.filter(email='[email protected]')
    >>> queryset.count()
    1
    >>> remove_filter('email', queryset)
    >>> queryset.count()
    1000
    ```
    """
    query = queryset.query
    q = Q(**{lookup: None})
    clause, _ = query._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))
错爱 2024-10-18 16:26:54

这是我在类似案例中所做的。

all_records = MyModel.objects.all()
only_valid = MyModel.objects.filter(valid=True)
only_valid.original = all_records

...

all_records = only_valid.original

显然,这也会清除任何其他过滤器,因此它并不适合所有情况。

Here's what I did in a similar case.

all_records = MyModel.objects.all()
only_valid = MyModel.objects.filter(valid=True)
only_valid.original = all_records

...

all_records = only_valid.original

Obviously this clears any other filters too so it won't be right for every case.

没︽人懂的悲伤 2024-10-18 16:26:54
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。

original_query_set = MyModel.objects.filter(**conditions)
model_class = orginal_query_set.model
new_query_set = model_class.objects.filter(**new_conditions)

You can use the .model attribute on a QuerySet to get the model class, then use the model class to make a brand new QuerySet.

时光无声 2024-10-18 16:26:54

感谢您让我检查 Boldewyn 的源代码。所以,似乎有一个新的方法就在filter()下面,具有相同的参数...称为exclude() (从提交迷你散列 ef6c680 开始,当它丢失行号时)

返回一个新的 QuerySet 实例,并与现有集合进行 NOT (args) AND 运算。

因此,回答原来的问题:

only_valid = MyModel.objects.filter(valid=True)
filtered_results = only_valid.exclude(the_condition_to_remove=True)

Thanks for making me check the source code Boldewyn. So, it seems there's a new method right below filter() with the same parameters... called exclude() (as of commit mini-hash ef6c680, for when it loses its line number)

Return a new QuerySet instance with NOT (args) ANDed to the existing set.

So, to answer the original question:

only_valid = MyModel.objects.filter(valid=True)
filtered_results = only_valid.exclude(the_condition_to_remove=True)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文