首页 > 解决方案 > 使用 Crispy Forms 渲染 django 的 Multiwidget 和 MutliValueField 文本区域

问题描述

TextField打算存储大量可以在逻辑上分成 10 部分的文本。我认为创建 10 个单独Textarea的 s 是有意义的,每个用于一个逻辑部分。因此,我进行了子类化MultiWidgetMultiValueField就像这样:

class MultiWidget(forms.widgets.MultiWidget):
    template_name = "custom_content_widget.html"
    attrs = {"class": "textarea form-control"}

    def __init__(self, attrs=None):
        widgets = [Textarea()] * 10
        super(MultiWidget, self).__init__(widgets, attrs)

    def decompress(self, value):
        if value:
            return value
        return ["", "", "", "", "", "", "", "", "", ""]


class ContentField(MultiValueField):
    widget = MultiWidget

    def __init__(self, *args, **kwargs):
        # Define one message for all fields.
        error_messages = {
            'required': 'This field is required.',
        }
        # Or define a different message for each field.
        fields = [CharField()] * 10

        super(ContentField, self).__init__(
            error_messages=error_messages, fields=fields, require_all_fields=True, *args, **kwargs)

        # self.helper = FormHelper()
        # self.helper.layout = Layout(
        #
        # )

    def compress(self, data_list):
        return " ".join(data_list)

custom_content_widget.html存在公正

{% for subwidget in widget.subwidgets %}
    {% with widget=subwidget %}
        {% include widget.template_name %}
    {% endwith %}
{% endfor %}

我想在其中使用这个 multiwidget 的简单模型和形式

class Opinion(models.Model):
    content = models.TextField()

class OpinionForm(forms.ModelForm):
    content = ContentField()

    class Meta:
        model = Opinion
        fields = ('__all__')

问题是,当我content在表单的 HMTL 中使用{{ form.content | as_crispy_field }}它时,它变得非常难看 在此处输入图像描述 ,我希望所有的Textareas 都呈现在另一个之下。这里的主要问题textarea是呈现为

<textarea name="content_0" cols="40" rows="10" class="textarea" required id="id_content_0">
</textarea>

而“正常”TextField呈现为

<textarea name="content" cols="40" rows="10" class="textarea form-control" required id="id_content">
</textarea>

而且我不知道如何强制小部件的类textarea form-control代替textarea. 最初,我发现了这个问题这个博客,但他们所做的只是将小部件正确地分组到行和列中。我在这里有什么遗漏吗?

标签: htmldjangobootstrap-4django-formsdjango-crispy-forms

解决方案


关键是将属性 dict 传递"class": "textarea form-control"MultiWidget构造函数,如下所示

class ContentField(MultiValueField):
    widget = MultiWidget({"class": "textarea form-control"})

    def __init__(self, *args, **kwargs):
        # Define one message for all fields.
        error_messages = {
            'required': 'This field is required.',
        }
        # Or define a different message for each field.
        fields = [CharField()] * 10

        super(ContentField, self).__init__(
            error_messages=error_messages, fields=fields, require_all_fields=True, *args, **kwargs)

    def compress(self, data_list):
        return " ".join(data_list)

推荐阅读