簡體   English   中英

Django Formsets-form.is_valid()為False,無法進行表單集驗證

[英]Django Formsets - form.is_valid() is False preventing formset validation

我正在利用一個表單集來使用戶訂閱多個提要。 我要求a)用戶通過選擇布爾值字段選擇訂閱,並且還需要標記訂閱,並且b)用戶必須訂閱指定數量的訂閱。

目前,以下代碼能夠a)確保用戶標記訂閱,但是我的某些表單is_valid()為False,因此無法驗證完整的表單集。 [edit]另外,相關的表單集錯誤消息也無法顯示。

下面是代碼:

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

根據要求,查看代碼:

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

任何幫助,將不勝感激。

PS。 為了全面披露,此代碼基於http://google.com/search?q=cache:rVtlfQ3QAjwJ:https://www.pointy-stick.com/blog/2009/01/23/advanced-formset-usage -django / + + django的表單集

[已解決]請參閱下面的解決方案。

解決了。 以下是該解決方案的快速介紹。

報告錯誤需要處理和格式化特殊的錯誤消息。 在表單集的源代碼中,我發現適用於整個表單的錯誤稱為non_form_errors並在此基礎上產生了自定義錯誤。 [注意:我找不到關於此的任何權威性文檔,所以有人可能知道更好的方法]。 代碼如下:

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

表單集的清潔方法也需要進行一些調整。 基本上,它檢查表單是否綁定(不是空表單,因此is_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")

有人可能會奇怪,為什么我選擇使用form ['field_name']。data格式訪問值。 這使我們能夠檢索原始值並始終獲得訂閱計數,從而使我可以返回整個表單集的所有相關消息,即單個表單的特定問題和更高級別的問題(例如訂閱數),這意味着用戶贏得了不必一遍又一遍地重新提交表格以遍歷錯誤列表。

最后,我錯過了模板的一個關鍵方面{{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 %}

我試圖避開我的問題...這不是一個好的解決方案,它非常容易被破解。 如果人們訂閱了所需數目的提要(在以下情況下,數目大於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 %}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM