Django RadioSelect 小部件,添加附加信息

Django RadioSelect widget, add additional information

我有这个简化的模型和表格:

class Books(models.Model):
    name = models.CharField(max_length=500)
    price = models.DecimalField(max_digits=6, decimal_places=2)
    default = models.BooleanField(default=False)

    def __str__(self):
        return self.name



class BookForm(forms.Form):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.fields['Field'] = forms.ModelChoiceField(queryset=None, empty_label=None, widget=forms.RadioSelect)
        self.fields['Field'].queryset = Books.objects.all()
        self.fields['Field'].initial = Books.objects.filter(default=True).first()

这将产生一个 RadioSelect-Form,如下所示:

(x) Book1
( ) Book2
( ) Book3

我的问题是,如何在 RadioSelect 表单中添加价格,它只是可见的。 它应该出现在书名之后,最好是不同的字体,我在 bootstrap class 上设置(例如“text-primary”)(这不是强制性的)

(x) Book1 (10 €)
( ) Book2 (20 €)
( ) Book3 (30 €)

我知道我可以return模型中的名称和价格,例如

class Books(models.Model):
    name = models.CharField(max_length=500)
    price = models.DecimalField(max_digits=6, decimal_places=2)
    default = models.BooleanField(default=False)

    def __str__(self):
        return '%s (%s €)' % (self.value, str(self.price))

但由于其他原因,我无法做到这一点。我只需要 return 这个名字。还有其他方法吗?

我什至阅读了 django-crispy-forms,但找不到解决方案。

您可以使用 .label_from_instance.

来自documentation

The __str__() method of the model will be called to generate string representations of the objects for use in the field’s choices. To provide customized representations, subclass ModelChoiceField and override label_from_instance.

您可以定义一个函数来为您提供所需的表示,然后在您的字段上设置 .label_from_instance

你的 BookForm 看起来像这样:

class BookForm(forms.Form):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.fields['Field'] = forms.ModelChoiceField(queryset=None, empty_label=None, widget=forms.RadioSelect)
        self.fields['Field'].queryset = Books.objects.all()
        self.fields['Field'].initial = Books.objects.filter(default=True).first()
        # customize how your option is rendered in the template
        self.fields["Field"].label_from_instance = lambda item: f"{item} ({item.price} €)"

要在标签上应用 CSS,请添加 HTML。除了使用 style='...',您还可以使用 类,因此它适用于 Bootstrap。

self.fields["Field"].label_from_instance = lambda item: f"{item} <span style='color:red;'>({item.price} €)</span>"

对于 3.7 之前的 Python 版本:

self.fields["Field"].label_from_instance = lambda item: str(item) + "<span style='color:red;'>(" + str(item.price) + " €)</span>"

然后像这样在模板中呈现您的表单:

<form action="{% url 'books' %}" method="post">
    {% csrf_token %}
    {% for hidden_field in form.hidden_fields %}
        {{ hidden_field }}
    {% endfor %}
    <ul>
    {% for choice in form.Field %}
        <li>{{ choice.choice_label|safe }}</li>
    {% endfor %}
    </ul>
    <input class="btn btn-dark" type="submit" value="Submit">
</form>

遍历您的字段的选择,然后您可以获得自定义标签:

{{ choice.choice_label|safe }}

需要 safe 过滤器,这样您的 HTML 就不会被转义。