Puede llevar a cabo a nivel de base de datos de operaciones bit a bit con F objects.
Si el campo no es negativo, significa que la condición field & mask > 0
se puede volver a escribir como (field > 0) AND (field >= (field & mask))
. Si desea verificar si se aplican todos los bits de mask
((field & mask) == mask
), puede compilar la expresión previa para cada bit y luego combinar las condiciones a través de sql AND
. Por favor, vea ejemplos de cómo se puede hacer. (Custom QuerySet es solo por conveniencia. Si utiliza versiones antiguas de django puede implementar has_one_of
y has_all
como funciones separadas o classmethods, o mejor PathThroughManager). Nota 1 * F
es una solución alternativa a la fuerza entre paréntesis durante la operación bit a bit, de lo contrario django (como para la versión 1.5) producirá mala SQL (colors >= colors & mask
, la comparación tiene mayor prioridad, por lo que significará 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()
Hola, soy en realidad el uso de MySQL (pensando en migrar a MongoDB, pero no soporta bit a bit consulta ATM) – user1102018
@ user1102018 que he acabo de comprobar el código, debería funcionar en MySQL, porque usa el campo entero normal y el bit a bit normal y | todos son compatibles con MySQL. – okm