Django RadioSelect小部件,添加其他信息

时间:2020-08-12 11:21:48

标签: django django-forms django-crispy-forms

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

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表单中添加价格,使其可见。 它应该出现在书名之后,最好还是以其他字体出现,这是我在引导程序类(例如“ text-primary”)上设置的(这不是强制性的)

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

我知道我可以在模型中返回名称和价格,例如

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

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

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

1 个答案:

答案 0 :(得分:2)

您可以使用.label_from_instance

来自documentation

将调用模型的__str__()方法来生成对象的字符串表示形式,以供在字段的选择中使用。要提供自定义表示,请子类ModelChoiceField并覆盖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才会转义。