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

时间:2015-02-17 12:21:54

标签: django django-models django-forms django-views

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

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

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

  1. 如何将包含我的客户用户名和ID的Queryset与将包含每个查询集对象的单选按钮对的FormSet相结合?我很确定我需要使用FormSet来保存单选按钮,我想我需要设置formset" s" initial"查询集的值,但我无法将它们连接到" connect"所以表格看起来像我上面所示。当我执行"查看来源"时,我看不到我的帐户查询集对象。在我的浏览器中。
  2. 如何通过new_accounts查询集将来自帐户模型的用户列的客户ID连接到表单中的uid字段?
  3. 如何遍历提交的formset并提取用户ID和单选按钮对象以供检查?
  4. 我真的很难绕过这些任务。非常感谢你的帮助。

    # 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>
    

1 个答案:

答案 0 :(得分:2)

这对于formset来说并不是一项真正的工作。您想要一个带有动态字段集的单个表单;每个字段的名称是客户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})