Wenn Sie ein Modellfeld mit einer Auswahloption haben, sind in der Regel einige magische Werte mit von Menschen lesbaren Namen verknüpft. Gibt es in Django eine bequeme Möglichkeit, diese Felder durch den vom Menschen lesbaren Namen anstelle des Werts festzulegen?
Betrachten Sie dieses Modell:
class Thing(models.Model):
PRIORITIES = (
(0, 'Low'),
(1, 'Normal'),
(2, 'High'),
)
priority = models.IntegerField(default=0, choices=PRIORITIES)
Irgendwann haben wir eine Thing-Instanz und möchten ihre Priorität festlegen. Offensichtlich könnten Sie tun,
thing.priority = 1
Dies zwingt Sie jedoch dazu, sich die Wert-Name-Zuordnung von PRIORITÄTEN zu merken. Das funktioniert nicht:
thing.priority = 'Normal' # Throws ValueError on .save()
Derzeit habe ich diese dumme Problemumgehung:
thing.priority = dict((key,value) for (value,key) in Thing.PRIORITIES)['Normal']
aber das ist klobig. Angesichts der Häufigkeit dieses Szenarios fragte ich mich, ob jemand eine bessere Lösung hätte. Gibt es eine Feldmethode zum Festlegen von Feldern nach Auswahlnamen, die ich völlig übersehen habe?
quelle
Ich würde wahrscheinlich das Reverse-Lookup-Diktat ein für alle Mal einrichten, aber wenn ich es nicht getan hätte, würde ich einfach verwenden:
Das scheint einfacher zu sein, als das Diktat spontan zu erstellen, nur um es wieder wegzuwerfen ;-).
quelle
Hier ist ein Feldtyp, den ich vor ein paar Minuten geschrieben habe und der meiner Meinung nach das tut, was Sie wollen. Sein Konstruktor erfordert ein Argument 'Auswahl', das entweder ein Tupel von 2 Tupeln im gleichen Format wie die Auswahloption für IntegerField sein kann, oder stattdessen eine einfache Liste von Namen (dh ChoiceField (('Niedrig', 'Normal', 'Hoch'), Standard = 'Niedrig')). Die Klasse kümmert sich für Sie um die Zuordnung von String zu Int. Sie sehen das Int nie.
quelle
Ich schätze die konstante Art der Definition, aber ich glaube, dass der Enum- Typ für diese Aufgabe bei weitem am besten geeignet ist. Sie können eine Ganzzahl und eine Zeichenfolge für ein Element gleichzeitig darstellen und gleichzeitig Ihren Code besser lesbar halten.
In Version 3.4 wurden Enums in Python eingeführt. Wenn Sie ein niedrigeres (z. B. v2.x) verwenden, können Sie es weiterhin haben, indem Sie das backportierte Paket installieren :
pip install enum34
.Das ist so ziemlich alles. Sie können das erben
ChoiceEnum
, um eigene Definitionen zu erstellen und diese in einer Modelldefinition wie folgt zu verwenden:Fragen sind das i-Tüpfelchen, wie Sie sich vorstellen können:
Die Darstellung in einer Zeichenfolge wird ebenfalls vereinfacht:
quelle
ChoiceEnum
, können Sie das.value
und verwenden,.name
wie @kirpit beschreibt, und die Verwendung vonchoices()
durch -tuple([(x.value, x.name) for x in cls])
entweder in einer Funktion (DRY) oder direkt im Konstruktor des Felds ersetzen .Verwenden Sie es so:
quelle
Ab Django 3.0 können Sie Folgendes verwenden:
quelle
Ersetzen Sie einfach Ihre Zahlen durch die von Menschen lesbaren Werte, die Sie möchten. So wie:
Dies macht es für den Menschen lesbar, Sie müssten jedoch Ihre eigene Reihenfolge definieren.
quelle
Meine Antwort ist sehr spät und mag heutzutage-Django-Experten offensichtlich erscheinen, aber für jeden, der hier landet, habe ich kürzlich eine sehr elegante Lösung entdeckt, die von Django-Modell-Utils gebracht wurde: https://django-model-utils.readthedocs.io/ de / latest / utilities.html # Auswahlmöglichkeiten
Mit diesem Paket können Sie Auswahlmöglichkeiten mit drei Tupeln definieren, wobei:
Folgendes können Sie also tun:
Diesen Weg:
Genießen :)
quelle
priority = models.IntegerField(default=PRIORITIES.Low, choices=PRIORITIES)
(Dazu muss natürlich die Prioritätszuweisung eingerückt werden, damit sie sich innerhalb der Thing-Klasse befindet.) Erwägen Sie auch die Verwendung von Wörtern / Zeichen in Kleinbuchstaben für die Python-ID, da Sie sich nicht auf eine Klasse, sondern auf einen Parameter beziehen (Ihre Auswahl würde dann:(0, 'low', 'Low'),
und so weiter).Ursprünglich habe ich eine modifizierte Version von @ Allans Antwort verwendet:
Vereinfacht mit dem
django-enumfields
Paketpaket, das ich jetzt benutze:quelle
Die Auswahloption des Modells akzeptiert eine Sequenz, die aus Iterablen von genau zwei Elementen besteht (z. B. [(A, B), (A, B) ...]), um sie als Auswahl für dieses Feld zu verwenden.
Darüber hinaus bietet Django Aufzählungstypen , die Sie in Unterklassen unterteilen können, um Auswahlmöglichkeiten auf übersichtliche Weise zu definieren:
Django unterstützt das Hinzufügen eines zusätzlichen Zeichenfolgenwerts am Ende dieses Tupels, der als lesbarer Name oder Bezeichnung verwendet werden soll. Das Etikett kann eine faul übersetzbare Zeichenfolge sein.
Hinweis: Sie verwenden können , dass die Verwendung von
ThingPriority.HIGH
,ThingPriority.['HIGH']
oder fürThingPriority(0)
den Zugriff oder Lookup - Enumeration Mitglieder.quelle