można wykonać na poziomie bazy danych operacje bitowe z F objects.
Jeśli pole jest nieujemne, oznacza to, że stan field & mask > 0
można ponownie napisać pod numerem . Jeśli chcesz sprawdzić, czy wszystkie bity z mask
mają zastosowanie ((field & mask) == mask
), możesz zbudować poprzednie wyrażenie dla każdego bitu, a następnie scalić warunki przez sql AND
. Zobacz przykład, jak to zrobić. (Custom QuerySet ma zastosowanie tylko dla wygody. Jeśli używasz starych wersji django, możesz implementować has_one_of
i has_all
jako oddzielne funkcje lub metody klas, lub lepiej PathThroughManager). Uwaga 1 * F
jest obejście zmusić nawias nad operacji bitowej, w przeciwnym razie django (jak dla wersji 1.5) będzie produkować złe SQL (colors >= colors & mask
, porównanie ma wyższy priorytet, więc będzie to oznaczać 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()
Cześć, jestem rzeczywiście przy MySQL (myślenie o migracji do MongoDB, ale nie obsługuje bitowe odpytuje ATM) – user1102018
@ user1102018 Właśnie sprawdziłem kodu, powinien działać na MySQL, ponieważ używa normalnego pola liczb całkowitych i zwykłego bitowego & i | które są obsługiwane przez MySQL. – okm