Đây là một câu hỏi cũ, nhưng tôi nghĩ tôi sẽ cho thấy làm thế nào nó có thể được thực hiện hợp lý đơn giản chỉ trong Django.
Đây là một lớp helper để chuẩn bị lựa chọn của bạn:
class BitChoices(object):
def __init__(self, choices):
self._choices = []
self._lookup = {}
for index, (key, val) in enumerate(choices):
index = 2**index
self._choices.append((index, val))
self._lookup[key] = index
def __iter__(self):
return iter(self._choices)
def __len__(self):
return len(self._choices)
def __getattr__(self, attr):
try:
return self._lookup[attr]
except KeyError:
raise AttributeError(attr)
def get_selected_keys(self, selection):
""" Return a list of keys for the given selection """
return [ k for k,b in self._lookup.iteritems() if b & selection]
def get_selected_values(self, selection):
""" Return a list of values for the given selection """
return [ v for b,v in self._choices if b & selection]
Xác định mô hình của bạn với một PositiveIntegerField, và các lựa chọn bạn muốn:
WEEKDAYS = BitChoices((('mon', 'Monday'), ('tue', 'Tuesday'), ('wed', 'Wednesday'),
('thu', 'Thursday'), ('fri', 'Friday'), ('sat', 'Saturday'),
('sun', 'Sunday')
))
Điều này có nghĩa bạn có thể truy cập vào các giá trị như này:
>>> print list(WEEKDAYS)
[(1, 'Monday'), (2, 'Tuesday'), (4, 'Wednesday'), (8, 'Thursday'), (16, 'Friday'), (32, 'Saturday'), (64, 'Sunday')]
>>> print WEEKDAYS.fri
16
>>> print WEEKDAYS.get_selected_values(52)
['Wednesday', 'Friday', 'Saturday']
Bây giờ hãy xác định mô hình của bạn với PositiveIntegerField
và các lựa chọn này:
class Entry(models.Model):
weekdays = models.PositiveIntegerField(choices=WEEKDAYS)
Và các mô hình của bạn đã hoàn tất. Đối với các truy vấn, sau đây hiện các trick:
Entry.objects.extra(where=["weekdays & %s"], params=[WEEKDAYS.fri])
Có thể có một cách để tạo một lớp con Q()
đối tượng mà gọn gàng gói truy vấn, vì vậy họ trông như thế này:
Entry.objects.filter(HasBit('weekdays', WEEKDAYS.fri))
Hoặc thậm chí Hack tại một F()
lớp con để tạo ra một cái gì đó như thế này:
Entry.objects.filter(weekdays=HasBit(WEEKDAYS.fri))
Nhưng tôi không có thời gian để khám phá rằng vào lúc này. .where
hoạt động tốt và có thể được tóm tắt thành một hàm queryset.
Một xem xét cuối cùng là bạn có thể ánh sáng để tạo trường mô hình tùy chỉnh chuyển đổi mặt nạ bit trong cơ sở dữ liệu thành danh sách hoặc được đặt bằng Python. Sau đó, bạn có thể sử dụng tiện ích SelectMultiple
(hoặc CheckboxSelectMultiple
) để cho phép người dùng chọn giá trị của họ trong quản trị viên.
Nếu không có thêm thông tin (kích thước của tập dữ liệu, chủ yếu là đọc vs chủ yếu là viết, vv) đi với bitfields cảm thấy như sợ hãi sớm tối ưu hóa. –
Tôi sẽ thêm thông tin bổ sung cho câu hỏi. Cảm ơn ngài Rowell. –
Bạn có cân nhắc việc thêm mối quan hệ nhiều đến nhiều giữa một mô hình 'Weekday' và mô hình được đề cập không? Tôi biết đây là một chút của một overkill xem xét rằng các ngày trong tuần được cố định về số lượng, nhưng nó sẽ làm cho lọc rất đơn giản. –