Kiedy masz pole modelu z opcją wyborów, zwykle masz pewne magiczne wartości związane z nazwami czytelnymi dla człowieka. Czy w Django istnieje wygodny sposób ustawiania tych pól na podstawie czytelnej dla człowieka nazwy zamiast wartości?
Rozważ ten model:
class Thing(models.Model):
PRIORITIES = (
(0, 'Low'),
(1, 'Normal'),
(2, 'High'),
)
priority = models.IntegerField(default=0, choices=PRIORITIES)
W pewnym momencie mamy instancję Thing i chcemy ustawić jej priorytet. Oczywiście możesz to zrobić
thing.priority = 1
Ale to zmusza cię do zapamiętania mapowania nazwy wartości dla PRIORYTETÓW. To nie działa:
thing.priority = 'Normal' # Throws ValueError on .save()
Obecnie mam to głupie obejście:
thing.priority = dict((key,value) for (value,key) in Thing.PRIORITIES)['Normal']
ale to jest niezgrabne. Biorąc pod uwagę, jak powszechny może być ten scenariusz, zastanawiałem się, czy ktoś ma lepsze rozwiązanie. Czy jest jakaś metoda ustawiania pól według nazwy wyboru, którą całkowicie przeoczyłem?
źródło
Prawdopodobnie skonfigurowałbym dyktando wyszukiwania wstecznego raz na zawsze, ale gdybym tego nie zrobił, użyłbym po prostu:
co wydaje się prostsze niż budowanie dyktu w locie tylko po to, aby go ponownie wyrzucić ;-).
źródło
Oto typ pola, który napisałem kilka minut temu i myślę, że robi to, co chcesz. Jego konstruktor wymaga argumentu „choice”, który może być albo krotką z 2 krotkami w tym samym formacie co opcja choice dla IntegerField, lub zamiast tego prostą listą nazw (np. ChoiceField (('Low', 'Normal', „Wysoki”), domyślnie = „Niski”)). Klasa dba o mapowanie ciągu znaków na int, nigdy nie zobaczysz int.
źródło
Doceniam ciągłe definiowanie, ale uważam, że typ Enum jest najlepszy do tego zadania. Mogą reprezentować liczbę całkowitą i ciąg znaków dla elementu w tym samym czasie, zachowując jednocześnie bardziej czytelny kod.
Wyliczenia zostały wprowadzone do Pythona w wersji 3.4. Jeśli używasz niżej (jak w wersji 2.x) nadal można mieć go instalując backportowaną pakiet :
pip install enum34
.To prawie wszystko. Możesz dziedziczyć,
ChoiceEnum
aby tworzyć własne definicje i używać ich w definicji modelu, na przykład:Zapytanie jest wisienką na torcie, jak można się domyślić:
Reprezentowanie ich w łańcuchu jest również łatwe:
źródło
ChoiceEnum
, możesz użyć.value
i,.name
jak opisuje @kirpit, i zastąpić użyciechoices()
z -tuple([(x.value, x.name) for x in cls])
albo w funkcji (DRY), albo bezpośrednio w konstruktorze pola.Użyj tego w ten sposób:
źródło
Od Django 3.0 możesz używać:
źródło
Po prostu zastąp swoje liczby wartościami czytelnymi dla człowieka, które chcesz. Takie jak:
To sprawia, że jest czytelny dla człowieka, jednak musiałbyś zdefiniować własną kolejność.
źródło
Moja odpowiedź jest bardzo późna i może wydawać się oczywista dla dzisiejszych ekspertów od Django, ale dla każdego, kto tu wyląduje, niedawno odkryłem bardzo eleganckie rozwiązanie wprowadzone przez django-model-utils: https://django-model-utils.readthedocs.io/ pl / latest / utilities.html # choice
Ten pakiet umożliwia zdefiniowanie wyborów za pomocą trzech krotek, gdzie:
Oto, co możesz zrobić:
Tą drogą:
Cieszyć się :)
źródło
priority = models.IntegerField(default=PRIORITIES.Low, choices=PRIORITIES)
(nie trzeba dodawać, że przypisanie priorytetu musi być wcięte, aby znajdowało się wewnątrz klasy rzeczy, aby to zrobić). Rozważ również użycie małych liter / znaków dla identyfikatora Pythona, ponieważ nie odnosisz się do klasy, ale zamiast tego parametru (twoje Wybory stałyby się wtedy:(0, 'low', 'Low'),
i tak dalej).Pierwotnie użyłem zmodyfikowanej wersji odpowiedzi @ Allana:
Uproszczony
django-enumfields
pakiet, którego teraz używam:źródło
Opcja wyborów modelu akceptuje sekwencję składającą się z iterowalnych dokładnie dwóch elementów (np. [(A, B), (A, B) ...]) do wyboru dla tego pola.
Ponadto Django zapewnia typy wyliczeniowe , które można podklasy definiować w celu zdefiniowania wyborów w zwięzły sposób:
Django obsługuje dodawanie dodatkowej wartości ciągu na końcu tej krotki, która będzie używana jako nazwa czytelna dla człowieka lub etykieta. Etykieta może być leniwym ciągiem do tłumaczenia.
Uwaga: można użyć, że używanie
ThingPriority.HIGH
,ThingPriority.['HIGH']
lubThingPriority(0)
do dostępu lub odnośników członków enum.źródło