1 回答

TA貢獻1772條經驗 獲得超8個贊
您可以在每條錯誤消息上放置一個唯一標識符,但這有點繁瑣,我不確定我會認為它有多“安全”。我認為對于您想要的更好的選擇是迭代表單中的字段,并一次呈現字段和錯誤消息。這篇文章的結尾描述了如何做到這一點。如果您真正想要的是將標識符放在錯誤消息上,而無需遍歷模板中的字段……好吧,請繼續閱讀。
艱難的道路
為了獲得為每個錯誤消息呈現的不僅僅是一個簡單的文本消息(不破壞模板中的表單),您需要ErrorList為ModelForm. 該類ErrorList在 HTML 中執行錯誤的呈現,因此通過創建和使用子類,您可以更改呈現的內容 - 包括從 ValidationError 本身添加特殊代碼。
from django.forms.utils import ErrorList
from django.utils.html import format_html, format_html_join
# This overrides the ErrorList class to provide the additional rendering
# features you want - in this example it only overrides it for the `ul` output
class ErrorListDerivative(ErrorList):
def as_ul(self):
if not self.data:
return ''
# Key part 1: the UL is now being rendered with a class for
# each of the errors which includes the error code from the
# ValidationError. You can then locate the UL by looking for that class.
return format_html(
'<ul class="{{}} {}">{{}}</ul>'.format(' '.join(('errorcode{}'.format(e.code) for e in self.data))),
self.error_class,
# Key Part 2: This adds the code from the validation error to the individual LIs
format_html_join('', '<li class="errorforcode{}">{}</li>', ((e.code, e.message) for e in self.data))
)
現在已經創建了一個以您想要的方式呈現事物的 ErrorList,TestForm 需要使用它。
class TestForm(forms.ModelForm):
# This __init__ is what makes the ModelForm use the custom ErrorList class you've created.
# The BaseForm from which ModelForm is derived (a few layers of inheritence deep) has an `error_class` argument to receive the class used to render errors. This just injects your custom class.
def __init__(self, *args, **kwargs):
kwargs_new = {'error_class': ErrorListDerivative}
kwargs_new.update(kwargs)
super().__init__(*args, **kwargs_new)
class Meta:
model = Restaurant
fields = [
'title',
'content',
]
然后,在您的 TestForm clean 函數中,將附加值傳遞code給ValidationErrors
def clean(self, *args, **kwargs):
title = self.cleaned_data.get("title")
content = self.cleaned_data.get("content")
error_dict = {}
# Key Part 3: Here we're including the custom error code in the
# ValidationError, which will be rendered out
if len(title) < 3:
error_dict['title'] = ValidationError("testerror1", code='title')
if len(content) < 3:
error_dict['content'] = ValidationError('testerror2', code='content')
if error_dict:
# Must admit, not sure if adding a code here will do anything at all
raise ValidationError(error_dict, code='3')
完成此操作后,HTML 輸出應如下所示:
<form id="my_form_id" method="post" novalidate="">
<label for="id_title">Title:</label>
<ul class="errorlist errorcodetitle">
<li class="errorforcodetitle">testerror1</li>
</ul><input type="text" name="title" value="ao" maxlength="100" required="" id="id_title">
<label for="id_content">Content:</label>
<ul class="errorlist errorcodecontent">
<li class="errorforcodecontent">testerror2</li>
</ul><input type="text" name="content" value="ao" maxlength="100" required="" id="id_content">
<button type="submit">Submit</button>
</form>
現在有了這些 UL 上的類,您可以使用該字段的名稱來定位相關的 UL 并將其隱藏。
$("#my_form_id").find('input, textarea').click(function(evt) {
$('.errorcode' + this.name).hide();
})
慣用的方式
如果您不想進入那個兔子洞,另一種方法是做一些更像 django 文檔中的示例“循環遍歷表單的字段”(https://docs.djangoproject.com/en/3.0/ topic/forms/#looping-over-the-form-s-fields)它不會在錯誤消息中為您提供自定義類(或 ids,無論您最終添加什么),但它更慣用。
類似于以下內容...
{% for field in form %}
<div class="fieldWrapper">
<div class="errorcode{{field.html_name}}">
{{ field.errors }}
</div>
{{ field.label_tag }} {{ field }}
{% if field.help_text %}
<p class="help">{{ field.help_text|safe }}</p>
{% endif %}
</div>
{% endfor %}
然后您可以使用與上述相同的 jquery:
$("#my_form_id").find('input, textarea').click(function(evt) {
$('.errorcode' + this.name).hide();
})
添加回答
舉報