这是一个老问题,但我想我会展示如何在 Django 中合理简单地完成它。
这是一个帮助您准备选择的辅助类:
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]
使用 PositiveIntegerField 定义您的模型,以及您想要的选择:
WEEKDAYS = BitChoices((('mon', 'Monday'), ('tue', 'Tuesday'), ('wed', 'Wednesday'),
('thu', 'Thursday'), ('fri', 'Friday'), ('sat', 'Saturday'),
('sun', 'Sunday')
))
这意味着您可以像这样访问这些值:
>>> 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']
现在定义你的模型PositiveIntegerField
以及这些选择:
class Entry(models.Model):
weekdays = models.PositiveIntegerField(choices=WEEKDAYS)
你的模型就完成了。对于查询,可以使用以下方法:
Entry.objects.extra(where=["weekdays & %s"], params=[WEEKDAYS.fri])
可能有一种方法可以创建Q()
object 子类巧妙地封装了查询,因此它们看起来像这样:
Entry.objects.filter(HasBit('weekdays', WEEKDAYS.fri))
或者甚至黑客攻击F()
子类来创建这样的东西:
Entry.objects.filter(weekdays=HasBit(WEEKDAYS.fri))
但我现在没有时间去探索这个。.where
工作正常并且可以抽象为查询集函数。
最后一个考虑因素是,您可能会创建一个自定义模型字段,将数据库中的位掩码转换为 Python 中的列表或集合。然后你可以使用SelectMultiple
小部件(或CheckboxSelectMultiple
)以允许用户在管理中选择他们的值。