- Author:
- [email protected]
- Posted:
- May 5, 2010
- Language:
- Python
- Version:
- 1.1
- Score:
- 0 (after 0 ratings)
This snippet for django-1.2 allows you to use bitwise operators without using QuerySet.extra()
from django.db.models import *
from somewhere import FQ
class BitWise(Model):
type = CharField(max_length=8)
value = IntegerField()
def __unicode__(self):
return '%s - %d' % (self.type, self.value)
>>> BitWise.objects.create(type='django', value=1)
<BitWise: django - 1>
>>> BitWise.objects.create(type='osso', value=3)
<BitWise: osso - 3>
>>> BitWise.objects.create(type='osso', value=7)
<BitWise: osso - 7>
>>> BitWise.objects.filter(FQ(F('value') & 1, 'gt', 0))
[<BitWise: django - 1>, <BitWise: osso - 3>, <BitWise: osso - 7>]
>>> BitWise.objects.filter(FQ(F('value') & 2, 'gt', 0))
[<BitWise: osso - 3>, <BitWise: osso - 7>]
>>> BitWise.objects.filter(FQ(F('value') & 1, 'gt', 0) & Q(type='django'))
[<BitWise: django - 1>]
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 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | from copy import deepcopy
from django.db import models
from django.db.models.sql.expressions import SQLEvaluator
from django.utils import tree
class FExpression(object):
'''
FExpression is the simplest way to reach the code path we need
and should not inherit from tree.Node or any subclass thereof.
FExpression currently only supports the integer comparison.
Partial string comparison and such do not work because of the
way these are defined in connection.operators. For those you
should use the regular filter methods django provides.
'''
def __init__(self, left_expression, lookup_type, right_expression):
self.left_expression, self.lookup_type, self.right_expression = \
left_expression, lookup_type, right_expression
def as_sql(self, qn, connection):
cast_sql = connection.ops.lookup_cast(self.lookup_type)
field = models.Field()
# expression is either a smart expression or a user parameter
if hasattr(self.left_expression, 'as_sql'):
left_sql, left_params = self.left_expression.as_sql(qn, connection)
left_sql = cast_sql % left_sql
else:
left_sql, left_params = cast_sql, field.get_db_prep_lookup(self.lookup_type, self.left_expression, connection=connection)
# right hand side is cast by the operator sql
if hasattr(self.right_expression, 'as_sql'):
right_sql, right_params = self.right_expression.as_sql(qn, connection)
else:
right_sql, right_params = '%s', field.get_db_prep_lookup(self.lookup_type, self.right_expression, connection=connection)
format = '%%s %s' % connection.operators[self.lookup_type]
return format % (left_sql, right_sql), list(left_params) + list(right_params)
class FNode(tree.Node):
'''
FNode inherits tree.Node to pass tests for the code path we need
This allows FNode to work without using complex_filter
'''
def __init__(self, left_expression, lookup_type, right_expression):
if not lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte'):
raise ValueError('Invalid operator, operator %r is not supported.' % lookup_type)
super(FNode, self).__init__()
self.left_expression, self.lookup_type, self.right_expression = \
left_expression, lookup_type, right_expression
def __deepcopy__(self, memodict):
obj = super(FNode, self).__deepcopy__(memodict)
obj.left_expression = deepcopy(self.left_expression, memodict)
obj.right_expression = deepcopy(self.right_expression, memodict)
obj.lookup_type = self.lookup_type
return obj
def add_to_query(self, query, aliases):
# evaluate if it is a query expression
if hasattr(self.left_expression, 'evaluate'):
self.left_expression = SQLEvaluator(self.left_expression, query)
if hasattr(self.right_expression, 'evaluate'):
self.right_expression = SQLEvaluator(self.right_expression, query)
query.where.add(FExpression(self.left_expression, self.lookup_type, self.right_expression), self.connector)
def FQ(*args, **kwargs):
'''
Wrap FNode in a Q object for it's logical operators
'''
return models.Q(FNode(*args, **kwargs))
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 11 months, 2 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 11 months, 3 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 6 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 7 months ago
- Help text hyperlinks by sa2812 1 year, 7 months ago
Comments
Very nice and useful for anyone stuck on pre-1.5
However, I found you also need to implement the relabel_aliases on the FExpression, otherwise, in subqueries, the aliases will not be used and the query will not run correctly. Something like this:
#
Please login first before commenting.