2009-07-09 15 views
98

Mam model:Django szablony: verbose wersja wyboru

from django.db import models 

CHOICES = (
    ('s', 'Glorious spam'), 
    ('e', 'Fabulous eggs'), 
) 

class MealOrder(models.Model): 
    meal = models.CharField(max_length=8, choices=CHOICES) 

mam postać:

from django.forms import ModelForm 

class MealOrderForm(ModelForm): 
    class Meta: 
     model = MealOrder 

I chcę używać formtools.preview. Domyślny szablon wypisuje krótką wersję wyboru („e” zamiast „Wspaniali jaj”), ponieważ posiadał wykorzystuje

{% for field in form %} 
<tr> 
<th>{{ field.label }}:</th> 
<td>{{ field.data }}</td> 
</tr> 
{% endfor %}. 

Chciałbym szablon jako ogólne, jak wspomniano, ale drukowanie „Fabulous jaja ' zamiast.

[jak miałem wątpliwości, gdzie jest prawdziwe pytanie, mam pogrubione to dla nas wszystkich :)]

wiem jak uzyskać opisowy wersję wyboru w sposób, który sam jest brzydki:

{{ form.meal.field.choices.1.1 }} 

prawdziwy ból jest potrzebne, aby uzyskać wybrany wyboru, a jedynym sposobem, zbliża się do mojego umysłu jest iteracja wyborów i sprawdzania {% ifequals currentChoice.0 choiceField.data %}, który jest jeszcze brzydsze.

Czy można to łatwo zrobić? Lub potrzebuje programowania szablonów? Czy nie powinno to być już dostępne w django?

Odpowiedz

4

Nie sądzę, że istnieje jakiś wbudowany sposób, aby to zrobić. Filtr może załatwić sprawę, ale:

@register.filter(name='display') 
def display_value(bf): 
    """Returns the display value of a BoundField""" 
    return dict(bf.field.choices).get(bf.data, '') 

Następnie można zrobić:

{% for field in form %} 
    <tr> 
     <th>{{ field.label }}:</th> 
     <td>{{ field.data|display }}</td> 
    </tr> 
{% endfor %} 
208

W Django szablony można użyć „get_FOO_display()” metodę, która będzie zwracać się do odczytania alias dla tej dziedzinie, gdzie "FOO" to nazwa pola.

Uwaga: w przypadku, gdy standardowe szablony FormPreview go nie używają, zawsze można provide your own templates dla tego formularza, który będzie zawierał coś w rodzaju {{ form.get_meal_display }}.

+1

Tak, wiem. Nie jest to jednak ogólna (uniwersalna) - chyba, że ​​znasz sposób na iterowanie w szablonie wszystkich metod get_FOO_display obiektu modelu :) Jestem zbyt leniwy, aby pisać nie generyczne szablony;) ​​ Co więcej, Dokumenty mówią, że jest to metoda modelu. Dlatego musiałaby to być forma modelu powiązana z istniejącym obiektem, co nie ma miejsca, a także nie jest ogólna. –

+0

Zawsze o tym zapominam – Sevenearths

+2

Pamiętaj, że to użycie nie jest ograniczone do widoków, get_FOO_display() to metoda na samym obiekcie modelu, dzięki czemu możesz go również użyć w kodzie modelu! Na przykład, w __unicode __() jest bardzo przydatny – Bogatyr

9

Na podstawie odpowiedzi Noego, oto wersja odporna na polach bez możliwości:

#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 

Nie jestem pewien pogoda jest ok aby użyć filtra do tego celu. Jeśli ktokolwiek ma lepsze rozwiązanie, chętnie go zobaczę :) Dziękuję Noah!

+0

+1 za wzmiankę o twojej ścieżce # annoyances/templatetags/... LOL ... Używam get_FOO_display(), który jest wymieniony na dole dokumentacji formularzy. –

+0

świetny pomysł z wykorzystaniem hasattr na wybory! – oden

6

Możemy rozszerzyć rozwiązanie filtra przez Noah być bardziej powszechne w kontaktach z danych i typów pól:

<table> 
{% for item in query %} 
    <tr> 
     {% for field in fields %} 
      <td>{{item|human_readable:field}}</td> 
     {% endfor %} 
    </tr> 
{% endfor %} 
</table> 

Oto kod:

#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) 
+0

Wydaje się całkiem uniwersalny :) Nie mogę powiedzieć na pewno, ponieważ od tego czasu nie zrobiłem zbyt wiele Python lub Django. To dość smutne, że nadal potrzebuje filtra innej firmy (nie ma go w Django) (inaczej powiesz nam, Ivan, czy nie?)) ... –

+0

@ArturGajowy Tak, od dziś nie ma takiej domyślnej funkcji w Django. Zaproponowałem to, [kto wie, może to zostanie zatwierdzone] (https://groups.google.com/group/django-developers/browse_thread/thread/9ff2222931b381c7). –

35

Najlepszym rozwiązaniem problemu jest używać funkcji pomocniczych. Jeśli wybory są przechowywane w zmiennej WYBORÓW i pole modelu przechowywania wybrany wybór jest „wybory” następnie można bezpośrednio wykorzystać

{{ x.get_choices_display }} 

w szablonie. Tutaj x jest instancją modelu. Mam nadzieję, że to pomaga.

+3

Dlaczego miałbyś odpowiedzieć w ten sposób 2 lata po uzyskaniu użytecznej odpowiedzi? A kto by to zagłosował? Jest to ta sama odpowiedź co @roberto zaledwie 2 lata później .... – boatcoder

+10

@ Mark0978 Powodem przebudowy tej odpowiedzi jest to, że (dla mnie) było wyraźniej podążać za odpowiedzią "na szczycie". YMMV. –

2

Dodaj do models.py jedną prostą funkcję:

def get_display(key, list): 
    d = dict(list) 
    if key in d: 
     return d[key] 
    return None 

Teraz można dostać opisowy wartość pola wyboru tak:

class MealOrder(models.Model): 
    meal = models.CharField(max_length=8, choices=CHOICES) 

    def meal_verbose(self): 
     return get_display(self.meal, CHOICES)  

Upd .: Nie jestem pewien, czy to rozwiązanie "pythonic" i "django-way" wystarczy czy nie, ale działa. :)

25

Przepraszam, jeśli ta odpowiedź jest zbędna z wymienionymi powyżej, ale wygląda na to, że ta nie została jeszcze zaoferowana i wydaje się dość czysta. Oto jak mam rozwiązać ten:

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] 

Mój pogląd przechodzi gałką do szablonu (uwaga: nie Scoop.values ​​()), a szablon zawiera:

{{ scoop.flavor_verbose }} 
+0

dziękuję :) to było dokładnie to, czego szukałem. –

-2

Z użycie tagu szablonu.

Prawie tak samo jak Arthur Gawjowj, ale ten jest przeznaczony do wyborów, które TYLKO używają wartości całkowitych zamiast ciągów.

# project/templatetags/project_tags.py 

from django.template.base import Library 


register = Library() 

@register.filter(name='pretty_form_value') 
def pretty_form_value(field): 
    """ 
    Returns field's data or it's verbose version 
    for a field with choices defined. 

    Usage:: 

     {% load project_tags %} 
     {{form.some_field|pretty_form_value}} 
    """ 
    if hasattr(field.field, 'choices'): 
     try: 
      return dict(field.field.choices)[int(field.data)] 
     except ValueError: 
      pass 
    return field.data 
Powiązane problemy