2015-05-07 5 views
6

У меня есть форма, которая позволяет мне сначала выбрать тип продукта, а затем выбрать продукт. Поскольку у меня есть более 1000 продуктов, я использую следующее, чтобы отфильтровать список продуктов для повышения производительности.Django - Отключить проверку поля формы

У меня есть следующий inlineform в моем views.py

OrderLineFormSet = inlineformset_factory(OrderHeader, OrderLine, OrderLineForm, extra = 1) 

В моем forms.py я проверить, если есть уже продукт выбран. Если выбран продукт, я показываю только продукты с таким же типом продукта, чтобы повысить производительность загрузки. Если продукт пуст, он загрузит все параметры продукта, чтобы он сохранил форму после выбора.

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) 

Это приводит к следующей форме

enter image description here

Однако, когда я изменить тип продукта на существующем виде (а затем с помощью JQuery для обновления выпадающего меню Product) я получаю сообщение об ошибке экономии , Я знаю, это потому, что выбор не является вариантом в раскрывающемся списке.

enter image description here

Мой вопрос: Как я могу отключить эту ошибку, так что сохраняет возможность я выбран, независимо от исходных параметров.

Ниже вы найдете мой 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)) 
+0

Если у меня все получилось, у вас есть варианты в форме продукта. Когда вы меняете существующий заказ, выбирая новый тип продукта, он загружает новые Продукты, которые не представлены в старой форме продукта. Таким образом, он выдает ValidationError. В этом случае вам необходимо вручную обработать эту ситуацию и повторно использовать параметры формы продукта. – sobolevn

+0

, когда вы говорите, что используете JQuery для обновления продукта - что вы на самом деле делаете? Вы запускаете ajax для получения новых продуктов для заполнения выбранного? – professorDante

+0

Да - при изменении выпадающего списка типа продукта – phicon

ответ

5

Override ModelChoiceField, например:

class MyModelChoiceField(ModelChoiceField): 

    def to_python(self, value): 
     try: 
      value = super().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) 
+2

Это сработало, отличный ответ. Мне пришлось удалить try: value = super(). To_python (value) как это поднял и ошибка, и он отлично работает без него и, таким образом, меняет «except» на «if». – phicon

0

Вы должны изменить

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 событие и сделать его обновить поле продукта

0
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 фильтрами.

+0

Это то, что я изначально имел. Поскольку это фабрика форм, создающая несколько форм. Если бы я добавил 20 форм в набор, он бы загрузил 20 x 1000 продуктов в выпадающих меню. Это занимает много времени для загрузки. – phicon

Смежные вопросы