我有一个Item对象,它与另一个对象Option有很多关系。我从Item对象创建一个modelform,就像这样;
class Item(models.Model):
category = models.ForeignKey(Category)
name = models.CharField(max_length=200)
price = models.DecimalField(max_digits=9, decimal_places=2, blank=True, null=True)
options = models.ManyToManyField(Option)
class OptionForm(ModelForm):
options = forms.ChoiceField(widget=forms.RadioSelect())
class Meta:
model = Item
fields = ( 'options', )
当我在模板中呈现表单时,它会为options
对象(预期行为)呈现所有可用的Item
,甚至是那些不是由特定项创建的对象。我希望能够加载由用户选择的特定项目定义的options
。如何覆盖表单以实现此类行为。例如,如果没有表单,我可以通过其ID呈现Items
自己的Options
。 item = Item.objects.get(pk=id)
答案 0 :(得分:0)
很难在运行中定义ModelForm,因为它们与模型中的结构密切相关。不过,您可以使用一些聪明的模板控制流和视图渲染来获得所需的效果。这是未经测试的,因此您可能会因此而变化。
<form method="post" action="">
{{ formset.management_form }}
{% for form in formset %}
{{ form.id }}
<ul>
{% if user_option.category %}
<li>{{ form.caregory }}</li>
{% endif %}
{% if user_option.name %}
<li>{{ form.name }}</li>
{% endif %}
{% if user_option.p_opt %}
<li>{{ form.price }}</li>
<li>{{ form.options }}</li>
{% endif %}
</ul>
{% endfor %}
</form>
来自Djano docs here。
答案 1 :(得分:0)
尝试覆盖表单的init方法并传入Item pk作为附加参数。这里的技巧是在调用父init之前弹出参数。
class ItemOptionsForm(forms.ModelForm):
class Meta:
model = Item
def __init__(self, *args, **kwargs):
# pop 'item_id' as parent's init is not expecting it
item_id = kwargs.pop('item_id', None)
# now it's safe to call the parent init
super(ItemOptionsForm, self).__init__(*args, **kwargs)
# Limit options to only the item's options
if item_id:
try:
item = Item.objects.get(id=item_id)
except:
raise ValidationError('No item found!')
self.fields['options'] = forms.ChoiceField(item.options)
然后,在您的视图中,创建如下表单:
form = ItemOptionsForm(item_id=item_id)
关于这一点的好处是你可以提出将在表单中显示的ValidationErrors。
请注意,这不会阻止某人向您的表单发布不属于该项的选项ID,因此您可能希望覆盖ModelForm.clean()以验证选项。
答案 2 :(得分:0)
从@jingo提供的链接django: How to limit field choices in formset?学习,我通过首先创建动态表单来解决问题;
def partial_order_item_form(item):
"""dynamic form limiting optional_items to their items"""
class PartialOrderItemform(forms.Form):
quantity = forms.IntegerField(widget=forms.TextInput(attrs={'size':'2', 'class':'quantity','maxlength':'5'}))
option = forms.ModelChoiceField(queryset=OptionalItems.objects.filter(item=item),widget= forms.RadioSelect())
return PartialOrderItemform
然后验证表格;
def show_item(request,id):
option = get_object_or_404(Item,pk=id)
if request.method == 'POST':
form = partial_order_item_form(option)
#bound form to POST data,
final_form = form(request.POST)
# check validation of posted data
if final_form.is_valid():
order.add_to_order(request)
url =urlresolvers.reverse('order_index',kwargs={'id':a.id})
# redirect to order page
return HttpResponseRedirect(url)
else:
form = partial_order_item_form(item=id)
context={
'form':form,
}
return render_to_response('item.html',context,context_instance=RequestContext(request))