Django - 禁用表单 select 字段验证
Django - Disable form select field validation
我有一个表格,可以让我先 select 产品类型,然后 select 产品。因为我有 1000 多种产品,所以我使用以下方法过滤产品列表以提高性能。
我的 views.py
中有以下内联表单
OrderLineFormSet = inlineformset_factory(OrderHeader, OrderLine, OrderLineForm, extra = 1)
在我的 forms.py 中,我检查是否已经有一个产品 selected。如果有产品 selected 我只显示具有相同产品类型的产品以提高加载性能。如果产品为空,它将加载所有产品选项,这样我就可以在 selection.
之后保存表格
class OrderLineForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(OrderLineForm, self).__init__(*args, **kwargs)
self.helper = FormHelper(self)
self.helper.form_show_errors = True
self.helper.error_text_inline = False
if self.instance.product is not None:
self.fields['product'] = forms.ModelChoiceField(queryset=Product.objects.filter(product_type_id=self.instance.product_type_id), required=False)
结果如下
但是,当我更改现有表单上的产品类型(然后使用 jQuery 更新产品下拉列表)时,我得到了保存错误。我知道这是因为 selection 不是下拉列表中的选项。
我的问题:我如何禁用此错误,以便它保存我 selected 的选项,而不考虑原始选项。
您会在下方找到我的 views.py 表格
def orderline_formset(request, id=None):
OrderLineFormSet = inlineformset_factory(OrderHeader, OrderLine, OrderLineForm, extra = 1)
orderheader = None
orderid = None
orderheaderid = 0
if id:
orderid = OrderHeader.objects.get(pk=id)
if request.POST:
if orderid:
form = OrderHeaderForm(request.POST, instance=orderid)
formset = OrderLineFormSet(request.POST,instance=orderid)
else:
form = OrderHeaderForm(request.POST)
formset = OrderLineFormSet(request.POST)
if form.is_valid() and formset.is_valid():
if orderid:
form.save() # update object
else:
orderid = form.save() # create object
formset.instance = orderid
formset.save()
messages.success(request, 'Order saved succesfully!')
return HttpResponseRedirect('/orderline_formset/' + str(orderid.pk))
else: # form invalid
messages.error(request, 'Order save error, please check mandatory fields')
else: # request.GET
if orderid:
invoiceheader = ""
if orderid.orderheader_invoice:
invoiceheader = " -- Invoice " + str(orderid.orderheader_invoice)
orderheader = "Order " + str(orderid.pk) + invoiceheader
orderheaderid = orderid.pk
form = OrderHeaderForm(instance=orderid)
formset = OrderLineFormSet(instance=orderid)
else:
orderheader = "New Order"
orderheaderid = 0
form = OrderHeaderForm(instance=OrderHeader())
formset = OrderLineFormSet(instance=OrderHeader())
return render_to_response("order-add.html", {'form' : form,'formset': formset,
'orderheader': orderheader,
'orderheaderid': orderheaderid},
context_instance=RequestContext(request))
你必须改变
self.fields['product'] = forms.ModelChoiceField(queryset=Product.objects.filter(product_type_id=self.instance.product_type_id), required=False)
到
self.fields['product'] = forms.ModelChoiceField(queryset=Product.objects.all(), required=False)
但您已经知道并且出于性能原因不想要它,因此您的其他解决方案是将其更改为
self.fields['product'] = ModelChoiceField(queryset=Product.objects.all(), widget=forms.HiddenInput, required=False)
然后在模板中手动构造 <select>
标签并使用 JS 处理 onchange
事件并使其更新产品字段
覆盖ModelChoiceField
,例如:
class MyModelChoiceField(ModelChoiceField):
def to_python(self, value):
try:
value = super(MyModelChoiceField, self).to_python(value)
except self.queryset.model.DoesNotExist:
key = self.to_field_name or 'pk'
value = Product.objects.filter(**{key: value})
if not value.exists():
raise ValidationError(self.error_messages['invalid_choice'], code='invalid_choice')
else:
value= value.first()
return value
并在您的表单中使用它。
self.fields['product'] = MyModelChoiceField(queryset=Product.objects.filter(product_type_id=self.instance.product_type_id), required=False)
class OrderLineForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(OrderLineForm, self).__init__(*args, **kwargs)
self.helper = FormHelper(self)
self.helper.form_show_errors = True
self.helper.error_text_inline = False
self.fields['product'] = forms.ModelChoiceField(
queryset=Product.objects.all())
self.fields['product'].required = False
在此之后,您可以使用 jquery 个过滤器过滤 select。
更新@ruddra 对 Django 1.11 的回答:
class DynamicModelChoiceField(ModelChoiceField):
def to_python(self, value):
try:
value = super().to_python(value)
except ValidationError:
key = self.to_field_name or 'pk'
value = self.queryset.model.objects.filter(**{key: value})
if not value.exists():
raise
value = value.first()
return value
我有一个表格,可以让我先 select 产品类型,然后 select 产品。因为我有 1000 多种产品,所以我使用以下方法过滤产品列表以提高性能。
我的 views.py
中有以下内联表单OrderLineFormSet = inlineformset_factory(OrderHeader, OrderLine, OrderLineForm, extra = 1)
在我的 forms.py 中,我检查是否已经有一个产品 selected。如果有产品 selected 我只显示具有相同产品类型的产品以提高加载性能。如果产品为空,它将加载所有产品选项,这样我就可以在 selection.
之后保存表格class OrderLineForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(OrderLineForm, self).__init__(*args, **kwargs)
self.helper = FormHelper(self)
self.helper.form_show_errors = True
self.helper.error_text_inline = False
if self.instance.product is not None:
self.fields['product'] = forms.ModelChoiceField(queryset=Product.objects.filter(product_type_id=self.instance.product_type_id), required=False)
结果如下
但是,当我更改现有表单上的产品类型(然后使用 jQuery 更新产品下拉列表)时,我得到了保存错误。我知道这是因为 selection 不是下拉列表中的选项。
我的问题:我如何禁用此错误,以便它保存我 selected 的选项,而不考虑原始选项。
您会在下方找到我的 views.py 表格
def orderline_formset(request, id=None):
OrderLineFormSet = inlineformset_factory(OrderHeader, OrderLine, OrderLineForm, extra = 1)
orderheader = None
orderid = None
orderheaderid = 0
if id:
orderid = OrderHeader.objects.get(pk=id)
if request.POST:
if orderid:
form = OrderHeaderForm(request.POST, instance=orderid)
formset = OrderLineFormSet(request.POST,instance=orderid)
else:
form = OrderHeaderForm(request.POST)
formset = OrderLineFormSet(request.POST)
if form.is_valid() and formset.is_valid():
if orderid:
form.save() # update object
else:
orderid = form.save() # create object
formset.instance = orderid
formset.save()
messages.success(request, 'Order saved succesfully!')
return HttpResponseRedirect('/orderline_formset/' + str(orderid.pk))
else: # form invalid
messages.error(request, 'Order save error, please check mandatory fields')
else: # request.GET
if orderid:
invoiceheader = ""
if orderid.orderheader_invoice:
invoiceheader = " -- Invoice " + str(orderid.orderheader_invoice)
orderheader = "Order " + str(orderid.pk) + invoiceheader
orderheaderid = orderid.pk
form = OrderHeaderForm(instance=orderid)
formset = OrderLineFormSet(instance=orderid)
else:
orderheader = "New Order"
orderheaderid = 0
form = OrderHeaderForm(instance=OrderHeader())
formset = OrderLineFormSet(instance=OrderHeader())
return render_to_response("order-add.html", {'form' : form,'formset': formset,
'orderheader': orderheader,
'orderheaderid': orderheaderid},
context_instance=RequestContext(request))
你必须改变
self.fields['product'] = forms.ModelChoiceField(queryset=Product.objects.filter(product_type_id=self.instance.product_type_id), required=False)
到
self.fields['product'] = forms.ModelChoiceField(queryset=Product.objects.all(), required=False)
但您已经知道并且出于性能原因不想要它,因此您的其他解决方案是将其更改为
self.fields['product'] = ModelChoiceField(queryset=Product.objects.all(), widget=forms.HiddenInput, required=False)
然后在模板中手动构造 <select>
标签并使用 JS 处理 onchange
事件并使其更新产品字段
覆盖ModelChoiceField
,例如:
class MyModelChoiceField(ModelChoiceField):
def to_python(self, value):
try:
value = super(MyModelChoiceField, self).to_python(value)
except self.queryset.model.DoesNotExist:
key = self.to_field_name or 'pk'
value = Product.objects.filter(**{key: value})
if not value.exists():
raise ValidationError(self.error_messages['invalid_choice'], code='invalid_choice')
else:
value= value.first()
return value
并在您的表单中使用它。
self.fields['product'] = MyModelChoiceField(queryset=Product.objects.filter(product_type_id=self.instance.product_type_id), required=False)
class OrderLineForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(OrderLineForm, self).__init__(*args, **kwargs)
self.helper = FormHelper(self)
self.helper.form_show_errors = True
self.helper.error_text_inline = False
self.fields['product'] = forms.ModelChoiceField(
queryset=Product.objects.all())
self.fields['product'].required = False
在此之后,您可以使用 jquery 个过滤器过滤 select。
更新@ruddra 对 Django 1.11 的回答:
class DynamicModelChoiceField(ModelChoiceField):
def to_python(self, value):
try:
value = super().to_python(value)
except ValidationError:
key = self.to_field_name or 'pk'
value = self.queryset.model.objects.filter(**{key: value})
if not value.exists():
raise
value = value.first()
return value