2012-03-29 45 views
5

Làm cách nào tôi có thể thực hiện các truy vấn bitwise trên DB bằng Django?
Tôi chưa tìm thấy bất kỳ điều gì về nó trong tài liệu.
Tôi có nên truy xuất bộ truy vấn và sau đó lọc theo chương trình không?Làm thế nào để thực hiện các truy vấn bitwise DB trong Django?

Nếu bạn quan tâm, tôi sử dụng bit ops thay thế cho câu hỏi IN() trong các truy vấn rất lớn và phức tạp, để cải thiện hiệu suất.
Tôi có một DB chứa hàng triệu mặt hàng (hồ sơ). Một số trường sử dụng biểu diễn nhị phân của một thuộc tính mục.
Ví dụ: các Màu lĩnh vực có thể có nhiều giá trị, vì vậy nó được cấu trúc như vậy:

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

(đây là những giá trị nhị phân)
Vì vậy, nếu một mục có màu đỏ và màu xanh, các Màu Trường sẽ chứa 0101.
Khi người dùng truy vấn DB, tôi sử dụng bitwise-OR để tìm các kết quả phù hợp (thay vì IN() rất chậm).

Trả lời

4

Kiểm tra django-bitfield, nó hoạt động tốt w/PostgreSQL (có lẽ cũng tốt MySQL)

+0

Hi, Tôi đang thực sự sử dụng MySQL (suy nghĩ của di cư đến MongoDB, nhưng nó không hỗ trợ Bitwise truy vấn ATM) – user1102018

+0

@ user1102018 Tôi vừa mới kiểm tra mã, nó nên làm việc trên MySQL, bởi vì nó sử dụng trường số nguyên bình thường và bitwise bình thường & và | tất cả đều được hỗ trợ bởi MySQL. – okm

3

Bạn có thể thực hiện cơ sở dữ liệu cấp hoạt động Bitwise với F objects.

Nếu trường không âm, điều đó có nghĩa là điều kiện field & mask > 0 có thể được viết lại là (field > 0) AND (field >= (field & mask)). Nếu bạn muốn kiểm tra xem tất cả các bit của mask có áp dụng ((field & mask) == mask) hay không, bạn có thể tạo biểu thức trước đó cho từng bit và sau đó hợp nhất các điều kiện thông qua sql AND. Xin vui lòng xem ví dụ làm thế nào nó có thể được thực hiện. (Custom QuerySet chỉ để thuận tiện. Nếu bạn sử dụng phiên bản django cũ, bạn có thể thực hiện has_one_ofhas_all làm các hàm riêng biệt hoặc các phép đo lớp, hoặc tốt hơn PathThroughManager). Lưu ý 1 * F là một cách giải quyết để buộc ngoặc đối với hoạt động Bitwise, nếu không django (như đối với phiên bản 1.5) sẽ sản xuất sql xấu (colors >= colors & mask, so sánh có ưu tiên cao hơn, vì vậy nó sẽ có nghĩa 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

nguồn nơi bạn học được. hoặc đó là ý tưởng của riêng bạn? –

+0

Vâng, đó là ý tưởng của riêng tôi, tôi tìm thấy câu hỏi này trong khi tìm kiếm giải pháp, và khi tôi cuối cùng đã thực hiện nó trong dự án của chúng tôi, chỉ cần quay trở lại để chia sẻ ý tưởng. –

6

Đối postgres db có lẽ bạn sử dụng thông số .extra() với django orm.

Ví dụ:

SomeModel.objects.extra(where=['brand_label & 3 = 3']) 
Các vấn đề liên quan