Quando você tem um campo de modelo com uma opção de escolha, você tende a ter alguns valores mágicos associados a nomes legíveis por humanos. Existe no Django uma maneira conveniente de definir esses campos pelo nome legível por humanos em vez do valor?
Considere este modelo:
class Thing(models.Model):
PRIORITIES = (
(0, 'Low'),
(1, 'Normal'),
(2, 'High'),
)
priority = models.IntegerField(default=0, choices=PRIORITIES)
Em algum ponto, temos uma instância de Thing e queremos definir sua prioridade. Obviamente, você poderia fazer,
thing.priority = 1
Mas isso força você a memorizar o mapeamento Nome-Valor de PRIORIDADES. Isso não funciona:
thing.priority = 'Normal' # Throws ValueError on .save()
Atualmente, tenho esta solução boba:
thing.priority = dict((key,value) for (value,key) in Thing.PRIORITIES)['Normal']
mas isso é desajeitado. Dado o quão comum esse cenário pode ser, eu queria saber se alguém teria uma solução melhor. Existe algum método de campo para definir campos por nome de escolha que eu ignorei totalmente?
fonte
Eu provavelmente configuraria o dict de pesquisa reversa de uma vez por todas, mas se não tivesse, eu apenas usaria:
o que parece mais simples do que construir o dicionário na hora apenas para jogá-lo fora novamente ;-).
fonte
Este é um tipo de campo que escrevi há alguns minutos que acho que faz o que você deseja. Seu construtor requer um argumento 'escolhas', que pode ser uma tupla de 2 tuplas no mesmo formato que a opção de escolhas para IntegerField, ou em vez de uma lista simples de nomes (ou seja, ChoiceField (('Low', 'Normal', 'Alto'), padrão = 'Baixo')). A classe cuida do mapeamento de string para int para você, você nunca vê o int.
fonte
Eu aprecio a forma constante de definição, mas acredito que o tipo Enum é muito melhor para essa tarefa. Eles podem representar um inteiro e uma string para um item ao mesmo tempo, mantendo seu código mais legível.
Enums foram introduzidos no Python na versão 3.4. Se você estiver usando qualquer (como v2.x) menor você ainda pode tê-lo através da instalação do pacote backported :
pip install enum34
.Isso é quase tudo. Você pode herdar o
ChoiceEnum
para criar suas próprias definições e usá-las em uma definição de modelo como:Consultar é a cereja do bolo, como você pode imaginar:
Representá-los em string também é fácil:
fonte
ChoiceEnum
, você pode usar o.value
e.name
como @kirpit descreve e substituir o uso dechoices()
portuple([(x.value, x.name) for x in cls])
- em uma função (DRY) ou diretamente no construtor do campo.Use-o assim:
fonte
A partir do Django 3.0, você pode usar:
fonte
Simplesmente substitua seus números pelos valores legíveis humanos que você deseja. Assim sendo:
Isso o torna legível por humanos, no entanto, você terá que definir seu próprio pedido.
fonte
Minha resposta está muito atrasada e pode parecer óbvia para os especialistas em Django de hoje, mas para quem quer que esteja aqui, recentemente descobri uma solução muito elegante trazida por django-model-utils: https://django-model-utils.readthedocs.io/ en / mais recente / utilities.html # escolhas
Este pacote permite que você defina escolhas com três tuplas, onde:
Então aqui está o que você pode fazer:
Deste jeito:
Aproveitar :)
fonte
priority = models.IntegerField(default=PRIORITIES.Low, choices=PRIORITIES)
(desnecessário dizer, a atribuição de prioridade deve ser indentada para estar dentro da classe Thing para fazer isso). Considere também o uso de palavras / caracteres minúsculos para o identificador python, já que você não está se referindo a uma classe, mas a um parâmetro (suas escolhas seriam então:(0, 'low', 'Low'),
e assim por diante).Originalmente, usei uma versão modificada da resposta de @Allan:
Simplificado com o
django-enumfields
pacote de pacote que agora uso:fonte
A opção de escolhas do modelo aceita uma sequência consistindo de iteráveis de exatamente dois itens (por exemplo, [(A, B), (A, B) ...]) para usar como escolhas para este campo.
Além disso, o Django fornece tipos de enumeração que você pode criar em subclasses para definir as opções de maneira concisa:
Django suporta a adição de um valor de string extra no final desta tupla para ser usado como o nome legível por humanos, ou rótulo. O rótulo pode ser uma string traduzível preguiçosa.
Nota: você pode usar que o uso
ThingPriority.HIGH
,ThingPriority.['HIGH']
ouThingPriority(0)
para o acesso ou membros de enumeração de pesquisa.fonte