Django şablonları: bir seçimin ayrıntılı sürümü


127

Bir modelim var:

from django.db import models

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

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

Bir formum var:

from django.forms import ModelForm

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

Ve formtools.preview kullanmak istiyorum. Varsayılan şablon, seçeneğin kısa versiyonunu ('Muhteşem yumurtalar' yerine 'e') yazdırır, çünkü kullanır

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

Bahsedilen kadar genel bir şablon istiyorum, ancak bunun yerine 'Muhteşem yumurtalar' yazdırmak istiyorum.

[gerçek sorunun nerede olduğuna dair şüphelerim olduğu için, hepimiz için cesurca yazdım :)]

Bir seçimin ayrıntılı versiyonunu kendisi çirkin bir şekilde nasıl elde edeceğimi biliyorum:

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

Asıl acı, seçilen seçimi yapmam gerekiyor ve aklıma gelen tek yol, seçimler ve kontrol yoluyla yinelemek {% ifequals currentChoice.0 choiceField.data %}ki bu daha da çirkin.

Kolayca yapılabilir mi? Ya da bazı şablon-etiket programlamasına mı ihtiyacı var? Bunun django'da zaten mevcut olması gerekmez mi?

Yanıtlar:


258

Django şablonlarında get_FOO_display(), alan için okunabilir takma adı döndüren " " yöntemini kullanabilirsiniz; burada 'FOO', alanın adıdır.

Not: Standart FormPreviewşablonların kullanmaması durumunda, o form için her zaman kendi şablonlarınızı sağlayabilirsiniz, bu şablonlar gibi bir şey içerecektir {{ form.get_meal_display }}.


1
Evet biliyorum. Yine de bu kadar genel (evrensel) değil - bir model nesnesinin tüm get_FOO_display yöntemlerini bir şablonda yinelemenin bir yolunu bilmediğiniz sürece :) Genel olmayan şablonlar yazmak için biraz fazla tembelim;) Ayrıca, dokümanlar bu bir model örneğin yöntemidir. Bu nedenle, durum ve aynı zamanda genel olmayan mevcut bir nesneye bağlı bir model formu olması gerekir.
Artur Gajowy

2
Bu kullanımın görünümlerle sınırlı olmadığını unutmayın, get_FOO_display () model nesnesinin kendisinde bir yöntemdir, böylece onu model kodunda da kullanabilirsiniz! Örneğin __unicode __ () çok kullanışlıdır
Bogatyr

51

Sorununuz için en iyi çözüm yardımcı işlevleri kullanmaktır. Seçenekler, SEÇİMLER değişkeninde saklanıyorsa ve seçilen seçeneği depolayan model alanı ' seçenekler ' ise , doğrudan kullanabilirsiniz

 {{ x.get_choices_display }}

şablonunuzda. Burada x, model örneğidir. Umarım yardımcı olur.


3
Yararlı bir cevap zaten verildikten 2 yıl sonra neden böyle cevap veresiniz? Ve kim oylayacak? Sadece 2 yıl sonra @roberto ile aynı cevap ....
boatcoder

15
@ Mark0978 bu cevaba olumlu oy vermenin nedeni (benim için) "en çok oylanan" cevabı takip etmenin daha net olması. YMMV.
Nir Levy

49

Bu yanıt yukarıda listelenenlerin dışında kalırsa özür dilerim, ancak bu yanıt henüz sunulmamış gibi görünüyor ve oldukça temiz görünüyor. Bunu şu şekilde çözdüm:

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]

Görünümüm şablona bir Kepçe iletir ( not: Scoop.values ​​() değil ) ve şablon şunları içerir:

{{ scoop.flavor_verbose }}

10

Noah'ın cevabına dayanarak, burada seçeneklerin olmadığı alanlardan etkilenmeyen bir sürüm var:

#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

Böyle bir amaçla filtre kullanmanın uygun olup olmadığından emin değilim. Herhangi birinin daha iyi bir çözümü varsa, onu görmekten memnun olurum :) Teşekkürler Noah!


Yolunuzdan bahsetmek için +1 # rahatsızlıklar / templatetags / ... LOL ... Docs formunun altında belirtilen get_FOO_display () kullanıyorum.
fmalina

seçimlerde hasattr kullanımı ile harika bir fikir!
oden

7

Veri ve alan türleri ile uğraşırken daha evrensel olacak şekilde Noah tarafından filtre çözümünü genişletebiliriz :

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

İşte 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)

Oldukça evrensel görünüyor :) Kesin olarak söyleyemem çünkü o zamandan beri çok fazla Python veya Django yapmadım. Yine de bir 3. parti (Django'ya dahil değil) filtresine ihtiyaç duyması çok üzücü (aksi halde bize söylersin Ivan, değil mi
?;

@ArturGajowy Evet, bugün itibariyle Django'da böyle bir varsayılan özellik yok. Teklif ettim, kim bilir, belki onaylanır .
Ivan Kharlamov

MÜKEMMEL! TIKIR TIKIR ÇALIŞIYOR! ÖZEL ŞABLON FİLTRELERİ ROX! TEŞEKKÜR EDERİM! :-)
CeDeROM

5

Bunu yapmanın yerleşik bir yolu olduğunu sanmıyorum. Yine de bir filtre hile yapabilir:

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

O zaman şunları yapabilirsiniz:

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

3

Models.py bir basit işlevi ekleyin:

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

Şimdi, bunun gibi seçim alanlarının ayrıntılı değerini elde edebilirsiniz:

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

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

Upd .: Emin değilim, bu çözümün "pitonik" ve "django-yolu" yeterli mi değil mi, ama işe yarıyor. :)


0

Model.get_FOO_display () var, burada FOO, seçeneklere sahip alanın adıdır.

Şablonunuzda şunu yapın:

{{ scoop.get_flavor_display }}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.