使用 Crispy Forms 渲染 django 的 Multiwidget 和 MutliValueField Textarea
Render django's Multiwidget & MutliValueField Textarea using Crispy Forms
我有一个 TextField
用于存储大量文本,这些文本可以在逻辑上分为 10 个部分。我认为创建 10 个单独的 Textarea
是有意义的,每个用于一个逻辑部分。因此,我像这样子class编辑了MultiWidget
和MultiValueField
:
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__')
问题是,当我在表单的 HMTL 中使用 content
作为 {{ form.content | as_crispy_field }}
时,它呈现得非常丑陋
我希望所有 Textarea
都呈现在另一个下方。这里的主要问题是 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>
而且我不知道如何强制小部件的 class 为 textarea form-control
而不是 textarea
。最初,我发现 this question and also this blog 但他们所做的只是将小部件正确地分组到行和列中。我在这里遗漏了什么吗?
关键是将带有 "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)
我有一个 TextField
用于存储大量文本,这些文本可以在逻辑上分为 10 个部分。我认为创建 10 个单独的 Textarea
是有意义的,每个用于一个逻辑部分。因此,我像这样子class编辑了MultiWidget
和MultiValueField
:
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__')
问题是,当我在表单的 HMTL 中使用 content
作为 {{ form.content | as_crispy_field }}
时,它呈现得非常丑陋
Textarea
都呈现在另一个下方。这里的主要问题是 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>
而且我不知道如何强制小部件的 class 为 textarea form-control
而不是 textarea
。最初,我发现 this question and also this blog 但他们所做的只是将小部件正确地分组到行和列中。我在这里遗漏了什么吗?
关键是将带有 "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)