【问题标题】:How to combine Django FormSet and QuerySet in view and template?如何在视图和模板中结合 Django FormSet 和 QuerySet?
【发布时间】:2015-04-18 03:23:05
【问题描述】:

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

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

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

  1. 如何将包含我的客户用户名和 ID 的查询集与包含每个查询集对象的单选按钮对的 FormSet 结合起来?我很确定我需要使用 FormSet 来保存单选按钮,并且我认为我需要将 formset 的“初始”值设置为查询集,但我无法让它们“连接”以便表单看起来像什么我已经在上面展示了。当我在浏览器中执行“查看源代码”时,我没有看到我的帐户查询集对象。
  2. 如何通过 new_accounts 查询集将来自 Account 模型的用户列的客户 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>

【问题讨论】:

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


    【解决方案1】:

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

    【讨论】:

    • 谢谢,丹尼尔。这看起来应该可以工作,但模板无法正确呈现。由于我不再呈现表单集,因此我将 HTML 更改为 {% for account in form.fields %} {{ account }} {% endfor %}。但我看到的只是用户 ID。我看不到如何显示用户名和单选按钮。我继续尝试解决这个问题。
    • 您只需要迭代 form,而不是 form.fields - 请参阅 the documentation。或者您可以直接输出form.as_p 以一次性渲染全部内容。
    • 我之前曾尝试过使用“{% for account in form %} {{ account.as_p }} {% endfor %}”,但在“for account in form”行中出现 AttributeError : 'int' 对象没有属性 'replace',该属性在 .../django/forms/forms.py 中的 pretty_name 第 30 行提出。
    • 对不起,您需要使用一个字符串作为表单名称,上面已更新(我还添加了一个标签)。它要么只是{{ form.as_p }} 要么是{% for field in form %} {{ field }} {% endfor %}
    • 谢谢你,丹尼尔。有效!我很感激你的帮助。我修复了您代码中的两个拼写错误,然后我还必须将“{{ field.label }}”添加到模板的“for field in form”块中以显示用户名。这是非常好的代码。我现在要回去查看所有表单文档,以确保我理解你所做的一切。显然,创建这个表单并不像看起来那么简单。
    猜你喜欢
    • 2020-09-16
    • 1970-01-01
    • 1970-01-01
    • 2021-02-15
    • 2021-09-06
    • 1970-01-01
    • 2012-05-26
    • 2020-07-06
    • 1970-01-01
    相关资源
    最近更新 更多