Login

Remove a clause from a queryset

Author:
wahuneke
Posted:
July 16, 2015
Language:
Python
Version:
1.6
Tags:
hack orm manager mixin queryset
Score:
0 (after 0 ratings)

I want to create Mixins for QuerySet objects that will by default filter out certain records (e.g. filter out "deleted" records, or filter out "unapproved" records, etc). I'd like those to be separate independent mixins. So in each of those, I override all() to filter out deleted or unapproved, etc. But, I also want to offer a method in the queryset to remove those filters or remove some part of those filters.

That's where this code comes in. After some examination of how QuerySets work, this seemed like the simplest method for "undoing" some filter in a queryset

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
"""
Use this hack to remove a where clause from a queryset

It assumes the following internals:

QuerySet has something called a query
query has something called a 'where' which is a tree root
that tree root is of type WhereNode and has connector 'OR' or 'AND' and some number of children
each child can be a simple clause (Constraint) or another WhereNode with a bunch of kids of its own
"""
from django.db.models.sql.where import *

__all__ = ['remove_clause', ]


def remove_clause(queryset, field_name):
    # Start the recursive fixin'
    _remove_clause(queryset.query.where, field_name)


def _remove_clause(node, field_name):
    if isinstance(node, WhereNode):
        null_these = []
        # look at each child and treat appropriately
        for i, child in enumerate(node.children):
            if isinstance(child, WhereNode):
                _remove_clause(child, field_name)
            elif isinstance(child, tuple) and isinstance(child[0], Constraint):
                if child[0].field.name == field_name:
                    null_these.append(i)

        # we have some children to "nullify"
        for null_this in null_these:
            if node.connector == 'AND':
                node.children[null_this] = EverythingNode()
            else:
                node.children[null_this] = NothingNode()

More like this

Comments

Please login first before commenting.