J'ai un modèle:
from Django.db import models
CHOICES = (
('s', 'Glorious spam'),
('e', 'Fabulous eggs'),
)
class MealOrder(models.Model):
meal = models.CharField(max_length=8, choices=CHOICES)
J'ai un formulaire:
from Django.forms import ModelForm
class MealOrderForm(ModelForm):
class Meta:
model = MealOrder
Et je veux utiliser formtools.preview. Le modèle par défaut imprime la version courte du choix ('e' au lieu de 'Fabulous eggs'), car il utilise
{% for field in form %}
<tr>
<th>{{ field.label }}:</th>
<td>{{ field.data }}</td>
</tr>
{% endfor %}.
Je voudrais un modèle aussi général que celui mentionné, mais en imprimant à la place des "œufs fabuleux".
[comme j'avais des doutes où est la vraie question, je l'ai mise en gras pour nous tous:)]
Je sais comment obtenir la version verbeuse d'un choix d'une manière qui est elle-même laide:
{{ form.meal.field.choices.1.1 }}
La vraie douleur est que j'ai besoin d'obtenir le choix sélectionné, et la seule façon qui me vient à l'esprit est d'itérer à travers les choix et de vérifier {% ifequals currentChoice.0 choiceField.data %}
, ce qui est encore plus laid.
Peut-on le faire facilement? Ou il a besoin d'une programmation de balises de modèle? Cela ne devrait-il pas être disponible dans Django déjà?
Dans les modèles Django vous pouvez utiliser la méthode " get_FOO_display()
", qui renverra l'alias lisible pour le champ, où 'FOO' est le nom du champ.
Remarque: dans le cas où les modèles standard FormPreview
ne l'utilisent pas, vous pouvez toujours fournir vos propres modèles pour ce formulaire, qui contiendra quelque chose comme {{ form.get_meal_display }}
.
La meilleure solution à votre problème consiste à utiliser des fonctions d'assistance. Si les choix sont stockés dans la variable [[# #]] choix [~ # ~] et que le champ modèle stockant le choix sélectionné est 'choix' alors vous pouvez directement utiliser
{{ x.get_choices_display }}
dans votre modèle. Ici, x est l'instance de modèle. J'espère que ça aide.
Je m'excuse si cette réponse est redondante avec l'une des réponses ci-dessus, mais il semble que celle-ci n'ait pas encore été proposée, et elle semble assez propre. Voici comment j'ai résolu cela:
from Django.db import models
class Scoop(models.Model):
FLAVOR_CHOICES = [
('c', 'Chocolate'),
('v', 'Vanilla'),
]
flavor = models.CharField(choices=FLAVOR_CHOICES)
def flavor_verbose(self):
return dict(Scoop.FLAVOR_CHOCIES)[self.flavor]
Ma vue transmet un Scoop au modèle (note: pas Scoop.values ()), et le modèle contient:
{{ scoop.flavor_verbose }}
Sur la base de la réponse de Noah, voici une version à l'abri des champs sans choix:
#annoyances/templatetags/data_verbose.py
from Django import template
register = template.Library()
@register.filter
def data_verbose(boundField):
"""
Returns field's data or it's verbose version
for a field with choices defined.
Usage::
{% load data_verbose %}
{{form.some_field|data_verbose}}
"""
data = boundField.data
field = boundField.field
return hasattr(field, 'choices') and dict(field.choices).get(data,'') or data
Je ne sais pas si c'est correct d'utiliser un filtre à cette fin. Si quelqu'un a une meilleure solution, je serai heureux de la voir :) Merci Noah!
Nous pouvons étendre la solution de filtrage par Noah pour être plus universel dans le traitement des types de données et de champs:
<table>
{% for item in query %}
<tr>
{% for field in fields %}
<td>{{item|human_readable:field}}</td>
{% endfor %}
</tr>
{% endfor %}
</table>
Voici le code:
#app_name/templatetags/custom_tags.py
def human_readable(value, arg):
if hasattr(value, 'get_' + str(arg) + '_display'):
return getattr(value, 'get_%s_display' % arg)()
Elif hasattr(value, str(arg)):
if callable(getattr(value, str(arg))):
return getattr(value, arg)()
else:
return getattr(value, arg)
else:
try:
return value[arg]
except KeyError:
return settings.TEMPLATE_STRING_IF_INVALID
register.filter('human_readable', human_readable)
Je ne pense pas qu'il existe un moyen intégré de le faire. Un filtre pourrait faire l'affaire, cependant:
@register.filter(name='display')
def display_value(bf):
"""Returns the display value of a BoundField"""
return dict(bf.field.choices).get(bf.data, '')
Ensuite, vous pouvez faire:
{% for field in form %}
<tr>
<th>{{ field.label }}:</th>
<td>{{ field.data|display }}</td>
</tr>
{% endfor %}
Ajoutez à votre models.py une fonction simple:
def get_display(key, list):
d = dict(list)
if key in d:
return d[key]
return None
Maintenant, vous pouvez obtenir la valeur détaillée de champs de choix comme celui-ci:
class MealOrder(models.Model):
meal = models.CharField(max_length=8, choices=CHOICES)
def meal_verbose(self):
return get_display(self.meal, CHOICES)
Upd .: Je ne sais pas, est-ce que cette solution "Pythonic" et "Django-way" est suffisante ou non, mais ça marche. :)