Cuando tiene un campo modelo con una opción de opciones, tiende a tener algunos valores mágicos asociados con nombres legibles por humanos. ¿Existe en Django una forma conveniente de configurar estos campos por el nombre legible por humanos en lugar del valor?
Considere este modelo:
class Thing(models.Model):
PRIORITIES = (
(0, 'Low'),
(1, 'Normal'),
(2, 'High'),
)
priority = models.IntegerField(default=0, choices=PRIORITIES)
En algún momento tenemos una instancia de Thing y queremos establecer su prioridad. Obviamente podrías hacer
thing.priority = 1
Pero eso te obliga a memorizar el mapeo Valor-Nombre de PRIORIDADES. Esto no funciona:
thing.priority = 'Normal' # Throws ValueError on .save()
Actualmente tengo esta tonta solución:
thing.priority = dict((key,value) for (value,key) in Thing.PRIORITIES)['Normal']
pero eso es torpe. Dado lo común que podría ser este escenario, me preguntaba si alguien tenía una solución mejor. ¿Existe algún método de campo para configurar campos por nombre de elección que pasé por alto por completo?
fuente
Probablemente establecería el dictado de búsqueda inversa de una vez por todas, pero si no lo hubiera hecho, simplemente usaría:
que parece más simple que construir el dict sobre la marcha solo para tirarlo de nuevo ;-).
fuente
Aquí hay un tipo de campo que escribí hace unos minutos que creo que hace lo que quieres. Su constructor requiere un argumento 'opciones', que puede ser una tupla de 2 tuplas en el mismo formato que la opción de opciones para IntegerField, o una lista simple de nombres (es decir, ChoiceField (('Low', 'Normal', 'Alto'), predeterminado = 'Bajo')). La clase se encarga del mapeo de string a int por usted, nunca ve el int.
fuente
Aprecio la forma de definición constante, pero creo que el tipo Enum es mucho mejor para esta tarea. Pueden representar números enteros y una cadena para un elemento al mismo tiempo, mientras mantienen su código más legible.
Las enumeraciones se introdujeron en Python en la versión 3.4. Si usted está usando alguna inferior (como la versión 2.x) que aún puede tener que mediante la instalación del paquete portado :
pip install enum34
.Esto es prácticamente todo. Puede heredar el
ChoiceEnum
para crear sus propias definiciones y usarlas en una definición de modelo como:Las consultas son la guinda del pastel, como puede imaginar:
Representarlos en cadena también es fácil:
fuente
ChoiceEnum
, puede usar.value
y.name
como describe @kirpit y reemplazar el uso dechoices()
con - yatuple([(x.value, x.name) for x in cls])
sea en una función (DRY) o directamente en el constructor del campo.Úselo así:
fuente
A partir de Django 3.0, puede usar:
fuente
Simplemente reemplace sus números con los valores legibles por humanos que le gustaría. Como tal:
Esto lo hace legible por humanos, sin embargo, tendrá que definir su propio orden.
fuente
Mi respuesta es muy tardía y puede parecer obvia para los expertos de Django de hoy en día, pero para quien aterrice aquí, recientemente descubrí una solución muy elegante traída por django-model-utils: https://django-model-utils.readthedocs.io/ es / latest / utilities.html # opciones
Este paquete le permite definir Choices con tres tuplas donde:
Así que esto es lo que puede hacer:
De esta manera:
Disfruta :)
fuente
priority = models.IntegerField(default=PRIORITIES.Low, choices=PRIORITIES)
(no hace falta decir que la asignación de prioridad debe tener sangría para estar dentro de la clase Thing para poder hacerlo). También considere usar palabras / caracteres en minúsculas para el identificador de Python, ya que no se está refiriendo a una clase, sino a un parámetro (sus Elecciones se convertirían en:(0, 'low', 'Low'),
y así sucesivamente).Originalmente utilicé una versión modificada de la respuesta de @ Allan:
Simplificado con el
django-enumfields
paquete del paquete que ahora uso:fuente
La opción de opciones del modelo acepta una secuencia que consiste en iterables de exactamente dos elementos (por ejemplo, [(A, B), (A, B) ...]) para usar como opciones para este campo.
Además, Django proporciona tipos de enumeración que puede subclasificar para definir opciones de una manera concisa:
Django admite la adición de un valor de cadena adicional al final de esta tupla para usarlo como nombre o etiqueta legible por humanos. La etiqueta puede ser una cadena traducible perezosa.
Nota: se puede usar que el uso de
ThingPriority.HIGH
,ThingPriority.['HIGH']
oThingPriority(0)
para el acceso o los miembros de enumeración de búsqueda.fuente