2011-01-11 33 views
5

Tôi có một biểu mẫu mà tôi muốn cập nhật đối tượng MyModel. Trên mô hình có một ràng buộc unique_together, fieldA cùng với fieldB. Trong biểu mẫu trong phương thức sạch, tôi kiểm tra ràng buộc duy nhất này.trường bị vô hiệu hóa không được chuyển qua - cách giải quyết cần thiết

Vì một số lý do, tôi phải hiển thị trườngA là chỉ đọc trong bản cập nhật. Do đó fieldA không được truyền qua. Vấn đề của tôi là nếu biểu mẫu không xác thực, biểu mẫu được hiển thị lại, nhưng tôi đã mất giá trị trong trườngA.

Tôi đã cố gắng đặt lại clean_data ['fieldA'], nhưng nó không hoạt động. Bất kỳ ý tưởng nào cần thay đổi?

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(): 
      .... 

Trả lời

11

Tôi đã có một niềm vui nho nhỏ nhìn vào cách hình thành công trình và đã đưa ra nhiều giải pháp, chỉ dành riêng cho các heck của nó.

Vì bạn đang vô hiệu hóa tiện ích chứ không phải trường, theo như biểu mẫu liên quan, nó luôn không nhận được gì cho trườngA và điều đó sẽ luôn thất bại khi xác thực.

Thử phương thức clean() sẽ không trợ giúp cho biểu mẫu không hợp lệ vì dữ liệu clean() là để xử lý.

Dường như cách dữ liệu kéo biểu mẫu cho hiển thị HTML là field.data, gọi là field.widget.value_from_datadict(POST, FILES, field_name) để nó luôn xem dữ liệu POST của bạn.

Vì vậy, tôi nghĩ bạn có một vài tùy chọn. Hack request.POST, hack biểu mẫu nội bộ POST dữ liệu hoặc hack value_from_datadict.


Hacking request.POST: thẳng về phía trước, có ý nghĩa.

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(): 
       # ... 

Hacking điển nội bộ:

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

Hacking value_from_datadict: kinda vô lý, nhưng minh họa những gì bạn có thể học hỏi từ đào vào nguồn

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

học kinh nghiệm một số điều thú ở đây:) Hope nó giúp.

+0

hackign request.POST là giải pháp! cám ơn vì cái này! –

+1

Rất tốt, nhưng bạn sẽ làm gì trong trường hợp hộp kiểm. Ho làm bạn phân biệt giữa một hộp kiểm bị vô hiệu hóa hoặc bỏ chọn. –

+0

Tôi tìm thấy bằng cách sử dụng "chỉ đọc" cho phần tử đầu vào tốt hơn so với hacking POST hoặc ... http://www.w3schools.com/tags/att_input_readonly.asp –

0

Tôi gặp phải sự cố tương tự và đây là cách tôi giải quyết nó.

tôi đặt lĩnh vực như ẩn:

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

Trong mẫu tôi hiển thị giá trị trường riêng biệt:

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

Trong trường hợp fieldA là một chọn menu:

{{ 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

Bạn có thể đặt nó trong các lớp mẫu như thế này:

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) 

Cách hoạt động, là nó kiểm tra để xem liệu có bất kỳ dữ liệu nào đã được chuyển cho hàm tạo của biểu mẫu hay không. Nếu nó có, nó sao chép nó (dữ liệu chưa được kiểm tra là không thay đổi) và sau đó đặt giá trị ban đầu vào trước khi tiếp tục khởi tạo biểu mẫu.

+0

Trong khi liên kết này có thể trả lời câu hỏi, tốt hơn nên bao gồm các phần thiết yếu của câu trả lời ở đây và cung cấp liên kết để tham khảo. Câu trả lời chỉ liên kết có thể trở thành không hợp lệ nếu trang được liên kết thay đổi. –

+0

Ok, tôi đã chỉnh sửa nó để nó có toàn bộ câu trả lời. – seddonym

0

Tôi giải quyết vấn đề này mà không cần chạm vào phần phụ trợ, tất cả những gì bạn cần là thêm lớp cụ thể vào trường của bạnA trong forms.py với thuộc tính 'hiển thị: ẩn'.

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

sau đó, trong các mẫu form.fieldA của bạn sẽ được ẩn nhưng không mất đi trong bài yêu cầu

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

vì vậy bạn vẫn sẽ có form.fieldA của bạn trong dữ liệu mẫu yêu cầu. Và trực quan trường của bạn sẽ luôn được điền bằng form.fieldA.value.

0

Tôi đã phải giải quyết một vấn đề tương tự, tôi đã sử dụng như hình thức dinamyc để tạo hàng mới vì vậy khi bạn chọn sản phẩm được hiển thị là bị vô hiệu hóa, nhưng cần lấy giá trị trên biểu mẫu trong chế độ xem, tôi đoán Jquery và JavaScript đã dễ dàng hơn cho tôi, vì vậy tôi tạo ra một sự kiện trước khi gửi loại bỏ các khuyết tật trên bộ chọn mà tôi sử dụng trong formets của tôi tôi đã sử dụng widget select2 cho thiết lập này để nó hoạt động với select2 quá:

Tất nhiên nút gửi id = "postForm" và id của id mẫu = "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

Tôi đã sử dụng j Truy vấn để giải quyết vấn đề bằng cách xóa bị vô hiệu hóa khỏi tất cả các yếu tố đầu vào trước khi gửi.

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

Used answer from another SO answer

Các vấn đề liên quan