我想在 Django 中处理多个字段。在 PHP 中,我使用生成的 HTML,例如:
<input type="text" name="myfield[1]" />
<input type="text" name="myfield[4]" />
<input type="text" name="myfield[5]" />
其中括号中的数字是来自 db(cookies 或其他来源)的 id。
当我处理这个表单时,我可以通过键(例如 1、4、5)从 $_POST['my field'] 数组中获取值。
我想知道,我怎样才能在 Django 中做同样的事情以及如何处理这样的多个字段? 我之前创建了一个复选框列表。在那里我可以将 id 存储在复选框字段的值中,但它不适用于文本字段,因为在值中我需要用户发送的值。
更新:
我是 Django 和 Python 的新手(几周前才开始使用 Django)。
楷模
from django.contrib.auth.models import User
class Order(models.Model):
category = models.ForeignKey(Category)
exhibition = models.ForeignKey(Exhibition)
user = models.ForeignKey(User)
date = models.DateField()
ordered = models.IntegerField()
class Exhibition(models.Model):
play = models.ForeignKey(Play)
date = models.DateTimeField()
class Category(models.Model):
name = models.CharField(max_length=30)
price = models.IntegerField()
total = models.IntegerField()
查看
from django.forms.models import modelformset_factory
from tickets.forms import CourierForm
def play_info_courier(request, pk):
data = get_object_or_404(Exhibition, pk=pk)
CourierFormSet = modelformset_factory(CourierForm, extra=0)
orders = Order.objects.filter(exhibition=data).values()
formset = CourierFormSet(initial=orders)
context = RequestContext(request, {'data': data, 'formset': formset})
return render_to_response('tickets/courier.html', context)
表格
class CourierForm(forms.ModelForm):
class Meta:
model = Order
html
<form method="post" action="">
{% csrf_token %}
{{ formset.management_form }}
<table class="table table-bordered table-hover">
{% for form in formset.forms %}
{% if forloop.first %}
<thead>
<tr>
{% for field in form %}
{% if field.name != 'id' %}
<th>{{ field.label|capfirst }}</th>
{% endif %}
{% endfor %}
</tr>
</thead>
{% endif %}
<tr>
<!-- here is my problem, how can I get username from User
or anything else from other related models? -->
<td>{{ form.user.username }}</td>
<td>{{ form.category.price }}</td>
<td>{{ form.date.value }}</td>
<td>{{ form.ordered }}</td>
</tr>
{% endfor %}
</table>
<input type="submit" name="order" value="Order"/>
<input type="submit" name="clean" value="Clean order"/>
</form>
请您参考如下方法:
在 Django 中,您使用 formsets实现这样的场景。
示例 View :
from django.shortcuts import render
from django import forms
from django.forms.formsets import formset_factory
class TestForm(forms.Form):
id = forms.IntegerField(label='id', widget=forms.HiddenInput)
value = forms.CharField(label='value')
TestFormSet = formset_factory(TestForm, extra=0)
def test(request):
if request.method == 'POST':
fs = TestFormSet(request.POST)
else:
fs = TestFormSet(initial=[
dict(id=1, value='foo'),
dict(id=4, value='bar'),
dict(id=5, value='baz'),
])
context = {
'fs': fs,
}
return render(request, 'formset/test.html', context)
formset/test.html 模板:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<form method="POST">{% csrf_token %}
{{ fs.management_form }}
{% for form in fs %}
{% for field in form %}
<div>{{ field }}</div>
{% endfor %}
<hr>
{% endfor %}
<button type="submit">Submit</button>
</form>
<hr>
{{ fs.cleaned_data }}
</body>
</html>
示例提交数据(fs.cleaned_data):
[
{
'id': 1,
'value': u'foo'
},
{
'id': 4,
'value': u'bar'
},
{
'id': 5,
'value': u'baz'
}
]
模型表单集
使用模型表单集,您 cannot generally supply the initial parameter正如您对常规表单集所做的那样 — initial 值将仅适用于 extra 表单,不适用于与模型的实际实例相关联的表单。
当你这样做时:
orders = Order.objects.filter(exhibition=data).values()
formset = CourierFormSet(initial=orders)
你可能是这个意思:
orders = Order.objects.filter(exhibition=data)
formset = CourierFormSet(queryset=orders)
这将为 Order.objects.filter(exhibition=data) 返回的所有实例实例化一个表单集。之后,表单集中的每个表单都会有一个 instance 属性,保存绑定(bind)到该表单的实际 Order 实例:
<td>{{ form.instance.user.username }}</td>
请注意,您的代码还有一些其他问题:
- 您只呈现表单集中的第一个表单,因为您在
{% if forloop.first %}block 中进行;这不太可能是您真正想要完成的。 - 您正在跳过表单的
id字段;这会将您提交的表单数据与您的初始模型实例分离——您希望将它们作为隐藏字段,这是在您呈现id字段时由表单集自动完成的。 modelformset_factory的第一个参数应该是 model 类,而不是表单类;你可能是说CourierFormSet = modelformset_factory(Order, form=CourierForm, extra=0)。
