如何在Django中执行DB按位查询?

时间:2012-03-29 07:51:43

标签: django bit-manipulation

如何使用Django对数据库执行按位查询?
我在文档中找不到任何关于它的内容 我应该检索一个查询集然后以编程方式过滤吗?

如果您有兴趣,我会在非常大且复杂的查询中使用按位操作替代 IN()语句,以提高性能。
我有一个包含数百万项(记录)的数据库。某些字段使用项属性的二进制表示 例如:颜色字段可以有多个值,因此结构如下:

0001 - Red
0010 - Green
0100 - Blue
1000 - White

(这些是二进制值)
因此,如果项目具有红色和蓝色,则颜色字段将包含0101 当用户查询数据库时,我使用按位或来查找匹配(而不是 IN(),这非常慢。)

4 个答案:

答案 0 :(得分:6)

对于postgres数据库,您可以使用.extra()参数与django orm。

例如:

SomeModel.objects.extra(where=['brand_label & 3 = 3'])

答案 1 :(得分:5)

您可以使用F objects执行数据库级按位操作。

如果字段为非否定字,则表示条件field & mask > 0可以重写为(field > 0) AND (field >= (field & mask))。如果要检查mask的所有位是否都适用((field & mask) == mask),则可以为每个位构建先前的表达式,然后通过sql AND合并条件。请参阅示例如何完成。 (自定义QuerySet只是为了方便。如果您使用旧的Django版本,您可以将has_one_ofhas_all实现为单独的函数或类方法,或者更好PathThroughManager)。注意1 * F是一种强制括号操作的解决方法,否则django(对于版本1.5)将产生错误的sql(colors >= colors & mask,比较具有更高的优先级,因此它将意味着TRUE & mask

import operator
from django.db import models
from django.db.models import Q, F

_bit = lambda x: 2**(x-1)
RED = _bit(1)
GREEN = _bit(2)
BLUE = _bit(3)
WHITE = _bit(4)


class ItemColorsQuerySet(models.QuerySet):

    def has_one_of(self, colors):
        """
            Only those that has at least one of provided colors
        """
        return self.filter(
            colors__gt=0,
            # field value contains one of supplied color bits
            colors__gte=1 * F('colors').bitand(reduce(operator.or_, colors, 0))
        )

    def has_all(self, colors):
        """
            Has all provided colors (and probably others)
        """
        # filter conditions for all supplied colors: 
        # each one is "field value has bit that represents color"
        colors_q = map(lambda c: Q(colors__gte=1 * F('colors').bitand(c)), colors)
        # one complex Q object merged via sql AND:
        # colors>0 and all color-bit conditions
        filter_q = reduce(operator.and_, colors_q, Q(colors__gt=0))
        return self.filter(filter_q)


class Item(models.Model):

    name = models.CharField(max_length=100, unique=True)
    # can handle many colors using bitwise logic. Zero means no color is set.
    colors = models.PositiveIntegerField(default=0)

    objects = ItemColorsQuerySet.as_manager()

答案 2 :(得分:4)

检查django-bitfield,它适用于PostgreSQL(可能还有MySQL)

答案 3 :(得分:2)

@Ivan Klass

您可以使用django orm F中的bitandbitor

# filter Red and Blue(0101)
Color.objects.annotate(
  color_filter=F('color').bitand(0101)
).filter(color_filter__gte=0101)

 # filter Red or Blue(0101)
Color.objects.annotate(
  color_filter=F('color').bitand(0101)
).filter(color_filter__gt=0)