2012-03-29 30 views
5

DB'de Django ile bitsel sorguları nasıl yapabilirim?
Dokümanlardaki hiçbir şeyi bulamadım.
Bir queryset'i almalı ve daha sonra programa filtre uygulamalı mıyım?Django'da DB bit sorgular nasıl gerçekleştirilir?

Performansı geliştirmek için, çok büyük ve karmaşık sorgularda IN() ifadelerine alternatif olarak bitsel olarak ops kullanıyorum.
Milyonlarca öğeyi içeren bir veritabanım var (kayıtlar). Bazı alanlar bir öğe özelliğinin ikili temsilini kullanır. Örneğin
: Renk alanında birden fazla değere sahip olabilir, bu yüzden bu kadar gibi yapılandırılmıştır:

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

(bu ikili değerlerdir)
bir öğe Kırmızı ve Mavi renkleri, Renk işareti olduğunda alanında 0101 bulunur.
Bir kullanıcı DB'yi sorgularsa, eşleşmeleri bulmak için bitwise-OR kullanın (çok yavaş olan IN() yerine).

cevap

4

Kontrol django-bitfield, iyi PostgreSQL (muhtemelen de iyi MySQL)

+0

Merhaba, ben aslında MySQL (MongoDB göç düşünme, ancak bitsel ATM sorgular desteklemez) kullanıyorum Ben sadece kod kontrol ettim – user1102018

+0

user1102018 @ MySQL üzerinde çalışmalı, çünkü normal tamsayı alanı ve normal bit ve & | hepsi MySQL tarafından desteklenmektedir. – okm

3

w/Sen F objects ile veritabanı düzey bit düzeyinde işlemler gerçekleştirebilir çalışır.

Alan negatif değilse, field & mask > 0 koşulunun (field > 0) AND (field >= (field & mask)) olarak yeniden yazılabileceği anlamına gelir. mask tüm bitlerinin ((field & mask) == mask) geçerli olup olmadığını kontrol etmek isterseniz, her bit için bir önceki ifadeyi oluşturabilir ve daha sonra koşulları AND sql aracılığıyla bir araya getirebilirsiniz. Lütfen örnek nasıl yapılabilir? (Özel QuerySet sadece kolaylık içindir. Eski django sürümlerini kullanırsanız, has_one_of ve has_all'u ayrı işlevler veya sınıf yöntemleri veya daha iyi PathThroughManager) uygulayabilirsiniz.

Postgres'e için
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

kaynak nereden öğrendiniz. ya da kendi fikrin mi? –

+0

Evet, bu benim kendi fikrimdi, çözüm ararken bu soruyu buldum ve sonunda projemize uyguladığımda, fikri paylaşmak için geri döndüm. –

6

öldürürsün db kötü sql üretecek aksi (sürüm 1.5 gibi) django, 1 * F bit düzeyinde işlem üzerinde parantez zorlamak için bir çözüm olduğunu unutmayın (colors >= colors & mask, karşılaştırma yüksek önceliğe sahiptir, bu nedenle TRUE & mask anlamına gelecektir) django orm ile .extra() params kullanın. Örneğin

: bunu

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