如何在视图和模板中结合 Django FormSet 和 QuerySet?

How to combine Django FormSet and QuerySet in view and template?

我有一个 Django 1.6 应用程序,它将包含一个显示客户列表的表单,每个名称旁边有一对 "Approve" 和 "Reject" 单选按钮,以指示我们是批准还是拒绝他们的付款方式。我希望在首次呈现表单时将每个单选按钮默认设置为 "Reject"。我还想在包含客户用户 ID 的每一行中包含一个隐藏的 "uid" 字段。当管理员单击每个用户名旁边的批准按钮 s/he 想要批准然后提交表单时,视图应该读取每个用户的每个隐藏 id 值,检查单选按钮,如果用户更新模型被批准。表单如下所示:

customer1 (hidden id) [ ] approve  [x] reject
customer2 (hidden id) [ ] approve  [x] reject
...
customerN (hidden id) [ ] approve  [x] reject

我有三个问题不太明白如何解决:

  1. 如何将包含我的客户用户名和 ID 的查询集与将包含每个查询集对象的单选按钮对的表单集结合起来?我很确定我需要使用 FormSet 来保存单选按钮,我想我需要将表单集的 "initial" 值设置为查询集,但我无法将它们设置为 "connect" 以便表格看起来像我上面显示的那样。当我在浏览器中执行 "view source" 时,我没有看到我的帐户查询集对象。
  2. 如何通过 new_accounts 查询集将来自客户模型的用户列的客户 ID 连接到表单中的 uid 字段?
  3. 如何遍历提交的表单集并提取用户 ID 和单选按钮对象进行检查?

我真的很难全神贯注于这些任务。非常感谢您的帮助。

# views.py
def review_payment_methods(request, template):
if request.method == "POST":
    payment_method_form = ReviewPaymentMethodForm(request.POST)
    if payment_method_form.is_valid():
        # How to iterate through form and pull out ids and radio button values??
        # Update Account table here
        return HttpResponseRedirect('/admin/')
else:
    new_accounts = Account.objects.filter(method_approved=False).values()
    PaymentMethodFormset = formset_factory(ReviewPaymentMethodForm, extra=new_accounts.count())
    formset = PaymentMethodFormset(initial=new_accounts)  # This doesn't seem to work
return render_to_response(template, locals(), context_instance=RequestContext(request))

# models.py
class Account(models.Model):
"""A user's account."""
user = models.OneToOneField(User, primary_key=True, unique=True)
method_approved = models.BooleanField(default=False)  # This contains Approve/Reject

# forms.py
from django import forms
from django.utils.safestring import mark_safe

class ReviewPaymentMethodForm(forms.Form):
    class HorizontalRadioRenderer(forms.RadioSelect.renderer):
        def render(self):
            return mark_safe(u'\n'.join([u'%s\n' % w for w in self]))

    DECISION_CHOICES = (('1', 'Approve'), ('2', 'Reject'))
    uid = forms.IntegerField(widget=forms.HiddenInput)
    decision = forms.ChoiceField(
        choices = DECISION_CHOICES,
        widget = forms.RadioSelect(renderer=HorizontalRadioRenderer),
        initial = '2',  # 1 => Approve, 2 => Reject
    )

# review_payment_methods.html
<div class="custom-content">
    <h1>Review Payment Methods</h1>
    <form action="." method="post">{% csrf_token %}
        {% for form in formset %}
            {{ form.as_p }}
        {% endfor %}
        <input type="submit" value="Submit" />
    </form>
</div>

这实际上不是表单集的工作。您想要一个带有一组动态字段的单一表单;每个字段的名称是客户 UID,其值是接受或拒绝。为此,您可以在实例化表单时以编程方式创建字段:

class ReviewPaymentMethodForm(forms.Form):
    def __init__(self, *args, **kwargs):
        accounts = kwargs.pop('accounts')
        super(ReviewPaymentMethodForm, self).__init__(*args, **kwargs)
        for account in accounts:
            self.fields[str(account.id)] = forms.ChoiceField(
                label=account.user.username,
                choices=DECISION_CHOICES,
                widget=forms.RadioSelect(renderer=HorizontalRadioRenderer),
                initial='2',  # 1 => Approve, 2 => Reject
            )

视图变为:

def review_payment_methods(request, template):
    new_accounts = Account.objects.filter(method_approved=False)
    if request.method == "POST":
        payment_method_form = ReviewPaymentMethodForm(request.POST, accounts=new_accounts)
        if payment_method_form.is_valid():
            for acc_id, value in payment_method_form.cleaned_data.items():
                approved = (value == '1')
                Account.objects.filter(pk=acc_id).update(method_approved=approved)
            return HttpResponseRedirect('/admin/')
    else:

        form = ReviewPaymentMethodForm(accounts=new_accounts)
    return render(request, template, {'form': form})