Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何覆盖django modelform以实现自定义行为_Django_Django Forms - Fatal编程技术网

如何覆盖django 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

我有一个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=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的问题很好,我还指定了属于该项目的
选项
。为什么要限制这些选项?例如,像咖啡这样的项目可能有大的或小的选项,像玉米煎饼这样的项目可能有牛排或鸡肉这样的选项。当我呈现表单时,它会呈现所有选项,这意味着咖啡会有大、小、牛排和鸡肉等选项,这是不对的。请看这里:。也许这是正确的方向。