如何覆盖django modelform以实现自定义行为
我有一个Item对象,它与另一个对象选项有很多关系。我从Item对象创建了一个modelform,如下所示如何覆盖django modelform以实现自定义行为,django,django-forms,Django,Django Forms,我有一个Item对象,它与另一个对象选项有很多关系。我从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=Tr
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', )
当我在模板中呈现表单时,它会呈现
项
对象(预期行为)的所有可用选项,甚至是那些不是由特定项创建的选项。我希望能够加载由用户选择的特定项定义的选项。如何重写表单以实现此类行为。例如,如果没有表单,我可以通过其id呈现项
自己的选项
。item=item.objects.get(pk=id)
很难动态定义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>
{{formset.management_form}
{formset%中表单的%s}
{{form.id}
{%if user_option.category%}
- {{form.caregory}}
{%endif%}
{%if user_option.name%}
- {{form.name}
{%endif%}
{%if user_option.p_opt%}
- {{form.price}}
- {{form.options}}
{%endif%}
{%endfor%}
从Djano文档中。尝试重写表单的init方法,并将项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)
这样做的好处是,您可以引发将在表单中显示的ValidationError
请注意,这不会阻止有人将不属于该项目的选项ID发布到您的表单中,因此您可能需要覆盖ModelForm.clean()以验证选项。从@jingo提供的链接中学习,我首先通过这样创建动态表单来解决问题
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))
然后像这样验证表单
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))
你能澄清你的问题吗?是否要动态实现由用户所需的选项定义的表单?或者只在用户定义的模型中放置一个特定的选项集?我认为在创建项目时@agconti的问题很好,我还指定了属于该项目的选项
。为什么要限制这些选项?例如,像咖啡这样的项目可能有大的或小的选项,像玉米煎饼这样的项目可能有牛排或鸡肉这样的选项。当我呈现表单时,它会呈现所有选项,这意味着咖啡会有大、小、牛排和鸡肉等选项,这是不对的。请看这里:。也许这是正确的方向。