2011-01-11 2 views
5

У меня есть форма, с которой я хочу обновить объект MyModel. На модели существует единственное ограничение типа fieldA вместе с полем B. В форме в чистом методе я проверяю это уникальное ограничение.отключенное поле не проходит - обходной путь

По некоторым причинам я должен показать fieldA как только в обновлении. Таким образом, поле А не проходит. Моя проблема в том, что если форма не проверяется, форма повторно отображается, но я потерял значение в поле А.

Я попытался сбросить cleaned_data ['fieldA'], но он не работает. Любая идея, что изменить?

Forms.py

class MyModelUpdateForm(forms.ModelForm): 
    class Meta: 
     model = MyModel 

    def __init__(self, *args, **kwargs): 
     super(MyModelUpdateForm, self).__init__(*args, **kwargs) 
     self.fields['fieldA'].widget.attrs['readonly'] = True 
     self.fields['fieldA'].widget.attrs['disabled'] = True 

    def clean(self): 
     cleaned_data = self.cleaned_data 
     fieldA= self.instance.fieldA 
     fieldB = cleaned_data.get("fieldB") 

     if MyModel.objects.filter(fieldA=fieldA, fieldB=fieldB).count() > 0: 
      #try to reset fieldA, since it is not passed through, since it is disabled 
      cleaned_data['fieldA'] = fieldA.pk #does not work 
      raise forms.ValidationError('some unique validation error') 
     return cleaned_data 

Views.py:

myModelobject = get_object_or_404(MyModel.objects, pk=mymodel_id) 

    if request.method == 'POST': 
     model_form = MyModelUpdateForm(request.POST, instance=myModelobject) 

     if model_form .is_valid(): 
      .... 

ответ

11

У меня было немного весело глядя, как формы работы и придумал несколько решений, просто ради этого.

Поскольку вы отключите виджет, а не поле, то насколько это касается формы, он всегда ничего не получает для поля A, и это всегда приведет к отказу.

Попытка что-то в методе clean() не поможет для недопустимых форм, поскольку данные clean() предназначены для обработки.

Похоже на то, как данные формы извлекают данные для отображения HTML: field.data, что является вызовом field.widget.value_from_datadict(POST, FILES, field_name), поэтому он всегда будет смотреть ваши данные POST.

Так что, я думаю, у вас есть несколько вариантов. Hack request.POST, взломать данные POST внутренней формы или взломать value_from_datadict.


Взлом request.POST: прямолинейный, имеет смысл.

myModelobject = get_object_or_404(MyModel.objects, pk=mymodel_id) 

     if request.method == 'POST': 
      POST = request.POST.copy() 
      POST['fieldA'] = myModelobject.fieldA 
      model_form = MyModelUpdateForm(POST, instance=myModelobject) 

      if model_form .is_valid(): 
       # ... 

Взлом внутренний словарь:

def __init__(self, *args, **kwargs): 
    super(MyModelUpdateForm, self).__init__(*args, **kwargs) 
    self.data.update({ 'fieldA': self.instance.fieldA }) 

хакерство value_from_datadict: вроде смешно, но показывает, что вы можете узнать из копаться в источнике

def __init__(self, *args, **kwargs): 
    super(MyModelUpdateForm, self).__init__(*args, **kwargs) 
    self.fields['fieldA'].widget.value_from_datadict = lambda *args: self.instance.first_name 

Изученного некоторые интересные вещи здесь:) Надежда помогает.

+0

hackign request.POST было решение! Спасибо за это! –

+1

Ничего, но что вы будете делать в случае флажков. Хо, вы различаете флажок, который отключен или не установлен. –

+0

Я нашел использование «readonly» для элемента ввода лучше, чем взломать POST или ... http://www.w3schools.com/tags/att_input_readonly.asp –

0

Я столкнулся с подобной проблемой, и вот как я ее решил.

Я установил поле скрытых:

self.fields['fieldA'].widget.attrs['style'] = 'display:none;' 

В шаблоне я показываю значение поля отдельно:

{{ form.fieldA.label_tag }} 
{{ form.fieldA }} 
{{ form.fieldA.value }} 
{{ form.fieldA.errors }} 

В случае FieldA является меню выбора:

{{ form.fieldA.label_tag }} 
{{ form.fieldA }} 
{% for value, title in form.fields.fieldA.choices %} 
    {% if value == form.fieldA.value %} 
     {{ title }} 
    {% endif %} 
{% endfor %} 
{{ form.fieldA.errors }} 
1

Вы можете положите его в класс вида следующим образом:

class MyForm(forms.Form): 

    MY_VALUE = 'SOMETHING' 
    myfield = forms.CharField(
     initial=MY_VALUE, 
     widget=forms.TextInput(attrs={'disabled': 'disabled'}) 

    def __init__(self, *args, **kwargs): 

     # If the form has been submitted, populate the disabled field 
     if 'data' in kwargs: 
      data = kwargs['data'].copy() 
      self.prefix = kwargs.get('prefix') 
      data[self.add_prefix('myfield')] = MY_VALUE 
      kwargs['data'] = data 

     super(MyForm, self).__init__(*args, **kwargs) 

Как это работает, проверяются ли какие-либо данные в конструкторе формы. Если он есть, он копирует его (необработанные данные неизменяемы), а затем помещает начальное значение в значение, прежде чем продолжать создавать экземпляр формы.

+0

Хотя эта ссылка может ответить на вопрос, лучше включить основные части ответа здесь и предоставить ссылку для справки. Ответные ссылки могут стать недействительными, если связанная страница изменится. –

+0

Хорошо, я отредактировал его, чтобы он получил весь ответ. – seddonym

0

Я решил такую ​​проблему, не касаясь бэкэнд-части, все, что вам нужно, это добавить определенный класс к вашему полюA в forms.py с свойством «видимость: скрытый».

self.fields['fieldA'].widget.attrs['class'] = 'visibility_hidden_class' 

затем, в шаблоне вашего form.fieldA будет скрыт, но не потерял в запросе после

{{ form.fieldA.label_tag }} 
{{ form.fieldA }} 
<input type="text" value="{{ form.fieldA.value }}" disabled /> 

так что вы все еще есть form.fieldA в данной форме запроса. И визуально ваше поле всегда будет заполнено с помощью form.fieldA.value.

0

Мне пришлось решить подобную проблему, я использовал, как dinamyc formset, для создания новой строки, поэтому, как только вы выбираете продукт, он был показан как отключенный, но нужно получить значение в форме в представлении, я думаю, JQuery и JavaScript был проще для меня, поэтому я генерирую предварительное событие, удаляя отключенное на селекторе, которое я использую в своих наборах форм. Я использовал виджет select2 для этой настройки, поэтому он также работает с select2:

Конечно кнопка отправки ID = "postForm" и идентификатор вида ид = "contractForm"

$('#postForm').click(function(e){ 
      e.preventDefault(); 
      $('select[id^="id_p_v"][id$="product"]').each(function(){ 
       // getIdNumber returns the digit value from id_field-n- in formset value 
       // p_v was the prefix of fomset 
       var id = getIdNumber($(this).attr('id')); 
       // I have an empty form for new forms so skip that one actually on send doesn't matter really. (form POST) but anyway skip 
       if(id != null){ 
        $(this).prop("disabled", false); 
       } 
      }); 
      $('#contractForm').submit(); 
      }); 
1

я использовал J Запрос для решения проблемы путем удаления отключенных от всех входов перед отправкой.

$('#my_form').submit(function(){ 
    $("#my_form :disabled").removeAttr('disabled'); 
}); 

Used answer from another SO answer

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