在Django模型中表示平日的多选字段 [英] Representing a multi-select field for weekdays in a Django model

查看:182
本文介绍了在Django模型中表示平日的多选字段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在寻找一种优雅的方式来代表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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆