2012-03-29 15 views
5

Come posso eseguire query bitwise sul DB con Django?
Non ho trovato nulla a riguardo nei documenti.
Devo recuperare un set di query e quindi filtrare programmaticamente?Come eseguire query bit a bit su DB in Django?

Se si è interessati, utilizzo le operazioni bit a bit come alternativa alle frasi IN() in query molto grandi e complesse, al fine di migliorare le prestazioni.
Ho un DB contenente milioni di elementi (record). Alcuni campi usano la rappresentazione binaria di una proprietà dell'oggetto.
Per esempio: il campo colore può avere valori multipli, quindi è strutturata in questo modo:

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

(questi sono valori binari)
Quindi, se un elemento è rosso e blu, i colori, il colori Il campo conterrà 0101.
Quando un utente esegue una query sul DB, utilizzo bitwise-OR per trovare corrispondenze (anziché IN() che è molto lento).

risposta

4

Controllare django-bitfield, funziona bene w/PostgreSQL (probabilmente anche ben MySQL)

+0

Ciao, In realtà sto usando MySQL (pensando di migrazione a MongoDB, ma non supporta bit a bit interroga ATM) – user1102018

+0

@ user1102018 Ho appena controllato il codice, dovrebbe funzionare su MySQL, perché usa normale campo intero e normale bitwise e e | che sono tutti supportati da MySQL. – okm

3

È possibile eseguire a livello di database operazioni bit per bit con F objects.

Se il campo è non negativo, significa che la condizione field & mask > 0 può essere riscritta come (field > 0) AND (field >= (field & mask)). Se si desidera verificare se tutti i bit di mask si applicano ((field & mask) == mask), è possibile creare un'espressione precedente per ogni bit e quindi unire le condizioni tramite sql AND. Si prega di vedere l'esempio come può essere fatto. (Custom QuerySet è solo per comodità.Se usi vecchie versioni di django puoi implementare has_one_of e has_all come funzioni separate o metodi di classe, o meglio PathThroughManager). Nota 1 * F è una soluzione alternativa per forzare parentesi nel corso dell'operazione bit a bit, altrimenti Django (come per la versione 1.5) produrrà male SQL (colors >= colors & mask, il confronto ha la priorità più alta, quindi vorrà dire 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() 
+0

fonte da dove l'hai imparato. o è la tua idea? –

+0

Sì, quella era la mia idea, ho trovato questa domanda mentre cercavo la soluzione, e quando finalmente l'ho implementata nel nostro progetto, sono tornata per condividere l'idea. –

6

Per postgres db si potrebbe utilizzare i parametri .extra() con django orm.

Ad esempio:

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