เทมเพลต Django: ตัวเลือกเวอร์ชัน verbose


127

ฉันมีโมเดล:

from django.db import models

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

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

ฉันมีแบบฟอร์ม:

from django.forms import ModelForm

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

และฉันต้องการใช้ formtools.preview เทมเพลตเริ่มต้นจะพิมพ์ตัวเลือกแบบสั้น ('e' แทน 'Fabulous eggs') เนื่องจากใช้

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

ฉันต้องการเทมเพลตทั่วไปตามที่กล่าวไว้ แต่พิมพ์ 'ไข่เยี่ยม' แทน

[ในขณะที่ฉันมีข้อสงสัยว่าคำถามที่แท้จริงอยู่ที่ไหนฉันจึงกล้าให้พวกเราทุกคน :)]

ฉันรู้วิธีรับตัวเลือกเวอร์ชัน verbose ในแบบที่น่าเกลียด:

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

ความเจ็บปวดที่แท้จริงคือฉันต้องได้รับตัวเลือกที่เลือกและวิธีเดียวที่จะมาถึงใจของฉันคือการทำซ้ำผ่านทางเลือกและการตรวจสอบ{% ifequals currentChoice.0 choiceField.data %}ซึ่งมันน่าเกลียดกว่านั้น

สามารถทำได้ง่ายหรือไม่? หรือต้องการโปรแกรม template-tag? ไม่ควรมีอยู่ใน django แล้วหรือ

คำตอบ:


258

ในเทมเพลต Django คุณสามารถใช้get_FOO_display()เมธอด "" ซึ่งจะส่งคืนนามแฝงที่อ่านได้สำหรับฟิลด์โดยที่ "FOO" คือชื่อของฟิลด์

หมายเหตุ: ในกรณีที่มาตรฐานFormPreviewแม่ไม่ได้ใช้มันแล้วคุณสามารถเสมอให้แบบของคุณเอง{{ form.get_meal_display }}สำหรับฟอร์มที่ซึ่งจะมีสิ่งที่ชอบ


1
ใช่ฉันรู้. แม้ว่าจะไม่เป็นแบบทั่วไป (สากล) - เว้นแต่คุณจะรู้วิธีการทำซ้ำในเทมเพลตโดยใช้วิธี get_FOO_display ของวัตถุแบบจำลองทั้งหมด :) ฉันค่อนข้างขี้เกียจเกินไปสำหรับการเขียนเทมเพลตที่ไม่ใช่แบบทั่วไป) นอกจากนี้เอกสารยังกล่าวว่า มันเป็นวิธีการของโมเดล ดังนั้นจึงต้องเป็นแบบจำลองที่ผูกไว้กับวัตถุที่มีอยู่ซึ่งไม่ใช่กรณีและไม่ใช่แบบทั่วไป
Artur Gajowy

2
โปรดทราบว่าการใช้งานนี้ไม่ จำกัด เฉพาะมุมมอง get_FOO_display () เป็นวิธีการบนวัตถุโมเดลเพื่อให้คุณสามารถใช้ในรหัสโมเดลได้เช่นกัน! ตัวอย่างเช่นใน __unicode __ () มีประโยชน์มาก
Bogatyr

51

ทางออกที่ดีที่สุดสำหรับปัญหาของคุณคือการใช้ฟังก์ชันตัวช่วย หากตัวเลือกถูกเก็บไว้ในCHOICESตัวแปรและฟิลด์โมเดลที่จัดเก็บตัวเลือกที่เลือกคือ ' ตัวเลือก ' คุณสามารถใช้

 {{ x.get_choices_display }}

ในเทมเพลตของคุณ ในที่นี้ x คือตัวอย่างของโมเดล หวังว่าจะช่วยได้


3
ทำไมคุณถึงตอบแบบนี้ 2 ปีหลังจากที่มีคำตอบที่เป็นประโยชน์แล้ว แล้วใครจะโหวตให้? คำตอบเดียวกับ @roberto เพียง 2 ปีต่อมา ....
boatcoder

15
@ Mark0978 เหตุผลในการโหวตคำตอบนี้เพราะ (สำหรับฉัน) มันชัดเจนกว่าที่จะทำตามคำตอบที่ได้รับการโหวตสูงสุด YMMV
Nir Levy

49

ขออภัยหากคำตอบนี้ซ้ำซ้อนกับรายการข้างต้น แต่ดูเหมือนว่าคำตอบนี้ยังไม่ได้รับการเสนอและดูเหมือนจะค่อนข้างสะอาด นี่คือวิธีที่ฉันแก้ไขสิ่งนี้:

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]

มุมมองของฉันส่ง Scoop ไปยังเทมเพลต (หมายเหตุ: ไม่ใช่ Scoop.values ​​()) และเทมเพลตประกอบด้วย:

{{ scoop.flavor_verbose }}

10

ตามคำตอบของโนอาห์นี่คือเวอร์ชันที่ป้องกันไม่ให้ฟิลด์ที่ไม่มีตัวเลือก:

#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

ฉันไม่แน่ใจว่าใช้ตัวกรองเพื่อจุดประสงค์ดังกล่าวได้หรือไม่ ถ้าใครมีวิธีแก้ปัญหาที่ดีกว่านี้ก็ยินดีรับชม :) ขอบคุณโนอาห์!


+1 สำหรับการกล่าวถึงเส้นทางของคุณ # การรบกวน / เทมเพลตแท็ก / ... ฮ่า ๆ ... ฉันใช้ get_FOO_display () ซึ่งระบุไว้ที่ด้านล่างของเอกสารแบบฟอร์ม
fmalina

ความคิดที่ดีกับการใช้ hasattr ในการเลือก!
โอเด้ง

7

เราสามารถขยายโซลูชันตัวกรองโดยNoah ให้เป็นสากลมากขึ้นในการจัดการกับข้อมูลและประเภทฟิลด์:

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

นี่คือรหัส:

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

ดูเหมือนจะเป็นสากล :) ไม่สามารถบอกได้อย่างแน่นอนเพราะฉันไม่ได้ทำ Python หรือ Django มากเกินไปตั้งแต่ตอนนั้น มันค่อนข้างน่าเศร้าที่ยังคงต้องการตัวกรองของบุคคลที่สาม (ไม่รวมอยู่ใน Django) (ไม่เช่นนั้นคุณจะบอกเราว่า Ivan คุณจะไม่?;)) ...
Artur Gajowy

@ArturGajowy ใช่ ณ วันนี้ไม่มีคุณลักษณะเริ่มต้นใน Django ผมได้เสนอว่าใครจะรู้บางทีมันอาจจะได้รับการอนุมัติ
Ivan Kharlamov

ที่สมบูรณ์แบบ! ทำงานเหมือนมีเสน่ห์! ตัวกรองเทมเพลตที่กำหนดเอง ROX! ขอบคุณ! :-)
CeDeROM

5

ฉันไม่คิดว่าจะมีวิธีทำแบบนั้นในตัว ตัวกรองอาจทำเคล็ดลับแม้ว่า:

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

จากนั้นคุณสามารถทำได้:

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

3

เพิ่มใน Models.py ของคุณฟังก์ชั่นง่ายๆ:

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

ตอนนี้คุณจะได้รับค่า verbose ของช่องทางเลือกดังนี้:

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

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

อัปเดต: ฉันไม่แน่ใจว่าโซลูชัน "pythonic" และ "django-way" เพียงพอหรือไม่ แต่ใช้ได้ผล :)


0

คุณมี Model.get_FOO_display () โดย FOO คือชื่อของฟิลด์ที่มีตัวเลือก

ในเทมเพลตของคุณให้ทำสิ่งนี้:

{{ scoop.get_flavor_display }}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.