Python Django Formsets-form.is_valid()为False,防止表单集验证
我正在利用一个表单集来让用户订阅多个提要。我要求a)用户通过选择布尔字段来选择订阅,并且还要求用户标记订阅;b)用户必须订阅指定数量的订阅 目前,下面的代码能够a)确保用户标记订阅,但是我的一些表单是_valid()是错误的,因此阻止了我对完整表单集的验证。[编辑]此外,相关表单集错误消息无法显示 代码如下:Python Django Formsets-form.is_valid()为False,防止表单集验证,python,django,django-forms,Python,Django,Django Forms,我正在利用一个表单集来让用户订阅多个提要。我要求a)用户通过选择布尔字段来选择订阅,并且还要求用户标记订阅;b)用户必须订阅指定数量的订阅 目前,下面的代码能够a)确保用户标记订阅,但是我的一些表单是_valid()是错误的,因此阻止了我对完整表单集的验证。[编辑]此外,相关表单集错误消息无法显示 代码如下: from django import forms from django.forms.formsets import BaseFormSet from tagging.forms impo
from django import forms
from django.forms.formsets import BaseFormSet
from tagging.forms import TagField
from rss.feeder.models import Feed
class FeedForm(forms.Form):
subscribe = forms.BooleanField(required=False, initial=False)
tags = TagField(required=False, initial='')
def __init__(self, *args, **kwargs):
feed = kwargs.pop("feed")
super(FeedForm, self).__init__(*args, **kwargs)
self.title = feed.title
self.description = feed.description
def clean(self):
"""apply our custom validation rules"""
data = self.cleaned_data
feed = data.get("subscribe")
tags = data.get("tags")
tag_len = len(tags.split())
self._errors = {}
if feed == True and tag_len < 1:
raise forms.ValidationError("No tags specified for feed")
return data
class FeedFormSet(BaseFormSet):
def __init__(self, *args, **kwargs):
self.feeds = list(kwargs.pop("feeds"))
self.req_subs = 3 # TODO: convert to kwargs arguement
self.extra = len(self.feeds)
super(FeedFormSet, self).__init__(*args, **kwargs)
# WARNING! Using undocumented. see for details...
def _construct_form(self, i, **kwargs):
kwargs["feed"] = self.feeds[i]
return super(FeedFormSet, self)._construct_form(i, **kwargs)
def clean(self):
"""Checks that only a required number of Feed subscriptions are present"""
if any(self.errors):
# Do nothing, don't bother doing anything unless all the FeedForms are valid
return
total_subs = 0
for i in range(0, self.extra):
form = self.forms[i]
feed = form.cleaned_data
subs = feed.get("subscribe")
if subs == True:
total_subs += 1
if total_subs != self.req_subs:
raise forms.ValidationError("More subscriptions...") # TODO more informative
return form.cleaned_data
任何帮助都将不胜感激
注:为了充分披露,本规范基于
[已解决]请参阅下面的解决方案。我试图绕过我的问题……这不是一个好的解决方案,这是一个非常棘手的问题。它允许用户在订阅所需数量的提要(在下面的情况下大于1)时继续操作,但是如果少于所需数量的提要,它将无法显示引发的错误消息
def clean(self):
count = 0
for i in range(0, self.extra):
form = self.forms[i]
try:
if form.cleaned_data:
count += 1
except AttributeError:
pass
if count > 1:
raise forms.ValidationError('not enough subscriptions')
return form.cleaned_data
我确实在模板中使用了{{formset.management_form}},据我所知,应该会显示错误。以防我被误导
{% extends "base.html" %}
{% load i18n %}
{% block content %}
<form action="." method="post">
{{ formset.management_form }}
<ol>
{% for form in formset.forms %}
{{ form.as_p }}
</li>
{% endfor %}
</ol>
<input type="submit">
</form>
{% endblock %}
{%extends“base.html”%}
{%load i18n%}
{%block content%}
{{formset.management_form}
{formset.forms%%中表单的%
{{form.as_p}}
{%endfor%}
{%endblock%}
已解决。下面是解决方案的简要介绍
报告错误需要操纵和格式化特殊错误消息。在formset的源代码中,我发现应用于整个表单的错误称为non_form_错误,并基于此生成了一个自定义错误。[注意:我找不到任何关于此的权威文档,因此有人可能知道更好的方法]。代码如下:
def append_non_form_error(self, message):
errors = super(FeedFormSet, self).non_form_errors()
errors.append(message)
raise forms.ValidationError(errors)
FormSetsClean方法也需要一些调整。基本上,它检查表单是否绑定(空的表单没有绑定,因此在问题中is\u valid是false),如果是,则访问检查订阅值
def clean(self):
"""Checks that only a required number of Feed subscriptions are present"""
count = 0
for form in self.forms:
if form.is_bound:
if form['subscribe'].data:
count += 1
if count > 0 and count != self.required:
self.append_non_form_error("not enough subs")
有些人可能想知道为什么我选择使用['field_name'].数据格式访问该值。这允许我们检索原始值并始终获得订阅计数,允许我返回整个表单集的所有相关消息,即单个表单的特定问题和更高级别的问题(如订阅数),这意味着用户不必反复提交表单来处理错误列表
最后,我缺少了模板的一个关键方面{{formset.non_form_errors}}标记。以下是更新的模板:
{% extends "base.html" %}
{% load i18n %}
{% block content %}
<form action="." method="post">
{{ formset.management_form }}
{{ formset.non_form_errors }}
<ol>
{% for form in formset.forms %}
<li><p>{{ form.title }}</p>
<p>{{ form.description }}</p>
{{ form.as_p }}
</li>
{% endfor %}
</ol>
<input type="submit">
</form>
{% endblock %}
{%extends“base.html”%}
{%load i18n%}
{%block content%}
{{formset.management_form}
{{formset.non_form_errors}
{formset.forms%%中表单的%
{{form.title}}
{{form.description}}
{{form.as_p}}
{%endfor%}
{%endblock%}
请同时显示查看代码。按要求添加查看代码。
{% extends "base.html" %}
{% load i18n %}
{% block content %}
<form action="." method="post">
{{ formset.management_form }}
{{ formset.non_form_errors }}
<ol>
{% for form in formset.forms %}
<li><p>{{ form.title }}</p>
<p>{{ form.description }}</p>
{{ form.as_p }}
</li>
{% endfor %}
</ol>
<input type="submit">
</form>
{% endblock %}