本文介绍了Django Formsets - form.is_valid()是False防止formset验证的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

限时删除!!

我正在使用一个表单来使用户订阅多个Feed。我需要a)用户通过选择一个布尔字段来选择订阅,并且还需要对订阅进行标记,以及b)用户必须订阅指定数量的订阅。



目前,以下代码能够确保用户标记订阅,但是我的一些表单is_valid()是False,从而阻止我对完整表单的验证。



以下是代码:



<$ p $从django导入表单的$ p code从django.forms.formsets导入的
导入BaseFormSet
从tagging.forms导入TagField
从rss.feeder.models导入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我们的自定义验证规则
data = self.cleaned_data
feed = data.get(subscribe)
tags = data.get(tags)
tag_len = len(tags.split())
self._errors = {}
如果feed == True和tag_len< 1:
raise forms.ValidationError(No feed specified for feed)
返回数据



class FeedFormSet(BaseFormSet):

def __init __(self,* args,** kwargs):
self.feeds = list(kwargs.pop(feeds))
self.req_subs = 3#TODO:convert对于kwargs arguement
self.extra = len(self.feeds)
super(FeedFormSet,self).__ init __(* args,** kwargs)

#警告!使用无证件。看看详情...
def _construct_form(self,i,** kwargs):
kwargs [feed] = self.feeds [i]
return super(FeedFormSet,self) $ _ $$

$ b def clean(self):
检查只有所需数量的Feed订阅存在
如果有的话(self.errors):
#不要做任何事情,除非所有FeedForms都有效
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
如果total_subs!= self.req_subs:
raise forms.ValidationError(更多订阅...)#TODO更多信息
返回表单.cleaned_data

根据要求,视图代码:

 <$来自django.forms的c $ c> import formets 
从django.http import Http404
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response

from rss .feeder.forms导入FeedForm
从rss.feeder.forms导入FeedFormSet
从rss.feeder.models导入Feed

FeedSet = formsets.formset_factory(FeedForm,FeedFormSet)

def feeds(request):
如果request.method ==POST:
formset = create_feed_formset(request.POST)
如果formset.is_valid():
#提交结果
return HttpResponseRedirect('/ feeder / thanks /')
else:
formset = create_feed_formset()
返回render_to_response('feeder / register_step_two.html ',{'formset':formset})


def create_feed_formset(data = None):
创建并填充feed formset
feed = Feed.objects.order_by('id')
如果不是feed:
#没有Feed找到,我们应该创建它们
raise Http404('Invalid Step')
返回FeedSet(data,feeds = feeds)#返回formset的实例

任何帮助将不胜感激。



Ps。为了完整披露,此代码基于



[已解决]请参阅下面的解决方案。 $ b

解决方案

已解决。以下是解决方案的一个快速实现。



报告所需的错误操作和形成特殊的错误消息。在formets的源代码中,我发现适用于整个表单的错误称为 non_form_errors ,并基于此产生自定义错误。 [注意:我找不到任何有关这方面的授权文件,所以有人可能会知道一个更好的方法]。代码如下:

  def append_non_form_error(self,message):
errors = super(FeedFormSet,self) non_form_errors()
errors.append(message)
raise forms.ValidationError(errors)

formet clean方法也需要一些调整。基本上,它检查表单是否被绑定(空的不是,因此is_valid在问题中为false),如果这样访问检查那里的订阅值。

  def clean(self):
检查只有所需数量的Feed订阅存在
count = 0
表示自己。 form:
如果form.is_bound:
如果form ['subscribe']。data:
count + = 1
如果count> 0和count!= self.required:
self.append_non_form_error(not enough subs)



形式['field_name']。data 格式访问该值。这允许我们检索原始值,并总是获得订阅的计数,允许我返回整个表单的所有相关消息,即个别表单和更高级别问题(如订阅数量)的具体问题,这意味着用户赢得不必重复提交表单,以通过错误列表。



最后,我错过了我的模板的一个关键方面, { {formset.non_form_errors}} 标签。以下是更新的模板:

  {%extendsbase.html%} 
{%load i18n%}

{%block content%}
< form action =。方法= POST >
{{formset.management_form}}
{{formset.non_form_errors}}
< ol>
{form for formset.forms%}
< li>< p> {{form.title}}< / p>
< p> {{form.description}}< / p>
{{form.as_p}}
< / li>
{%endfor%}
< / ol>
< input type =submit>
< / form>

{%endblock%}


I'm am utilizing a formset to enable users subscribe to multiple feeds. I require a) Users chose a subscription by selecting a boolean field, and are also required to tag the subscription and b) a user must subscribe to an specified number of subscriptions.

Currently the below code is capable of a) ensuring the users tags a subscription, however some of my forms is_valid() are False and thus preventing my validation of the full formset. [edit] Also, the relevant formset error message fails to display.

Below is the code:

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

As requested, the view code:

from django.forms import formsets
from django.http import Http404
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response

from rss.feeder.forms import FeedForm
from rss.feeder.forms import FeedFormSet
from rss.feeder.models import Feed

FeedSet = formsets.formset_factory(FeedForm, FeedFormSet)

def feeds(request):
    if request.method == "POST":
        formset = create_feed_formset(request.POST)
        if formset.is_valid():
            # submit the results
            return HttpResponseRedirect('/feeder/thanks/')
    else:
        formset = create_feed_formset()
    return render_to_response('feeder/register_step_two.html', {'formset': formset})


def create_feed_formset(data=None):
    """Create and populate a feed formset"""
    feeds = Feed.objects.order_by('id')
    if not feeds:
        # No feeds found, we should have created them
        raise Http404('Invalid Step')
    return FeedSet(data, feeds=feeds)        # return the instance of the formset

Any help would be appreciated.

Ps. For full disclosure, this code is based on http://google.com/search?q=cache:rVtlfQ3QAjwJ:https://www.pointy-stick.com/blog/2009/01/23/advanced-formset-usage-django/+django+formset

[Solved] See solution below.

解决方案

Solved. Below is a quick run through of the solution.

Reporting the error required manipulating and formating a special error message. In the source code for formsets I found the errors that apply to a whole form are known as non_form_errors and produced a custom error based on this. [note: I couldn't find any authoritive documentation on this, so someone might know a better way]. The code is below:

def append_non_form_error(self, message):
    errors = super(FeedFormSet, self).non_form_errors()
    errors.append(message)
    raise forms.ValidationError(errors)

The formsets clean method also needed a few tweaks. Basically it checks the if the forms is bound (empty ones aren't, hence is_valid is false in the question) and if so accesses checks there subscribe value.

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

Some might wonder why I choose to access the value using the form['field_name'].data format. This allows us to retrieve the raw value and always get a count on subscriptions, allowing me to return all relevant messages for the entire formset, i.e. specific problems with individual forms and higher level problems (like number of subscriptions), meaning that the user won't have to resubmit the form over and over to work through the list of errors.

Finally, I was missing one crucial aspect of my template, the {{ formset.non_form_errors }} tag. Below is the updated template:

{% 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 %}

这篇关于Django Formsets - form.is_valid()是False防止formset验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

1403页,肝出来的..

09-08 00:54