Mẫu Django: phiên bản dài dòng của sự lựa chọn


127

Tôi có một mô hình:

from django.db import models

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

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

Tôi có một hình thức:

from django.forms import ModelForm

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

Và tôi muốn sử dụng formtools.preview. Mẫu mặc định in phiên bản ngắn của sự lựa chọn ('e' thay vì 'Trứng tuyệt vời'), vì nó sử dụng

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

Tôi muốn một mẫu chung chung như đã đề cập, nhưng in 'Trứng tuyệt vời' thay vào đó.

[như tôi đã nghi ngờ đâu là câu hỏi thực sự, tôi đã in đậm nó cho tất cả chúng ta :)]

Tôi biết làm thế nào để có được phiên bản dài dòng của một lựa chọn theo cách mà bản thân nó xấu xí:

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

Nỗi đau thực sự là tôi cần có được sự lựa chọn, và cách duy nhất nảy ra trong đầu tôi là lặp đi lặp lại thông qua các lựa chọn và kiểm tra {% ifequals currentChoice.0 choiceField.data %}, thậm chí còn xấu hơn.

Nó có thể được thực hiện dễ dàng? Hoặc nó cần một số lập trình thẻ mẫu? Không nên có sẵn trong django?

Câu trả lời:


258

Trong các mẫu Django, bạn có thể sử dụng get_FOO_display()phương thức "", sẽ trả về bí danh có thể đọc được cho trường, trong đó 'FOO' là tên của trường.

Lưu ý: trong trường hợp các FormPreviewmẫu tiêu chuẩn không sử dụng nó, thì bạn luôn có thể cung cấp các mẫu của riêng bạn cho mẫu đó, sẽ chứa một cái gì đó như thế nào {{ form.get_meal_display }}.


1
Vâng tôi biết. Mặc dù vậy, nó không phải là chung (phổ quát) - trừ khi bạn biết cách lặp lại trong một mẫu trên tất cả các phương thức get_FOO_display của một đối tượng mô hình :) Tôi hơi lười biếng khi viết các mẫu không chung chung;) Ngoài ra, các tài liệu nói đó là một phương thức của mô hình. Do đó, nó phải là một dạng mẫu liên kết với một đối tượng hiện có không phải là trường hợp và cũng không phải là chung.
Artur Gajowy

2
Lưu ý rằng việc sử dụng này không giới hạn ở các khung nhìn, get_FOO_display () là một phương thức trên chính đối tượng mô hình để bạn cũng có thể sử dụng nó trong mã mô hình! Ví dụ: trong __unicode __ () nó rất tiện dụng
Bogatyr

51

Giải pháp tốt nhất cho vấn đề của bạn là sử dụng các hàm trợ giúp. Nếu các lựa chọn được lưu trữ trong biến LỰA CHỌN và trường mô hình lưu trữ lựa chọn đã chọn là ' lựa chọn ' thì bạn có thể trực tiếp sử dụng

 {{ x.get_choices_display }}

trong mẫu của bạn. Ở đây, x là ví dụ mô hình. Hy vọng nó giúp.


3
Tại sao bạn lại trả lời như vậy 2 năm sau khi đã có câu trả lời hữu ích? Và ai sẽ bình chọn nó? Câu trả lời của nó giống như @roberto chỉ 2 năm sau ....
Boatcoder

15
@ Mark0978 lý do để nâng cao câu trả lời này là vì (đối với tôi) việc theo dõi câu trả lời "được bình chọn hàng đầu" là rõ ràng hơn. YMMV.
Nir Levy

49

Tôi xin lỗi nếu câu trả lời này là dư thừa với bất kỳ danh sách nào ở trên, nhưng có vẻ như câu trả lời này chưa được cung cấp và có vẻ khá sạch sẽ. Đây là cách tôi đã giải quyết điều này:

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]

Chế độ xem của tôi chuyển Scoop cho mẫu (lưu ý: không phải Scoop.values ​​()) và mẫu chứa:

{{ scoop.flavor_verbose }}

10

Dựa trên câu trả lời của Nô-ê, đây là phiên bản miễn dịch với các trường mà không có lựa chọn:

#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

Tôi không chắc chắn có ổn không khi sử dụng bộ lọc cho mục đích đó. Nếu bất cứ ai có giải pháp tốt hơn, tôi sẽ rất vui khi thấy nó :) Cảm ơn bạn Nô-ê!


+1 để đề cập đến đường dẫn của bạn # phiền toái / templatetags / ... LOL ... Tôi sử dụng get_FOO_display (), được đề cập ở dưới cùng của tài liệu biểu mẫu.
fmalina

ý tưởng tuyệt vời với việc sử dụng hasattr trên các lựa chọn!
oden

7

Chúng ta có thể mở rộng giải pháp bộ lọc của Nô-ê để phổ cập hơn trong việc xử lý các loại dữ liệu và trường:

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

Đây là mã:

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

Có vẻ khá phổ biến :) Không thể chắc chắn, vì tôi đã không làm quá nhiều Python hoặc Django kể từ thời điểm đó. Tuy nhiên, điều khá buồn là nó vẫn cần bộ lọc của bên thứ 3 (không bao gồm trong Django) (nếu không bạn sẽ nói với chúng tôi, Ivan, phải không?)) ...
Artur Gajowy

@ArturGajowy Vâng, tính đến ngày hôm nay, không có tính năng mặc định như vậy trong Django. Tôi đã đề xuất nó, ai biết được, có lẽ nó sẽ được chấp thuận .
Ivan Kharlamov

HOÀN HẢO! CÔNG TRÌNH THÍCH MỘT CHARM! BỘ LỌC TÙY CHỈNH ROX! CẢM ƠN BẠN! :-)
CeDeROM

5

Tôi không nghĩ rằng có bất kỳ cách tích hợp nào để làm điều đó. Mặc dù vậy, một bộ lọc có thể thực hiện thủ thuật:

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

Sau đó, bạn có thể làm:

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

3

Thêm vào mô hình của bạn một chức năng đơn giản:

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

Bây giờ, bạn có thể nhận giá trị dài dòng của các trường lựa chọn như thế:

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

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

Cập nhật.: Tôi không chắc chắn, giải pháp đó có hay không :)


0

Bạn có Model.get_FOO_display () trong đó FOO là tên của trường có các lựa chọn.

Trong mẫu của bạn làm điều này:

{{ scoop.get_flavor_display }}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.