Django:首次提交后的Strange Formset行为

时间:2014-03-08 22:05:08

标签: python django forms django-forms

提前发帖!

这是my previous question的后续内容,其中涉及创建一个将一个表单与每个用户相关联的反馈页面。我能够做到这一点,但它是以我认为是一种被黑客攻击的方式完成的,因为在我提交反馈一次后,我看到了一些非常奇怪的行为。

我们之前没有提交过任何反馈意见,现在我想向三个人中的两个人提交反馈意见(img)。隐藏的management_form详细信息如下所示:

<input id="id_form-TOTAL_FORMS" name="form-TOTAL_FORMS" type="hidden" value="3" />
<input id="id_form-INITIAL_FORMS" name="form-INITIAL_FORMS" type="hidden" value="0" />  
<input id="id_form-MAX_NUM_FORMS" name="form-MAX_NUM_FORMS" type="hidden" value="1000" />

在提交时,这会成功在反馈表中创建两个新条目。问题是,如果我进入任何反馈页面(如同任何用户),我会看到我已经创建的反馈,并且我在提交时会收到错误。

如果我现在转到一个或两个用户的页面,我会看到一个或两个表单(这很好)但是management_form数据不正确。例如,在一个用户页面上,我将看到此management_form数据:

<input id="id_form-TOTAL_FORMS" name="form-TOTAL_FORMS" type="hidden" value="3" />
<input id="id_form-INITIAL_FORMS" name="form-INITIAL_FORMS" type="hidden" value="2" />   
<input id="id_form-MAX_NUM_FORMS" name="form-MAX_NUM_FORMS" type="hidden" value="1000" />

并收到此错误:

MultiValueDictKeyError at /feedback/2/
"u'form-1-id'"

由于我只应该看到一个表格,我所看到的一切,并且它已经设置为已经创建的两个反馈中的第一个,但显然是管理数据的问题。初始值应为0(不是2),总表格应为1(不是3)。

如果我转到具有相同数量用户的页面,我将看到原始的三个反馈表单,并使用此management_form数据:

<input id="id_form-TOTAL_FORMS" name="form-TOTAL_FORMS" type="hidden" value="5" />
<input id="id_form-INITIAL_FORMS" name="form-INITIAL_FORMS" type="hidden" value="2" />
<input id="id_form-MAX_NUM_FORMS" name="form-MAX_NUM_FORMS" type="hidden" value="1000" />

同样,总数应为3(不是5),初始值应为0(不是2)。这次我没有收到任何错误,因为我会收到一条消息,说我需要填写两个甚至不会出现在页面上的表格的值。

希望能够很好地解释这个问题,所以这里是代码:

models.py

class Feedback(models.Model):
    action = models.ForeignKey(Action)
    feedback = models.CharField(max_length=1)
    feedback_by = models.ForeignKey(UserProfile, related_name='feedback_by')
    feedback_for = models.ForeignKey(UserProfile, related_name='feedback_for')
    comment = models.CharField(max_length=200)
    created = models.DateTimeField()
    modified = models.DateTimeField()

    def save(self, *args, **kwargs):        
        if not self.id:
            self.created = datetime.datetime.today()
        self.modified = datetime.datetime.today()

        return super(Feedback, self).save(*args, **kwargs)

forms.py

class FeedbackForm(forms.ModelForm):
    choices = (('g', '(+1) Positive'),
               ('b', '(±0) Negative'),
               ('n', '(-1) No Show'),
               ('d', 'Don\'t Leave Feedback'))
    feedback = forms.ChoiceField(widget=forms.RadioSelect(), choices=choices, initial='d')
    comment = forms.CharField(widget=forms.Textarea())

    class Meta:
        model = Feedback
        fields = ['feedback_for','feedback','comment']

views.py

@login_required
def new_feedback(request, action_id):

    action = get_object_or_404(Action, id=action_id)
    profile = UserProfile.objects.get(user_id=request.user.id)  
    participants = all_info_many_profiles(action.participants.filter(~Q(id=profile.id)))

    fbformset = modelformset_factory(Feedback, form=FeedbackForm, extra=len(participants))

    if request.method == 'POST':    
        formset = fbformset(request.POST, request.FILES)
        if formset.is_valid():
            #formset.save(commit=False)
            for form in formset:
                tmp = form.save(commit=False)
                tmp.action = action
                tmp.feedback_by = profile
                if tmp.feedback != 'd':
                    tmp.save()
            return index(request)
        else:
            print formset.errors
            #return index(request)        
    else:
        formset = fbformset()

    return render(request, 'app/new_feedback.html', 
                  {'action': action, 'participants': participants, 'formset': formset}
                  )

feedback.html

{% load multifor %}
{% block body_block %}
    <h1>Leave Feedback</h1>  

    <form method="post" action="{% url 'app:new_feedback' action.id%}">
        {% csrf_token %}
        {% comment %}
        <input id="id_form-TOTAL_FORMS" name="form-TOTAL_FORMS" type="hidden" value="{{participants.count}}" />
        <input id="id_form-INITIAL_FORMS" name="form-INITIAL_FORMS" type="hidden" value="0" />
        <input id="id_form-MAX_NUM_FORMS" name="form-MAX_NUM_FORMS" type="hidden" value="1000" />
        {% endcomment %}
        {{ formset.management_form }}
        {{ formset.errors }}
        {% for form in formset; participant in participants %}
            {{ form.id }}
            {{ form.errors }}
            <input id="id_form-{{forloop.counter0}}-feedback_for" name="form-{{forloop.counter0}}-feedback_for" type="hidden" value="{{participant.id}}" /> <br />
            {{ form.feedback_for.label }} {{ participant.username }}: <br />
            {% for radio in form.feedback %}
                {{ radio }} <br />
            {% endfor %}<br />
            {{ form.comment.label }} {{ form.comment }} <br /><br />
        {% endfor %}
        <input type="submit" name="submit" value="Submit Feedback" />
    </form>

{% endblock %}

1 个答案:

答案 0 :(得分:0)

问题是你使用的是modelformset_factory,这个工厂与模型绑定,它会通过填充东西“{3}}来”帮助“你。

您可以使用普通this is why the count is at 5获得所需的结果。 Django的文档有formset_factory