2010-09-08 12 views
8

Ich habe nach einem eleganten Weg gesucht, ein mehrfach ausgewähltes Wochentagsfeld (Mon, Di, Mi ...) in einem Django Modell darzustellen. Ich dachte ursprünglich daran, mit Bit-Rechnen in ein ganzzahliges Feld zu gehen, aber ich bin mir nicht sicher, ob das der richtige Weg wäre.Darstellen eines Mehrfachauswahlfeldes für Wochentage in einem Django Modell

Dies wäre ein meist gelesenes Feld. Ich möchte, dass die Queryset-Methode etwa Entry.objects.get(weekdays__contains=MONDAY) ist, wobei MONDAY eine Konstante wäre.

Vielleicht könnte jemand eine bessere Lösung finden? Oder hat jemand etwas Ähnliches getan und hat einen Beispielcode, den sie beitragen könnten?

+0

Ohne weitere Informationen (Größe des Datensatzes, meist lesen vs meist schreiben, etc.) geht mit Bitfields fühlt sich wie die gefürchtete vorzeitige Optimierung. –

+0

Ich werde zusätzliche Informationen an die Frage anhängen. Danke Herr Rowell. –

+0

Haben Sie darüber nachgedacht, eine Viele-zu-viele-Beziehung zwischen einem "Weekday" -Modell und dem fraglichen Modell hinzuzufügen? Ich weiß, das ist ein bisschen Overkill, wenn man bedenkt, dass die Wochentage in der Anzahl festgelegt sind, aber es würde die Filterung sehr einfach machen. –

Antwort

14

Dies ist eine alte Frage, aber ich dachte, ich würde zeigen, wie es einfach in Django einfach gemacht werden könnte.

Hier ist eine Hilfsklasse für Ihre Entscheidungen vorbereiten:

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] 

Definieren Sie Ihr Modell mit einem PositiveIntegerField, und die Entscheidungen würden Sie gerne:

WEEKDAYS = BitChoices((('mon', 'Monday'), ('tue', 'Tuesday'), ('wed', 'Wednesday'), 
       ('thu', 'Thursday'), ('fri', 'Friday'), ('sat', 'Saturday'), 
       ('sun', 'Sunday') 
      )) 

Dies bedeutet, dass Sie die Werte zugreifen können wie dies:

>>> 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'] 

Definieren Sie jetzt Ihr Modell mit PositiveIntegerField und diese Auswahlmöglichkeiten:

class Entry(models.Model): 
    weekdays = models.PositiveIntegerField(choices=WEEKDAYS) 

Und Ihre Modelle sind fertig. Bei Abfragen, tut folgendes den Trick:

Entry.objects.extra(where=["weekdays & %s"], params=[WEEKDAYS.fri]) 

Es kann ein Weg sein, um eine Q() Objektunterklasse zu erstellen, die fein säuberlich Abfragen Pakete, so dass sie wie folgt aussehen:

Entry.objects.filter(HasBit('weekdays', WEEKDAYS.fri)) 

oder Hack auch bei einem F() Unterklasse, so etwas zu schaffen:

Entry.objects.filter(weekdays=HasBit(WEEKDAYS.fri)) 

Aber ich habe nicht die Zeit, die zur Zeit zu erkunden. .where funktioniert einwandfrei und kann in eine Queryset-Funktion abstrahiert werden.

Eine letzte Überlegung ist, dass Sie möglicherweise ein benutzerdefiniertes Modellfeld erstellen, das die Bitmaske in der Datenbank in eine Liste oder einen Satz in Python konvertiert. Sie können dann ein SelectMultiple Widget (oder CheckboxSelectMultiple) verwenden, damit der Benutzer seine Werte im Admin auswählen kann.

+0

Diese Antwort http: // stackoverflow.com/questions/19645227/django-create-multiselect-checkbox-input thematisiert das Thema in Bezug auf das Widget – Yablargo

+0

Ich möchte nur noch einmal Danke sagen, ich war in der Lage zu stolpern durch den Aufbau eines Widget gegen Ihre Klasse, und es funktioniert wie ein Champion. – Yablargo

+0

@ Yablargo und Autor: Vielen Dank! Ich war auch in der Lage, ein Widget gegen Ihre Klasse zu machen, aber ich bleibe bei der umgekehrten Funktion (von (String) -Wert (sagen wir "12") zu Datadict {(4, "Mittwoch"), (8, " Donnerstag ")} um Anfangsdaten zu zeigen (und zu bearbeiten) Könnten Sie bitte hier helfen: http://Stackoverflow.com/q/25575951/3849359? Danke eine Million! – gabn88

Verwandte Themen