Login

Remove a clause from a queryset

Author:
wahuneke
Posted:
July 16, 2015
Language:
Python
Version:
1.6
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

  1. Template tag - list punctuation for a list of items by shapiromatron 10 months, 1 week ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 2 weeks ago
  3. Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
  5. Help text hyperlinks by sa2812 1 year, 6 months ago

Comments

pyarun (on January 14, 2020):

This is good, but will not work from djang0 >= 1.9.0

#

Please login first before commenting.