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.