Esta es una vieja pregunta, pero pensé que mostraría cómo se podía hacer razonablemente simplemente en Django.
Aquí es una clase de ayuda para la preparación de sus opciones:
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]
definir su modelo con un PositiveIntegerField, y las opciones que le gustaría:
WEEKDAYS = BitChoices((('mon', 'Monday'), ('tue', 'Tuesday'), ('wed', 'Wednesday'),
('thu', 'Thursday'), ('fri', 'Friday'), ('sat', 'Saturday'),
('sun', 'Sunday')
))
Esto significa que puede acceder a los valores como esto:
>>> 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']
Defina ahora su modelo con PositiveIntegerField
y estas opciones:
class Entry(models.Model):
weekdays = models.PositiveIntegerField(choices=WEEKDAYS)
Y sus modelos están listos. Para consultas, lo que sigue es el truco:
Entry.objects.extra(where=["weekdays & %s"], params=[WEEKDAYS.fri])
Puede haber una manera de crear una subclase Q()
objeto que cuidadosamente los paquetes de consultas, por lo que este aspecto:
Entry.objects.filter(HasBit('weekdays', WEEKDAYS.fri))
O incluso cortar a una F()
subclase para crear algo como esto:
Entry.objects.filter(weekdays=HasBit(WEEKDAYS.fri))
Pero no tengo el tiempo para explorar que por el momento. .where
funciona bien y se puede abstraer en una función queryset.
Una consideración final es que puede encenderse para crear un campo de modelo personalizado que convierta la máscara de bits en la base de datos a una lista o conjunto en Python. Luego puede usar un widget SelectMultiple
(o CheckboxSelectMultiple
) para permitir que el usuario seleccione sus valores en el administrador.
Sin más información (tamaño del conjunto de datos, sobre todo leer frente a escribir en su mayoría, etc.) que va con bitfields se siente como la temida optimización prematura. –
Adjuntaré información adicional a la pregunta. Gracias Sr. Rowell. –
¿Ha considerado agregar una relación de muchos a muchos entre un modelo 'Weekday' y el modelo en cuestión? Sé que esto es un poco exagerado teniendo en cuenta que los días de la semana son fijos en número, pero harían el filtrado muy directo. –