在Django模型中表示平日的多选字段 [英] Representing a multi-select field for weekdays in a Django model
问题描述
我一直在寻找一种优雅的方式来代表Django模式中的多选工作日(周一,周二,周三...)。我最初考虑使用逐位数学去整数字段,但我不知道这是否会是这样的方式。
这将是一个大多读取的字段。我想要的Queryset方法就像 Entry.objects.get(weekdays__contains = MONDAY)
其中 MONDAY
将是一个常数。
也许有人可以提出一个更好的解决方案?或者也许有人做了类似的事情,并提供了一些可以贡献的示例代码?
这是一个旧问题,我会显示如何在Django中合理地完成。
这是一个帮助类,用于准备您的选择:
self._lookup = {}
self._lookup = {} {pre>
class BitChoices(object):
def __init __(self,choices):
self._choices =
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]
除了KeyError:
提高AttributeError(attr)
def get_selected_keys(self,selection):
返回一个用于给定选择的键
return [k for k,b in self._lookup.iteritems()if b&选择]
def get_selected_values(self,selection):
返回给定选择的值列表
return [v for b,v in self如果b&选择]
使用PositiveIntegerField定义您的模型,以及您想要的选择:
WEEKDAYS = BitChoices((('mon','Monday'),('tue','Tuesday'),('wed'星期三),
('thu','星期四'),('星期五','星期五'),('sat','星期六'),
)
))
这意味着你可以访问这样的值:
>>>打印列表(WEEKDAYS)
[(1,'星期一)',(2,'星期二'),(4,'星期三'),(8,'星期四'),(16,'星期五'), (32,'星期六'),(64,'星期日')]
>>>>打印WEEKDAYS.fri
16
>>>打印WEEKDAYS.get_selected_values(52)
['星期三','星期五','星期六')
现在,使用 PositiveIntegerField
定义您的模型,并选择以下选项:
class Entry(models.Model):
weekdays = models.PositiveIntegerField(choices = WEEKDAYS)
<你的模型已经完成了。对于查询,以下是诀窍:
Entry.objects.extra(where = [weekdays&%s] ,params = [WEEKDAYS.fri])
可能有一种方式来创建一个 Q()
对象子类整齐地打包查询,所以它们如下所示:
条目.objects.filter(HasBit('weekdays',WEEKDAYS.fri))
甚至骇客 F()
子类创建如下:
Entry.objects .filter(weekdays = HasBit(WEEKDAYS.fri))
但是我没有时间现在探索。 .where
正常工作,可以抽象为查询功能。
最后一个考虑是,您可以点亮创建一个自定义模型字段,将数据库中的位掩码转换为列表或在Python中设置。然后,您可以使用 SelectMultiple
小部件(或 CheckboxSelectMultiple
)来允许用户在管理员中选择其值。 / p>
I've been searching for an elegant way to represent a multi-select weekday field (Mon, Tues, Wed...) in a Django model. I was initially thinking of going integer field using bitwise math but I am not sure if this would be the way to go.
This would be a mostly-read field. I would want the Queryset method to be something like Entry.objects.get(weekdays__contains=MONDAY)
Where MONDAY
would be a constant.
Perhaps someone could come up with a better solution? Or maybe someone has done something similar and has some example code they could contribute?
This is an old question, but I thought I would show how it could be done reasonably simply in Django.
Here is a helper class for preparing your choices:
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]
Define your model with a PositiveIntegerField, and the choices you would like:
WEEKDAYS = BitChoices((('mon', 'Monday'), ('tue', 'Tuesday'), ('wed', 'Wednesday'),
('thu', 'Thursday'), ('fri', 'Friday'), ('sat', 'Saturday'),
('sun', 'Sunday')
))
This means you can access the values like this:
>>> 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']
Now define your model with a PositiveIntegerField
and these choices:
class Entry(models.Model):
weekdays = models.PositiveIntegerField(choices=WEEKDAYS)
And your models are done. For queries, the following does the trick:
Entry.objects.extra(where=["weekdays & %s"], params=[WEEKDAYS.fri])
There may be a way to create a Q()
object subclass that neatly packages queries, so they look like this:
Entry.objects.filter(HasBit('weekdays', WEEKDAYS.fri))
Or even hack at a F()
subclass to create something like this:
Entry.objects.filter(weekdays=HasBit(WEEKDAYS.fri))
But I don't have the time to explore that at the moment. .where
works fine and can be abstracted into a queryset function.
One final consideration is that you might light to make a custom model field that converts the bit mask in the database to a list or set in Python. You could then use a SelectMultiple
widget (or CheckboxSelectMultiple
) to allow the user to select their values in the admin.
这篇关于在Django模型中表示平日的多选字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!